1 /*
2 Copyright (c) 2012, Broadcom Europe Ltd
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above copyright
10       notice, this list of conditions and the following disclaimer in the
11       documentation and/or other materials provided with the distribution.
12     * Neither the name of the copyright holder nor the
13       names of its contributors may be used to endorse or promote products
14       derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 /*=============================================================================
29 Copyright (c) 2008 Broadcom Europe Limited.
30 All rights reserved.
31 
32 Project  :  khronos
33 Module   :  VG client
34 
35 FILE DESCRIPTION
36 VG client-side function definitions. Dispatches VG calls via RPC or direct
37 call. Some functions require support for control messages just over 1kB in
38 length, 2kB should be fine for all functions.
39 =============================================================================*/
40 
41 /*
42    Potential spec bugs:
43 
44    vgImageSubData, vgGetImageSubData, vgWritePixels, and vgReadPixels require
45       the data pointer to be aligned, but do not require the stride to be
46       aligned. This seems a little useless, so we require that both the pointer
47       and stride are aligned (unless height is 1, in which case we just require
48       that the pointer is aligned)
49 */
50 
51 #define VG_VGEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
52 
53 #include "interface/khronos/common/khrn_client_mangle.h"
54 #include "interface/khronos/common/khrn_int_common.h"
55 
56 #include "interface/khronos/common/khrn_client_platform.h"
57 #include "interface/khronos/common/khrn_client_rpc.h"
58 #include "interface/khronos/vg/vg_client.h"
59 
60 #include "interface/khronos/egl/egl_client_config.h"
61 
62 #include "interface/khronos/common/khrn_int_color.h"
63 #include "interface/khronos/common/khrn_int_math.h"
64 #include "interface/khronos/common/khrn_int_util.h"
65 
66 #include "interface/khronos/include/VG/openvg.h"
67 #include "interface/khronos/include/VG/vgext.h"
68 #include "interface/khronos/include/VG/vgu.h"
69 
70 #include "interface/khronos/vg/vg_int_config.h"
71 #include "interface/khronos/vg/vg_int_mat3x3.h"
72 #ifdef RPC_DIRECT
73    #include "interface/khronos/vg/vg_int_impl.h" /* for _impl function calls */
74 #endif
75 #if defined(WIN32) || defined(__mips__)
76 #include "interface/khronos/common/khrn_int_misc_impl.h"
77 #endif
78 
79 #include "interface/khronos/vg/vg_int_util.h"
80 
81 #include <stdlib.h>
82 #include <string.h>
83 
84 /******************************************************************************
85 shared state
86 ******************************************************************************/
87 
vg_client_shared_state_alloc(void)88 VG_CLIENT_SHARED_STATE_T *vg_client_shared_state_alloc(void)
89 {
90    VG_CLIENT_SHARED_STATE_T *shared_state;
91    KHR_STATUS_T status;
92 
93    shared_state = (VG_CLIENT_SHARED_STATE_T *)khrn_platform_malloc(sizeof(VG_CLIENT_SHARED_STATE_T), "VG_CLIENT_SHARED_STATE_T");
94    if (!shared_state) {
95       return NULL;
96    }
97 
98    status = platform_mutex_create(&shared_state->mutex);
99    if (status != KHR_SUCCESS) {
100       khrn_platform_free(shared_state);
101       return NULL;
102    }
103 
104    if (!khrn_pointer_map_init(&shared_state->objects, 128)) {
105       platform_mutex_destroy(&shared_state->mutex);
106       khrn_platform_free(shared_state);
107       return NULL;
108    }
109 
110    shared_state->ref_count = 1;
111    shared_state->stems_count = 0;
112 
113    return shared_state;
114 }
115 
116 static void object_free(void *object);
117 
object_free_callback(KHRN_POINTER_MAP_T * pointer_map,uint32_t key,void * object,void * data)118 static void object_free_callback(KHRN_POINTER_MAP_T *pointer_map, uint32_t key, void *object, void *data)
119 {
120    UNUSED(pointer_map);
121    UNUSED(key);
122    UNUSED(data);
123 
124    object_free(object);
125 }
126 
vg_client_shared_state_free(VG_CLIENT_SHARED_STATE_T * shared_state)127 void vg_client_shared_state_free(VG_CLIENT_SHARED_STATE_T *shared_state)
128 {
129    vcos_assert(shared_state->ref_count == 0);
130    khrn_pointer_map_iterate(&shared_state->objects, object_free_callback, NULL);
131    khrn_pointer_map_term(&shared_state->objects);
132    platform_mutex_destroy(&shared_state->mutex);
133    khrn_platform_free(shared_state);
134 }
135 
136 /******************************************************************************
137 state
138 ******************************************************************************/
139 
vg_client_state_alloc(VG_CLIENT_SHARED_STATE_T * shared_state)140 VG_CLIENT_STATE_T *vg_client_state_alloc(VG_CLIENT_SHARED_STATE_T *shared_state)
141 {
142    VGuint i;
143 
144    VG_CLIENT_STATE_T *state = (VG_CLIENT_STATE_T *)khrn_platform_malloc(sizeof(VG_CLIENT_STATE_T), "VG_CLIENT_STATE_T");
145    if (!state) {
146       return NULL;
147    }
148 
149    vg_client_shared_state_acquire(shared_state);
150    state->shared_state = shared_state;
151 
152    state->render_callback = NULL;
153    state->flush_callback = NULL;
154 
155    state->matrix_mode = VG_MATRIX_PATH_USER_TO_SURFACE;
156    for (i = 0; i != ARR_COUNT(state->matrices); ++i) {
157       vg_mat3x3_set_identity(&state->matrices[i].client);
158       vg_mat3x3_set_identity(&state->matrices[i].server);
159    }
160 
161    state->fill_rule = VG_EVEN_ODD;
162    state->stroke_line_width = 1.0f;
163    state->stroke_cap_style = VG_CAP_BUTT;
164    state->stroke_join_style = VG_JOIN_MITER;
165    state->stroke_miter_limit = 4.0f;
166    state->stroke_dash_pattern_count = 0;
167    state->stroke_dash_phase = 0.0f;
168    state->stroke_dash_phase_reset = false;
169    state->image_quality = VG_IMAGE_QUALITY_FASTER;
170    state->image_mode = VG_DRAW_IMAGE_NORMAL;
171 
172    state->scissoring = false;
173    state->scissor_rects_count = 0;
174 
175    state->rendering_quality = VG_RENDERING_QUALITY_BETTER;
176 
177    state->fill_paint = VG_INVALID_HANDLE;
178    state->stroke_paint = VG_INVALID_HANDLE;
179    state->tile_fill_color[0] = 0.0f;
180    state->tile_fill_color[1] = 0.0f;
181    state->tile_fill_color[2] = 0.0f;
182    state->tile_fill_color[3] = 0.0f;
183    state->clear_color[0] = 0.0f;
184    state->clear_color[1] = 0.0f;
185    state->clear_color[2] = 0.0f;
186    state->clear_color[3] = 0.0f;
187 
188    state->color_transform = false;
189    state->color_transform_values[0] = 1.0f;
190    state->color_transform_values[1] = 1.0f;
191    state->color_transform_values[2] = 1.0f;
192    state->color_transform_values[3] = 1.0f;
193    state->color_transform_values[4] = 0.0f;
194    state->color_transform_values[5] = 0.0f;
195    state->color_transform_values[6] = 0.0f;
196    state->color_transform_values[7] = 0.0f;
197 
198    state->blend_mode = VG_BLEND_SRC_OVER;
199    state->masking = false;
200 
201    state->filter_format_linear = false;
202    state->filter_format_pre = false;
203    state->filter_channel_mask = VG_RED | VG_GREEN | VG_BLUE | VG_ALPHA;
204 
205    state->pixel_layout = VG_PIXEL_LAYOUT_UNKNOWN;
206 
207    return state;
208 }
209 
vg_client_state_free(VG_CLIENT_STATE_T * state)210 void vg_client_state_free(VG_CLIENT_STATE_T *state)
211 {
212    vg_client_shared_state_release(state->shared_state);
213    khrn_platform_free(state);
214 }
215 
216 /******************************************************************************
217 helpers
218 ******************************************************************************/
219 
clear_error(void)220 static void clear_error(void)
221 {
222    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
223    RPC_CALL0(vgClearError_impl,
224              thread,
225              VGCLEARERROR_ID);
226 }
227 
set_error(VGErrorCode error)228 static void set_error(VGErrorCode error)
229 {
230    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
231    RPC_CALL1(vgSetError_impl,
232              thread,
233              VGSETERROR_ID,
234              RPC_ENUM(error));
235 }
236 
get_error(void)237 static VGErrorCode get_error(void)
238 {
239    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
240    return (VGErrorCode)RPC_ENUM_RES(RPC_CALL0_RES(vgGetError_impl,
241                                                   thread,
242                                                   VGGETERROR_ID));
243 }
244 
is_aligned(const void * p,VGuint alignment)245 static INLINE bool is_aligned(const void *p, VGuint alignment)
246 {
247    vcos_assert(is_power_of_2(alignment));
248    return ((uintptr_t)p & (alignment - 1)) == 0;
249 }
250 
is_aligned_float(const VGfloat * p)251 static INLINE bool is_aligned_float(const VGfloat *p)
252 {
253    return is_aligned(p, alignof(VGfloat));
254 }
255 
is_aligned_short(const VGshort * p)256 static INLINE bool is_aligned_short(const VGshort *p)
257 {
258    return is_aligned(p, alignof(VGshort));
259 }
260 
is_aligned_int(const VGint * p)261 static INLINE bool is_aligned_int(const VGint *p)
262 {
263    return is_aligned(p, alignof(VGint));
264 }
265 
is_aligned_uint(const VGuint * p)266 static INLINE bool is_aligned_uint(const VGuint *p)
267 {
268    return is_aligned(p, alignof(VGuint));
269 }
270 
is_aligned_path_datatype(const void * p,VGPathDatatype path_datatype)271 static bool is_aligned_path_datatype(const void *p, VGPathDatatype path_datatype)
272 {
273    switch (path_datatype) {
274    case VG_PATH_DATATYPE_S_8:  return true;
275    case VG_PATH_DATATYPE_S_16: return is_aligned_short((const VGshort *)p);
276    case VG_PATH_DATATYPE_S_32: return is_aligned_int((const VGint *)p);
277    case VG_PATH_DATATYPE_F:    return is_aligned_float((const VGfloat *)p);
278    default:                    UNREACHABLE(); return false;
279    }
280 }
281 
is_aligned_image_format(const void * p,VGImageFormat image_format)282 static bool is_aligned_image_format(const void *p, VGImageFormat image_format)
283 {
284    switch (image_format) {
285    case VG_sRGBX_8888:
286    case VG_sRGBA_8888:
287    case VG_sRGBA_8888_PRE:
288    case VG_lRGBX_8888:
289    case VG_lRGBA_8888:
290    case VG_lRGBA_8888_PRE:
291    case VG_sXRGB_8888:
292    case VG_sARGB_8888:
293    case VG_sARGB_8888_PRE:
294    case VG_lXRGB_8888:
295    case VG_lARGB_8888:
296    case VG_lARGB_8888_PRE:
297    case VG_sBGRX_8888:
298    case VG_sBGRA_8888:
299    case VG_sBGRA_8888_PRE:
300    case VG_lBGRX_8888:
301    case VG_lBGRA_8888:
302    case VG_lBGRA_8888_PRE:
303    case VG_sXBGR_8888:
304    case VG_sABGR_8888:
305    case VG_sABGR_8888_PRE:
306    case VG_lXBGR_8888:
307    case VG_lABGR_8888:
308    case VG_lABGR_8888_PRE:
309       return is_aligned_uint((const VGuint *)p);
310    case VG_sRGB_565:
311    case VG_sRGBA_5551:
312    case VG_sRGBA_4444:
313    case VG_sARGB_1555:
314    case VG_sARGB_4444:
315    case VG_sBGR_565:
316    case VG_sBGRA_5551:
317    case VG_sBGRA_4444:
318    case VG_sABGR_1555:
319    case VG_sABGR_4444:
320       return is_aligned_short((const VGshort *)p);
321    case VG_sL_8:
322    case VG_lL_8:
323    case VG_A_8:
324    case VG_BW_1:
325    case VG_A_1:
326    case VG_A_4:
327       return true;
328    default:
329       UNREACHABLE();
330       return false;
331    }
332 }
333 
contains_illegal_segment(const VGubyte * segments,VGint segments_count)334 static bool contains_illegal_segment(const VGubyte *segments, VGint segments_count)
335 {
336    for (; segments_count != 0; ++segments, --segments_count) {
337       switch (*segments & ~VG_RELATIVE) {
338       case VG_CLOSE_PATH: break;
339       case VG_MOVE_TO:    break;
340       case VG_LINE_TO:    break;
341       case VG_HLINE_TO:   break;
342       case VG_VLINE_TO:   break;
343       case VG_QUAD_TO:    break;
344       case VG_CUBIC_TO:   break;
345       case VG_SQUAD_TO:   break;
346       case VG_SCUBIC_TO:  break;
347       case VG_SCCWARC_TO: break;
348       case VG_SCWARC_TO:  break;
349       case VG_LCCWARC_TO: break;
350       case VG_LCWARC_TO:  break;
351       default:            return true;
352       }
353    }
354    return false;
355 }
356 
get_coords_count(const VGubyte * segments,VGint segments_count)357 static VGuint get_coords_count(const VGubyte *segments, VGint segments_count)
358 {
359    VGuint coords_count = 0;
360    for (; segments_count != 0; ++segments, --segments_count) {
361       coords_count += get_segment_coords_count(*segments & ~VG_RELATIVE);
362    }
363    return coords_count;
364 }
365 
normalise_segment(VGuint segment)366 static VGuint normalise_segment(VGuint segment)
367 {
368    switch (segment) {
369    case VG_CLOSE_PATH: return VG_CLOSE_PATH;
370    case VG_MOVE_TO:    return VG_MOVE_TO;
371    case VG_LINE_TO:    return VG_LINE_TO;
372    case VG_HLINE_TO:   return VG_LINE_TO;
373    case VG_VLINE_TO:   return VG_LINE_TO;
374    case VG_QUAD_TO:    return VG_CUBIC_TO;
375    case VG_CUBIC_TO:   return VG_CUBIC_TO;
376    case VG_SQUAD_TO:   return VG_CUBIC_TO;
377    case VG_SCUBIC_TO:  return VG_CUBIC_TO;
378 
379    /*
380       on the client-side, we don't care about the different arc types, just
381       normalise them all to the same type
382    */
383 
384    case VG_SCCWARC_TO: return VG_SCCWARC_TO;
385    case VG_SCWARC_TO:  return VG_SCCWARC_TO;
386    case VG_LCCWARC_TO: return VG_SCCWARC_TO;
387    case VG_LCWARC_TO:  return VG_SCCWARC_TO;
388    default:            UNREACHABLE(); return 0;
389    }
390 }
391 
interpolate_segments_compatible(const VGubyte * begin_segments,const VGubyte * end_segments,VGuint segments_count)392 static bool interpolate_segments_compatible(const VGubyte *begin_segments, const VGubyte *end_segments, VGuint segments_count)
393 {
394    for (; segments_count != 0; ++begin_segments, ++end_segments, --segments_count) {
395       if (normalise_segment(*begin_segments & ~VG_RELATIVE) != normalise_segment(*end_segments & ~VG_RELATIVE)) {
396          return false;
397       }
398    }
399    return true;
400 }
401 
402 #ifndef RPC_DIRECT
403 
get_log2_image_format_bpp(VGImageFormat image_format)404 static VGuint get_log2_image_format_bpp(VGImageFormat image_format)
405 {
406    switch (image_format) {
407    case VG_sRGBX_8888:
408    case VG_sRGBA_8888:
409    case VG_sRGBA_8888_PRE:
410    case VG_lRGBX_8888:
411    case VG_lRGBA_8888:
412    case VG_lRGBA_8888_PRE:
413    case VG_sXRGB_8888:
414    case VG_sARGB_8888:
415    case VG_sARGB_8888_PRE:
416    case VG_lXRGB_8888:
417    case VG_lARGB_8888:
418    case VG_lARGB_8888_PRE:
419    case VG_sBGRX_8888:
420    case VG_sBGRA_8888:
421    case VG_sBGRA_8888_PRE:
422    case VG_lBGRX_8888:
423    case VG_lBGRA_8888:
424    case VG_lBGRA_8888_PRE:
425    case VG_sXBGR_8888:
426    case VG_sABGR_8888:
427    case VG_sABGR_8888_PRE:
428    case VG_lXBGR_8888:
429    case VG_lABGR_8888:
430    case VG_lABGR_8888_PRE:
431       return 5;
432    case VG_sRGB_565:
433    case VG_sRGBA_5551:
434    case VG_sRGBA_4444:
435    case VG_sARGB_1555:
436    case VG_sARGB_4444:
437    case VG_sBGR_565:
438    case VG_sBGRA_5551:
439    case VG_sBGRA_4444:
440    case VG_sABGR_1555:
441    case VG_sABGR_4444:
442       return 4;
443    case VG_sL_8:
444    case VG_lL_8:
445    case VG_A_8:
446       return 3;
447    case VG_A_4:
448       return 2;
449    case VG_BW_1:
450    case VG_A_1:
451       return 0;
452    default:
453       UNREACHABLE();
454       return 0;
455    }
456 }
457 
458 #endif
459 
param_to_int(bool are_floats,const void * values,VGuint i)460 static VGint param_to_int(
461    bool are_floats,
462    const void *values,
463    VGuint i)
464 {
465    vcos_assert(values);
466    return are_floats ?
467       float_to_int_floor(clean_float(((const VGfloat *)values)[i])) :
468       ((const VGint *)values)[i];
469 }
470 
params_to_ints(VGint * ints,bool are_floats,const void * values,VGuint count)471 static bool params_to_ints(
472    VGint *ints,
473    bool are_floats,
474    const void *values,
475    VGuint count)
476 {
477    bool changed = false;
478    VGuint i;
479    for (i = 0; i != count; ++i) {
480       VGint x = param_to_int(are_floats, values, i);
481       if (ints[i] != x) {
482          changed = true;
483          ints[i] = x;
484       }
485    }
486    return changed;
487 }
488 
param_to_float(bool are_floats,const void * values,VGuint i)489 static VGfloat param_to_float(
490    bool are_floats,
491    const void *values,
492    VGuint i)
493 {
494    vcos_assert(values);
495    return are_floats ?
496       ((const VGfloat *)values)[i] :
497       (VGfloat)((const VGint *)values)[i];
498 }
499 
params_to_floats(VGfloat * floats,bool are_floats,const void * values,VGuint count)500 static bool params_to_floats(
501    VGfloat *floats,
502    bool are_floats,
503    const void *values,
504    VGuint count)
505 {
506    bool changed = false;
507    VGuint i;
508    for (i = 0; i != count; ++i) {
509       VGfloat x = param_to_float(are_floats, values, i);
510       if (!floats_identical(floats[i], x)) {
511          changed = true;
512          floats[i] = x;
513       }
514    }
515    return changed;
516 }
517 
int_to_param(bool are_floats,void * values,VGuint i,VGint value)518 static void int_to_param(
519    bool are_floats,
520    void *values,
521    VGuint i,
522    VGint value)
523 {
524    if (are_floats) {
525       ((VGfloat *)values)[i] = (VGfloat)value;
526    } else {
527       ((VGint *)values)[i] = value;
528    }
529 }
530 
ints_to_params(bool are_floats,void * values,VGuint count,const VGint * ints)531 static void ints_to_params(
532    bool are_floats,
533    void *values,
534    VGuint count,
535    const VGint *ints)
536 {
537    VGuint i;
538    for (i = 0; i != count; ++i) {
539       int_to_param(are_floats, values, i, ints[i]);
540    }
541 }
542 
float_to_param(bool are_floats,void * values,VGuint i,VGfloat value)543 static void float_to_param(
544    bool are_floats,
545    void *values,
546    VGuint i,
547    VGfloat value)
548 {
549    if (are_floats) {
550       ((VGfloat *)values)[i] = value;
551    } else {
552       ((VGint *)values)[i] = float_to_int_floor(clean_float(value));
553    }
554 }
555 
floats_to_params(bool are_floats,void * values,VGuint count,const VGfloat * floats)556 static void floats_to_params(
557    bool are_floats,
558    void *values,
559    VGuint count,
560    const VGfloat *floats)
561 {
562    VGuint i;
563    for (i = 0; i != count; ++i) {
564       float_to_param(are_floats, values, i, floats[i]);
565    }
566 }
567 
get_stem(VG_CLIENT_STATE_T * state)568 static VGHandle get_stem(VG_CLIENT_STATE_T *state)
569 {
570    VGHandle vg_handle;
571 
572    platform_mutex_acquire(&state->shared_state->mutex);
573 
574    if (state->shared_state->stems_count == 0) {
575       CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
576       RPC_HIGH_PRIORITY_BEGIN(thread);
577       state->shared_state->stems_count = RPC_UINT_RES(RPC_CALL2_OUT_CTRL_RES(vgCreateStems_impl,
578                                                                              thread,
579                                                                              VGCREATESTEMS_ID,
580                                                                              VG_CLIENT_STEMS_COUNT_MAX,
581                                                                              state->shared_state->stems));
582       RPC_HIGH_PRIORITY_END(thread);
583    }
584    vg_handle = (state->shared_state->stems_count == 0) ? VG_INVALID_HANDLE : state->shared_state->stems[--state->shared_state->stems_count];
585 
586    platform_mutex_release(&state->shared_state->mutex);
587 
588    return vg_handle;
589 }
590 
destroy_stem(VGHandle vg_handle)591 static void destroy_stem(VGHandle vg_handle)
592 {
593    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
594    RPC_CALL1(vgDestroyStem_impl,
595              thread,
596              VGDESTROYSTEM_ID,
597              RPC_HANDLE(vg_handle));
598 }
599 
font_alloc(void)600 static VG_CLIENT_FONT_T *font_alloc(void)
601 {
602    VG_CLIENT_FONT_T *font = (VG_CLIENT_FONT_T *)khrn_platform_malloc(sizeof(VG_CLIENT_FONT_T), "VG_CLIENT_FONT_T");
603    if (!font) {
604       return NULL;
605    }
606 
607    font->object_type = VG_CLIENT_OBJECT_TYPE_FONT;
608 #if EGL_BRCM_global_image && EGL_KHR_image
609    if (!khrn_global_image_map_init(&font->glyph_global_images, 8)) {
610       khrn_platform_free(font);
611       return NULL;
612    }
613 #endif
614 
615    return font;
616 }
617 
font_free(VG_CLIENT_FONT_T * font)618 static void font_free(VG_CLIENT_FONT_T *font)
619 {
620 #if EGL_BRCM_global_image && EGL_KHR_image
621    khrn_global_image_map_term(&font->glyph_global_images);
622 #endif
623    khrn_platform_free(font);
624 }
625 
image_alloc(VGImageFormat format,VGint width,VGint height,VGuint global_image_id_0,VGuint global_image_id_1)626 static VG_CLIENT_IMAGE_T *image_alloc(VGImageFormat format, VGint width, VGint height
627 #if EGL_BRCM_global_image && EGL_KHR_image
628    , VGuint global_image_id_0, VGuint global_image_id_1
629 #endif
630    )
631 {
632    VG_CLIENT_IMAGE_T *image = (VG_CLIENT_IMAGE_T *)khrn_platform_malloc(sizeof(VG_CLIENT_IMAGE_T), "VG_CLIENT_IMAGE_T");
633    if (!image) {
634       return NULL;
635    }
636 
637    image->object_type = VG_CLIENT_OBJECT_TYPE_IMAGE;
638    image->format = format;
639    image->width = width;
640    image->height = height;
641 #if EGL_BRCM_global_image && EGL_KHR_image
642    if (global_image_id_0 || global_image_id_1) {
643       platform_acquire_global_image(global_image_id_0, global_image_id_1);
644    }
645    image->global_image_id[0] = global_image_id_0;
646    image->global_image_id[1] = global_image_id_1;
647 #endif
648 
649    return image;
650 }
651 
image_free(VG_CLIENT_IMAGE_T * image)652 static void image_free(VG_CLIENT_IMAGE_T *image)
653 {
654 #if EGL_BRCM_global_image && EGL_KHR_image
655    if (image->global_image_id[0] || image->global_image_id[1]) {
656       platform_release_global_image(image->global_image_id[0], image->global_image_id[1]);
657    }
658 #endif
659    khrn_platform_free(image);
660 }
661 
mask_layer_alloc(VGint width,VGint height)662 static VG_CLIENT_MASK_LAYER_T *mask_layer_alloc(VGint width, VGint height)
663 {
664    VG_CLIENT_MASK_LAYER_T *mask_layer = (VG_CLIENT_MASK_LAYER_T *)khrn_platform_malloc(sizeof(VG_CLIENT_MASK_LAYER_T), "VG_CLIENT_MASK_LAYER_T");
665    if (!mask_layer) {
666       return NULL;
667    }
668 
669    mask_layer->object_type = VG_CLIENT_OBJECT_TYPE_MASK_LAYER;
670    mask_layer->width = width;
671    mask_layer->height = height;
672 
673    return mask_layer;
674 }
675 
mask_layer_free(VG_CLIENT_MASK_LAYER_T * mask_layer)676 static void mask_layer_free(VG_CLIENT_MASK_LAYER_T *mask_layer)
677 {
678    khrn_platform_free(mask_layer);
679 }
680 
need_paint_gradient(VGint param_type)681 static bool need_paint_gradient(VGint param_type)
682 {
683    return (param_type == VG_PAINT_COLOR_RAMP_SPREAD_MODE) ||
684           (param_type == VG_PAINT_COLOR_RAMP_PREMULTIPLIED) ||
685           (param_type == VG_PAINT_COLOR_RAMP_STOPS) ||
686           (param_type == VG_PAINT_LINEAR_GRADIENT) ||
687           (param_type == VG_PAINT_RADIAL_GRADIENT);
688 }
689 
paint_alloc(void)690 static VG_CLIENT_PAINT_T *paint_alloc(void)
691 {
692    VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)khrn_platform_malloc(sizeof(VG_CLIENT_PAINT_T), "VG_CLIENT_PAINT_T");
693    if (!paint) {
694       return NULL;
695    }
696 
697    paint->object_type = VG_CLIENT_OBJECT_TYPE_PAINT;
698    paint->type = VG_PAINT_TYPE_COLOR;
699    paint->color[0] = 0.0f;
700    paint->color[1] = 0.0f;
701    paint->color[2] = 0.0f;
702    paint->color[3] = 1.0f;
703    paint->gradient = NULL; /* will be allocated when required */
704    paint->pattern_tiling_mode = VG_TILE_FILL;
705    paint->pattern = VG_INVALID_HANDLE;
706 #if EGL_BRCM_global_image && EGL_KHR_image
707    paint->pattern_global_image_id[0] = 0;
708    paint->pattern_global_image_id[1] = 0;
709 #endif
710 
711    return paint;
712 }
713 
paint_alloc_gradient(VG_CLIENT_PAINT_T * paint)714 static bool paint_alloc_gradient(VG_CLIENT_PAINT_T *paint)
715 {
716    VG_CLIENT_PAINT_GRADIENT_T *gradient;
717 
718    vcos_assert(!paint->gradient);
719 
720    gradient = (VG_CLIENT_PAINT_GRADIENT_T *)khrn_platform_malloc(sizeof(VG_CLIENT_PAINT_GRADIENT_T), "VG_CLIENT_PAINT_GRADIENT_T");
721    if (!gradient) {
722       return false;
723    }
724 
725    gradient->linear[0] = 0.0f;
726    gradient->linear[1] = 0.0f;
727    gradient->linear[2] = 1.0f;
728    gradient->linear[3] = 0.0f;
729    gradient->radial[0] = 0.0f;
730    gradient->radial[1] = 0.0f;
731    gradient->radial[2] = 0.0f;
732    gradient->radial[3] = 0.0f;
733    gradient->radial[4] = 1.0f;
734    gradient->ramp_spread_mode = VG_COLOR_RAMP_SPREAD_PAD;
735    gradient->ramp_pre = true;
736    gradient->ramp_stops = NULL;
737    gradient->ramp_stops_count = 0;
738 
739    paint->gradient = gradient;
740 
741    return true;
742 }
743 
paint_free(VG_CLIENT_PAINT_T * paint)744 static void paint_free(VG_CLIENT_PAINT_T *paint)
745 {
746 #if EGL_BRCM_global_image && EGL_KHR_image
747    if (paint->pattern_global_image_id[0] || paint->pattern_global_image_id[1]) {
748       platform_release_global_image(paint->pattern_global_image_id[0], paint->pattern_global_image_id[1]);
749    }
750 #endif
751    if (paint->gradient) {
752       if (paint->gradient->ramp_stops) {
753          khrn_platform_free(paint->gradient->ramp_stops);
754       }
755       khrn_platform_free(paint->gradient);
756    }
757    khrn_platform_free(paint);
758 }
759 
need_path_segments(VGbitfield caps)760 static bool need_path_segments(VGbitfield caps)
761 {
762    /*
763       need segments for vgModifyPath and interpolating from, but also need for
764       appending from incase the path being appended to needs segments (we don't
765       want to have to go to the server to get them)
766    */
767 
768    return !!(caps & (VG_PATH_CAPABILITY_APPEND_FROM |
769                      VG_PATH_CAPABILITY_MODIFY |
770                      VG_PATH_CAPABILITY_TRANSFORM_FROM |
771                      VG_PATH_CAPABILITY_INTERPOLATE_FROM));
772 }
773 
path_alloc(VGint format,VGPathDatatype datatype,VGfloat scale,VGfloat bias,VGbitfield caps,VGint segments_capacity)774 static VG_CLIENT_PATH_T *path_alloc(VGint format, VGPathDatatype datatype, VGfloat scale, VGfloat bias, VGbitfield caps, VGint segments_capacity)
775 {
776    VG_CLIENT_PATH_T *path = (VG_CLIENT_PATH_T *)khrn_platform_malloc(sizeof(VG_CLIENT_PATH_T), "VG_CLIENT_PATH_T");
777    if (!path) {
778       return NULL;
779    }
780 
781    path->object_type = VG_CLIENT_OBJECT_TYPE_PATH;
782    path->format = format;
783    path->datatype = datatype;
784    path->scale = scale;
785    path->bias = bias;
786    path->caps = caps;
787    if (need_path_segments(caps)) {
788       khrn_vector_init(&path->segments, clampi(segments_capacity, 0, 1024));
789    }
790 
791    return path;
792 }
793 
path_update_caps(VG_CLIENT_PATH_T * path,VGbitfield caps)794 static void path_update_caps(VG_CLIENT_PATH_T *path, VGbitfield caps)
795 {
796    if (!need_path_segments(path->caps) && need_path_segments(caps)) {
797       khrn_vector_init(&path->segments, 0);
798    }
799    if (need_path_segments(path->caps) && !need_path_segments(caps)) {
800       khrn_vector_term(&path->segments);
801    }
802    path->caps = caps;
803 }
804 
path_free(VG_CLIENT_PATH_T * path)805 static void path_free(VG_CLIENT_PATH_T *path)
806 {
807    if (need_path_segments(path->caps)) {
808       khrn_vector_term(&path->segments);
809    }
810    khrn_platform_free(path);
811 }
812 
object_free(void * object)813 static void object_free(void *object)
814 {
815    switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
816    case VG_CLIENT_OBJECT_TYPE_FONT:       font_free((VG_CLIENT_FONT_T *)object); break;
817    case VG_CLIENT_OBJECT_TYPE_IMAGE:      image_free((VG_CLIENT_IMAGE_T *)object); break;
818    case VG_CLIENT_OBJECT_TYPE_MASK_LAYER: mask_layer_free((VG_CLIENT_MASK_LAYER_T *)object); break;
819    case VG_CLIENT_OBJECT_TYPE_PAINT:      paint_free((VG_CLIENT_PAINT_T *)object); break;
820    case VG_CLIENT_OBJECT_TYPE_PATH:       path_free((VG_CLIENT_PATH_T *)object); break;
821    default:                               UNREACHABLE();
822    }
823 }
824 
825 /*
826    see nice_handle in middleware/khronos/vg/vg_set.c
827 */
828 
nice_handle(VGHandle vg_handle)829 static INLINE uint32_t nice_handle(VGHandle vg_handle)
830 {
831    return _ror((uint32_t)vg_handle, 31);
832 }
833 
insert_object(VG_CLIENT_STATE_T * state,VGHandle vg_handle,void * object)834 static bool insert_object(VG_CLIENT_STATE_T *state, VGHandle vg_handle, void *object)
835 {
836    void *prev_object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
837    if (prev_object) {
838       object_free(prev_object);
839    }
840    return khrn_pointer_map_insert(&state->shared_state->objects, nice_handle(vg_handle), object);
841 }
842 
delete_object(VG_CLIENT_STATE_T * state,VGHandle vg_handle,VG_CLIENT_OBJECT_TYPE_T type)843 static void delete_object(VG_CLIENT_STATE_T *state, VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T type)
844 {
845    void *object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
846    if (object && (*(VG_CLIENT_OBJECT_TYPE_T *)object == type)) {
847       object_free(object);
848       khrn_pointer_map_delete(&state->shared_state->objects, nice_handle(vg_handle));
849    }
850 }
851 
lookup_object(VG_CLIENT_STATE_T * state,VGHandle vg_handle,VG_CLIENT_OBJECT_TYPE_T type)852 static INLINE void *lookup_object(VG_CLIENT_STATE_T *state, VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T type)
853 {
854    void *object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
855    return (object && (*(VG_CLIENT_OBJECT_TYPE_T *)object == type)) ? object : NULL;
856 }
857 
get_matrix_sync(VG_CLIENT_STATE_T * state,VGMatrixMode matrix_mode)858 static INLINE VG_MAT3X3_SYNC_T *get_matrix_sync(VG_CLIENT_STATE_T *state, VGMatrixMode matrix_mode)
859 {
860    vcos_assert(
861       (matrix_mode >= VG_MATRIX_PATH_USER_TO_SURFACE) &&
862       (matrix_mode < (VG_MATRIX_PATH_USER_TO_SURFACE + ARR_COUNT(state->matrices))));
863    return state->matrices + (matrix_mode - VG_MATRIX_PATH_USER_TO_SURFACE);
864 }
865 
is_matrix_affine(VGMatrixMode matrix_mode)866 static INLINE bool is_matrix_affine(VGMatrixMode matrix_mode)
867 {
868    return matrix_mode != VG_MATRIX_IMAGE_USER_TO_SURFACE;
869 }
870 
sync_matrix(VG_CLIENT_STATE_T * state,VGMatrixMode matrix_mode)871 static void sync_matrix(VG_CLIENT_STATE_T *state, VGMatrixMode matrix_mode)
872 {
873    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
874    VG_MAT3X3_SYNC_T *matrix_sync = get_matrix_sync(state, matrix_mode);
875    if (!vg_mat3x3_identical(&matrix_sync->server, &matrix_sync->client)) {
876       RPC_CALL2_IN_CTRL(vgLoadMatrix_impl,
877                         thread,
878                         VGLOADMATRIX_ID,
879                         RPC_ENUM(matrix_mode),
880                         &matrix_sync->client,
881                         sizeof(VG_MAT3X3_T));
882       matrix_sync->server = matrix_sync->client;
883    }
884 }
885 
886 /******************************************************************************
887 api misc
888 ******************************************************************************/
889 
vgGetError(void)890 VG_API_CALL VGErrorCode VG_API_ENTRY vgGetError(void) VG_API_EXIT
891 {
892    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
893    if (!VG_GET_CLIENT_STATE(thread)) {
894       return VG_NO_CONTEXT_ERROR;
895    }
896 
897    return get_error();
898 }
899 
vgFlush(void)900 VG_API_CALL void VG_API_ENTRY vgFlush(void) VG_API_EXIT
901 {
902    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
903    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
904    if (!state) {
905       return;
906    }
907 
908    RPC_CALL0(vgFlush_impl,
909              thread,
910              VGFLUSH_ID);
911    RPC_FLUSH(thread);
912 
913 #ifdef KHRN_COMMAND_MODE_DISPLAY
914    {
915       //Check for single buffered windows surface in which case call surface updater
916       EGL_SURFACE_T *surface = CLIENT_GET_THREAD_STATE()->openvg.draw;
917       if (surface->type == WINDOW && surface->buffers==1) {
918          platform_surface_update(surface->internal_handle);
919       }
920    }
921 #endif
922 
923    if (state->flush_callback)
924       state->flush_callback(false);
925 }
926 
vgFinish(void)927 VG_API_CALL void VG_API_ENTRY vgFinish(void) VG_API_EXIT
928 {
929    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
930    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
931    if (!state) {
932       return;
933    }
934 
935    (void)RPC_UINT_RES(RPC_CALL0_RES(vgFinish_impl,
936                                     thread,
937                                     VGFINISH_ID)); /* return value ignored -- read performed to ensure blocking */
938 
939 #ifdef KHRN_COMMAND_MODE_DISPLAY
940    {
941    //Check for single buffered windows surface in which case call surface updater
942       EGL_SURFACE_T *surface = CLIENT_GET_THREAD_STATE()->openvg.draw;
943       if (surface->type == WINDOW && surface->buffers==1) {
944          platform_surface_update(surface->internal_handle);
945       }
946    }
947 #endif
948 
949    if (state->flush_callback)
950       state->flush_callback(true);
951 }
952 
953 /******************************************************************************
954 api get/set
955 ******************************************************************************/
956 
set_iv_server(VGParamType param_type,VGint count,const VGint * values)957 static void set_iv_server(
958    VGParamType param_type,
959    VGint count,
960    const VGint *values)
961 {
962    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
963    RPC_CALL3_IN_CTRL(vgSetiv_impl,
964                      thread,
965                      VGSETIV_ID,
966                      RPC_ENUM(param_type),
967                      RPC_INT(count),
968                      values,
969                      count * sizeof(VGint));
970 }
971 
set_fv_server(VGParamType param_type,VGint count,const VGfloat * values)972 static void set_fv_server(
973    VGParamType param_type,
974    VGint count,
975    const VGfloat *values)
976 {
977    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
978    RPC_CALL3_IN_CTRL(vgSetfv_impl,
979                      thread,
980                      VGSETFV_ID,
981                      RPC_ENUM(param_type),
982                      RPC_INT(count),
983                      values,
984                      count * sizeof(VGfloat));
985 }
986 
get_fv_server(VGParamType param_type,VGint count,VGfloat * values)987 static void get_fv_server(
988    VGParamType param_type,
989    VGint count,
990    VGfloat *values)
991 {
992    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
993    RPC_CALL3_OUT_CTRL(vgGetfv_impl,
994                       thread,
995                       VGGETFV_ID,
996                       RPC_ENUM(param_type),
997                       RPC_INT(count),
998                       values);
999 }
1000 
set_parameter_iv_server(VGHandle vg_handle,VG_CLIENT_OBJECT_TYPE_T object_type,VGint param_type,VGint count,const VGint * values)1001 static void set_parameter_iv_server(
1002    VGHandle vg_handle,
1003    VG_CLIENT_OBJECT_TYPE_T object_type,
1004    VGint param_type,
1005    VGint count,
1006    const VGint *values)
1007 {
1008    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1009    RPC_CALL5_IN_CTRL(vgSetParameteriv_impl,
1010                      thread,
1011                      VGSETPARAMETERIV_ID,
1012                      RPC_HANDLE(vg_handle),
1013                      RPC_ENUM(object_type),
1014                      RPC_INT(param_type),
1015                      RPC_INT(count),
1016                      values,
1017                      count * sizeof(VGint));
1018 }
1019 
set_parameter_fv_server(VGHandle vg_handle,VG_CLIENT_OBJECT_TYPE_T object_type,VGint param_type,VGint count,const VGfloat * values)1020 static void set_parameter_fv_server(
1021    VGHandle vg_handle,
1022    VG_CLIENT_OBJECT_TYPE_T object_type,
1023    VGint param_type,
1024    VGint count,
1025    const VGfloat *values)
1026 {
1027    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1028    RPC_CALL5_IN_CTRL(vgSetParameterfv_impl,
1029                      thread,
1030                      VGSETPARAMETERFV_ID,
1031                      RPC_HANDLE(vg_handle),
1032                      RPC_ENUM(object_type),
1033                      RPC_INT(param_type),
1034                      RPC_INT(count),
1035                      values,
1036                      count * sizeof(VGfloat));
1037 }
1038 
get_parameter_iv_server(VGHandle vg_handle,VG_CLIENT_OBJECT_TYPE_T object_type,VGint param_type,VGint count,VGint * values)1039 static bool get_parameter_iv_server(
1040    VGHandle vg_handle,
1041    VG_CLIENT_OBJECT_TYPE_T object_type,
1042    VGint param_type,
1043    VGint count,
1044    VGint *values)
1045 {
1046    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1047    return RPC_BOOLEAN_RES(RPC_CALL5_OUT_CTRL_RES(vgGetParameteriv_impl,
1048                                                  thread,
1049                                                  VGGETPARAMETERIV_ID,
1050                                                  RPC_HANDLE(vg_handle),
1051                                                  RPC_ENUM(object_type),
1052                                                  RPC_INT(param_type),
1053                                                  RPC_INT(count),
1054                                                  values));
1055 }
1056 
set_ifv(CLIENT_THREAD_STATE_T * thread,VG_CLIENT_STATE_T * state,VGParamType param_type,VGint count,bool are_floats,const void * values)1057 static void set_ifv(
1058    CLIENT_THREAD_STATE_T *thread,
1059    VG_CLIENT_STATE_T *state,
1060    VGParamType param_type,
1061    VGint count,
1062    bool are_floats,
1063    const void *values)
1064 {
1065    /*
1066     * If 'count' is greater than zero, then our caller must have verified
1067     * that 'values' is non-NULL.
1068     * If 'count' is zero, then 'values' *must not* be dereferenced.
1069     * Note that params_to_floats() and params_to_ints() handle a zero 'count'
1070     * argument correctly and do not dereference 'values' in this case.
1071     * Other functions, e.g. param_to_int() and param_to_float(), require a
1072     * check before calling.
1073     */
1074    VGint value_i = (count == 1) ? param_to_int(are_floats, values, 0) : 0;
1075    VGfloat value_f = (count == 1) ? param_to_float(are_floats, values, 0) : 0.0f;
1076 
1077    switch (param_type) {
1078    /*
1079       settable scalar param types
1080    */
1081 
1082    #define CASE(PARAM_TYPE, OK, DO) \
1083       case PARAM_TYPE: \
1084       { \
1085          if ((count != 1) || !(OK)) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
1086          DO; \
1087          break; \
1088       }
1089    #define CASE_I_SERVER(PARAM_TYPE, OK, VALUE, FN) CASE(PARAM_TYPE, OK, if (VALUE != FN(value_i)) { VALUE = FN(value_i); set_iv_server(PARAM_TYPE, 1, &value_i); })
1090    #define CASE_F_SERVER(PARAM_TYPE, OK, VALUE) CASE(PARAM_TYPE, OK, if (!floats_identical(VALUE, value_f)) { VALUE = value_f; set_fv_server(PARAM_TYPE, 1, &value_f); })
1091    CASE(VG_MATRIX_MODE, is_matrix_mode((VGMatrixMode)value_i), state->matrix_mode = (VGMatrixMode)value_i)
1092    CASE_I_SERVER(VG_FILL_RULE, is_fill_rule((VGFillRule)value_i), state->fill_rule, (VGFillRule))
1093    CASE_I_SERVER(VG_IMAGE_QUALITY, is_image_quality((VGImageQuality)value_i), state->image_quality, (VGImageQuality))
1094    CASE_I_SERVER(VG_RENDERING_QUALITY, is_rendering_quality((VGRenderingQuality)value_i), state->rendering_quality, (VGRenderingQuality))
1095    CASE_I_SERVER(VG_BLEND_MODE, is_blend_mode((VGBlendMode)value_i), state->blend_mode, (VGBlendMode))
1096    CASE_I_SERVER(VG_IMAGE_MODE, is_image_mode((VGImageMode)value_i), state->image_mode, (VGImageMode))
1097    CASE_I_SERVER(VG_COLOR_TRANSFORM, true, state->color_transform, clean_boolean)
1098    CASE_F_SERVER(VG_STROKE_LINE_WIDTH, true, state->stroke_line_width)
1099    CASE_I_SERVER(VG_STROKE_CAP_STYLE, is_cap_style((VGCapStyle)value_i), state->stroke_cap_style, (VGCapStyle))
1100    CASE_I_SERVER(VG_STROKE_JOIN_STYLE, is_join_style((VGJoinStyle)value_i), state->stroke_join_style, (VGJoinStyle))
1101    CASE_F_SERVER(VG_STROKE_MITER_LIMIT, true, state->stroke_miter_limit)
1102    CASE_F_SERVER(VG_STROKE_DASH_PHASE, true, state->stroke_dash_phase)
1103    CASE_I_SERVER(VG_STROKE_DASH_PHASE_RESET, true, state->stroke_dash_phase_reset, clean_boolean)
1104    CASE_I_SERVER(VG_MASKING, true, state->masking, clean_boolean)
1105    CASE_I_SERVER(VG_SCISSORING, true, state->scissoring, clean_boolean)
1106    CASE(VG_PIXEL_LAYOUT, is_pixel_layout((VGPixelLayout)value_i), state->pixel_layout = (VGPixelLayout)value_i)
1107    CASE_I_SERVER(VG_FILTER_FORMAT_LINEAR, true, state->filter_format_linear, clean_boolean)
1108    CASE_I_SERVER(VG_FILTER_FORMAT_PREMULTIPLIED, true, state->filter_format_pre, clean_boolean)
1109    CASE_I_SERVER(VG_FILTER_CHANNEL_MASK, true, state->filter_channel_mask, )
1110    #undef CASE_F_SERVER
1111    #undef CASE_I_SERVER
1112    #undef CASE
1113 
1114    /*
1115       read-only scalar param types
1116    */
1117 
1118    case VG_SCREEN_LAYOUT:
1119    case VG_MAX_SCISSOR_RECTS:
1120    case VG_MAX_DASH_COUNT:
1121    case VG_MAX_KERNEL_SIZE:
1122    case VG_MAX_SEPARABLE_KERNEL_SIZE:
1123    case VG_MAX_COLOR_RAMP_STOPS:
1124    case VG_MAX_IMAGE_WIDTH:
1125    case VG_MAX_IMAGE_HEIGHT:
1126    case VG_MAX_IMAGE_PIXELS:
1127    case VG_MAX_IMAGE_BYTES:
1128    case VG_MAX_FLOAT:
1129    case VG_MAX_GAUSSIAN_STD_DEVIATION:
1130    {
1131       if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
1132       break;
1133    }
1134 
1135    /*
1136       vector param types
1137    */
1138 
1139    case VG_SCISSOR_RECTS:
1140    {
1141       if (count & 0x3) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1142       count = _min(count, VG_CONFIG_MAX_SCISSOR_RECTS * 4);
1143       if (params_to_ints(
1144          state->scissor_rects,
1145          are_floats, values, count) ||
1146          (state->scissor_rects_count != count)) {
1147          state->scissor_rects_count = count;
1148          set_iv_server(VG_SCISSOR_RECTS, count, state->scissor_rects);
1149       }
1150       break;
1151    }
1152    case VG_COLOR_TRANSFORM_VALUES:
1153    {
1154       if (count != 8) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1155       if (params_to_floats(
1156          state->color_transform_values,
1157          are_floats, values, count)) {
1158          set_fv_server(VG_COLOR_TRANSFORM_VALUES, 8, state->color_transform_values);
1159       }
1160       break;
1161    }
1162    case VG_STROKE_DASH_PATTERN:
1163    {
1164       count = _min(count, VG_CONFIG_MAX_DASH_COUNT);
1165       if (params_to_floats(
1166          state->stroke_dash_pattern,
1167          are_floats, values, count) ||
1168          (state->stroke_dash_pattern_count != count)) {
1169          state->stroke_dash_pattern_count = count;
1170          set_fv_server(VG_STROKE_DASH_PATTERN, count, state->stroke_dash_pattern);
1171       }
1172       break;
1173    }
1174    case VG_TILE_FILL_COLOR:
1175    case VG_CLEAR_COLOR:
1176    {
1177       VGfloat *color;
1178       if (count != 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1179       color = (param_type == VG_TILE_FILL_COLOR) ? state->tile_fill_color : state->clear_color;
1180       if (params_to_floats(
1181          color,
1182          are_floats, values, count)) {
1183          VGint rgba = color_floats_to_rgba_clean(color);
1184          set_iv_server(param_type, 1, &rgba);
1185       }
1186       break;
1187    }
1188    case VG_GLYPH_ORIGIN:
1189    {
1190       /*
1191          don't store on client as it can change
1192       */
1193 
1194       VGfloat glyph_origin[2];
1195       if (count != 2) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1196       (void)params_to_floats(
1197          glyph_origin,
1198          are_floats, values, count); /* ignore return -- it doesn't mean anything in this case */
1199       set_fv_server(VG_GLYPH_ORIGIN, 2, glyph_origin);
1200       break;
1201    }
1202 
1203    /*
1204       invalid param type
1205    */
1206 
1207    default:
1208       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1209    }
1210 }
1211 
get_ifv(CLIENT_THREAD_STATE_T * thread,VG_CLIENT_STATE_T * state,VGParamType param_type,VGint count,bool are_floats,void * values)1212 static void get_ifv(
1213    CLIENT_THREAD_STATE_T *thread,
1214    VG_CLIENT_STATE_T *state,
1215    VGParamType param_type,
1216    VGint count,
1217    bool are_floats,
1218    void *values)
1219 {
1220    switch (param_type) {
1221    /*
1222       scalar param types
1223    */
1224 
1225    #define CASE(PARAM_TYPE, FN, VALUE) \
1226       case PARAM_TYPE: \
1227       { \
1228          if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
1229          FN(are_floats, values, 0, VALUE); \
1230          break; \
1231       }
1232    #define CASE_I(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, int_to_param, VALUE)
1233    #define CASE_F(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, float_to_param, VALUE)
1234    CASE_I(VG_MATRIX_MODE, state->matrix_mode)
1235    CASE_I(VG_FILL_RULE, state->fill_rule)
1236    CASE_I(VG_IMAGE_QUALITY, state->image_quality)
1237    CASE_I(VG_RENDERING_QUALITY, state->rendering_quality)
1238    CASE_I(VG_BLEND_MODE, state->blend_mode)
1239    CASE_I(VG_IMAGE_MODE, state->image_mode)
1240    CASE_I(VG_COLOR_TRANSFORM, state->color_transform)
1241    CASE_F(VG_STROKE_LINE_WIDTH, state->stroke_line_width)
1242    CASE_I(VG_STROKE_CAP_STYLE, state->stroke_cap_style)
1243    CASE_I(VG_STROKE_JOIN_STYLE, state->stroke_join_style)
1244    CASE_F(VG_STROKE_MITER_LIMIT, state->stroke_miter_limit)
1245    CASE_F(VG_STROKE_DASH_PHASE, state->stroke_dash_phase)
1246    CASE_I(VG_STROKE_DASH_PHASE_RESET, state->stroke_dash_phase_reset)
1247    CASE_I(VG_MASKING, state->masking)
1248    CASE_I(VG_SCISSORING, state->scissoring)
1249    CASE_I(VG_PIXEL_LAYOUT, state->pixel_layout)
1250    CASE_I(VG_SCREEN_LAYOUT, VG_CONFIG_SCREEN_LAYOUT)
1251    CASE_I(VG_FILTER_FORMAT_LINEAR, state->filter_format_linear)
1252    CASE_I(VG_FILTER_FORMAT_PREMULTIPLIED, state->filter_format_pre)
1253    CASE_I(VG_FILTER_CHANNEL_MASK, state->filter_channel_mask)
1254    CASE_I(VG_MAX_SCISSOR_RECTS, VG_CONFIG_MAX_SCISSOR_RECTS)
1255    CASE_I(VG_MAX_DASH_COUNT, VG_CONFIG_MAX_DASH_COUNT)
1256    CASE_I(VG_MAX_KERNEL_SIZE, VG_CONFIG_MAX_KERNEL_SIZE)
1257    CASE_I(VG_MAX_SEPARABLE_KERNEL_SIZE, VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE)
1258    CASE_I(VG_MAX_COLOR_RAMP_STOPS, VG_CONFIG_MAX_COLOR_RAMP_STOPS)
1259    CASE_I(VG_MAX_IMAGE_WIDTH, VG_CONFIG_MAX_IMAGE_WIDTH)
1260    CASE_I(VG_MAX_IMAGE_HEIGHT, VG_CONFIG_MAX_IMAGE_HEIGHT)
1261    CASE_I(VG_MAX_IMAGE_PIXELS, VG_CONFIG_MAX_IMAGE_PIXELS)
1262    CASE_I(VG_MAX_IMAGE_BYTES, VG_CONFIG_MAX_IMAGE_BYTES)
1263    CASE_F(VG_MAX_FLOAT, VG_CONFIG_MAX_FLOAT)
1264    CASE_F(VG_MAX_GAUSSIAN_STD_DEVIATION, VG_CONFIG_MAX_GAUSSIAN_STD_DEVIATION)
1265    #undef CASE_F
1266    #undef CASE_I
1267    #undef CASE
1268 
1269    /*
1270       vector param types
1271    */
1272 
1273    case VG_SCISSOR_RECTS:
1274    {
1275       if ((VGuint)count > state->scissor_rects_count) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1276       ints_to_params(
1277          are_floats, values, count,
1278          state->scissor_rects);
1279       break;
1280    }
1281    case VG_COLOR_TRANSFORM_VALUES:
1282    {
1283       if (count > 8) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1284       floats_to_params(
1285          are_floats, values, count,
1286          state->color_transform_values);
1287       break;
1288    }
1289    case VG_STROKE_DASH_PATTERN:
1290    {
1291       if ((VGuint)count > state->stroke_dash_pattern_count) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1292       floats_to_params(
1293          are_floats, values, count,
1294          state->stroke_dash_pattern);
1295       break;
1296    }
1297    case VG_TILE_FILL_COLOR:
1298    case VG_CLEAR_COLOR:
1299    {
1300       if (count > 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1301       floats_to_params(
1302          are_floats, values, count,
1303          (param_type == VG_TILE_FILL_COLOR) ? state->tile_fill_color : state->clear_color);
1304       break;
1305    }
1306    case VG_GLYPH_ORIGIN:
1307    {
1308       VGfloat glyph_origin[2];
1309       if (count > 2) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1310       get_fv_server(VG_GLYPH_ORIGIN, 2, glyph_origin);
1311       floats_to_params(
1312          are_floats, values, count,
1313          glyph_origin);
1314       break;
1315    }
1316 
1317    /*
1318       invalid param type
1319    */
1320 
1321    default:
1322       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1323    }
1324 }
1325 
set_parameter_ifv(CLIENT_THREAD_STATE_T * thread,VG_CLIENT_STATE_T * state,VGHandle vg_handle,VGint param_type,VGint count,bool are_floats,const void * values)1326 static void set_parameter_ifv(
1327    CLIENT_THREAD_STATE_T *thread,
1328    VG_CLIENT_STATE_T *state,
1329    VGHandle vg_handle,
1330    VGint param_type,
1331    VGint count,
1332    bool are_floats,
1333    const void *values)
1334 {
1335    /*
1336     * If 'count' is greater than zero, then our caller must have verified
1337     * that 'values' is non-NULL.
1338     * If 'count' is zero, then 'values' *must not* be dereferenced.
1339     * Note that params_to_floats() and params_to_ints() handle a zero 'count'
1340     * argument correctly and do not dereference 'values' in this case.
1341     * Other functions, e.g. param_to_int() and param_to_float(), require a
1342     * check before calling.
1343     */
1344    void *object;
1345 
1346    platform_mutex_acquire(&state->shared_state->mutex);
1347 
1348    object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
1349    if (!object) {
1350       set_error(VG_BAD_HANDLE_ERROR);
1351       platform_mutex_release(&state->shared_state->mutex);
1352       return;
1353    }
1354 
1355    switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
1356    case VG_CLIENT_OBJECT_TYPE_PATH:
1357    {
1358       switch (param_type) {
1359       /*
1360          read-only scalar param types
1361       */
1362 
1363       case VG_PATH_FORMAT:
1364       case VG_PATH_DATATYPE:
1365       case VG_PATH_SCALE:
1366       case VG_PATH_BIAS:
1367       case VG_PATH_NUM_SEGMENTS:
1368       case VG_PATH_NUM_COORDS:
1369       {
1370          if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
1371          break;
1372       }
1373 
1374       /*
1375          invalid param type
1376       */
1377 
1378       default:
1379          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1380       }
1381 
1382       break;
1383    }
1384    case VG_CLIENT_OBJECT_TYPE_PAINT:
1385    {
1386       VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)object;
1387       VGint value_i;
1388 
1389       if (!paint->gradient &&
1390          need_paint_gradient(param_type) &&
1391          !paint_alloc_gradient(paint)) {
1392          set_error(VG_OUT_OF_MEMORY_ERROR);
1393          break;
1394       }
1395 
1396       value_i = (count == 1) ? param_to_int(are_floats, values, 0) : 0;
1397 
1398       switch (param_type) {
1399       /*
1400          settable scalar param types
1401       */
1402 
1403       #define CASE_I_SERVER(PARAM_TYPE, OK, VALUE, FN) \
1404          case PARAM_TYPE: \
1405          { \
1406             if ((count != 1) || !(OK)) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
1407             if (VALUE != FN(value_i)) { \
1408                VALUE = FN(value_i); \
1409                set_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, PARAM_TYPE, 1, &value_i); \
1410             } \
1411             break; \
1412          }
1413       CASE_I_SERVER(VG_PAINT_TYPE, is_paint_type((VGPaintType)value_i), paint->type, (VGPaintType))
1414       CASE_I_SERVER(VG_PAINT_COLOR_RAMP_SPREAD_MODE, is_color_ramp_spread_mode((VGColorRampSpreadMode)value_i), paint->gradient->ramp_spread_mode, (VGColorRampSpreadMode))
1415       CASE_I_SERVER(VG_PAINT_COLOR_RAMP_PREMULTIPLIED, true, paint->gradient->ramp_pre, clean_boolean)
1416       CASE_I_SERVER(VG_PAINT_PATTERN_TILING_MODE, is_tiling_mode((VGTilingMode)value_i), paint->pattern_tiling_mode, (VGTilingMode))
1417       #undef CASE_I_SERVER
1418 
1419       /*
1420          vector param types
1421       */
1422 
1423       case VG_PAINT_COLOR:
1424       {
1425          if (count != 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1426          if (params_to_floats(
1427             paint->color,
1428             are_floats, values, count)) {
1429             VGint rgba = color_floats_to_rgba_clean(paint->color);
1430             set_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_COLOR, 1, &rgba);
1431          }
1432          break;
1433       }
1434       case VG_PAINT_COLOR_RAMP_STOPS:
1435       {
1436          if ((count % 5) != 0) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1437          count = _min(count, VG_CONFIG_MAX_COLOR_RAMP_STOPS * 5);
1438          if (paint->gradient->ramp_stops_count != count) {
1439             VGfloat *ramp_stops = NULL;
1440             if (count != 0) {
1441                ramp_stops = (VGfloat *)khrn_platform_malloc(count * sizeof(VGfloat), "VG_CLIENT_PAINT_GRADIENT_T.ramp_stops");
1442                if (!ramp_stops) {
1443                   set_error(VG_OUT_OF_MEMORY_ERROR);
1444                   break;
1445                }
1446             }
1447             if (paint->gradient->ramp_stops) {
1448                khrn_platform_free(paint->gradient->ramp_stops);
1449             }
1450             paint->gradient->ramp_stops = ramp_stops;
1451          }
1452          if (params_to_floats(
1453             paint->gradient->ramp_stops,
1454             are_floats, values, count) ||
1455             (paint->gradient->ramp_stops_count != count)) {
1456             paint->gradient->ramp_stops_count = count;
1457             set_parameter_fv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_COLOR_RAMP_STOPS, count, paint->gradient->ramp_stops);
1458          }
1459          break;
1460       }
1461       case VG_PAINT_LINEAR_GRADIENT:
1462       {
1463          if (count != 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1464          if (params_to_floats(
1465             paint->gradient->linear,
1466             are_floats, values, count)) {
1467             set_parameter_fv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_LINEAR_GRADIENT, 4, paint->gradient->linear);
1468          }
1469          break;
1470       }
1471       case VG_PAINT_RADIAL_GRADIENT:
1472       {
1473          if (count != 5) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1474          if (params_to_floats(
1475             paint->gradient->radial,
1476             are_floats, values, count)) {
1477             set_parameter_fv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_RADIAL_GRADIENT, 5, paint->gradient->radial);
1478          }
1479          break;
1480       }
1481 
1482       /*
1483          invalid param type
1484       */
1485 
1486       default:
1487          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1488       }
1489 
1490       break;
1491    }
1492    case VG_CLIENT_OBJECT_TYPE_IMAGE:
1493    {
1494       switch (param_type) {
1495       /*
1496          read-only scalar param types
1497       */
1498 
1499       case VG_IMAGE_FORMAT:
1500       case VG_IMAGE_WIDTH:
1501       case VG_IMAGE_HEIGHT:
1502       {
1503          if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
1504          break;
1505       }
1506 
1507       /*
1508          invalid param type
1509       */
1510 
1511       default:
1512          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1513       }
1514 
1515       break;
1516    }
1517    case VG_CLIENT_OBJECT_TYPE_MASK_LAYER:
1518    {
1519       switch (param_type) {
1520       /*
1521          read-only scalar param types
1522       */
1523 
1524       case VG_IMAGE_WIDTH:
1525       case VG_IMAGE_HEIGHT:
1526       {
1527          if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
1528          break;
1529       }
1530 
1531       /*
1532          invalid param type
1533       */
1534 
1535       default:
1536          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1537       }
1538 
1539       break;
1540    }
1541    case VG_CLIENT_OBJECT_TYPE_FONT:
1542    {
1543       switch (param_type) {
1544       /*
1545          read-only scalar param types
1546       */
1547 
1548       case VG_FONT_NUM_GLYPHS:
1549       {
1550          if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
1551          break;
1552       }
1553 
1554       /*
1555          invalid param type
1556       */
1557 
1558       default:
1559          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1560       }
1561 
1562       break;
1563    }
1564    default:
1565    {
1566       UNREACHABLE();
1567    }
1568    }
1569 
1570    platform_mutex_release(&state->shared_state->mutex);
1571 }
1572 
get_parameter_ifv(CLIENT_THREAD_STATE_T * thread,VG_CLIENT_STATE_T * state,VGHandle vg_handle,VGint param_type,VGint count,bool are_floats,void * values)1573 static void get_parameter_ifv(
1574    CLIENT_THREAD_STATE_T *thread,
1575    VG_CLIENT_STATE_T *state,
1576    VGHandle vg_handle,
1577    VGint param_type,
1578    VGint count,
1579    bool are_floats,
1580    void *values)
1581 {
1582    void *object;
1583 
1584    platform_mutex_acquire(&state->shared_state->mutex);
1585 
1586    object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
1587    if (!object) {
1588       set_error(VG_BAD_HANDLE_ERROR);
1589       platform_mutex_release(&state->shared_state->mutex);
1590       return;
1591    }
1592 
1593    #define CASE(PARAM_TYPE, FN, VALUE) \
1594       case PARAM_TYPE: \
1595       { \
1596          if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
1597          FN(are_floats, values, 0, VALUE); \
1598          break; \
1599       }
1600    #define CASE_I(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, int_to_param, VALUE)
1601    #define CASE_F(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, float_to_param, VALUE)
1602 
1603    switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
1604    case VG_CLIENT_OBJECT_TYPE_PATH:
1605    {
1606       VG_CLIENT_PATH_T *path = (VG_CLIENT_PATH_T *)object;
1607 
1608       switch (param_type) {
1609       /*
1610          scalar param types
1611       */
1612 
1613       CASE_I(VG_PATH_FORMAT, path->format)
1614       CASE_I(VG_PATH_DATATYPE, path->datatype)
1615       CASE_F(VG_PATH_SCALE, path->scale)
1616       CASE_F(VG_PATH_BIAS, path->bias)
1617       case VG_PATH_NUM_SEGMENTS:
1618       case VG_PATH_NUM_COORDS:
1619       {
1620          if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1621          if (need_path_segments(path->caps)) {
1622             int_to_param(are_floats, values, 0, (param_type == VG_PATH_NUM_SEGMENTS) ?
1623                path->segments.size :
1624                get_coords_count((const VGubyte *)path->segments.data, path->segments.size));
1625          } else {
1626             VGint value;
1627             if (get_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PATH, param_type, 1, &value)) {
1628                int_to_param(are_floats, values, 0, value);
1629             }
1630          }
1631          break;
1632       }
1633 
1634       /*
1635          invalid param type
1636       */
1637 
1638       default:
1639          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1640       }
1641 
1642       break;
1643    }
1644    case VG_CLIENT_OBJECT_TYPE_PAINT:
1645    {
1646       VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)object;
1647 
1648       if (!paint->gradient &&
1649          need_paint_gradient(param_type) &&
1650          !paint_alloc_gradient(paint)) {
1651          set_error(VG_OUT_OF_MEMORY_ERROR);
1652          break;
1653       }
1654 
1655       switch (param_type) {
1656       /*
1657          scalar param types
1658       */
1659 
1660       CASE_I(VG_PAINT_TYPE, paint->type)
1661       CASE_I(VG_PAINT_COLOR_RAMP_SPREAD_MODE, paint->gradient->ramp_spread_mode)
1662       CASE_I(VG_PAINT_COLOR_RAMP_PREMULTIPLIED, paint->gradient->ramp_pre)
1663       CASE_I(VG_PAINT_PATTERN_TILING_MODE, paint->pattern_tiling_mode)
1664 
1665       /*
1666          vector param types
1667       */
1668 
1669       case VG_PAINT_COLOR:
1670       {
1671          if (count > 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1672          floats_to_params(
1673             are_floats, values, count,
1674             paint->color);
1675          break;
1676       }
1677       case VG_PAINT_COLOR_RAMP_STOPS:
1678       {
1679          if ((VGuint)count > paint->gradient->ramp_stops_count) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1680          floats_to_params(
1681             are_floats, values, count,
1682             paint->gradient->ramp_stops);
1683          break;
1684       }
1685       case VG_PAINT_LINEAR_GRADIENT:
1686       {
1687          if (count > 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1688          floats_to_params(
1689             are_floats, values, count,
1690             paint->gradient->linear);
1691          break;
1692       }
1693       case VG_PAINT_RADIAL_GRADIENT:
1694       {
1695          if (count > 5) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1696          floats_to_params(
1697             are_floats, values, count,
1698             paint->gradient->radial);
1699          break;
1700       }
1701 
1702       /*
1703          invalid param type
1704       */
1705 
1706       default:
1707          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1708       }
1709 
1710       break;
1711    }
1712    case VG_CLIENT_OBJECT_TYPE_IMAGE:
1713    {
1714       VG_CLIENT_IMAGE_T *image = (VG_CLIENT_IMAGE_T *)object;
1715 
1716       switch (param_type) {
1717       /*
1718          scalar param types
1719       */
1720 
1721       CASE_I(VG_IMAGE_FORMAT, image->format)
1722       CASE_I(VG_IMAGE_WIDTH, image->width)
1723       CASE_I(VG_IMAGE_HEIGHT, image->height)
1724 
1725       /*
1726          invalid param type
1727       */
1728 
1729       default:
1730          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1731       }
1732 
1733       break;
1734    }
1735    case VG_CLIENT_OBJECT_TYPE_MASK_LAYER:
1736    {
1737       VG_CLIENT_MASK_LAYER_T *mask_layer = (VG_CLIENT_MASK_LAYER_T *)object;
1738 
1739       switch (param_type) {
1740       /*
1741          scalar param types
1742       */
1743 
1744       CASE_I(VG_IMAGE_WIDTH, mask_layer->width)
1745       CASE_I(VG_IMAGE_HEIGHT, mask_layer->height)
1746 
1747       /*
1748          invalid param type
1749       */
1750 
1751       default:
1752          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1753       }
1754 
1755       break;
1756    }
1757    case VG_CLIENT_OBJECT_TYPE_FONT:
1758    {
1759       switch (param_type) {
1760       /*
1761          scalar param types
1762       */
1763 
1764       case VG_FONT_NUM_GLYPHS:
1765       {
1766          VGint glyphs_count;
1767          if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
1768          if (get_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_FONT, VG_FONT_NUM_GLYPHS, 1, &glyphs_count)) {
1769             int_to_param(are_floats, values, 0, glyphs_count);
1770          }
1771          break;
1772       }
1773 
1774       /*
1775          invalid param type
1776       */
1777 
1778       default:
1779          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1780       }
1781 
1782       break;
1783    }
1784    default:
1785    {
1786       UNREACHABLE();
1787    }
1788    }
1789 
1790    #undef CASE_F
1791    #undef CASE_I
1792    #undef CASE
1793 
1794    platform_mutex_release(&state->shared_state->mutex);
1795 }
1796 
vgSetf(VGParamType param_type,VGfloat value)1797 VG_API_CALL void VG_API_ENTRY vgSetf(
1798    VGParamType param_type,
1799    VGfloat value) VG_API_EXIT
1800 {
1801    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1802    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
1803    if (!state) {
1804       return;
1805    }
1806 
1807    if (is_vector_param_type(param_type)) {
1808       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1809       return;
1810    }
1811 
1812    set_ifv(thread, state, param_type, 1, true, &value);
1813 }
1814 
vgSeti(VGParamType param_type,VGint value)1815 VG_API_CALL void VG_API_ENTRY vgSeti(
1816    VGParamType param_type,
1817    VGint value) VG_API_EXIT
1818 {
1819    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1820    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
1821    if (!state) {
1822       return;
1823    }
1824 
1825    if (is_vector_param_type(param_type)) {
1826       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1827       return;
1828    }
1829 
1830    set_ifv(thread, state, param_type, 1, false, &value);
1831 }
1832 
vgSetfv(VGParamType param_type,VGint count,const VGfloat * values)1833 VG_API_CALL void VG_API_ENTRY vgSetfv(
1834    VGParamType param_type,
1835    VGint count,
1836    const VGfloat *values) VG_API_EXIT
1837 {
1838    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1839    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
1840    if (!state) {
1841       return;
1842    }
1843 
1844    /*
1845     * Verify the arguments, and report an error if any of the following holds:
1846     *   - 'count' is negative
1847     *   - 'count' is greater than zero and 'values' is NULL
1848     *   - 'values' is non-NULL but not aligned on an float boundary
1849     *
1850     * If 'count' is zero, then 'values' will not (and must not) be dereferenced
1851     * in this function or any of it's descendents.  The OpenVG Specification
1852     * Version 1.1, section 5.2 Setting and Querying Context Parameter Values
1853     * states:
1854     *
1855     *   "If the count parameter is 0, the pointer argument is not dereferenced.
1856     *    For example, the call vgSet(VG_STROKE_DASH_PATTERN, 0, (void *) 0)
1857     *    sets the dash pattern to a zero-length array (which has the effect of
1858     *    disabling dashing) without dereferencing the third parameter."
1859     *
1860     * Automatic checking tools such as Coverity may flag this case ('values'
1861     * not verified non-NULL when 'count' is zero) as a potential NULL pointer
1862     * dereference. In this case it is not.
1863     */
1864    if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_float(values))) {
1865       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1866       return;
1867    }
1868 
1869    set_ifv(thread, state, param_type, count, true, values);
1870 }
1871 
vgSetiv(VGParamType param_type,VGint count,const VGint * values)1872 VG_API_CALL void VG_API_ENTRY vgSetiv(
1873    VGParamType param_type,
1874    VGint count,
1875    const VGint *values) VG_API_EXIT
1876 {
1877    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1878    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
1879    if (!state) {
1880       return;
1881    }
1882 
1883    /*
1884     * Verify the arguments, and report an error if any of the following holds:
1885     *   - 'count' is negative
1886     *   - 'count' is greater than zero and 'values' is NULL
1887     *   - 'values' is non-NULL but not aligned on an integer boundary
1888     *
1889     * If 'count' is zero, then 'values' will not (and must not) be dereferenced
1890     * in this function or any of it's descendents.  See the comment in vgSetfv()
1891     * above for more detail.
1892     *
1893     * Automatic checking tools such as Coverity may flag this case ('values'
1894     * not verified non-NULL when 'count' is zero) as a potential NULL pointer
1895     * dereference. In this case it is not.
1896     */
1897    if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_int(values))) {
1898       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1899       return;
1900    }
1901 
1902    set_ifv(thread, state, param_type, count, false, values);
1903 }
1904 
vgGetf(VGParamType param_type)1905 VG_API_CALL VGfloat VG_API_ENTRY vgGetf(
1906    VGParamType param_type) VG_API_EXIT
1907 {
1908    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1909    VGfloat value = 0.0f;
1910 
1911    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
1912    if (!state) {
1913       return 0.0f;
1914    }
1915 
1916    if (is_vector_param_type(param_type)) {
1917       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1918       return 0.0f;
1919    }
1920 
1921    get_ifv(thread, state, param_type, 1, true, &value);
1922    return value;
1923 }
1924 
vgGeti(VGParamType param_type)1925 VG_API_CALL VGint VG_API_ENTRY vgGeti(
1926    VGParamType param_type) VG_API_EXIT
1927 {
1928    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
1929    VGint value = 0;
1930 
1931    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
1932    if (!state) {
1933       return 0;
1934    }
1935 
1936    if (is_vector_param_type(param_type)) {
1937       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
1938       return 0;
1939    }
1940 
1941    get_ifv(thread, state, param_type, 1, false, &value);
1942    return value;
1943 }
1944 
vgGetVectorSize(VGParamType param_type)1945 VG_API_CALL VGint VG_API_ENTRY vgGetVectorSize(
1946    VGParamType param_type) VG_API_EXIT
1947 {
1948 
1949    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(CLIENT_GET_THREAD_STATE());
1950    if (!state) {
1951       return 0;
1952    }
1953 
1954    switch (param_type) {
1955    /*
1956       scalar param types
1957    */
1958 
1959    case VG_MATRIX_MODE:
1960    case VG_FILL_RULE:
1961    case VG_IMAGE_QUALITY:
1962    case VG_RENDERING_QUALITY:
1963    case VG_BLEND_MODE:
1964    case VG_IMAGE_MODE:
1965    case VG_COLOR_TRANSFORM:
1966    case VG_STROKE_LINE_WIDTH:
1967    case VG_STROKE_CAP_STYLE:
1968    case VG_STROKE_JOIN_STYLE:
1969    case VG_STROKE_MITER_LIMIT:
1970    case VG_STROKE_DASH_PHASE:
1971    case VG_STROKE_DASH_PHASE_RESET:
1972    case VG_MASKING:
1973    case VG_SCISSORING:
1974    case VG_PIXEL_LAYOUT:
1975    case VG_SCREEN_LAYOUT:
1976    case VG_FILTER_FORMAT_LINEAR:
1977    case VG_FILTER_FORMAT_PREMULTIPLIED:
1978    case VG_FILTER_CHANNEL_MASK:
1979    case VG_MAX_SCISSOR_RECTS:
1980    case VG_MAX_DASH_COUNT:
1981    case VG_MAX_KERNEL_SIZE:
1982    case VG_MAX_SEPARABLE_KERNEL_SIZE:
1983    case VG_MAX_COLOR_RAMP_STOPS:
1984    case VG_MAX_IMAGE_WIDTH:
1985    case VG_MAX_IMAGE_HEIGHT:
1986    case VG_MAX_IMAGE_PIXELS:
1987    case VG_MAX_IMAGE_BYTES:
1988    case VG_MAX_FLOAT:
1989    case VG_MAX_GAUSSIAN_STD_DEVIATION: return 1;
1990 
1991    /*
1992       vector param types
1993    */
1994 
1995    case VG_SCISSOR_RECTS:          return state->scissor_rects_count;
1996    case VG_COLOR_TRANSFORM_VALUES: return 8;
1997    case VG_STROKE_DASH_PATTERN:    return state->stroke_dash_pattern_count;
1998    case VG_TILE_FILL_COLOR:
1999    case VG_CLEAR_COLOR:            return 4;
2000    case VG_GLYPH_ORIGIN:           return 2;
2001 
2002    /*
2003       invalid param type
2004    */
2005 
2006    default: set_error(VG_ILLEGAL_ARGUMENT_ERROR); return 0;
2007    }
2008 }
2009 
vgGetfv(VGParamType param_type,VGint count,VGfloat * values)2010 VG_API_CALL void VG_API_ENTRY vgGetfv(
2011    VGParamType param_type,
2012    VGint count,
2013    VGfloat *values) VG_API_EXIT
2014 {
2015    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2016    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2017    if (!state) {
2018       return;
2019    }
2020 
2021    if ((count <= 0) || !values || !is_aligned_float(values)) {
2022       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2023       return;
2024    }
2025 
2026    get_ifv(thread, state, param_type, count, true, values);
2027 }
2028 
vgGetiv(VGParamType param_type,VGint count,VGint * values)2029 VG_API_CALL void VG_API_ENTRY vgGetiv(
2030    VGParamType param_type,
2031    VGint count,
2032    VGint *values) VG_API_EXIT
2033 {
2034    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2035    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2036    if (!state) {
2037       return;
2038    }
2039 
2040    if ((count <= 0) || !values || !is_aligned_int(values)) {
2041       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2042       return;
2043    }
2044 
2045    get_ifv(thread, state, param_type, count, false, values);
2046 }
2047 
vgSetParameterf(VGHandle vg_handle,VGint param_type,VGfloat value)2048 VG_API_CALL void VG_API_ENTRY vgSetParameterf(
2049    VGHandle vg_handle,
2050    VGint param_type,
2051    VGfloat value) VG_API_EXIT
2052 {
2053    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2054    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2055    if (!state) {
2056       return;
2057    }
2058 
2059    if (is_vector_object_param_type(param_type)) {
2060       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2061       return;
2062    }
2063 
2064    set_parameter_ifv(thread, state, vg_handle, param_type, 1, true, &value);
2065 }
2066 
vgSetParameteri(VGHandle vg_handle,VGint param_type,VGint value)2067 VG_API_CALL void VG_API_ENTRY vgSetParameteri(
2068    VGHandle vg_handle,
2069    VGint param_type,
2070    VGint value) VG_API_EXIT
2071 {
2072    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2073    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2074    if (!state) {
2075       return;
2076    }
2077 
2078    if (is_vector_object_param_type(param_type)) {
2079       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2080       return;
2081    }
2082 
2083    set_parameter_ifv(thread, state, vg_handle, param_type, 1, false, &value);
2084 }
2085 
vgSetParameterfv(VGHandle vg_handle,VGint param_type,VGint count,const VGfloat * values)2086 VG_API_CALL void VG_API_ENTRY vgSetParameterfv(
2087    VGHandle vg_handle,
2088    VGint param_type,
2089    VGint count,
2090    const VGfloat *values) VG_API_EXIT
2091 {
2092    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2093    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2094    if (!state) {
2095       return;
2096    }
2097 
2098    /*
2099     * Verify the arguments, and report an error if any of the following holds:
2100     *   - 'count' is negative
2101     *   - 'count' is greater than zero and 'values' is NULL
2102     *   - 'values' is non-NULL but not aligned on an float boundary
2103     *
2104     * If 'count' is zero, then 'values' will not (and must not) be dereferenced
2105     * in this function or any of it's descendents.  See the comment in vgSetfv()
2106     * above for more detail.
2107     *
2108     * Automatic checking tools such as Coverity may flag this case ('values'
2109     * not verified non-NULL when 'count' is zero) as a potential NULL pointer
2110     * dereference. In this case it is not.
2111     */
2112    if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_float(values))) {
2113       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2114       return;
2115    }
2116 
2117    set_parameter_ifv(thread, state, vg_handle, param_type, count, true, values);
2118 }
2119 
vgSetParameteriv(VGHandle vg_handle,VGint param_type,VGint count,const VGint * values)2120 VG_API_CALL void VG_API_ENTRY vgSetParameteriv(
2121    VGHandle vg_handle,
2122    VGint param_type,
2123    VGint count,
2124    const VGint *values) VG_API_EXIT
2125 {
2126    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2127    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2128    if (!state) {
2129       return;
2130    }
2131 
2132    /*
2133     * Verify the arguments, and report an error if any of the following holds:
2134     *   - 'count' is negative
2135     *   - 'count' is greater than zero and 'values' is NULL
2136     *   - 'values' is non-NULL but not aligned on an integer boundary
2137     *
2138     * If 'count' is zero, then 'values' will not (and must not) be dereferenced
2139     * in this function or any of it's descendents.  See the comment in vgSetfv()
2140     * above for more detail.
2141     *
2142     * Automatic checking tools such as Coverity may flag this case ('values'
2143     * not verified non-NULL when 'count' is zero) as a potential NULL pointer
2144     * dereference. In this case it is not.
2145     */
2146    if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_int(values))) {
2147       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2148       return;
2149    }
2150 
2151    set_parameter_ifv(thread, state, vg_handle, param_type, count, false, values);
2152 }
2153 
vgGetParameterf(VGHandle vg_handle,VGint param_type)2154 VG_API_CALL VGfloat VG_API_ENTRY vgGetParameterf(
2155    VGHandle vg_handle,
2156    VGint param_type) VG_API_EXIT
2157 {
2158    VGfloat value = 0.0f;
2159 
2160    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2161    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2162    if (!state) {
2163       return 0.0f;
2164    }
2165 
2166    if (is_vector_object_param_type(param_type)) {
2167       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2168       return 0.0f;
2169    }
2170 
2171    get_parameter_ifv(thread, state, vg_handle, param_type, 1, true, &value);
2172    return value;
2173 }
2174 
vgGetParameteri(VGHandle vg_handle,VGint param_type)2175 VG_API_CALL VGint VG_API_ENTRY vgGetParameteri(
2176    VGHandle vg_handle,
2177    VGint param_type) VG_API_EXIT
2178 {
2179    VGint value = 0;
2180 
2181    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2182    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2183    if (!state) {
2184       return 0;
2185    }
2186 
2187    if (is_vector_object_param_type(param_type)) {
2188       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2189       return 0;
2190    }
2191 
2192    get_parameter_ifv(thread, state, vg_handle, param_type, 1, false, &value);
2193    return value;
2194 }
2195 
vgGetParameterVectorSize(VGHandle vg_handle,VGint param_type)2196 VG_API_CALL VGint VG_API_ENTRY vgGetParameterVectorSize(
2197    VGHandle vg_handle,
2198    VGint param_type) VG_API_EXIT
2199 {
2200    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2201    void *object;
2202    VGint count = 0;
2203 
2204    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2205    if (!state) {
2206       return 0;
2207    }
2208 
2209    platform_mutex_acquire(&state->shared_state->mutex);
2210 
2211    object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
2212    if (!object) {
2213       set_error(VG_BAD_HANDLE_ERROR);
2214       platform_mutex_release(&state->shared_state->mutex);
2215       return 0;
2216    }
2217 
2218    switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
2219    case VG_CLIENT_OBJECT_TYPE_PATH:
2220    {
2221       switch (param_type) {
2222       /*
2223          scalar param types
2224       */
2225 
2226       case VG_PATH_FORMAT:
2227       case VG_PATH_DATATYPE:
2228       case VG_PATH_SCALE:
2229       case VG_PATH_BIAS:
2230       case VG_PATH_NUM_SEGMENTS:
2231       case VG_PATH_NUM_COORDS:
2232       {
2233          count = 1;
2234          break;
2235       }
2236 
2237       /*
2238          invalid param type
2239       */
2240 
2241       default:
2242          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2243       }
2244 
2245       break;
2246    }
2247    case VG_CLIENT_OBJECT_TYPE_PAINT:
2248    {
2249       switch (param_type) {
2250       /*
2251          scalar param types
2252       */
2253 
2254       case VG_PAINT_TYPE:
2255       case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
2256       case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
2257       case VG_PAINT_PATTERN_TILING_MODE:
2258       {
2259          count = 1;
2260          break;
2261       }
2262 
2263       /*
2264          vector param types
2265       */
2266 
2267       case VG_PAINT_COLOR:
2268       {
2269          count = 4;
2270          break;
2271       }
2272       case VG_PAINT_COLOR_RAMP_STOPS:
2273       {
2274          VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)object;
2275          count = paint->gradient ? paint->gradient->ramp_stops_count : 0;
2276          break;
2277       }
2278       case VG_PAINT_LINEAR_GRADIENT:
2279       {
2280          count = 4;
2281          break;
2282       }
2283       case VG_PAINT_RADIAL_GRADIENT:
2284       {
2285          count = 5;
2286          break;
2287       }
2288 
2289       /*
2290          invalid param type
2291       */
2292 
2293       default:
2294          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2295       }
2296 
2297       break;
2298    }
2299    case VG_CLIENT_OBJECT_TYPE_IMAGE:
2300    {
2301       switch (param_type) {
2302       /*
2303          scalar param types
2304       */
2305 
2306       case VG_IMAGE_FORMAT:
2307       case VG_IMAGE_WIDTH:
2308       case VG_IMAGE_HEIGHT:
2309       {
2310          count = 1;
2311          break;
2312       }
2313 
2314       /*
2315          invalid param type
2316       */
2317 
2318       default:
2319          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2320       }
2321 
2322       break;
2323    }
2324    case VG_CLIENT_OBJECT_TYPE_MASK_LAYER:
2325    {
2326       switch (param_type) {
2327       /*
2328          scalar param types
2329       */
2330 
2331       case VG_IMAGE_WIDTH:
2332       case VG_IMAGE_HEIGHT:
2333       {
2334          count = 1;
2335          break;
2336       }
2337 
2338       /*
2339          invalid param type
2340       */
2341 
2342       default:
2343          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2344       }
2345 
2346       break;
2347    }
2348    case VG_CLIENT_OBJECT_TYPE_FONT:
2349    {
2350       switch (param_type) {
2351       /*
2352          scalar param types
2353       */
2354 
2355       case VG_FONT_NUM_GLYPHS:
2356       {
2357          count = 1;
2358          break;
2359       }
2360 
2361       /*
2362          invalid param type
2363       */
2364 
2365       default:
2366          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2367       }
2368 
2369       break;
2370    }
2371    default:
2372    {
2373       UNREACHABLE();
2374    }
2375    }
2376 
2377    platform_mutex_release(&state->shared_state->mutex);
2378    return count;
2379 }
2380 
vgGetParameterfv(VGHandle vg_handle,VGint param_type,VGint count,VGfloat * values)2381 VG_API_CALL void VG_API_ENTRY vgGetParameterfv(
2382    VGHandle vg_handle,
2383    VGint param_type,
2384    VGint count,
2385    VGfloat *values) VG_API_EXIT
2386 {
2387    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2388    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2389    if (!state) {
2390       return;
2391    }
2392 
2393    if ((count <= 0) || !values || !is_aligned_float(values)) {
2394       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2395       return;
2396    }
2397 
2398    get_parameter_ifv(thread, state, vg_handle, param_type, count, true, values);
2399 }
2400 
vgGetParameteriv(VGHandle vg_handle,VGint param_type,VGint count,VGint * values)2401 VG_API_CALL void VG_API_ENTRY vgGetParameteriv(
2402    VGHandle vg_handle,
2403    VGint param_type,
2404    VGint count,
2405    VGint *values) VG_API_EXIT
2406 {
2407    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2408    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2409    if (!state) {
2410       return;
2411    }
2412 
2413    if ((count <= 0) || !values || !is_aligned_int(values)) {
2414       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2415       return;
2416    }
2417 
2418    get_parameter_ifv(thread, state, vg_handle, param_type, count, false, values);
2419 }
2420 
2421 /******************************************************************************
2422 api matrices
2423 ******************************************************************************/
2424 
vgLoadIdentity(void)2425 VG_API_CALL void VG_API_ENTRY vgLoadIdentity(void) VG_API_EXIT
2426 {
2427    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2428    VG_MAT3X3_SYNC_T *matrix_sync;
2429 
2430    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2431    if (!state) {
2432       return;
2433    }
2434 
2435    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2436    vg_mat3x3_set_identity(&matrix_sync->client);
2437 }
2438 
vgLoadMatrix(const VGfloat * matrix)2439 VG_API_CALL void VG_API_ENTRY vgLoadMatrix(const VGfloat *matrix) VG_API_EXIT
2440 {
2441    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2442    VG_MAT3X3_SYNC_T *matrix_sync;
2443 
2444    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2445    if (!state) {
2446       return;
2447    }
2448 
2449    if (!matrix || !is_aligned_float(matrix)) {
2450       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2451       return;
2452    }
2453 
2454    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2455    vg_mat3x3_set_clean(&matrix_sync->client, matrix, is_matrix_affine(state->matrix_mode));
2456 }
2457 
vgGetMatrix(VGfloat * matrix)2458 VG_API_CALL void VG_API_ENTRY vgGetMatrix(VGfloat *matrix) VG_API_EXIT
2459 {
2460    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2461    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2462    if (!state) {
2463       return;
2464    }
2465 
2466    if (!matrix || !is_aligned_float(matrix)) {
2467       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2468       return;
2469    }
2470 
2471    vg_mat3x3_get(&get_matrix_sync(state, state->matrix_mode)->client, matrix);
2472 }
2473 
vgMultMatrix(const VGfloat * matrix)2474 VG_API_CALL void VG_API_ENTRY vgMultMatrix(const VGfloat *matrix) VG_API_EXIT
2475 {
2476    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2477    VG_MAT3X3_T a;
2478    VG_MAT3X3_SYNC_T *matrix_sync;
2479 
2480    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2481    if (!state) {
2482       return;
2483    }
2484 
2485    if (!matrix || !is_aligned_float(matrix)) {
2486       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2487       return;
2488    }
2489 
2490    vg_mat3x3_set_clean(&a, matrix, is_matrix_affine(state->matrix_mode));
2491 
2492    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2493    vg_mat3x3_postmul(&matrix_sync->client, &a);
2494 }
2495 
vgTranslate(VGfloat x,VGfloat y)2496 VG_API_CALL void VG_API_ENTRY vgTranslate(VGfloat x, VGfloat y) VG_API_EXIT
2497 {
2498    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2499    VG_CLIENT_STATE_T *state;
2500    VG_MAT3X3_SYNC_T *matrix_sync;
2501 
2502    x = clean_float(x);
2503    y = clean_float(y);
2504 
2505    state = VG_GET_CLIENT_STATE(thread);
2506    if (!state) {
2507       return;
2508    }
2509 
2510    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2511    vg_mat3x3_postmul_translate(&matrix_sync->client, x, y);
2512 }
2513 
vgScale(VGfloat x,VGfloat y)2514 VG_API_CALL void VG_API_ENTRY vgScale(VGfloat x, VGfloat y) VG_API_EXIT
2515 {
2516    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2517    VG_CLIENT_STATE_T *state;
2518    VG_MAT3X3_SYNC_T *matrix_sync;
2519 
2520    x = clean_float(x);
2521    y = clean_float(y);
2522 
2523    state = VG_GET_CLIENT_STATE(thread);
2524    if (!state) {
2525       return;
2526    }
2527 
2528    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2529    vg_mat3x3_postmul_scale(&matrix_sync->client, x, y);
2530 }
2531 
vgShear(VGfloat x,VGfloat y)2532 VG_API_CALL void VG_API_ENTRY vgShear(VGfloat x, VGfloat y) VG_API_EXIT
2533 {
2534    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2535    VG_CLIENT_STATE_T *state;
2536    VG_MAT3X3_SYNC_T *matrix_sync;
2537 
2538    x = clean_float(x);
2539    y = clean_float(y);
2540 
2541    state = VG_GET_CLIENT_STATE(thread);
2542    if (!state) {
2543       return;
2544    }
2545 
2546    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2547    vg_mat3x3_postmul_shear(&matrix_sync->client, x, y);
2548 }
2549 
vgRotate(VGfloat angle)2550 VG_API_CALL void VG_API_ENTRY vgRotate(VGfloat angle) VG_API_EXIT
2551 {
2552    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2553    VG_CLIENT_STATE_T *state;
2554    VG_MAT3X3_SYNC_T *matrix_sync;
2555 
2556    angle = clean_float(angle);
2557 
2558    state = VG_GET_CLIENT_STATE(thread);
2559    if (!state) {
2560       return;
2561    }
2562 
2563    matrix_sync = get_matrix_sync(state, state->matrix_mode);
2564    vg_mat3x3_postmul_rotate(&matrix_sync->client, angle * (PI / 180.0f));
2565 }
2566 
2567 /******************************************************************************
2568 api mask/clear
2569 ******************************************************************************/
2570 
vgMask(VGHandle vg_handle,VGMaskOperation operation,VGint dst_x,VGint dst_y,VGint width,VGint height)2571 VG_API_CALL void VG_API_ENTRY vgMask(
2572    VGHandle vg_handle, /* theoretically image under vg 1.0 */
2573    VGMaskOperation operation,
2574    VGint dst_x, VGint dst_y,
2575    VGint width, VGint height) VG_API_EXIT
2576 {
2577    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2578    if (!VG_GET_CLIENT_STATE(thread)) {
2579       return;
2580    }
2581 
2582    RPC_CALL6(vgMask_impl,
2583              thread,
2584              VGMASK_ID,
2585              RPC_HANDLE(vg_handle),
2586              RPC_ENUM(operation),
2587              RPC_INT(dst_x),
2588              RPC_INT(dst_y),
2589              RPC_INT(width),
2590              RPC_INT(height));
2591 }
2592 
vgRenderToMask(VGPath vg_handle,VGbitfield paint_modes,VGMaskOperation operation)2593 VG_API_CALL void VG_API_ENTRY vgRenderToMask(
2594    VGPath vg_handle,
2595    VGbitfield paint_modes,
2596    VGMaskOperation operation) VG_API_EXIT
2597 {
2598    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2599    VG_CLIENT_STATE_T *state;
2600 
2601 #ifdef VG_NO_STROKING
2602    paint_modes &= ~VG_STROKE_PATH;
2603    if (!paint_modes) { return; }
2604 #endif
2605 
2606    state = VG_GET_CLIENT_STATE(thread);
2607    if (!state) {
2608       return;
2609    }
2610 
2611    sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
2612 
2613    RPC_CALL3(vgRenderToMask_impl,
2614              thread,
2615              VGRENDERTOMASK_ID,
2616              RPC_HANDLE(vg_handle),
2617              RPC_BITFIELD(paint_modes),
2618              RPC_ENUM(operation));
2619 }
2620 
vgCreateMaskLayer(VGint width,VGint height)2621 VG_API_CALL VGMaskLayer VG_API_ENTRY vgCreateMaskLayer(
2622    VGint width, VGint height) VG_API_EXIT
2623 {
2624    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2625    VGHandle vg_handle;
2626    VG_CLIENT_MASK_LAYER_T *mask_layer;
2627 
2628    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2629    if (!state) {
2630       return VG_INVALID_HANDLE;
2631    }
2632 
2633    if ((width <= 0) || (height <= 0) ||
2634       (width > VG_CONFIG_MAX_IMAGE_WIDTH) || (height > VG_CONFIG_MAX_IMAGE_HEIGHT) ||
2635       ((width * height) > VG_CONFIG_MAX_IMAGE_PIXELS)) {
2636       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2637       return VG_INVALID_HANDLE;
2638    }
2639 
2640    if (egl_config_get_mask_format(egl_config_to_id(
2641       CLIENT_GET_THREAD_STATE()->openvg.draw->config)) == IMAGE_FORMAT_INVALID) {
2642       return VG_INVALID_HANDLE;
2643    }
2644 
2645    vg_handle = get_stem(state);
2646    if (vg_handle == VG_INVALID_HANDLE) {
2647       set_error(VG_OUT_OF_MEMORY_ERROR);
2648       return VG_INVALID_HANDLE;
2649    }
2650 
2651    mask_layer = mask_layer_alloc(width, height);
2652    if (!mask_layer) {
2653       set_error(VG_OUT_OF_MEMORY_ERROR);
2654       destroy_stem(vg_handle);
2655       return VG_INVALID_HANDLE;
2656    }
2657 
2658    platform_mutex_acquire(&state->shared_state->mutex);
2659    if (!insert_object(state, vg_handle, mask_layer)) {
2660       set_error(VG_OUT_OF_MEMORY_ERROR);
2661       platform_mutex_release(&state->shared_state->mutex);
2662       mask_layer_free(mask_layer);
2663       destroy_stem(vg_handle);
2664       return VG_INVALID_HANDLE;
2665    }
2666    platform_mutex_release(&state->shared_state->mutex);
2667 
2668    RPC_CALL3(vgCreateMaskLayer_impl,
2669              thread,
2670              VGCREATEMASKLAYER_ID,
2671              RPC_HANDLE(vg_handle),
2672              RPC_INT(width),
2673              RPC_INT(height));
2674 
2675    return vg_handle;
2676 }
2677 
vgDestroyMaskLayer(VGMaskLayer vg_handle)2678 VG_API_CALL void VG_API_ENTRY vgDestroyMaskLayer(
2679    VGMaskLayer vg_handle) VG_API_EXIT
2680 {
2681    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2682    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2683    if (!state) {
2684       return;
2685    }
2686 
2687    platform_mutex_acquire(&state->shared_state->mutex);
2688    delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_MASK_LAYER);
2689    platform_mutex_release(&state->shared_state->mutex);
2690 
2691    RPC_CALL1(vgDestroyMaskLayer_impl,
2692              thread,
2693              VGDESTROYMASKLAYER_ID,
2694              RPC_HANDLE(vg_handle));
2695 }
2696 
vgFillMaskLayer(VGMaskLayer vg_handle,VGint x,VGint y,VGint width,VGint height,VGfloat value)2697 VG_API_CALL void VG_API_ENTRY vgFillMaskLayer(
2698    VGMaskLayer vg_handle,
2699    VGint x, VGint y,
2700    VGint width, VGint height,
2701    VGfloat value) VG_API_EXIT
2702 {
2703    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2704    value = clean_float(value);
2705 
2706    if (!VG_GET_CLIENT_STATE(thread)) {
2707       return;
2708    }
2709 
2710    RPC_CALL6(vgFillMaskLayer_impl,
2711              thread,
2712              VGFILLMASKLAYER_ID,
2713              RPC_HANDLE(vg_handle),
2714              RPC_INT(x), RPC_INT(y),
2715              RPC_INT(width), RPC_INT(height),
2716              RPC_FLOAT(value));
2717 }
2718 
vgCopyMask(VGMaskLayer dst_vg_handle,VGint dst_x,VGint dst_y,VGint src_x,VGint src_y,VGint width,VGint height)2719 VG_API_CALL void VG_API_ENTRY vgCopyMask(
2720    VGMaskLayer dst_vg_handle,
2721    VGint dst_x, VGint dst_y,
2722    VGint src_x, VGint src_y,
2723    VGint width, VGint height) VG_API_EXIT
2724 {
2725    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2726    if (!VG_GET_CLIENT_STATE(thread)) {
2727       return;
2728    }
2729 
2730    RPC_CALL7(vgCopyMask_impl,
2731              thread,
2732              VGCOPYMASK_ID,
2733              RPC_HANDLE(dst_vg_handle),
2734              RPC_INT(dst_x), RPC_INT(dst_y),
2735              RPC_INT(src_x), RPC_INT(src_y),
2736              RPC_INT(width), RPC_INT(height));
2737 }
2738 
vgClear(VGint x,VGint y,VGint width,VGint height)2739 VG_API_CALL void VG_API_ENTRY vgClear(
2740    VGint x, VGint y,
2741    VGint width, VGint height) VG_API_EXIT
2742 {
2743    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2744    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2745    if (!state) {
2746       return;
2747    }
2748 
2749    //TODO: pixmap behaviour can be better optimized to handle clears
2750    if (state->render_callback)
2751       state->render_callback();
2752 
2753    RPC_CALL4(vgClear_impl,
2754              thread,
2755              VGCLEAR_ID,
2756              RPC_INT(x),
2757              RPC_INT(y),
2758              RPC_INT(width),
2759              RPC_INT(height));
2760 }
2761 
2762 /******************************************************************************
2763 api path
2764 ******************************************************************************/
2765 
vgCreatePath(VGint format,VGPathDatatype datatype,VGfloat scale,VGfloat bias,VGint segments_capacity,VGint coords_capacity,VGbitfield caps)2766 VG_API_CALL VGPath VG_API_ENTRY vgCreatePath(
2767    VGint format,
2768    VGPathDatatype datatype,
2769    VGfloat scale, VGfloat bias,
2770    VGint segments_capacity,
2771    VGint coords_capacity,
2772    VGbitfield caps) VG_API_EXIT
2773 {
2774    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2775    VG_CLIENT_STATE_T *state;
2776    VGHandle vg_handle;
2777    VG_CLIENT_PATH_T *path;
2778 
2779    scale = clean_float(scale);
2780    bias = clean_float(bias);
2781    caps &= VG_PATH_CAPABILITY_ALL;
2782 
2783    state = VG_GET_CLIENT_STATE(thread);
2784    if (!state) {
2785       return VG_INVALID_HANDLE;
2786    }
2787 
2788    if (!is_path_format(format)) {
2789       set_error(VG_UNSUPPORTED_PATH_FORMAT_ERROR);
2790       return VG_INVALID_HANDLE;
2791    }
2792    if (!is_path_datatype(datatype) || is_zero(scale)) {
2793       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
2794       return VG_INVALID_HANDLE;
2795    }
2796 
2797    vg_handle = get_stem(state);
2798    if (vg_handle == VG_INVALID_HANDLE) {
2799       set_error(VG_OUT_OF_MEMORY_ERROR);
2800       return VG_INVALID_HANDLE;
2801    }
2802 
2803    path = path_alloc(format, datatype, scale, bias, caps, segments_capacity);
2804    if (!path) {
2805       set_error(VG_OUT_OF_MEMORY_ERROR);
2806       destroy_stem(vg_handle);
2807       return VG_INVALID_HANDLE;
2808    }
2809 
2810    platform_mutex_acquire(&state->shared_state->mutex);
2811    if (!insert_object(state, vg_handle, path)) {
2812       set_error(VG_OUT_OF_MEMORY_ERROR);
2813       platform_mutex_release(&state->shared_state->mutex);
2814       path_free(path);
2815       destroy_stem(vg_handle);
2816       return VG_INVALID_HANDLE;
2817    }
2818    platform_mutex_release(&state->shared_state->mutex);
2819 
2820    RPC_CALL8(vgCreatePath_impl,
2821              thread,
2822              VGCREATEPATH_ID,
2823              RPC_HANDLE(vg_handle),
2824              RPC_INT(format),
2825              RPC_ENUM(datatype),
2826              RPC_FLOAT(scale), RPC_FLOAT(bias),
2827              RPC_INT(segments_capacity),
2828              RPC_INT(coords_capacity),
2829              RPC_BITFIELD(caps));
2830 
2831    return vg_handle;
2832 }
2833 
vgClearPath(VGPath vg_handle,VGbitfield caps)2834 VG_API_CALL void VG_API_ENTRY vgClearPath(
2835    VGPath vg_handle,
2836    VGbitfield caps) VG_API_EXIT
2837 {
2838    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2839    VG_CLIENT_STATE_T *state;
2840    VG_CLIENT_PATH_T *path;
2841 
2842    caps &= VG_PATH_CAPABILITY_ALL;
2843 
2844    state = VG_GET_CLIENT_STATE(thread);
2845    if (!state) {
2846       return;
2847    }
2848 
2849    platform_mutex_acquire(&state->shared_state->mutex);
2850    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2851    if (path) {
2852       if (need_path_segments(path->caps) && need_path_segments(caps)) {
2853          khrn_vector_clear(&path->segments);
2854       }
2855       path_update_caps(path, caps);
2856    }
2857    platform_mutex_release(&state->shared_state->mutex);
2858 
2859    RPC_CALL2(vgClearPath_impl,
2860              thread,
2861              VGCLEARPATH_ID,
2862              RPC_HANDLE(vg_handle),
2863              RPC_BITFIELD(caps));
2864 }
2865 
vgDestroyPath(VGPath vg_handle)2866 VG_API_CALL void VG_API_ENTRY vgDestroyPath(
2867    VGPath vg_handle) VG_API_EXIT
2868 {
2869    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2870    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2871    if (!state) {
2872       return;
2873    }
2874 
2875    platform_mutex_acquire(&state->shared_state->mutex);
2876    delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2877    platform_mutex_release(&state->shared_state->mutex);
2878 
2879    RPC_CALL1(vgDestroyPath_impl,
2880              thread,
2881              VGDESTROYPATH_ID,
2882              RPC_HANDLE(vg_handle));
2883 }
2884 
vgRemovePathCapabilities(VGPath vg_handle,VGbitfield caps)2885 VG_API_CALL void VG_API_ENTRY vgRemovePathCapabilities(
2886    VGPath vg_handle,
2887    VGbitfield caps) VG_API_EXIT
2888 {
2889    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2890    VG_CLIENT_PATH_T *path;
2891 
2892    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2893    if (!state) {
2894       return;
2895    }
2896 
2897    platform_mutex_acquire(&state->shared_state->mutex);
2898    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2899    if (path) {
2900       path_update_caps(path, path->caps & ~caps);
2901    }
2902    platform_mutex_release(&state->shared_state->mutex);
2903 
2904    RPC_CALL2(vgRemovePathCapabilities_impl,
2905              thread,
2906              VGREMOVEPATHCAPABILITIES_ID,
2907              RPC_HANDLE(vg_handle),
2908              RPC_BITFIELD(caps));
2909 }
2910 
vgGetPathCapabilities(VGPath vg_handle)2911 VG_API_CALL VGbitfield VG_API_ENTRY vgGetPathCapabilities(
2912    VGPath vg_handle) VG_API_EXIT
2913 {
2914    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2915    VGbitfield caps = 0;
2916    VG_CLIENT_PATH_T *path;
2917 
2918    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2919    if (!state) {
2920       return 0;
2921    }
2922 
2923    platform_mutex_acquire(&state->shared_state->mutex);
2924    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2925    if (path) {
2926       caps = path->caps;
2927    } else {
2928       set_error(VG_BAD_HANDLE_ERROR);
2929    }
2930    platform_mutex_release(&state->shared_state->mutex);
2931 
2932    return caps;
2933 }
2934 
vgAppendPath(VGPath dst_vg_handle,VGPath src_vg_handle)2935 VG_API_CALL void VG_API_ENTRY vgAppendPath(
2936    VGPath dst_vg_handle,
2937    VGPath src_vg_handle) VG_API_EXIT
2938 {
2939    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2940    VG_CLIENT_PATH_T *dst;
2941    VG_CLIENT_PATH_T *src;
2942 
2943    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2944    if (!state) {
2945       return;
2946    }
2947 
2948    platform_mutex_acquire(&state->shared_state->mutex);
2949    dst = (VG_CLIENT_PATH_T *)lookup_object(state, dst_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2950    src = (VG_CLIENT_PATH_T *)lookup_object(state, src_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2951    if (dst && src &&
2952       (dst->caps & VG_PATH_CAPABILITY_APPEND_TO) && (src->caps & VG_PATH_CAPABILITY_APPEND_FROM) &&
2953       need_path_segments(dst->caps)) {
2954       VGuint segments_count = src->segments.size;
2955       if (!khrn_vector_extend(&dst->segments, segments_count)) {
2956          set_error(VG_OUT_OF_MEMORY_ERROR);
2957          platform_mutex_release(&state->shared_state->mutex);
2958          return;
2959       }
2960       memcpy((VGubyte *)dst->segments.data + (dst->segments.size - segments_count), src->segments.data, segments_count);
2961    }
2962    platform_mutex_release(&state->shared_state->mutex);
2963 
2964    RPC_CALL2(vgAppendPath_impl,
2965              thread,
2966              VGAPPENDPATH_ID,
2967              RPC_HANDLE(dst_vg_handle),
2968              RPC_HANDLE(src_vg_handle));
2969 }
2970 
vgAppendPathData(VGPath vg_handle,VGint segments_count,const VGubyte * segments,const void * coords)2971 VG_API_CALL void VG_API_ENTRY vgAppendPathData(
2972    VGPath vg_handle,
2973    VGint segments_count, const VGubyte *segments,
2974    const void *coords) VG_API_EXIT
2975 {
2976    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
2977    VG_CLIENT_PATH_T *path;
2978    VGPathDatatype datatype;
2979    VGuint datatype_size;
2980 
2981    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
2982    if (!state) {
2983       return;
2984    }
2985 
2986    platform_mutex_acquire(&state->shared_state->mutex);
2987 
2988    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
2989    if (!path) {
2990       set_error(VG_BAD_HANDLE_ERROR);
2991       platform_mutex_release(&state->shared_state->mutex);
2992       return;
2993    }
2994 
2995    datatype = path->datatype;
2996 
2997    if ((segments_count <= 0) || !segments ||
2998       contains_illegal_segment(segments, segments_count) ||
2999       !coords || !is_aligned_path_datatype(coords, datatype)) {
3000       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3001       platform_mutex_release(&state->shared_state->mutex);
3002       return;
3003    }
3004 
3005    if (!(path->caps & VG_PATH_CAPABILITY_APPEND_TO)) {
3006       set_error(VG_PATH_CAPABILITY_ERROR);
3007       platform_mutex_release(&state->shared_state->mutex);
3008       return;
3009    }
3010 
3011    if (need_path_segments(path->caps)) {
3012       if (!khrn_vector_extend(&path->segments, segments_count)) {
3013          set_error(VG_OUT_OF_MEMORY_ERROR);
3014          platform_mutex_release(&state->shared_state->mutex);
3015          return;
3016       }
3017       memcpy((VGubyte *)path->segments.data + (path->segments.size - segments_count), segments, segments_count);
3018    }
3019 
3020    platform_mutex_release(&state->shared_state->mutex);
3021 
3022    datatype_size = get_path_datatype_size(datatype);
3023 
3024    #ifdef RPC_DIRECT
3025       {
3026          VGuint coords_count = 0;
3027          VGuint i;
3028          for (i = 0; i != segments_count; ++i) {
3029             coords_count += get_segment_coords_count(segments[i] & ~VG_RELATIVE);
3030          }
3031 
3032          RPC_CALL6(vgAppendPathData_impl, thread, no_id,
3033             vg_handle,
3034             datatype,
3035             segments_count, segments,
3036             coords_count * datatype_size, coords);
3037       }
3038    #else
3039       /*
3040          split into multiple calls if necessary to avoid overflowing control buffer
3041       */
3042 
3043       while (segments_count != 0) {
3044          #define MESSAGE_SIZE 20
3045 
3046          VGuint size_max = rpc_send_ctrl_longest(thread, MESSAGE_SIZE + rpc_pad_ctrl(1) + rpc_pad_ctrl(6 * datatype_size)) - MESSAGE_SIZE; /* fit at least one segment */
3047          VGint chunk_segments_count = 0;
3048          VGuint chunk_coords_size = 0;
3049          for (; chunk_segments_count != segments_count; ++chunk_segments_count) {
3050             VGuint segment_coords_size = get_segment_coords_count(segments[chunk_segments_count] & ~VG_RELATIVE) * datatype_size;
3051             if ((rpc_pad_ctrl(chunk_segments_count + 1) +
3052                rpc_pad_ctrl(chunk_coords_size + segment_coords_size)) > size_max) {
3053                /*
3054                   can't fit this segment in
3055                */
3056 
3057                break;
3058             }
3059             chunk_coords_size += segment_coords_size;
3060          }
3061 
3062          {
3063             uint32_t message[] = {
3064                VGAPPENDPATHDATA_ID,
3065                RPC_HANDLE(vg_handle),
3066                RPC_ENUM(datatype),
3067                RPC_INT(chunk_segments_count),
3068                RPC_UINT(chunk_coords_size) };
3069             vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
3070 
3071             #undef MESSAGE_SIZE
3072             CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3073 
3074             rpc_send_ctrl_begin(thread, sizeof(message) + rpc_pad_ctrl(chunk_segments_count) + rpc_pad_ctrl(chunk_coords_size));
3075             rpc_send_ctrl_write(thread, message, sizeof(message));
3076             rpc_send_ctrl_write(thread, (uint32_t *)segments, chunk_segments_count);
3077             rpc_send_ctrl_write(thread, (uint32_t *)coords, chunk_coords_size);
3078             rpc_send_ctrl_end(thread);
3079          }
3080 
3081          segments_count -= chunk_segments_count;
3082          segments += chunk_segments_count;
3083          coords = (const uint8_t *)coords + chunk_coords_size;
3084       }
3085    #endif
3086 }
3087 
vgModifyPathCoords(VGPath vg_handle,VGint segments_i,VGint segments_count,const void * coords)3088 VG_API_CALL void VG_API_ENTRY vgModifyPathCoords(
3089    VGPath vg_handle,
3090    VGint segments_i, VGint segments_count,
3091    const void *coords) VG_API_EXIT
3092 {
3093    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3094    VG_CLIENT_PATH_T *path;
3095    VGPathDatatype datatype;
3096    VGuint datatype_size;
3097    VGuint coords_offset;
3098    VGuint coords_size;
3099 
3100    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3101    if (!state) {
3102       return;
3103    }
3104 
3105    platform_mutex_acquire(&state->shared_state->mutex);
3106 
3107    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
3108    if (!path) {
3109       set_error(VG_BAD_HANDLE_ERROR);
3110       platform_mutex_release(&state->shared_state->mutex);
3111       return;
3112    }
3113 
3114    if (!(path->caps & VG_PATH_CAPABILITY_MODIFY)) {
3115       set_error(VG_PATH_CAPABILITY_ERROR);
3116       platform_mutex_release(&state->shared_state->mutex);
3117       return;
3118    }
3119 
3120    datatype = path->datatype;
3121 
3122    if ((segments_i < 0) || (segments_count <= 0) ||
3123       /* will fit in VGuint (may not fit in VGint) */
3124       (((VGuint)(segments_i + segments_count)) > path->segments.size) ||
3125       !coords || !is_aligned_path_datatype(coords, datatype)) {
3126       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3127       platform_mutex_release(&state->shared_state->mutex);
3128       return;
3129    }
3130 
3131    datatype_size = get_path_datatype_size(path->datatype);
3132    coords_offset = get_coords_count((const VGubyte *)path->segments.data, segments_i) * datatype_size;
3133    coords_size = get_coords_count((const VGubyte *)path->segments.data + segments_i, segments_count) * datatype_size;
3134 
3135    platform_mutex_release(&state->shared_state->mutex);
3136 
3137    #ifdef RPC_DIRECT
3138       RPC_CALL5(vgModifyPathCoords_impl, thread, no_id,
3139          vg_handle,
3140          datatype,
3141          coords_offset, coords_size, coords);
3142    #else
3143       /*
3144          split into multiple calls if necessary to avoid overflowing control buffer
3145       */
3146 
3147       while (coords_size != 0) {
3148          #define MESSAGE_SIZE 20
3149 
3150          VGuint chunk_coords_size = _min(coords_size, rpc_send_ctrl_longest(thread, MESSAGE_SIZE + rpc_pad_ctrl(4)) - MESSAGE_SIZE); /* fit at least one coordinate */
3151 
3152          uint32_t message[] = {
3153             VGMODIFYPATHCOORDS_ID,
3154             RPC_HANDLE(vg_handle),
3155             RPC_ENUM(datatype),
3156             RPC_UINT(coords_offset),
3157             RPC_UINT(chunk_coords_size) };
3158          vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
3159 
3160          #undef MESSAGE_SIZE
3161 
3162          rpc_send_ctrl_begin(thread, sizeof(message) + rpc_pad_ctrl(chunk_coords_size));
3163          rpc_send_ctrl_write(thread, message, sizeof(message));
3164          rpc_send_ctrl_write(thread, (uint32_t *)coords, chunk_coords_size);
3165          rpc_send_ctrl_end(thread);
3166 
3167          coords_size -= chunk_coords_size;
3168          coords_offset += chunk_coords_size;
3169          coords = (const uint8_t *)coords + chunk_coords_size;
3170       }
3171    #endif
3172 }
3173 
vgTransformPath(VGPath dst_vg_handle,VGPath src_vg_handle)3174 VG_API_CALL void VG_API_ENTRY vgTransformPath(
3175    VGPath dst_vg_handle,
3176    VGPath src_vg_handle) VG_API_EXIT
3177 {
3178    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3179    VG_CLIENT_PATH_T *dst;
3180    VG_CLIENT_PATH_T *src;
3181 
3182    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3183    if (!state) {
3184       return;
3185    }
3186 
3187    platform_mutex_acquire(&state->shared_state->mutex);
3188    dst = (VG_CLIENT_PATH_T *)lookup_object(state, dst_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
3189    src = (VG_CLIENT_PATH_T *)lookup_object(state, src_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
3190    if (dst && src &&
3191       (dst->caps & VG_PATH_CAPABILITY_TRANSFORM_TO) && (src->caps & VG_PATH_CAPABILITY_TRANSFORM_FROM) &&
3192       need_path_segments(dst->caps)) {
3193       VGuint segments_count = src->segments.size;
3194       if (!khrn_vector_extend(&dst->segments, segments_count)) {
3195          set_error(VG_OUT_OF_MEMORY_ERROR);
3196          platform_mutex_release(&state->shared_state->mutex);
3197          return;
3198       }
3199       {
3200          VGubyte *dst_segments = (VGubyte *)dst->segments.data + (dst->segments.size - segments_count);
3201          const VGubyte *src_segments = (const VGubyte *)src->segments.data;
3202          for (; segments_count != 0; ++dst_segments, ++src_segments, --segments_count) {
3203             VGuint segment = *src_segments;
3204             if (((segment & ~VG_RELATIVE) == VG_HLINE_TO) || ((segment & ~VG_RELATIVE) == VG_VLINE_TO)) {
3205                segment = VG_LINE_TO | (segment & VG_RELATIVE);
3206             }
3207 
3208             /*
3209                on the server, we also flip arc types if the determinant of the path
3210                user to surface matrix is negative, but we don't actually care about
3211                the particular arc type on the client
3212             */
3213 
3214             *dst_segments = (VGubyte)segment;
3215          }
3216       }
3217    }
3218    platform_mutex_release(&state->shared_state->mutex);
3219 
3220    sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
3221 
3222    RPC_CALL2(vgTransformPath_impl,
3223              thread,
3224              VGTRANSFORMPATH_ID,
3225              RPC_HANDLE(dst_vg_handle),
3226              RPC_HANDLE(src_vg_handle));
3227 }
3228 
vgInterpolatePath(VGPath dst_vg_handle,VGPath begin_vg_handle,VGPath end_vg_handle,VGfloat t)3229 VG_API_CALL VGboolean VG_API_ENTRY vgInterpolatePath(
3230    VGPath dst_vg_handle,
3231    VGPath begin_vg_handle,
3232    VGPath end_vg_handle,
3233    VGfloat t) VG_API_EXIT
3234 {
3235    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3236    VG_CLIENT_STATE_T *state;
3237    VG_CLIENT_PATH_T *dst;
3238    VG_CLIENT_PATH_T *begin;
3239    VG_CLIENT_PATH_T *end;
3240 
3241    t = clean_float(t);
3242 
3243    state = VG_GET_CLIENT_STATE(thread);
3244    if (!state) {
3245       return VG_FALSE;
3246    }
3247 
3248    platform_mutex_acquire(&state->shared_state->mutex);
3249    dst = (VG_CLIENT_PATH_T *)lookup_object(state, dst_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
3250    begin = (VG_CLIENT_PATH_T *)lookup_object(state, begin_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
3251    end = (VG_CLIENT_PATH_T *)lookup_object(state, end_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
3252    if (dst && begin && end &&
3253       (dst->caps & VG_PATH_CAPABILITY_INTERPOLATE_TO) && (begin->caps & VG_PATH_CAPABILITY_INTERPOLATE_FROM) && (end->caps & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
3254       if ((begin->segments.size != end->segments.size) ||
3255          !interpolate_segments_compatible((const VGubyte *)begin->segments.data, (const VGubyte *)end->segments.data, begin->segments.size)) {
3256          /*
3257             incompatible paths. no error -- just return false
3258          */
3259 
3260          platform_mutex_release(&state->shared_state->mutex);
3261          return VG_FALSE;
3262       }
3263       if (need_path_segments(dst->caps)) {
3264          VGuint segments_count = begin->segments.size;
3265          if (!khrn_vector_extend(&dst->segments, segments_count)) {
3266             set_error(VG_OUT_OF_MEMORY_ERROR);
3267             platform_mutex_release(&state->shared_state->mutex);
3268             return VG_FALSE;
3269          }
3270          {
3271             VGubyte *dst_segments = (VGubyte *)dst->segments.data + (dst->segments.size - segments_count);
3272             const VGubyte *begin_segments = (const VGubyte *)begin->segments.data;
3273             for (; segments_count != 0; ++dst_segments, ++begin_segments, --segments_count) {
3274                *dst_segments = (VGubyte)normalise_segment(*begin_segments & ~VG_RELATIVE);
3275             }
3276          }
3277       }
3278    }
3279    platform_mutex_release(&state->shared_state->mutex);
3280 
3281    RPC_CALL4(vgInterpolatePath_impl,
3282              thread,
3283              VGINTERPOLATEPATH_ID,
3284              RPC_HANDLE(dst_vg_handle),
3285              RPC_HANDLE(begin_vg_handle),
3286              RPC_HANDLE(end_vg_handle),
3287              RPC_FLOAT(t));
3288 
3289    return VG_TRUE;
3290 }
3291 
vgPathLength(VGPath vg_handle,VGint segments_i,VGint segments_count)3292 VG_API_CALL VGfloat VG_API_ENTRY vgPathLength(
3293    VGPath vg_handle,
3294    VGint segments_i, VGint segments_count) VG_API_EXIT
3295 {
3296    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3297    if (!VG_GET_CLIENT_STATE(thread)) {
3298       return 0.0f;
3299    }
3300 
3301    return RPC_FLOAT_RES(RPC_CALL3_RES(vgPathLength_impl,
3302                                       thread,
3303                                       VGPATHLENGTH_ID,
3304                                       RPC_HANDLE(vg_handle),
3305                                       RPC_INT(segments_i), RPC_INT(segments_count)));
3306 }
3307 
vgPointAlongPath(VGPath vg_handle,VGint segments_i,VGint segments_count,VGfloat distance,VGfloat * x,VGfloat * y,VGfloat * tangent_x,VGfloat * tangent_y)3308 VG_API_CALL void VG_API_ENTRY vgPointAlongPath(
3309    VGPath vg_handle,
3310    VGint segments_i, VGint segments_count,
3311    VGfloat distance,
3312    VGfloat *x, VGfloat *y,
3313    VGfloat *tangent_x, VGfloat *tangent_y) VG_API_EXIT
3314 {
3315    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3316    VGfloat values[4];
3317 
3318    distance = clean_float(distance);
3319 
3320    if (!VG_GET_CLIENT_STATE(thread)) {
3321       return;
3322    }
3323 
3324    if ((x && !is_aligned_float(x)) || (y && !is_aligned_float(y)) ||
3325       (tangent_x && !is_aligned_float(tangent_x)) || (tangent_y && !is_aligned_float(tangent_y))) {
3326       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3327       return;
3328    }
3329 
3330    if (RPC_BOOLEAN_RES(RPC_CALL6_OUT_CTRL_RES(vgPointAlongPath_impl,
3331                                               thread,
3332                                               VGPOINTALONGPATH_ID,
3333                                               RPC_HANDLE(vg_handle),
3334                                               RPC_INT(segments_i), RPC_INT(segments_count),
3335                                               RPC_FLOAT(distance),
3336                                               RPC_BITFIELD(((x && y) << 0) | ((tangent_x && tangent_y) << 1)),
3337                                               values))) {
3338       /*
3339          no error occurred on the server side
3340       */
3341 
3342       if (x && y) {
3343          *x = values[0];
3344          *y = values[1];
3345       }
3346       if (tangent_x && tangent_y) {
3347          *tangent_x = values[2];
3348          *tangent_y = values[3];
3349       }
3350    }
3351 }
3352 
vgPathBounds(VGPath vg_handle,VGfloat * min_x,VGfloat * min_y,VGfloat * width,VGfloat * height)3353 VG_API_CALL void VG_API_ENTRY vgPathBounds(
3354    VGPath vg_handle,
3355    VGfloat *min_x, VGfloat *min_y,
3356    VGfloat *width, VGfloat *height) VG_API_EXIT
3357 {
3358    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3359    VGfloat values[4];
3360 
3361    if (!VG_GET_CLIENT_STATE(thread)) {
3362       return;
3363    }
3364 
3365    if (!min_x || !is_aligned_float(min_x) || !min_y || !is_aligned_float(min_y) ||
3366       !width || !is_aligned_float(width) || !height || !is_aligned_float(height)) {
3367       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3368       return;
3369    }
3370 
3371    if (RPC_BOOLEAN_RES(RPC_CALL2_OUT_CTRL_RES(vgPathBounds_impl,
3372                                               thread,
3373                                               VGPATHBOUNDS_ID,
3374                                               RPC_HANDLE(vg_handle),
3375                                               values))) {
3376       /*
3377          no error occurred on the server side
3378       */
3379 
3380       *min_x = values[0];
3381       *min_y = values[1];
3382       *width = values[2];
3383       *height = values[3];
3384    }
3385 }
3386 
vgPathTransformedBounds(VGPath vg_handle,VGfloat * min_x,VGfloat * min_y,VGfloat * width,VGfloat * height)3387 VG_API_CALL void VG_API_ENTRY vgPathTransformedBounds(
3388    VGPath vg_handle,
3389    VGfloat *min_x, VGfloat *min_y,
3390    VGfloat *width, VGfloat *height) VG_API_EXIT
3391 {
3392    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3393    VGfloat values[4];
3394 
3395    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3396    if (!state) {
3397       return;
3398    }
3399 
3400    if (!min_x || !is_aligned_float(min_x) || !min_y || !is_aligned_float(min_y) ||
3401       !width || !is_aligned_float(width) || !height || !is_aligned_float(height)) {
3402       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3403       return;
3404    }
3405 
3406    sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
3407 
3408    if (RPC_BOOLEAN_RES(RPC_CALL2_OUT_CTRL_RES(vgPathTransformedBounds_impl,
3409                                               thread,
3410                                               VGPATHTRANSFORMEDBOUNDS_ID,
3411                                               RPC_HANDLE(vg_handle),
3412                                               values))) {
3413       /*
3414          no error occurred on the server side
3415       */
3416 
3417       *min_x = values[0];
3418       *min_y = values[1];
3419       *width = values[2];
3420       *height = values[3];
3421    }
3422 }
3423 
vgDrawPath(VGPath vg_handle,VGbitfield paint_modes)3424 VG_API_CALL void VG_API_ENTRY vgDrawPath(
3425    VGPath vg_handle,
3426    VGbitfield paint_modes) VG_API_EXIT
3427 {
3428    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3429    VG_CLIENT_STATE_T *state;
3430 
3431 #ifdef VG_NO_STROKING
3432    paint_modes &= ~VG_STROKE_PATH;
3433    if (!paint_modes) { return; }
3434 #endif
3435 
3436    state = VG_GET_CLIENT_STATE(thread);
3437    if (!state) {
3438       return;
3439    }
3440 
3441    sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
3442    if (paint_modes & VG_FILL_PATH) {
3443       sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER);
3444    }
3445    if (paint_modes & VG_STROKE_PATH) {
3446       sync_matrix(state, VG_MATRIX_STROKE_PAINT_TO_USER);
3447    }
3448 
3449    if (state->render_callback)
3450       state->render_callback();
3451 
3452    RPC_CALL2(vgDrawPath_impl,
3453              thread,
3454              VGDRAWPATH_ID,
3455              RPC_HANDLE(vg_handle),
3456              RPC_BITFIELD(paint_modes));
3457 }
3458 
3459 /******************************************************************************
3460 api paint
3461 ******************************************************************************/
3462 
vgCreatePaint(void)3463 VG_API_CALL VGPaint VG_API_ENTRY vgCreatePaint(void) VG_API_EXIT
3464 {
3465    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3466    VGHandle vg_handle;
3467    VG_CLIENT_PAINT_T *paint;
3468 
3469    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3470    if (!state) {
3471       return VG_INVALID_HANDLE;
3472    }
3473 
3474    vg_handle = get_stem(state);
3475    if (vg_handle == VG_INVALID_HANDLE) {
3476       set_error(VG_OUT_OF_MEMORY_ERROR);
3477       return VG_INVALID_HANDLE;
3478    }
3479 
3480    paint = paint_alloc();
3481    if (!paint) {
3482       set_error(VG_OUT_OF_MEMORY_ERROR);
3483       destroy_stem(vg_handle);
3484       return VG_INVALID_HANDLE;
3485    }
3486 
3487    platform_mutex_acquire(&state->shared_state->mutex);
3488    if (!insert_object(state, vg_handle, paint)) {
3489       set_error(VG_OUT_OF_MEMORY_ERROR);
3490       platform_mutex_release(&state->shared_state->mutex);
3491       paint_free(paint);
3492       destroy_stem(vg_handle);
3493       return VG_INVALID_HANDLE;
3494    }
3495    platform_mutex_release(&state->shared_state->mutex);
3496 
3497    RPC_CALL1(vgCreatePaint_impl,
3498              thread,
3499              VGCREATEPAINT_ID,
3500              RPC_HANDLE(vg_handle));
3501 
3502    return vg_handle;
3503 }
3504 
vgDestroyPaint(VGPaint vg_handle)3505 VG_API_CALL void VG_API_ENTRY vgDestroyPaint(
3506    VGPaint vg_handle) VG_API_EXIT
3507 {
3508    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3509    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3510    if (!state) {
3511       return;
3512    }
3513 
3514    platform_mutex_acquire(&state->shared_state->mutex);
3515    delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
3516    platform_mutex_release(&state->shared_state->mutex);
3517 
3518    RPC_CALL1(vgDestroyPaint_impl,
3519              thread,
3520              VGDESTROYPAINT_ID,
3521              RPC_HANDLE(vg_handle));
3522 }
3523 
vgSetPaint(VGPaint vg_handle,VGbitfield paint_modes)3524 VG_API_CALL void VG_API_ENTRY vgSetPaint(
3525    VGPaint vg_handle,
3526    VGbitfield paint_modes) VG_API_EXIT
3527 {
3528    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3529    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3530    if (!state) {
3531       return;
3532    }
3533 
3534    if (!is_paint_modes(paint_modes)) {
3535       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3536       return;
3537    }
3538 
3539    platform_mutex_acquire(&state->shared_state->mutex);
3540    if ((vg_handle != VG_INVALID_HANDLE) &&
3541       !lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT)) {
3542       set_error(VG_BAD_HANDLE_ERROR);
3543       platform_mutex_release(&state->shared_state->mutex);
3544       return;
3545    }
3546    platform_mutex_release(&state->shared_state->mutex);
3547 
3548    if (((paint_modes & VG_FILL_PATH) && (state->fill_paint != vg_handle)) ||
3549       ((paint_modes & VG_STROKE_PATH) && (state->stroke_paint != vg_handle))) {
3550       if (paint_modes & VG_FILL_PATH) {
3551          state->fill_paint = vg_handle;
3552       }
3553       if (paint_modes & VG_STROKE_PATH) {
3554          state->stroke_paint = vg_handle;
3555       }
3556       RPC_CALL2(vgSetPaint_impl,
3557                 thread,
3558                 VGSETPAINT_ID,
3559                 RPC_HANDLE(vg_handle),
3560                 RPC_BITFIELD(paint_modes));
3561    }
3562 }
3563 
vgGetPaint(VGPaintMode paint_mode)3564 VG_API_CALL VGPaint VG_API_ENTRY vgGetPaint(
3565    VGPaintMode paint_mode) VG_API_EXIT
3566 {
3567    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3568    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3569    if (!state) {
3570       return VG_INVALID_HANDLE;
3571    }
3572 
3573    if (!is_paint_mode(paint_mode)) {
3574       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3575       return VG_INVALID_HANDLE;
3576    }
3577 
3578    return (paint_mode == VG_FILL_PATH) ? state->fill_paint : state->stroke_paint;
3579 }
3580 
vgSetColor(VGPaint vg_handle,VGuint rgba)3581 VG_API_CALL void VG_API_ENTRY vgSetColor(
3582    VGPaint vg_handle,
3583    VGuint rgba) VG_API_EXIT
3584 {
3585    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3586    VG_CLIENT_STATE_T *state;
3587    VG_CLIENT_PAINT_T *paint;
3588 
3589    rgba = khrn_color_rgba_flip(rgba);
3590 
3591    state = VG_GET_CLIENT_STATE(thread);
3592    if (!state) {
3593       return;
3594    }
3595 
3596    platform_mutex_acquire(&state->shared_state->mutex);
3597    paint = (VG_CLIENT_PAINT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
3598    if (!paint) {
3599       set_error(VG_BAD_HANDLE_ERROR);
3600       platform_mutex_release(&state->shared_state->mutex);
3601       return;
3602    }
3603    if (color_floats_to_rgba_clean(paint->color) != rgba) {
3604       set_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_COLOR, 1, (const VGint *)&rgba);
3605    }
3606    khrn_color_rgba_to_floats(paint->color, rgba);
3607    platform_mutex_release(&state->shared_state->mutex);
3608 }
3609 
vgGetColor(VGPaint vg_handle)3610 VG_API_CALL VGuint VG_API_ENTRY vgGetColor(
3611    VGPaint vg_handle) VG_API_EXIT
3612 {
3613    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3614    VG_CLIENT_PAINT_T *paint;
3615    VGuint rgba;
3616 
3617    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3618    if (!state) {
3619       return 0;
3620    }
3621 
3622    platform_mutex_acquire(&state->shared_state->mutex);
3623    paint = (VG_CLIENT_PAINT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
3624    if (!paint) {
3625       set_error(VG_BAD_HANDLE_ERROR);
3626       platform_mutex_release(&state->shared_state->mutex);
3627       return 0;
3628    }
3629    rgba = color_floats_to_rgba_clean(paint->color);
3630    platform_mutex_release(&state->shared_state->mutex);
3631    return khrn_color_rgba_flip(rgba);
3632 }
3633 
vgPaintPattern(VGPaint vg_handle,VGImage pattern_vg_handle)3634 VG_API_CALL void VG_API_ENTRY vgPaintPattern(
3635    VGPaint vg_handle,
3636    VGImage pattern_vg_handle) VG_API_EXIT
3637 {
3638    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3639    VG_CLIENT_PAINT_T *paint;
3640    VG_CLIENT_IMAGE_T *pattern;
3641 
3642    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3643    if (!state) {
3644       return;
3645    }
3646 
3647    platform_mutex_acquire(&state->shared_state->mutex);
3648    paint = (VG_CLIENT_PAINT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
3649    pattern = (pattern_vg_handle == VG_INVALID_HANDLE) ? NULL : (VG_CLIENT_IMAGE_T *)lookup_object(state, pattern_vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
3650    if (!paint || ((pattern_vg_handle != VG_INVALID_HANDLE) && !pattern)) {
3651       set_error(VG_BAD_HANDLE_ERROR);
3652       platform_mutex_release(&state->shared_state->mutex);
3653       return;
3654    }
3655    if (paint->pattern != pattern_vg_handle) {
3656       paint->pattern = pattern_vg_handle;
3657 #if EGL_BRCM_global_image && EGL_KHR_image
3658       if (pattern && (pattern->global_image_id[0] || pattern->global_image_id[1])) {
3659          platform_acquire_global_image(pattern->global_image_id[0], pattern->global_image_id[1]);
3660       }
3661       if (paint->pattern_global_image_id[0] || paint->pattern_global_image_id[1]) {
3662          platform_release_global_image(paint->pattern_global_image_id[0], paint->pattern_global_image_id[1]);
3663       }
3664       paint->pattern_global_image_id[0] = pattern ? pattern->global_image_id[0] : 0;
3665       paint->pattern_global_image_id[1] = pattern ? pattern->global_image_id[1] : 0;
3666 #endif
3667       RPC_CALL2(vgPaintPattern_impl,
3668                 thread,
3669                 VGPAINTPATTERN_ID,
3670                 RPC_HANDLE(vg_handle),
3671                 RPC_HANDLE(pattern_vg_handle));
3672    }
3673    platform_mutex_release(&state->shared_state->mutex);
3674 }
3675 
3676 /******************************************************************************
3677 api image
3678 ******************************************************************************/
3679 
vgCreateImage(VGImageFormat format,VGint width,VGint height,VGbitfield allowed_quality)3680 VG_API_CALL VGImage VG_API_ENTRY vgCreateImage(
3681    VGImageFormat format,
3682    VGint width, VGint height,
3683    VGbitfield allowed_quality) VG_API_EXIT
3684 {
3685    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3686    VGHandle vg_handle;
3687    VG_CLIENT_IMAGE_T *image;
3688 
3689    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3690    if (!state) {
3691       return VG_INVALID_HANDLE;
3692    }
3693 
3694    if (!is_allowed_quality(allowed_quality) ||
3695       (width <= 0) || (height <= 0) ||
3696       (width > VG_CONFIG_MAX_IMAGE_WIDTH) || (height > VG_CONFIG_MAX_IMAGE_HEIGHT) ||
3697       ((width * height) > VG_CONFIG_MAX_IMAGE_PIXELS)) { /* todo: VG_CONFIG_MAX_IMAGE_BYTES */
3698       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3699       return VG_INVALID_HANDLE;
3700    }
3701    if (!is_image_format(format)) {
3702       set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
3703       return VG_INVALID_HANDLE;
3704    }
3705 
3706    vg_handle = get_stem(state);
3707    if (vg_handle == VG_INVALID_HANDLE) {
3708       set_error(VG_OUT_OF_MEMORY_ERROR);
3709       return VG_INVALID_HANDLE;
3710    }
3711 
3712    image = image_alloc(format, width, height
3713 #if EGL_BRCM_global_image && EGL_KHR_image
3714       , 0, 0
3715 #endif
3716       );
3717    if (!image) {
3718       set_error(VG_OUT_OF_MEMORY_ERROR);
3719       destroy_stem(vg_handle);
3720       return VG_INVALID_HANDLE;
3721    }
3722 
3723    platform_mutex_acquire(&state->shared_state->mutex);
3724    if (!insert_object(state, vg_handle, image)) {
3725       set_error(VG_OUT_OF_MEMORY_ERROR);
3726       platform_mutex_release(&state->shared_state->mutex);
3727       image_free(image);
3728       destroy_stem(vg_handle);
3729       return VG_INVALID_HANDLE;
3730    }
3731    platform_mutex_release(&state->shared_state->mutex);
3732 
3733    RPC_CALL5(vgCreateImage_impl,
3734              thread,
3735              VGCREATEIMAGE_ID,
3736              RPC_HANDLE(vg_handle),
3737              RPC_ENUM(format),
3738              RPC_INT(width), RPC_INT(height),
3739              RPC_BITFIELD(allowed_quality));
3740 
3741    return vg_handle;
3742 }
3743 
vgDestroyImage(VGImage vg_handle)3744 VG_API_CALL void VG_API_ENTRY vgDestroyImage(
3745    VGImage vg_handle) VG_API_EXIT
3746 {
3747    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3748    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3749    if (!state) {
3750       return;
3751    }
3752 
3753    platform_mutex_acquire(&state->shared_state->mutex);
3754    delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
3755    platform_mutex_release(&state->shared_state->mutex);
3756 
3757    RPC_CALL1(vgDestroyImage_impl,
3758              thread,
3759              VGDESTROYIMAGE_ID,
3760              RPC_HANDLE(vg_handle));
3761 }
3762 
vgClearImage(VGImage vg_handle,VGint x,VGint y,VGint width,VGint height)3763 VG_API_CALL void VG_API_ENTRY vgClearImage(
3764    VGImage vg_handle,
3765    VGint x, VGint y,
3766    VGint width, VGint height) VG_API_EXIT
3767 {
3768    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3769    if (!VG_GET_CLIENT_STATE(thread)) {
3770       return;
3771    }
3772 
3773    RPC_CALL5(vgClearImage_impl,
3774              thread,
3775              VGCLEARIMAGE_ID,
3776              RPC_HANDLE(vg_handle),
3777              RPC_INT(x), RPC_INT(y),
3778              RPC_INT(width), RPC_INT(height));
3779 }
3780 
vgImageSubData(VGImage vg_handle,const void * data,VGint data_stride,VGImageFormat data_format,VGint dst_x,VGint dst_y,VGint width,VGint height)3781 VG_API_CALL void VG_API_ENTRY vgImageSubData(
3782    VGImage vg_handle,
3783    const void *data, VGint data_stride,
3784    VGImageFormat data_format,
3785    VGint dst_x, VGint dst_y,
3786    VGint width, VGint height) VG_API_EXIT
3787 {
3788    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3789    VG_CLIENT_IMAGE_T *dst;
3790    VGint dst_width;
3791    VGint dst_height;
3792    VGint src_x = 0, src_y = 0;
3793 
3794    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3795    if (!state) {
3796       return;
3797    }
3798 
3799    if (!is_image_format(data_format)) {
3800       set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
3801       return;
3802    }
3803 
3804    if (!data || !is_aligned_image_format(data, data_format) ||
3805       ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
3806       (width <= 0) || (height <= 0)) {
3807       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3808       return;
3809    }
3810 
3811    platform_mutex_acquire(&state->shared_state->mutex);
3812 
3813    dst = (VG_CLIENT_IMAGE_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
3814    if (!dst) {
3815       set_error(VG_BAD_HANDLE_ERROR);
3816       platform_mutex_release(&state->shared_state->mutex);
3817       return;
3818    }
3819 
3820    dst_width = dst->width;
3821    dst_height = dst->height;
3822 
3823    platform_mutex_release(&state->shared_state->mutex);
3824 
3825    khrn_clip_rect2(
3826       &dst_x, &dst_y, &src_x, &src_y, &width, &height,
3827       0, 0, dst_width, dst_height,
3828       0, 0, width, height);
3829 
3830    if (width <= 0 || height <= 0) {
3831       return;
3832    }
3833 
3834    data = (const VGubyte *)data + (src_y * data_stride);
3835 
3836    #ifdef RPC_DIRECT
3837       RPC_CALL11(vgImageSubData_impl, thread, no_id,
3838          vg_handle,
3839          dst_width, dst_height,
3840          data, data_stride,
3841          data_format,
3842          src_x,
3843          dst_x, dst_y,
3844          width, height);
3845    #else
3846       {
3847          VGuint log2_bpp = get_log2_image_format_bpp(data_format);
3848          VGuint line_size;
3849          VGuint chunk_height_max;
3850 
3851          data = (const VGubyte *)data + ((src_x << log2_bpp) >> 3);
3852          src_x = ((src_x << log2_bpp) & 0x7) >> log2_bpp;
3853 
3854          line_size = (((src_x + width) << log2_bpp) + 0x7) >> 3;
3855 
3856          /*
3857             split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
3858          */
3859 
3860          chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
3861          vcos_assert((height == 0) || (chunk_height_max != 0));
3862 
3863          while (height != 0) {
3864             VGint chunk_height = _min(height, chunk_height_max);
3865 
3866             uint32_t message[] = {
3867                VGIMAGESUBDATA_ID,
3868                RPC_HANDLE(vg_handle),
3869                RPC_INT(dst_width), RPC_INT(dst_height),
3870                RPC_UINT(line_size),
3871                RPC_ENUM(data_format),
3872                RPC_INT(src_x),
3873                RPC_INT(dst_x), RPC_INT(dst_y),
3874                RPC_INT(width), RPC_INT(chunk_height) };
3875 
3876             rpc_begin(thread);
3877             rpc_send_ctrl_begin(thread, sizeof(message));
3878             rpc_send_ctrl_write(thread, message, sizeof(message));
3879             rpc_send_ctrl_end(thread);
3880             rpc_send_bulk_gather(thread, data, line_size, data_stride, chunk_height);
3881             data = (const VGubyte *)data + (chunk_height * data_stride);
3882             rpc_end(thread);
3883 
3884             height -= chunk_height;
3885             dst_y += chunk_height;
3886          }
3887       }
3888    #endif
3889 }
3890 
vgGetImageSubData(VGImage vg_handle,void * data,VGint data_stride,VGImageFormat data_format,VGint src_x,VGint src_y,VGint width,VGint height)3891 VG_API_CALL void VG_API_ENTRY vgGetImageSubData(
3892    VGImage vg_handle,
3893    void *data, VGint data_stride,
3894    VGImageFormat data_format,
3895    VGint src_x, VGint src_y,
3896    VGint width, VGint height) VG_API_EXIT
3897 {
3898    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
3899    VG_CLIENT_IMAGE_T *src;
3900    VGint src_width;
3901    VGint src_height;
3902    VGint dst_x = 0, dst_y = 0;
3903 
3904    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
3905    if (!state) {
3906       return;
3907    }
3908 
3909    if (!is_image_format(data_format)) {
3910       set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
3911       return;
3912    }
3913 
3914    if (!data || !is_aligned_image_format(data, data_format) ||
3915       ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
3916       (width <= 0) || (height <= 0)) {
3917       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
3918       return;
3919    }
3920 
3921    platform_mutex_acquire(&state->shared_state->mutex);
3922 
3923    src = (VG_CLIENT_IMAGE_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
3924    if (!src) {
3925       set_error(VG_BAD_HANDLE_ERROR);
3926       platform_mutex_release(&state->shared_state->mutex);
3927       return;
3928    }
3929 
3930    src_width = src->width;
3931    src_height = src->height;
3932 
3933    platform_mutex_release(&state->shared_state->mutex);
3934 
3935    khrn_clip_rect2(
3936       &dst_x, &dst_y, &src_x, &src_y, &width, &height,
3937       0, 0, width, height,
3938       0, 0, src_width, src_height);
3939 
3940    if (width <= 0 || height <= 0) {
3941       return;
3942    }
3943 
3944    data = (VGubyte *)data + (dst_y * data_stride);
3945 
3946    #ifdef RPC_DIRECT
3947       RPC_CALL11(vgGetImageSubData_impl, thread, no_id,
3948          vg_handle,
3949          src_width, src_height,
3950          data, data_stride,
3951          data_format,
3952          dst_x,
3953          src_x, src_y,
3954          width, height);
3955    #else
3956       {
3957          VGuint log2_bpp = get_log2_image_format_bpp(data_format);
3958          VGuint line_size;
3959          VGuint first_mask;
3960          VGuint last_mask;
3961          VGuint chunk_height_max;
3962 
3963          data = (VGubyte *)data + ((dst_x << log2_bpp) >> 3);
3964          dst_x = ((dst_x << log2_bpp) & 0x7) >> log2_bpp;
3965 
3966          line_size = (((dst_x + width) << log2_bpp) + 0x7) >> 3;
3967          first_mask = (1 << (dst_x << log2_bpp)) - 1;
3968          last_mask = ~((2 << ((((dst_x + width) << log2_bpp) - 1) & 0x7)) - 1) & 0xff;
3969 
3970          /*
3971             split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
3972          */
3973 
3974          chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
3975          vcos_assert((height == 0) || (chunk_height_max != 0));
3976 
3977          while (height != 0) {
3978             VGint chunk_height = _min(height, chunk_height_max);
3979 
3980             uint32_t message[] = {
3981                VGGETIMAGESUBDATA_ID,
3982                RPC_HANDLE(vg_handle),
3983                RPC_INT(src_width), RPC_INT(src_height),
3984                RPC_UINT(line_size),
3985                RPC_ENUM(data_format),
3986                RPC_INT(dst_x),
3987                RPC_INT(src_x), RPC_INT(src_y),
3988                RPC_INT(width), RPC_INT(chunk_height) };
3989 
3990             rpc_begin(thread);
3991             rpc_send_ctrl_begin(thread, sizeof(message));
3992             rpc_send_ctrl_write(thread, message, sizeof(message));
3993             rpc_send_ctrl_end(thread);
3994             {
3995                uint32_t len[] = { 0, data_stride, chunk_height, first_mask, last_mask };
3996                rpc_recv(thread, data, len, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_BULK_SCATTER | RPC_RECV_FLAG_LEN));
3997                data = (VGubyte *)data + (chunk_height * data_stride);
3998                if (len[0] == 0) {  //The command has failed so no data sent back
3999                   rpc_end(thread);
4000                   break;
4001                }
4002                vcos_assert(len[0] == line_size);
4003             }
4004             rpc_end(thread);
4005             height -= chunk_height;
4006             src_y += chunk_height;
4007          }
4008       }
4009    #endif
4010 }
4011 
vgChildImage(VGImage parent_vg_handle,VGint x,VGint y,VGint width,VGint height)4012 VG_API_CALL VGImage VG_API_ENTRY vgChildImage(
4013    VGImage parent_vg_handle,
4014    VGint x, VGint y,
4015    VGint width, VGint height) VG_API_EXIT
4016 {
4017    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4018    VG_CLIENT_IMAGE_T *parent;
4019    VGImageFormat format;
4020    VGint parent_width;
4021    VGint parent_height;
4022 #if EGL_BRCM_global_image && EGL_KHR_image
4023    VGuint parent_global_image_id_0, parent_global_image_id_1;
4024 #endif
4025    VGHandle vg_handle;
4026    VG_CLIENT_IMAGE_T *image;
4027 
4028    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4029    if (!state) {
4030       return VG_INVALID_HANDLE;
4031    }
4032 
4033    platform_mutex_acquire(&state->shared_state->mutex);
4034 
4035    parent = (VG_CLIENT_IMAGE_T *)lookup_object(state, parent_vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
4036    if (!parent) {
4037       set_error(VG_BAD_HANDLE_ERROR);
4038       platform_mutex_release(&state->shared_state->mutex);
4039       return VG_INVALID_HANDLE;
4040    }
4041 
4042    format = parent->format;
4043    parent_width = parent->width;
4044    parent_height = parent->height;
4045 #if EGL_BRCM_global_image && EGL_KHR_image
4046    parent_global_image_id_0 = parent->global_image_id[0];
4047    parent_global_image_id_1 = parent->global_image_id[1];
4048 #endif
4049 
4050    platform_mutex_release(&state->shared_state->mutex); /* mustn't hold this mutex when calling get_stem, so release now and acquire again later */
4051 
4052    if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0) ||
4053       /* x + width / y + height will fit in VGuint (may not fit in VGint) */
4054       (((VGuint)(x + width)) > (VGuint)parent_width) ||
4055       (((VGuint)(y + height)) > (VGuint)parent_height)) {
4056       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4057       return VG_INVALID_HANDLE;
4058    }
4059 
4060    vg_handle = get_stem(state);
4061    if (vg_handle == VG_INVALID_HANDLE) {
4062       set_error(VG_OUT_OF_MEMORY_ERROR);
4063       return VG_INVALID_HANDLE;
4064    }
4065 
4066    image = image_alloc(format, width, height
4067 #if EGL_BRCM_global_image && EGL_KHR_image
4068       , parent_global_image_id_0, parent_global_image_id_1
4069 #endif
4070       );
4071    if (!image) {
4072       set_error(VG_OUT_OF_MEMORY_ERROR);
4073       destroy_stem(vg_handle);
4074       return VG_INVALID_HANDLE;
4075    }
4076 
4077    platform_mutex_acquire(&state->shared_state->mutex);
4078    if (!insert_object(state, vg_handle, image)) {
4079       set_error(VG_OUT_OF_MEMORY_ERROR);
4080       platform_mutex_release(&state->shared_state->mutex);
4081       image_free(image);
4082       destroy_stem(vg_handle);
4083       return VG_INVALID_HANDLE;
4084    }
4085    platform_mutex_release(&state->shared_state->mutex);
4086 
4087    RPC_CALL8(vgChildImage_impl,
4088              thread,
4089              VGCHILDIMAGE_ID,
4090              RPC_HANDLE(vg_handle),
4091              RPC_HANDLE(parent_vg_handle),
4092              RPC_INT(parent_width), RPC_INT(parent_height),
4093              RPC_INT(x), RPC_INT(y),
4094              RPC_INT(width), RPC_INT(height));
4095 
4096    return vg_handle;
4097 }
4098 
vgGetParent(VGImage vg_handle)4099 VG_API_CALL VGImage VG_API_ENTRY vgGetParent(
4100    VGImage vg_handle) VG_API_EXIT
4101 {
4102    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4103    if (!VG_GET_CLIENT_STATE(thread)) {
4104       return VG_INVALID_HANDLE;
4105    }
4106 
4107    return RPC_HANDLE_RES(RPC_CALL1_RES(vgGetParent_impl,
4108                                        thread,
4109                                        VGGETPARENT_ID,
4110                                        RPC_HANDLE(vg_handle)));
4111 }
4112 
vgCopyImage(VGImage dst_vg_handle,VGint dst_x,VGint dst_y,VGImage src_vg_handle,VGint src_x,VGint src_y,VGint width,VGint height,VGboolean dither)4113 VG_API_CALL void VG_API_ENTRY vgCopyImage(
4114    VGImage dst_vg_handle, VGint dst_x, VGint dst_y,
4115    VGImage src_vg_handle, VGint src_x, VGint src_y,
4116    VGint width, VGint height,
4117    VGboolean dither) VG_API_EXIT
4118 {
4119    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4120    if (!VG_GET_CLIENT_STATE(thread)) {
4121       return;
4122    }
4123 
4124    RPC_CALL9(vgCopyImage_impl,
4125              thread,
4126              VGCOPYIMAGE_ID,
4127              RPC_HANDLE(dst_vg_handle), RPC_INT(dst_x), RPC_INT(dst_y),
4128              RPC_HANDLE(src_vg_handle), RPC_INT(src_x), RPC_INT(src_y),
4129              RPC_INT(width), RPC_INT(height),
4130              RPC_BOOLEAN(clean_boolean(dither)));
4131 }
4132 
vgDrawImage(VGImage vg_handle)4133 VG_API_CALL void VG_API_ENTRY vgDrawImage(
4134    VGImage vg_handle) VG_API_EXIT
4135 {
4136    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4137    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4138    if (!state) {
4139       return;
4140    }
4141 
4142    sync_matrix(state, VG_MATRIX_IMAGE_USER_TO_SURFACE);
4143    sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER);
4144 
4145    if (state->render_callback)
4146       state->render_callback();
4147 
4148    RPC_CALL1(vgDrawImage_impl,
4149              thread,
4150              VGDRAWIMAGE_ID,
4151              RPC_HANDLE(vg_handle));
4152 }
4153 
4154 /******************************************************************************
4155 api framebuffer
4156 ******************************************************************************/
4157 
vgSetPixels(VGint dst_x,VGint dst_y,VGImage src_vg_handle,VGint src_x,VGint src_y,VGint width,VGint height)4158 VG_API_CALL void VG_API_ENTRY vgSetPixels(
4159    VGint dst_x, VGint dst_y,
4160    VGImage src_vg_handle, VGint src_x, VGint src_y,
4161    VGint width, VGint height) VG_API_EXIT
4162 {
4163    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4164    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4165    if (!state) {
4166       return;
4167    }
4168 
4169    if (state->render_callback)
4170       state->render_callback();
4171 
4172    RPC_CALL7(vgSetPixels_impl,
4173              thread,
4174              VGSETPIXELS_ID,
4175              RPC_INT(dst_x), RPC_INT(dst_y),
4176              RPC_HANDLE(src_vg_handle), RPC_INT(src_x), RPC_INT(src_y),
4177              RPC_INT(width), RPC_INT(height));
4178 }
4179 
vgWritePixels(const void * data,VGint data_stride,VGImageFormat data_format,VGint dst_x,VGint dst_y,VGint width,VGint height)4180 VG_API_CALL void VG_API_ENTRY vgWritePixels(
4181    const void *data, VGint data_stride,
4182    VGImageFormat data_format,
4183    VGint dst_x, VGint dst_y,
4184    VGint width, VGint height) VG_API_EXIT
4185 {
4186    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4187    EGL_SURFACE_T *frame;
4188    VGint src_x = 0, src_y = 0;
4189 
4190    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4191    if (!state) {
4192       return;
4193    }
4194 
4195    if (!is_image_format(data_format)) {
4196       set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
4197       return;
4198    }
4199 
4200    if (!data || !is_aligned_image_format(data, data_format) ||
4201       ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
4202       (width <= 0) || (height <= 0)) {
4203       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4204       return;
4205    }
4206 
4207    frame = CLIENT_GET_THREAD_STATE()->openvg.draw;
4208 
4209    khrn_clip_rect2(
4210       &dst_x, &dst_y, &src_x, &src_y, &width, &height,
4211       0, 0, frame->width, frame->height,
4212       0, 0, width, height);
4213 
4214    if (width <= 0 || height <= 0) {
4215       return;
4216    }
4217 
4218    data = (const VGubyte *)data + (src_y * data_stride);
4219 
4220    if (state->render_callback)
4221       state->render_callback();
4222 
4223    #ifdef RPC_DIRECT
4224       RPC_CALL8(vgWritePixels_impl, thread, no_id,
4225          data, data_stride,
4226          data_format,
4227          src_x,
4228          dst_x, dst_y,
4229          width, height);
4230    #else
4231       {
4232          VGuint log2_bpp = get_log2_image_format_bpp(data_format);
4233          VGuint line_size;
4234          VGuint chunk_height_max;
4235 
4236          data = (const VGubyte *)data + ((src_x << log2_bpp) >> 3);
4237          src_x = ((src_x << log2_bpp) & 0x7) >> log2_bpp;
4238 
4239          line_size = (((src_x + width) << log2_bpp) + 0x7) >> 3;
4240 
4241          /*
4242             split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
4243          */
4244 
4245          chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
4246          vcos_assert((height == 0) || (chunk_height_max != 0));
4247 
4248          while (height != 0) {
4249             VGint chunk_height = _min(height, chunk_height_max);
4250 
4251             uint32_t message[] = {
4252                VGWRITEPIXELS_ID,
4253                RPC_UINT(line_size),
4254                RPC_ENUM(data_format),
4255                RPC_INT(src_x),
4256                RPC_INT(dst_x), RPC_INT(dst_y),
4257                RPC_INT(width), RPC_INT(chunk_height) };
4258 
4259             rpc_begin(thread);
4260             rpc_send_ctrl_begin(thread, sizeof(message));
4261             rpc_send_ctrl_write(thread, message, sizeof(message));
4262             rpc_send_ctrl_end(thread);
4263             rpc_send_bulk_gather(thread, data, line_size, data_stride, chunk_height);
4264             data = (const VGubyte *)data + (chunk_height * data_stride);
4265             rpc_end(thread);
4266 
4267             height -= chunk_height;
4268             dst_y += chunk_height;
4269          }
4270       }
4271    #endif
4272 }
4273 
vgGetPixels(VGImage dst_vg_handle,VGint dst_x,VGint dst_y,VGint src_x,VGint src_y,VGint width,VGint height)4274 VG_API_CALL void VG_API_ENTRY vgGetPixels(
4275    VGImage dst_vg_handle, VGint dst_x, VGint dst_y,
4276    VGint src_x, VGint src_y,
4277    VGint width, VGint height) VG_API_EXIT
4278 {
4279    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4280    if (!VG_GET_CLIENT_STATE(thread)) {
4281       return;
4282    }
4283 
4284    RPC_CALL7(vgGetPixels_impl,
4285              thread,
4286              VGGETPIXELS_ID,
4287              RPC_HANDLE(dst_vg_handle), RPC_INT(dst_x), RPC_INT(dst_y),
4288              RPC_INT(src_x), RPC_INT(src_y),
4289              RPC_INT(width), RPC_INT(height));
4290 }
4291 
vgReadPixels(void * data,VGint data_stride,VGImageFormat data_format,VGint src_x,VGint src_y,VGint width,VGint height)4292 VG_API_CALL void VG_API_ENTRY vgReadPixels(
4293    void *data, VGint data_stride,
4294    VGImageFormat data_format,
4295    VGint src_x, VGint src_y,
4296    VGint width, VGint height) VG_API_EXIT
4297 {
4298    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4299    EGL_SURFACE_T *frame;
4300    VGint dst_x = 0, dst_y = 0;
4301 
4302    if (!VG_GET_CLIENT_STATE(thread)) {
4303       return;
4304    }
4305 
4306    if (!is_image_format(data_format)) {
4307       set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
4308       return;
4309    }
4310 
4311    if (!data || !is_aligned_image_format(data, data_format) ||
4312       ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
4313       (width <= 0) || (height <= 0)) {
4314       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4315       return;
4316    }
4317 
4318    frame = CLIENT_GET_THREAD_STATE()->openvg.draw;
4319 
4320    khrn_clip_rect2(
4321       &dst_x, &dst_y, &src_x, &src_y, &width, &height,
4322       0, 0, width, height,
4323       0, 0, frame->width, frame->height);
4324 
4325    if (width <= 0 || height <= 0) {
4326       return;
4327    }
4328 
4329    data = (VGubyte *)data + (dst_y * data_stride);
4330 
4331    #ifdef RPC_DIRECT
4332       RPC_CALL8(vgReadPixels_impl, thread, no_id,
4333          data, data_stride,
4334          data_format,
4335          dst_x,
4336          src_x, src_y,
4337          width, height);
4338    #else
4339       {
4340          VGuint log2_bpp = get_log2_image_format_bpp(data_format);
4341          VGuint line_size;
4342          VGuint first_mask;
4343          VGuint last_mask;
4344          VGuint chunk_height_max;
4345 
4346          data = (VGubyte *)data + ((dst_x << log2_bpp) >> 3);
4347          dst_x = ((dst_x << log2_bpp) & 0x7) >> log2_bpp;
4348 
4349          line_size = (((dst_x + width) << log2_bpp) + 0x7) >> 3;
4350          first_mask = (1 << (dst_x << log2_bpp)) - 1;
4351          last_mask = ~((2 << ((((dst_x + width) << log2_bpp) - 1) & 0x7)) - 1) & 0xff;
4352 
4353          /*
4354             split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
4355          */
4356 
4357          chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
4358          vcos_assert((height == 0) || (chunk_height_max != 0));
4359 
4360          while (height != 0) {
4361             VGint chunk_height = _min(height, chunk_height_max);
4362 
4363             uint32_t message[] = {
4364                VGREADPIXELS_ID,
4365                RPC_UINT(line_size),
4366                RPC_ENUM(data_format),
4367                RPC_INT(dst_x),
4368                RPC_INT(src_x), RPC_INT(src_y),
4369                RPC_INT(width), RPC_INT(chunk_height) };
4370 
4371 #ifndef __SYMBIAN32__
4372             rpc_begin(thread);
4373 #endif
4374             rpc_send_ctrl_begin(thread, sizeof(message));
4375             rpc_send_ctrl_write(thread, message, sizeof(message));
4376             rpc_send_ctrl_end(thread);
4377             {
4378                uint32_t len[] = { line_size, data_stride, chunk_height, first_mask, last_mask };
4379                rpc_recv(thread, data, len, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_BULK_SCATTER));
4380                data = (VGubyte *)data + (chunk_height * data_stride);
4381             }
4382 #ifndef __SYMBIAN32__
4383             rpc_end(thread);
4384 #endif
4385             height -= chunk_height;
4386             src_y += chunk_height;
4387          }
4388       }
4389    #endif
4390 }
4391 
vgCopyPixels(VGint dst_x,VGint dst_y,VGint src_x,VGint src_y,VGint width,VGint height)4392 VG_API_CALL void VG_API_ENTRY vgCopyPixels(
4393    VGint dst_x, VGint dst_y,
4394    VGint src_x, VGint src_y,
4395    VGint width, VGint height) VG_API_EXIT
4396 {
4397    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4398    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4399    if (!state) {
4400       return;
4401    }
4402 
4403    if (state->render_callback)
4404       state->render_callback();
4405 
4406    RPC_CALL6(vgCopyPixels_impl,
4407              thread,
4408              VGCOPYPIXELS_ID,
4409              RPC_INT(dst_x), RPC_INT(dst_y),
4410              RPC_INT(src_x), RPC_INT(src_y),
4411              RPC_INT(width), RPC_INT(height));
4412 }
4413 
4414 /******************************************************************************
4415 api fonts
4416 ******************************************************************************/
4417 
vgCreateFont(VGint glyphs_capacity)4418 VG_API_CALL VGFont VG_API_ENTRY vgCreateFont(
4419    VGint glyphs_capacity) VG_API_EXIT
4420 {
4421    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4422    VGHandle vg_handle;
4423    VG_CLIENT_FONT_T *font;
4424 
4425    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4426    if (!state) {
4427       return VG_INVALID_HANDLE;
4428    }
4429 
4430    if (glyphs_capacity < 0) {
4431       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4432       return VG_INVALID_HANDLE;
4433    }
4434 
4435    vg_handle = get_stem(state);
4436    if (vg_handle == VG_INVALID_HANDLE) {
4437       set_error(VG_OUT_OF_MEMORY_ERROR);
4438       return VG_INVALID_HANDLE;
4439    }
4440 
4441    font = font_alloc();
4442    if (!font) {
4443       set_error(VG_OUT_OF_MEMORY_ERROR);
4444       destroy_stem(vg_handle);
4445       return VG_INVALID_HANDLE;
4446    }
4447 
4448    platform_mutex_acquire(&state->shared_state->mutex);
4449    if (!insert_object(state, vg_handle, font)) {
4450       set_error(VG_OUT_OF_MEMORY_ERROR);
4451       platform_mutex_release(&state->shared_state->mutex);
4452       font_free(font);
4453       destroy_stem(vg_handle);
4454       return VG_INVALID_HANDLE;
4455    }
4456    platform_mutex_release(&state->shared_state->mutex);
4457 
4458    RPC_CALL2(vgCreateFont_impl,
4459              thread,
4460              VGCREATEFONT_ID,
4461              RPC_HANDLE(vg_handle),
4462              RPC_INT(glyphs_capacity));
4463 
4464    return vg_handle;
4465 }
4466 
vgDestroyFont(VGFont vg_handle)4467 VG_API_CALL void VG_API_ENTRY vgDestroyFont(
4468    VGFont vg_handle) VG_API_EXIT
4469 {
4470    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4471    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4472    if (!state) {
4473       return;
4474    }
4475 
4476    platform_mutex_acquire(&state->shared_state->mutex);
4477    delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
4478    platform_mutex_release(&state->shared_state->mutex);
4479 
4480    RPC_CALL1(vgDestroyFont_impl,
4481              thread,
4482              VGDESTROYFONT_ID,
4483              RPC_HANDLE(vg_handle));
4484 }
4485 
vgSetGlyphToPath(VGFont vg_handle,VGuint glyph_id,VGPath path_vg_handle,VGboolean is_hinted,VGfloat glyph_origin[2],VGfloat escapement[2])4486 VG_API_CALL void VG_API_ENTRY vgSetGlyphToPath(
4487    VGFont vg_handle,
4488    VGuint glyph_id,
4489    VGPath path_vg_handle,
4490    VGboolean is_hinted,
4491    VGfloat glyph_origin[2],
4492    VGfloat escapement[2]) VG_API_EXIT
4493 {
4494    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4495 #if EGL_BRCM_global_image && EGL_KHR_image
4496    VG_CLIENT_FONT_T *font;
4497 #endif
4498 
4499    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4500    if (!state) {
4501       return;
4502    }
4503 
4504    if (!glyph_origin || !is_aligned_float(glyph_origin) ||
4505       !escapement || !is_aligned_float(escapement)) {
4506       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4507       return;
4508    }
4509 
4510 #if EGL_BRCM_global_image && EGL_KHR_image
4511    platform_mutex_acquire(&state->shared_state->mutex);
4512    font = (VG_CLIENT_FONT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
4513    if (font && ((path_vg_handle == VG_INVALID_HANDLE) || lookup_object(state, path_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH))) {
4514       khrn_global_image_map_delete(&font->glyph_global_images, glyph_id);
4515    }
4516    platform_mutex_release(&state->shared_state->mutex);
4517 #endif
4518 
4519    RPC_CALL8(vgSetGlyphToPath_impl,
4520              thread,
4521              VGSETGLYPHTOPATH_ID,
4522              RPC_HANDLE(vg_handle),
4523              RPC_UINT(glyph_id),
4524              RPC_HANDLE(path_vg_handle),
4525              RPC_BOOLEAN(clean_boolean(is_hinted)),
4526              RPC_FLOAT(clean_float(glyph_origin[0])), RPC_FLOAT(clean_float(glyph_origin[1])),
4527              RPC_FLOAT(clean_float(escapement[0])), RPC_FLOAT(clean_float(escapement[1])));
4528 }
4529 
vgSetGlyphToImage(VGFont vg_handle,VGuint glyph_id,VGImage image_vg_handle,VGfloat glyph_origin[2],VGfloat escapement[2])4530 VG_API_CALL void VG_API_ENTRY vgSetGlyphToImage(
4531    VGFont vg_handle,
4532    VGuint glyph_id,
4533    VGImage image_vg_handle,
4534    VGfloat glyph_origin[2],
4535    VGfloat escapement[2]) VG_API_EXIT
4536 {
4537    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4538 #if EGL_BRCM_global_image && EGL_KHR_image
4539    VG_CLIENT_FONT_T *font;
4540    VG_CLIENT_IMAGE_T *image;
4541 #endif
4542 
4543    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4544    if (!state) {
4545       return;
4546    }
4547 
4548    if (!glyph_origin || !is_aligned_float(glyph_origin) ||
4549       !escapement || !is_aligned_float(escapement)) {
4550       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4551       return;
4552    }
4553 
4554 #if EGL_BRCM_global_image && EGL_KHR_image
4555    platform_mutex_acquire(&state->shared_state->mutex);
4556    font = (VG_CLIENT_FONT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
4557    image = (image_vg_handle == VG_INVALID_HANDLE) ? NULL : (VG_CLIENT_IMAGE_T *)lookup_object(state, image_vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
4558    if (font && ((image_vg_handle == VG_INVALID_HANDLE) || image)) {
4559       if (image && (image->global_image_id[0] || image->global_image_id[1])) {
4560          if (!khrn_global_image_map_insert(&font->glyph_global_images, glyph_id,
4561             image->global_image_id[0] | ((uint64_t)image->global_image_id[1] << 32))) {
4562             set_error(VG_OUT_OF_MEMORY_ERROR);
4563             platform_mutex_release(&state->shared_state->mutex);
4564             return;
4565          }
4566       } else {
4567          khrn_global_image_map_delete(&font->glyph_global_images, glyph_id);
4568       }
4569    }
4570    platform_mutex_release(&state->shared_state->mutex);
4571 #endif
4572 
4573    RPC_CALL7(vgSetGlyphToImage_impl,
4574              thread,
4575              VGSETGLYPHTOIMAGE_ID,
4576              RPC_HANDLE(vg_handle),
4577              RPC_UINT(glyph_id),
4578              RPC_HANDLE(image_vg_handle),
4579              RPC_FLOAT(clean_float(glyph_origin[0])), RPC_FLOAT(clean_float(glyph_origin[1])),
4580              RPC_FLOAT(clean_float(escapement[0])), RPC_FLOAT(clean_float(escapement[1])));
4581 }
4582 
vgClearGlyph(VGFont vg_handle,VGuint glyph_id)4583 VG_API_CALL void VG_API_ENTRY vgClearGlyph(
4584    VGFont vg_handle,
4585    VGuint glyph_id) VG_API_EXIT
4586 {
4587    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4588 #if EGL_BRCM_global_image && EGL_KHR_image
4589    VG_CLIENT_FONT_T *font;
4590 #endif
4591 
4592    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
4593    if (!state) {
4594       return;
4595    }
4596 
4597 #if EGL_BRCM_global_image && EGL_KHR_image
4598    platform_mutex_acquire(&state->shared_state->mutex);
4599    font = (VG_CLIENT_FONT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
4600    if (font) {
4601       khrn_global_image_map_delete(&font->glyph_global_images, glyph_id);
4602    }
4603    platform_mutex_release(&state->shared_state->mutex);
4604 #endif
4605 
4606    RPC_CALL2(vgClearGlyph_impl,
4607              thread,
4608              VGCLEARGLYPH_ID,
4609              RPC_HANDLE(vg_handle),
4610              RPC_UINT(glyph_id));
4611 }
4612 
vgDrawGlyph(VGFont vg_handle,VGuint glyph_id,VGbitfield paint_modes,VGboolean allow_autohinting)4613 VG_API_CALL void VG_API_ENTRY vgDrawGlyph(
4614    VGFont vg_handle,
4615    VGuint glyph_id,
4616    VGbitfield paint_modes,
4617    VGboolean allow_autohinting) VG_API_EXIT
4618 {
4619    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4620    VG_CLIENT_STATE_T *state;
4621 
4622 #ifdef VG_NO_STROKING
4623    paint_modes &= ~VG_STROKE_PATH;
4624    if (!paint_modes) { return; }
4625 #endif
4626 
4627    state = VG_GET_CLIENT_STATE(thread);
4628    if (!state) {
4629       return;
4630    }
4631 
4632    sync_matrix(state, VG_MATRIX_GLYPH_USER_TO_SURFACE);
4633    sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER); /* image glyphs will use, so have to send even if paint_modes doesn't have VG_FILL_PATH */
4634    if (paint_modes & VG_STROKE_PATH) {
4635       sync_matrix(state, VG_MATRIX_STROKE_PAINT_TO_USER);
4636    }
4637 
4638    if (state->render_callback)
4639       state->render_callback();
4640 
4641    RPC_CALL4(vgDrawGlyph_impl,
4642              thread,
4643              VGDRAWGLYPH_ID,
4644              RPC_HANDLE(vg_handle),
4645              RPC_UINT(glyph_id),
4646              RPC_BITFIELD(paint_modes),
4647              RPC_BOOLEAN(clean_boolean(allow_autohinting)));
4648 }
4649 
vgDrawGlyphs(VGFont vg_handle,VGint glyphs_count,const VGuint * glyph_ids,const VGfloat * adjustments_x,const VGfloat * adjustments_y,VGbitfield paint_modes,VGboolean allow_autohinting)4650 VG_API_CALL void VG_API_ENTRY vgDrawGlyphs(
4651    VGFont vg_handle,
4652    VGint glyphs_count,
4653    const VGuint *glyph_ids,
4654    const VGfloat *adjustments_x,
4655    const VGfloat *adjustments_y,
4656    VGbitfield paint_modes,
4657    VGboolean allow_autohinting) VG_API_EXIT
4658 {
4659    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4660    VG_CLIENT_STATE_T *state;
4661 
4662 #ifdef VG_NO_STROKING
4663    paint_modes &= ~VG_STROKE_PATH;
4664    if (!paint_modes) { return; }
4665 #endif
4666 
4667    state = VG_GET_CLIENT_STATE(thread);
4668    if (!state) {
4669       return;
4670    }
4671 
4672    if ((glyphs_count <= 0) || !glyph_ids || !is_aligned_uint(glyph_ids) ||
4673       (adjustments_x && !is_aligned_float(adjustments_x)) ||
4674       (adjustments_y && !is_aligned_float(adjustments_y))) {
4675       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4676       return;
4677    }
4678 
4679    sync_matrix(state, VG_MATRIX_GLYPH_USER_TO_SURFACE);
4680    sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER); /* image glyphs will use, so have to send even if paint_modes doesn't have VG_FILL_PATH */
4681    if (paint_modes & VG_STROKE_PATH) {
4682       sync_matrix(state, VG_MATRIX_STROKE_PAINT_TO_USER);
4683    }
4684 
4685    if (state->render_callback)
4686       state->render_callback();
4687 
4688    #ifdef RPC_DIRECT
4689       RPC_CALL7(vgDrawGlyphs_impl, thread, no_id,
4690          vg_handle,
4691          glyphs_count, glyph_ids,
4692          adjustments_x, adjustments_y,
4693          paint_modes,
4694          clean_boolean(allow_autohinting));
4695    #else
4696       {
4697          /*
4698             split into multiple calls if necessary to avoid overflowing control buffer
4699 
4700             todo: if there's an invalid glyph, we're not supposed to draw anything
4701             at all. currently, this works on a per-chunk level (ie we will try to
4702             draw the glyphs in a chunk iff there are no invalid glyphs in the chunk)
4703          */
4704 
4705          VGuint glyph_size = sizeof(VGuint) +
4706             (adjustments_x ? sizeof(VGfloat) : 0) +
4707             (adjustments_y ? sizeof(VGfloat) : 0);
4708 
4709          while (glyphs_count != 0) {
4710             #define MESSAGE_SIZE 24
4711 
4712             /* at least 8 glyphs. this is a hack for the cts -- it checks that we don't draw anything if there's an invalid glyph (see above) */
4713             VGint chunk_glyphs_count = _min(glyphs_count, (rpc_send_ctrl_longest(thread, MESSAGE_SIZE + (8 * glyph_size)) - MESSAGE_SIZE) / glyph_size);
4714 
4715             uint32_t message[] = {
4716                VGDRAWGLYPHS_ID,
4717                RPC_HANDLE(vg_handle),
4718                RPC_INT(chunk_glyphs_count),
4719                RPC_BITFIELD((!!adjustments_x << 0) | (!!adjustments_y << 1)),
4720                RPC_BITFIELD(paint_modes),
4721                RPC_BOOLEAN(clean_boolean(allow_autohinting)) };
4722             vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
4723 
4724             #undef MESSAGE_SIZE
4725 
4726             rpc_send_ctrl_begin(thread, sizeof(message) + (chunk_glyphs_count * glyph_size));
4727             rpc_send_ctrl_write(thread, message, sizeof(message));
4728             rpc_send_ctrl_write(thread, (uint32_t *)glyph_ids, chunk_glyphs_count * sizeof(VGuint));
4729             if (adjustments_x) { rpc_send_ctrl_write(thread, (uint32_t *)adjustments_x, chunk_glyphs_count * sizeof(VGfloat)); }
4730             if (adjustments_y) { rpc_send_ctrl_write(thread, (uint32_t *)adjustments_y, chunk_glyphs_count * sizeof(VGfloat)); }
4731             rpc_send_ctrl_end(thread);
4732 
4733             glyphs_count -= chunk_glyphs_count;
4734             glyph_ids += chunk_glyphs_count;
4735             if (adjustments_x) { adjustments_x += chunk_glyphs_count; }
4736             if (adjustments_y) { adjustments_y += chunk_glyphs_count; }
4737          }
4738       }
4739    #endif
4740 }
4741 
4742 /******************************************************************************
4743 api filters
4744 ******************************************************************************/
4745 
vgColorMatrix(VGImage dst_vg_handle,VGImage src_vg_handle,const VGfloat * matrix)4746 VG_API_CALL void VG_API_ENTRY vgColorMatrix(
4747    VGImage dst_vg_handle, VGImage src_vg_handle,
4748    const VGfloat *matrix) VG_API_EXIT
4749 {
4750    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4751    if (!VG_GET_CLIENT_STATE(thread)) {
4752       return;
4753    }
4754 
4755    if (!matrix || !is_aligned_float(matrix)) {
4756       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4757       return;
4758    }
4759 
4760    RPC_CALL3_IN_CTRL(vgColorMatrix_impl,
4761                      thread,
4762                      VGCOLORMATRIX_ID,
4763                      RPC_HANDLE(dst_vg_handle),
4764                      RPC_HANDLE(src_vg_handle),
4765                      matrix,
4766                      20 * sizeof(VGfloat));
4767 }
4768 
vgConvolve(VGImage dst_vg_handle,VGImage src_vg_handle,VGint kernel_width,VGint kernel_height,VGint shift_x,VGint shift_y,const VGshort * kernel,VGfloat scale,VGfloat bias,VGTilingMode tiling_mode)4769 VG_API_CALL void VG_API_ENTRY vgConvolve(
4770    VGImage dst_vg_handle, VGImage src_vg_handle,
4771    VGint kernel_width, VGint kernel_height,
4772    VGint shift_x, VGint shift_y,
4773    const VGshort *kernel,
4774    VGfloat scale, VGfloat bias,
4775    VGTilingMode tiling_mode) VG_API_EXIT
4776 {
4777    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4778    scale = clean_float(scale);
4779    bias = clean_float(bias);
4780 
4781    if (!VG_GET_CLIENT_STATE(thread)) {
4782       return;
4783    }
4784 
4785    if ((kernel_width <= 0) || (kernel_height <= 0) ||
4786       (kernel_width > VG_CONFIG_MAX_KERNEL_SIZE) || (kernel_height > VG_CONFIG_MAX_KERNEL_SIZE) ||
4787       !kernel || !is_aligned_short(kernel)) {
4788       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4789       return;
4790    }
4791 
4792    RPC_CALL10_IN_CTRL(vgConvolve_impl,
4793                       thread,
4794                       VGCONVOLVE_ID,
4795                       RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
4796                       RPC_INT(kernel_width), RPC_INT(kernel_height),
4797                       RPC_INT(shift_x), RPC_INT(shift_y),
4798                       RPC_FLOAT(scale), RPC_FLOAT(bias),
4799                       RPC_ENUM(tiling_mode),
4800                       kernel,
4801                       kernel_width * kernel_height * sizeof(VGshort));
4802 }
4803 
vgSeparableConvolve(VGImage dst_vg_handle,VGImage src_vg_handle,VGint kernel_width,VGint kernel_height,VGint shift_x,VGint shift_y,const VGshort * kernel_x,const VGshort * kernel_y,VGfloat scale,VGfloat bias,VGTilingMode tiling_mode)4804 VG_API_CALL void VG_API_ENTRY vgSeparableConvolve(
4805    VGImage dst_vg_handle, VGImage src_vg_handle,
4806    VGint kernel_width, VGint kernel_height,
4807    VGint shift_x, VGint shift_y,
4808    const VGshort *kernel_x,
4809    const VGshort *kernel_y,
4810    VGfloat scale, VGfloat bias,
4811    VGTilingMode tiling_mode) VG_API_EXIT
4812 {
4813    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4814    scale = clean_float(scale);
4815    bias = clean_float(bias);
4816 
4817    if (!VG_GET_CLIENT_STATE(thread)) {
4818       return;
4819    }
4820 
4821    if ((kernel_width <= 0) || (kernel_height <= 0) ||
4822       (kernel_width > VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE) || (kernel_height > VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE) ||
4823       !kernel_x || !is_aligned_short(kernel_x) || !kernel_y || !is_aligned_short(kernel_y)) {
4824       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4825       return;
4826    }
4827 
4828    #ifdef RPC_DIRECT
4829       RPC_CALL11(vgSeparableConvolve_impl, thread, no_id,
4830          dst_vg_handle, src_vg_handle,
4831          kernel_width, kernel_height,
4832          shift_x, shift_y,
4833          kernel_x, kernel_y,
4834          scale, bias,
4835          tiling_mode);
4836    #else
4837       {
4838          uint32_t message[] = {
4839             VGSEPARABLECONVOLVE_ID,
4840             RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
4841             RPC_INT(kernel_width), RPC_INT(kernel_height),
4842             RPC_INT(shift_x), RPC_INT(shift_y),
4843             RPC_FLOAT(scale), RPC_FLOAT(bias),
4844             RPC_ENUM(tiling_mode) };
4845 
4846          VGuint kernel_x_size = kernel_width * sizeof(VGshort);
4847          VGuint kernel_y_size = kernel_height * sizeof(VGshort);
4848 
4849          rpc_send_ctrl_begin(thread, sizeof(message) + rpc_pad_ctrl(kernel_x_size) + rpc_pad_ctrl(kernel_y_size));
4850          rpc_send_ctrl_write(thread, message, sizeof(message));
4851          rpc_send_ctrl_write(thread, (uint32_t *)kernel_x, kernel_x_size);
4852          rpc_send_ctrl_write(thread, (uint32_t *)kernel_y, kernel_y_size);
4853          rpc_send_ctrl_end(thread);
4854       }
4855    #endif
4856 }
4857 
vgGaussianBlur(VGImage dst_vg_handle,VGImage src_vg_handle,VGfloat std_dev_x,VGfloat std_dev_y,VGTilingMode tiling_mode)4858 VG_API_CALL void VG_API_ENTRY vgGaussianBlur(
4859    VGImage dst_vg_handle, VGImage src_vg_handle,
4860    VGfloat std_dev_x, VGfloat std_dev_y,
4861    VGTilingMode tiling_mode) VG_API_EXIT
4862 {
4863    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4864    std_dev_x = clean_float(std_dev_x);
4865    std_dev_y = clean_float(std_dev_y);
4866 
4867    if (!VG_GET_CLIENT_STATE(thread)) {
4868       return;
4869    }
4870 
4871    RPC_CALL5(vgGaussianBlur_impl,
4872              thread,
4873              VGGAUSSIANBLUR_ID,
4874              RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
4875              RPC_FLOAT(std_dev_x), RPC_FLOAT(std_dev_y),
4876              RPC_ENUM(tiling_mode));
4877 }
4878 
vgLookup(VGImage dst_vg_handle,VGImage src_vg_handle,const VGubyte * red_lut,const VGubyte * green_lut,const VGubyte * blue_lut,const VGubyte * alpha_lut,VGboolean output_linear,VGboolean output_pre)4879 VG_API_CALL void VG_API_ENTRY vgLookup(
4880    VGImage dst_vg_handle, VGImage src_vg_handle,
4881    const VGubyte *red_lut,
4882    const VGubyte *green_lut,
4883    const VGubyte *blue_lut,
4884    const VGubyte *alpha_lut,
4885    VGboolean output_linear,
4886    VGboolean output_pre) VG_API_EXIT
4887 {
4888    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4889    if (!VG_GET_CLIENT_STATE(thread)) {
4890       return;
4891    }
4892 
4893    if (!red_lut || !green_lut || !blue_lut || !alpha_lut) {
4894       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4895       return;
4896    }
4897 
4898    #ifdef RPC_DIRECT
4899       RPC_CALL8(vgLookup_impl, thread, no_id,
4900          dst_vg_handle, src_vg_handle,
4901          red_lut, green_lut, blue_lut, alpha_lut,
4902          clean_boolean(output_linear),
4903          clean_boolean(output_pre));
4904    #else
4905       {
4906          uint32_t message[] = {
4907             VGLOOKUP_ID,
4908             RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
4909             RPC_BOOLEAN(clean_boolean(output_linear)),
4910             RPC_BOOLEAN(clean_boolean(output_pre)) };
4911 
4912          rpc_send_ctrl_begin(thread, sizeof(message) + 1024);
4913          rpc_send_ctrl_write(thread, message, sizeof(message));
4914          rpc_send_ctrl_write(thread, (uint32_t *)red_lut, 256);
4915          rpc_send_ctrl_write(thread, (uint32_t *)green_lut, 256);
4916          rpc_send_ctrl_write(thread, (uint32_t *)blue_lut, 256);
4917          rpc_send_ctrl_write(thread, (uint32_t *)alpha_lut, 256);
4918          rpc_send_ctrl_end(thread);
4919       }
4920    #endif
4921 }
4922 
vgLookupSingle(VGImage dst_vg_handle,VGImage src_vg_handle,const VGuint * lut,VGImageChannel source_channel,VGboolean output_linear,VGboolean output_pre)4923 VG_API_CALL void VG_API_ENTRY vgLookupSingle(
4924    VGImage dst_vg_handle, VGImage src_vg_handle,
4925    const VGuint *lut,
4926    VGImageChannel source_channel,
4927    VGboolean output_linear,
4928    VGboolean output_pre) VG_API_EXIT
4929 {
4930    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4931    if (!VG_GET_CLIENT_STATE(thread)) {
4932       return;
4933    }
4934 
4935    if (!lut || !is_aligned_uint(lut)) {
4936       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4937       return;
4938    }
4939 
4940    RPC_CALL6_IN_CTRL(vgLookupSingle_impl,
4941                      thread,
4942                      VGLOOKUPSINGLE_ID,
4943                      RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
4944                      RPC_ENUM(source_channel),
4945                      RPC_BOOLEAN(clean_boolean(output_linear)),
4946                      RPC_BOOLEAN(clean_boolean(output_pre)),
4947                      lut,
4948                      256 * sizeof(VGuint));
4949 }
4950 
4951 /******************************************************************************
4952 api client-side stuff
4953 ******************************************************************************/
4954 
vgHardwareQuery(VGHardwareQueryType hardware_query_type,VGint setting)4955 VG_API_CALL VGHardwareQueryResult VG_API_ENTRY vgHardwareQuery(
4956    VGHardwareQueryType hardware_query_type,
4957    VGint setting) VG_API_EXIT
4958 {
4959    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4960    if (!VG_GET_CLIENT_STATE(thread)) {
4961       return (VGHardwareQueryResult)0;
4962    }
4963 
4964    if (!is_hardware_query_type(hardware_query_type) ||
4965       ((hardware_query_type == VG_IMAGE_FORMAT_QUERY) && !is_image_format((VGImageFormat)setting)) ||
4966       ((hardware_query_type == VG_PATH_DATATYPE_QUERY) && !is_path_datatype((VGPathDatatype)setting))) {
4967       set_error(VG_ILLEGAL_ARGUMENT_ERROR);
4968       return (VGHardwareQueryResult)0;
4969    }
4970 
4971    return VG_HARDWARE_ACCELERATED;
4972 }
4973 
vgGetString(VGStringID name)4974 VG_API_CALL const VGubyte * VG_API_ENTRY vgGetString(VGStringID name) VG_API_EXIT
4975 {
4976    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
4977    if (!VG_GET_CLIENT_STATE(thread)) {
4978       return NULL;
4979    }
4980 
4981    switch (name) {
4982    case VG_VENDOR:     return (const VGubyte *)VG_CONFIG_VENDOR;
4983    case VG_RENDERER:   return (const VGubyte *)VG_CONFIG_RENDERER;
4984    case VG_VERSION:    return (const VGubyte *)"1.1";
4985    case VG_EXTENSIONS: return (const VGubyte *)VG_CONFIG_EXTENSIONS;
4986    default:            return NULL;
4987    }
4988 }
4989 
4990 /******************************************************************************
4991 api vgu
4992 ******************************************************************************/
4993 
get_vgu_error(void)4994 static VGUErrorCode get_vgu_error(void)
4995 {
4996    switch (get_error()) {
4997    case VG_NO_ERROR:               return VGU_NO_ERROR;
4998    case VG_BAD_HANDLE_ERROR:       return VGU_BAD_HANDLE_ERROR;
4999    case VG_ILLEGAL_ARGUMENT_ERROR: return VGU_ILLEGAL_ARGUMENT_ERROR;
5000    case VG_OUT_OF_MEMORY_ERROR:    return VGU_OUT_OF_MEMORY_ERROR;
5001    case VG_PATH_CAPABILITY_ERROR:  return VGU_PATH_CAPABILITY_ERROR;
5002    default:                        UNREACHABLE(); return (VGUErrorCode)0;
5003    }
5004 }
5005 
vguLine(VGPath vg_handle,VGfloat p0_x,VGfloat p0_y,VGfloat p1_x,VGfloat p1_y)5006 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguLine(
5007    VGPath vg_handle,
5008    VGfloat p0_x, VGfloat p0_y,
5009    VGfloat p1_x, VGfloat p1_y) VGU_API_EXIT
5010 {
5011    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5012    VG_CLIENT_STATE_T *state;
5013    VG_CLIENT_PATH_T *path;
5014 
5015    p0_x = clean_float(p0_x);
5016    p0_y = clean_float(p0_y);
5017    p1_x = clean_float(p1_x);
5018    p1_y = clean_float(p1_y);
5019 
5020    state = VG_GET_CLIENT_STATE(thread);
5021    if (!state) {
5022       return VGU_NO_ERROR;
5023    }
5024 
5025    clear_error();
5026 
5027    platform_mutex_acquire(&state->shared_state->mutex);
5028    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
5029    if (path &&
5030       (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
5031       need_path_segments(path->caps)) {
5032       VGubyte *segments;
5033       if (!khrn_vector_extend(&path->segments, 2)) {
5034          platform_mutex_release(&state->shared_state->mutex);
5035          return VGU_OUT_OF_MEMORY_ERROR;
5036       }
5037       segments = (VGubyte *)path->segments.data + (path->segments.size - 2);
5038       segments[0] = VG_MOVE_TO_ABS;
5039       segments[1] = VG_LINE_TO_ABS;
5040    }
5041    platform_mutex_release(&state->shared_state->mutex);
5042 
5043    RPC_CALL5(vguLine_impl,
5044              thread,
5045              VGULINE_ID,
5046              RPC_HANDLE(vg_handle),
5047              RPC_FLOAT(p0_x), RPC_FLOAT(p0_y),
5048              RPC_FLOAT(p1_x), RPC_FLOAT(p1_y));
5049 
5050    return get_vgu_error();
5051 }
5052 
vguPolygon(VGPath vg_handle,const VGfloat * ps,VGint ps_count,VGboolean close)5053 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguPolygon(
5054    VGPath vg_handle,
5055    const VGfloat *ps, VGint ps_count,
5056    VGboolean close) VGU_API_EXIT
5057 {
5058    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5059    VG_CLIENT_PATH_T *path;
5060 
5061    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
5062    if (!state) {
5063       return VGU_NO_ERROR;
5064    }
5065 
5066    clear_error();
5067 
5068    if ((ps_count <= 0) || !ps || !is_aligned_float(ps)) {
5069       return VGU_ILLEGAL_ARGUMENT_ERROR;
5070    }
5071 
5072    platform_mutex_acquire(&state->shared_state->mutex);
5073    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
5074    if (path &&
5075       (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
5076       need_path_segments(path->caps)) {
5077       VGubyte *segments;
5078       VGuint segments_count = ps_count + (close ? 1 : 0);
5079       if (!khrn_vector_extend(&path->segments, segments_count)) {
5080          platform_mutex_release(&state->shared_state->mutex);
5081          return VGU_OUT_OF_MEMORY_ERROR;
5082       }
5083       segments = (VGubyte *)path->segments.data + (path->segments.size - segments_count);
5084       memset(segments, VG_LINE_TO_ABS, segments_count);
5085       segments[0] = VG_MOVE_TO_ABS;
5086       if (close) { segments[segments_count - 1] = VG_CLOSE_PATH; }
5087    }
5088    platform_mutex_release(&state->shared_state->mutex);
5089 
5090    #ifdef RPC_DIRECT
5091       RPC_CALL5(vguPolygon_impl, thread, no_id,
5092          vg_handle,
5093          ps, ps_count,
5094          true, clean_boolean(close));
5095    #else
5096       {
5097          /*
5098             split into multiple calls if necessary to avoid overflowing control buffer
5099          */
5100 
5101          bool first = true;
5102          while (ps_count != 0) {
5103             #define MESSAGE_SIZE 20
5104 
5105             VGint chunk_ps_count = _min(ps_count, (rpc_send_ctrl_longest(thread, MESSAGE_SIZE + (2 * sizeof(VGfloat))) - MESSAGE_SIZE) / (2 * sizeof(VGfloat))); /* at least one p */
5106             bool last = chunk_ps_count == ps_count;
5107 
5108             uint32_t message[] = {
5109                VGUPOLYGON_ID,
5110                RPC_HANDLE(vg_handle),
5111                RPC_INT(chunk_ps_count),
5112                RPC_BOOLEAN(first), RPC_BOOLEAN(last && close) };
5113             vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
5114 
5115             #undef MESSAGE_SIZE
5116 
5117             rpc_send_ctrl_begin(thread,
5118                sizeof(message) +
5119                (chunk_ps_count * 2 * sizeof(VGfloat)));
5120             rpc_send_ctrl_write(thread, message, sizeof(message));
5121             rpc_send_ctrl_write(thread, (uint32_t *)ps, chunk_ps_count * 2 * sizeof(VGfloat));
5122             rpc_send_ctrl_end(thread);
5123 
5124             ps_count -= chunk_ps_count;
5125             ps += 2 * chunk_ps_count;
5126             first = false;
5127          }
5128       }
5129    #endif
5130 
5131    return get_vgu_error();
5132 }
5133 
vguRect(VGPath vg_handle,VGfloat x,VGfloat y,VGfloat width,VGfloat height)5134 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRect(
5135    VGPath vg_handle,
5136    VGfloat x, VGfloat y,
5137    VGfloat width, VGfloat height) VGU_API_EXIT
5138 {
5139    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5140    VG_CLIENT_STATE_T *state;
5141    VG_CLIENT_PATH_T *path;
5142 
5143    x = clean_float(x);
5144    y = clean_float(y);
5145    width = clean_float(width);
5146    height = clean_float(height);
5147 
5148    state = VG_GET_CLIENT_STATE(thread);
5149    if (!state) {
5150       return VGU_NO_ERROR;
5151    }
5152 
5153    clear_error();
5154 
5155    if (is_le_zero(width) || is_le_zero(height)) {
5156       return VGU_ILLEGAL_ARGUMENT_ERROR;
5157    }
5158 
5159    platform_mutex_acquire(&state->shared_state->mutex);
5160    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
5161    if (path &&
5162       (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
5163       need_path_segments(path->caps)) {
5164       VGubyte *segments;
5165       if (!khrn_vector_extend(&path->segments, 5)) {
5166          platform_mutex_release(&state->shared_state->mutex);
5167          return VGU_OUT_OF_MEMORY_ERROR;
5168       }
5169       segments = (VGubyte *)path->segments.data + (path->segments.size - 5);
5170       segments[0] = VG_MOVE_TO_ABS;
5171       segments[1] = VG_HLINE_TO_REL;
5172       segments[2] = VG_VLINE_TO_REL;
5173       segments[3] = VG_HLINE_TO_REL;
5174       segments[4] = VG_CLOSE_PATH;
5175    }
5176    platform_mutex_release(&state->shared_state->mutex);
5177 
5178    RPC_CALL5(vguRect_impl,
5179              thread,
5180              VGURECT_ID,
5181              RPC_HANDLE(vg_handle),
5182              RPC_FLOAT(x), RPC_FLOAT(y),
5183              RPC_FLOAT(width), RPC_FLOAT(height));
5184 
5185    return get_vgu_error();
5186 }
5187 
vguRoundRect(VGPath vg_handle,VGfloat x,VGfloat y,VGfloat width,VGfloat height,VGfloat arc_width,VGfloat arc_height)5188 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRoundRect(
5189    VGPath vg_handle,
5190    VGfloat x, VGfloat y,
5191    VGfloat width, VGfloat height,
5192    VGfloat arc_width, VGfloat arc_height) VGU_API_EXIT
5193 {
5194    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5195    VG_CLIENT_STATE_T *state;
5196    VG_CLIENT_PATH_T *path;
5197 
5198    x = clean_float(x);
5199    y = clean_float(y);
5200    width = clean_float(width);
5201    height = clean_float(height);
5202    arc_width = clean_float(arc_width);
5203    arc_height = clean_float(arc_height);
5204 
5205    state = VG_GET_CLIENT_STATE(thread);
5206    if (!state) {
5207       return VGU_NO_ERROR;
5208    }
5209 
5210    clear_error();
5211 
5212    if (is_le_zero(width) || is_le_zero(height)) {
5213       return VGU_ILLEGAL_ARGUMENT_ERROR;
5214    }
5215 
5216    platform_mutex_acquire(&state->shared_state->mutex);
5217    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
5218    if (path &&
5219       (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
5220       need_path_segments(path->caps)) {
5221       VGubyte *segments;
5222       if (!khrn_vector_extend(&path->segments, 10)) {
5223          platform_mutex_release(&state->shared_state->mutex);
5224          return VGU_OUT_OF_MEMORY_ERROR;
5225       }
5226       segments = (VGubyte *)path->segments.data + (path->segments.size - 10);
5227       segments[0] = VG_MOVE_TO_ABS;
5228       segments[1] = VG_HLINE_TO_REL;
5229       segments[2] = VG_SCCWARC_TO_REL;
5230       segments[3] = VG_VLINE_TO_REL;
5231       segments[4] = VG_SCCWARC_TO_REL;
5232       segments[5] = VG_HLINE_TO_REL;
5233       segments[6] = VG_SCCWARC_TO_REL;
5234       segments[7] = VG_VLINE_TO_REL;
5235       segments[8] = VG_SCCWARC_TO_REL;
5236       segments[9] = VG_CLOSE_PATH;
5237    }
5238    platform_mutex_release(&state->shared_state->mutex);
5239 
5240    RPC_CALL7(vguRoundRect_impl,
5241              thread,
5242              VGUROUNDRECT_ID,
5243              RPC_HANDLE(vg_handle),
5244              RPC_FLOAT(x), RPC_FLOAT(y),
5245              RPC_FLOAT(width), RPC_FLOAT(height),
5246              RPC_FLOAT(arc_width), RPC_FLOAT(arc_height));
5247 
5248    return get_vgu_error();
5249 }
5250 
vguEllipse(VGPath vg_handle,VGfloat x,VGfloat y,VGfloat width,VGfloat height)5251 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguEllipse(
5252    VGPath vg_handle,
5253    VGfloat x, VGfloat y,
5254    VGfloat width, VGfloat height) VGU_API_EXIT
5255 {
5256    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5257    VG_CLIENT_STATE_T *state;
5258    VG_CLIENT_PATH_T *path;
5259 
5260    x = clean_float(x);
5261    y = clean_float(y);
5262    width = clean_float(width);
5263    height = clean_float(height);
5264 
5265    state = VG_GET_CLIENT_STATE(thread);
5266    if (!state) {
5267       return VGU_NO_ERROR;
5268    }
5269 
5270    clear_error();
5271 
5272    if (is_le_zero(width) || is_le_zero(height)) {
5273       return VGU_ILLEGAL_ARGUMENT_ERROR;
5274    }
5275 
5276    platform_mutex_acquire(&state->shared_state->mutex);
5277    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
5278    if (path &&
5279       (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
5280       need_path_segments(path->caps)) {
5281       VGubyte *segments;
5282       if (!khrn_vector_extend(&path->segments, 4)) {
5283          platform_mutex_release(&state->shared_state->mutex);
5284          return VGU_OUT_OF_MEMORY_ERROR;
5285       }
5286       segments = (VGubyte *)path->segments.data + (path->segments.size - 4);
5287       segments[0] = VG_MOVE_TO_ABS;
5288       segments[1] = VG_SCCWARC_TO_REL;
5289       segments[2] = VG_SCCWARC_TO_REL;
5290       segments[3] = VG_CLOSE_PATH;
5291    }
5292    platform_mutex_release(&state->shared_state->mutex);
5293 
5294    RPC_CALL5(vguEllipse_impl,
5295              thread,
5296              VGUELLIPSE_ID,
5297              RPC_HANDLE(vg_handle),
5298              RPC_FLOAT(x), RPC_FLOAT(y),
5299              RPC_FLOAT(width), RPC_FLOAT(height));
5300 
5301    return get_vgu_error();
5302 }
5303 
vguArc(VGPath vg_handle,VGfloat x,VGfloat y,VGfloat width,VGfloat height,VGfloat start_angle,VGfloat angle_extent,VGUArcType arc_type)5304 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguArc(
5305    VGPath vg_handle,
5306    VGfloat x, VGfloat y,
5307    VGfloat width, VGfloat height,
5308    VGfloat start_angle, VGfloat angle_extent,
5309    VGUArcType arc_type) VGU_API_EXIT
5310 {
5311    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5312    VG_CLIENT_STATE_T *state;
5313    VGuint angle_o180;
5314    VG_CLIENT_PATH_T *path;
5315 
5316    x = clean_float(x);
5317    y = clean_float(y);
5318    width = clean_float(width);
5319    height = clean_float(height);
5320    start_angle = clean_float(start_angle);
5321    angle_extent = clean_float(angle_extent);
5322 
5323    state = VG_GET_CLIENT_STATE(thread);
5324    if (!state) {
5325       return VGU_NO_ERROR;
5326    }
5327 
5328    clear_error();
5329 
5330    if (is_le_zero(width) || is_le_zero(height) || !is_arc_type(arc_type)) {
5331       return VGU_ILLEGAL_ARGUMENT_ERROR;
5332    }
5333 
5334    angle_o180 = float_to_int_zero(absf_(angle_extent) * (1.0f / 180.0f));
5335 
5336    platform_mutex_acquire(&state->shared_state->mutex);
5337    path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
5338    if (path &&
5339       (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
5340       need_path_segments(path->caps)) {
5341       VGubyte *segments;
5342       VGuint segments_count = 2 + angle_o180;
5343       switch (arc_type) {
5344       case VGU_ARC_OPEN:  break;
5345       case VGU_ARC_CHORD: segments_count += 1; break;
5346       case VGU_ARC_PIE:   segments_count += 2; break;
5347       default:            UNREACHABLE();
5348       }
5349       if (!khrn_vector_extend(&path->segments, segments_count)) {
5350          platform_mutex_release(&state->shared_state->mutex);
5351          return VGU_OUT_OF_MEMORY_ERROR;
5352       }
5353       segments = (VGubyte *)path->segments.data + (path->segments.size - segments_count);
5354       segments[0] = VG_MOVE_TO_ABS;
5355       memset(segments + 1, VG_SCCWARC_TO_ABS, segments_count - 1); /* don't care about actual arc type on client */
5356       if (arc_type == VGU_ARC_PIE) { segments[segments_count - 2] = VG_LINE_TO_ABS; }
5357       if ((arc_type == VGU_ARC_CHORD) || (arc_type == VGU_ARC_PIE)) { segments[segments_count - 1] = VG_CLOSE_PATH; }
5358    }
5359    platform_mutex_release(&state->shared_state->mutex);
5360 
5361    RPC_CALL9(vguArc_impl,
5362              thread,
5363              VGUARC_ID,
5364              RPC_HANDLE(vg_handle),
5365              RPC_FLOAT(x), RPC_FLOAT(y),
5366              RPC_FLOAT(width), RPC_FLOAT(height),
5367              RPC_FLOAT(start_angle), RPC_FLOAT(angle_extent), RPC_UINT(angle_o180),
5368              RPC_ENUM(arc_type));
5369 
5370    return get_vgu_error();
5371 }
5372 
5373 /*
5374    based on "Fundamentals of Texture Mapping and Image Warping" by Paul S Heckbert
5375 */
5376 
warp_square_to_quad(VG_MAT3X3_T * a,VGfloat p0_x,VGfloat p0_y,VGfloat p1_x,VGfloat p1_y,VGfloat p2_x,VGfloat p2_y,VGfloat p3_x,VGfloat p3_y)5377 static bool warp_square_to_quad(VG_MAT3X3_T *a,
5378    VGfloat p0_x, VGfloat p0_y,
5379    VGfloat p1_x, VGfloat p1_y,
5380    VGfloat p2_x, VGfloat p2_y,
5381    VGfloat p3_x, VGfloat p3_y)
5382 {
5383    VGfloat d1_x = p1_x - p3_x;
5384    VGfloat d1_y = p1_y - p3_y;
5385    VGfloat d2_x = p2_x - p3_x;
5386    VGfloat d2_y = p2_y - p3_y;
5387 
5388    VGfloat d = (d1_x * d2_y) - (d1_y * d2_x);
5389 
5390    VGfloat oo_d;
5391    VGfloat sum_x;
5392    VGfloat sum_y;
5393    VGfloat g;
5394    VGfloat h;
5395 
5396    if (absf_(d) < EPS) {
5397       return false;
5398    }
5399    oo_d = recip_(d);
5400 
5401    sum_x = (p0_x + p3_x) - (p1_x + p2_x);
5402    sum_y = (p0_y + p3_y) - (p1_y + p2_y);
5403 
5404    g = ((sum_x * d2_y) - (sum_y * d2_x)) * oo_d;
5405    h = ((d1_x * sum_y) - (d1_y * sum_x)) * oo_d;
5406 
5407    a->m[0][0] = (p1_x - p0_x) + (g * p1_x);
5408    a->m[0][1] = (p2_x - p0_x) + (h * p2_x);
5409    a->m[0][2] = p0_x;
5410 
5411    a->m[1][0] = (p1_y - p0_y) + (g * p1_y);
5412    a->m[1][1] = (p2_y - p0_y) + (h * p2_y);
5413    a->m[1][2] = p0_y;
5414 
5415    a->m[2][0] = g;
5416    a->m[2][1] = h;
5417    a->m[2][2] = 1.0f;
5418 
5419    return true;
5420 }
5421 
warp_quad_to_square(VG_MAT3X3_T * a,VGfloat p0_x,VGfloat p0_y,VGfloat p1_x,VGfloat p1_y,VGfloat p2_x,VGfloat p2_y,VGfloat p3_x,VGfloat p3_y)5422 static bool warp_quad_to_square(VG_MAT3X3_T *a,
5423    VGfloat p0_x, VGfloat p0_y,
5424    VGfloat p1_x, VGfloat p1_y,
5425    VGfloat p2_x, VGfloat p2_y,
5426    VGfloat p3_x, VGfloat p3_y)
5427 {
5428    if (!warp_square_to_quad(a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) ||
5429       !vg_mat3x3_is_invertible(a)) {
5430       return false;
5431    }
5432    vg_mat3x3_invert(a);
5433    return true;
5434 }
5435 
vguComputeWarpQuadToSquare(VGfloat p0_x,VGfloat p0_y,VGfloat p1_x,VGfloat p1_y,VGfloat p2_x,VGfloat p2_y,VGfloat p3_x,VGfloat p3_y,VGfloat * matrix)5436 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToSquare(
5437    VGfloat p0_x, VGfloat p0_y,
5438    VGfloat p1_x, VGfloat p1_y,
5439    VGfloat p2_x, VGfloat p2_y,
5440    VGfloat p3_x, VGfloat p3_y,
5441    VGfloat *matrix) VGU_API_EXIT
5442 {
5443    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5444    VG_MAT3X3_T a;
5445 
5446    p0_x = clean_float(p0_x);
5447    p0_y = clean_float(p0_y);
5448    p1_x = clean_float(p1_x);
5449    p1_y = clean_float(p1_y);
5450    p2_x = clean_float(p2_x);
5451    p2_y = clean_float(p2_y);
5452    p3_x = clean_float(p3_x);
5453    p3_y = clean_float(p3_y);
5454 
5455    if (!VG_GET_CLIENT_STATE(thread)) {
5456       return VGU_NO_ERROR;
5457    }
5458 
5459    if (!matrix || !is_aligned_float(matrix)) {
5460       return VGU_ILLEGAL_ARGUMENT_ERROR;
5461    }
5462 
5463    if (!warp_quad_to_square(&a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y)) {
5464       return VGU_BAD_WARP_ERROR;
5465    }
5466    vg_mat3x3_get(&a, matrix);
5467    return VGU_NO_ERROR;
5468 }
5469 
vguComputeWarpSquareToQuad(VGfloat p0_x,VGfloat p0_y,VGfloat p1_x,VGfloat p1_y,VGfloat p2_x,VGfloat p2_y,VGfloat p3_x,VGfloat p3_y,VGfloat * matrix)5470 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpSquareToQuad(
5471    VGfloat p0_x, VGfloat p0_y,
5472    VGfloat p1_x, VGfloat p1_y,
5473    VGfloat p2_x, VGfloat p2_y,
5474    VGfloat p3_x, VGfloat p3_y,
5475    VGfloat *matrix) VGU_API_EXIT
5476 {
5477    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5478    VG_MAT3X3_T a;
5479 
5480    p0_x = clean_float(p0_x);
5481    p0_y = clean_float(p0_y);
5482    p1_x = clean_float(p1_x);
5483    p1_y = clean_float(p1_y);
5484    p2_x = clean_float(p2_x);
5485    p2_y = clean_float(p2_y);
5486    p3_x = clean_float(p3_x);
5487    p3_y = clean_float(p3_y);
5488 
5489    if (!VG_GET_CLIENT_STATE(thread)) {
5490       return VGU_NO_ERROR;
5491    }
5492 
5493    if (!matrix || !is_aligned_float(matrix)) {
5494       return VGU_ILLEGAL_ARGUMENT_ERROR;
5495    }
5496 
5497    if (!warp_square_to_quad(&a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y)) {
5498       return VGU_BAD_WARP_ERROR;
5499    }
5500    vg_mat3x3_get(&a, matrix);
5501    return VGU_NO_ERROR;
5502 }
5503 
vguComputeWarpQuadToQuad(VGfloat p0_x,VGfloat p0_y,VGfloat p1_x,VGfloat p1_y,VGfloat p2_x,VGfloat p2_y,VGfloat p3_x,VGfloat p3_y,VGfloat q0_x,VGfloat q0_y,VGfloat q1_x,VGfloat q1_y,VGfloat q2_x,VGfloat q2_y,VGfloat q3_x,VGfloat q3_y,VGfloat * matrix)5504 VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToQuad(
5505    VGfloat p0_x, VGfloat p0_y,
5506    VGfloat p1_x, VGfloat p1_y,
5507    VGfloat p2_x, VGfloat p2_y,
5508    VGfloat p3_x, VGfloat p3_y,
5509    VGfloat q0_x, VGfloat q0_y,
5510    VGfloat q1_x, VGfloat q1_y,
5511    VGfloat q2_x, VGfloat q2_y,
5512    VGfloat q3_x, VGfloat q3_y,
5513    VGfloat *matrix) VGU_API_EXIT
5514 {
5515    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5516    VG_MAT3X3_T a, b;
5517 
5518    p0_x = clean_float(p0_x);
5519    p0_y = clean_float(p0_y);
5520    p1_x = clean_float(p1_x);
5521    p1_y = clean_float(p1_y);
5522    p2_x = clean_float(p2_x);
5523    p2_y = clean_float(p2_y);
5524    p3_x = clean_float(p3_x);
5525    p3_y = clean_float(p3_y);
5526    q0_x = clean_float(q0_x);
5527    q0_y = clean_float(q0_y);
5528    q1_x = clean_float(q1_x);
5529    q1_y = clean_float(q1_y);
5530    q2_x = clean_float(q2_x);
5531    q2_y = clean_float(q2_y);
5532    q3_x = clean_float(q3_x);
5533    q3_y = clean_float(q3_y);
5534 
5535    if (!VG_GET_CLIENT_STATE(thread)) {
5536       return VGU_NO_ERROR;
5537    }
5538 
5539    if (!matrix || !is_aligned_float(matrix)) {
5540       return VGU_ILLEGAL_ARGUMENT_ERROR;
5541    }
5542 
5543    if (!warp_square_to_quad(&a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) ||
5544       !warp_quad_to_square(&b, q0_x, q0_y, q1_x, q1_y, q2_x, q2_y, q3_x, q3_y)) {
5545       return VGU_BAD_WARP_ERROR;
5546    }
5547    vg_mat3x3_postmul(&a, &b);
5548    vg_mat3x3_get(&a, matrix);
5549    return VGU_NO_ERROR;
5550 }
5551 
5552 /******************************************************************************
5553 VG_KHR_EGL_image
5554 ******************************************************************************/
5555 
5556 #if VG_KHR_EGL_image
5557 
vgCreateEGLImageTargetKHR(VGeglImageKHR src_egl_handle)5558 VG_API_CALL VGImage VG_API_ENTRY vgCreateEGLImageTargetKHR(
5559    VGeglImageKHR src_egl_handle) VG_API_EXIT
5560 {
5561    CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
5562 #if EGL_BRCM_global_image
5563    VGuint global_image_id[2];
5564 #endif
5565    VGuint format_width_height[3];
5566    VGImage vg_handle;
5567    VG_CLIENT_IMAGE_T *image;
5568 
5569    VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
5570    if (!state) {
5571       return VG_INVALID_HANDLE;
5572    }
5573 
5574 #if EGL_BRCM_global_image
5575    if ((uintptr_t)src_egl_handle & (1 << 31)) {
5576       CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();
5577       uint64_t id;
5578 
5579       CLIENT_LOCK();
5580       id = process->inited ? khrn_global_image_map_lookup(&process->global_image_egl_images, (uint32_t)(uintptr_t)src_egl_handle) : 0;
5581       CLIENT_UNLOCK();
5582       if (!id) {
5583          set_error(VG_ILLEGAL_ARGUMENT_ERROR);
5584          return VG_INVALID_HANDLE;
5585       }
5586       global_image_id[0] = (VGuint)id;
5587       global_image_id[1] = (VGuint)(id >> 32);
5588 
5589       platform_get_global_image_info(global_image_id[0], global_image_id[1],
5590          format_width_height + 0, format_width_height + 1, format_width_height + 2);
5591 
5592       if (!(format_width_height[0] & EGL_PIXEL_FORMAT_VG_IMAGE_BRCM) ||
5593          (format_width_height[1] == 0) || (format_width_height[2] == 0) ||
5594          (format_width_height[1] > VG_CONFIG_MAX_IMAGE_WIDTH) || (format_width_height[2] > VG_CONFIG_MAX_IMAGE_HEIGHT)) {
5595          set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
5596          return VG_INVALID_HANDLE;
5597       }
5598 
5599       switch (format_width_height[0] & ~EGL_PIXEL_FORMAT_USAGE_MASK_BRCM) {
5600       case EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM: format_width_height[0] = VG_sARGB_8888_PRE; break;
5601       case EGL_PIXEL_FORMAT_ARGB_8888_BRCM:     format_width_height[0] = VG_sARGB_8888; break;
5602       case EGL_PIXEL_FORMAT_XRGB_8888_BRCM:     format_width_height[0] = VG_sXRGB_8888; break;
5603       case EGL_PIXEL_FORMAT_RGB_565_BRCM:       format_width_height[0] = VG_sRGB_565; break;
5604       case EGL_PIXEL_FORMAT_A_8_BRCM:           format_width_height[0] = VG_A_8; break;
5605       default:                                  UNREACHABLE();
5606       }
5607 
5608       vg_handle = get_stem(state);
5609       if (vg_handle == VG_INVALID_HANDLE) {
5610          set_error(VG_OUT_OF_MEMORY_ERROR);
5611          return VG_INVALID_HANDLE;
5612       }
5613 
5614       RPC_CALL3(vgCreateImageFromGlobalImage_impl,
5615                 thread,
5616                 VGCREATEIMAGEFROMGLOBALIMAGE_ID,
5617                 RPC_HANDLE(vg_handle),
5618                 RPC_UINT(global_image_id[0]),
5619                 RPC_UINT(global_image_id[1]));
5620    } else {
5621       global_image_id[0] = 0;
5622       global_image_id[1] = 0;
5623 #endif
5624       vg_handle = RPC_HANDLE_RES(RPC_CALL2_OUT_CTRL_RES(vgCreateEGLImageTargetKHR_impl,
5625                                                         thread,
5626                                                         VGCREATEEGLIMAGETARGETKHR_ID,
5627                                                         RPC_EGLID(src_egl_handle),
5628                                                         format_width_height));
5629       if (vg_handle == VG_INVALID_HANDLE) {
5630          return VG_INVALID_HANDLE;
5631       }
5632 #if EGL_BRCM_global_image
5633    }
5634 #endif
5635 
5636    image = image_alloc((VGImageFormat)format_width_height[0], format_width_height[1], format_width_height[2]
5637 #if EGL_BRCM_global_image
5638       , global_image_id[0], global_image_id[1]
5639 #endif
5640       );
5641    if (!image) {
5642       set_error(VG_OUT_OF_MEMORY_ERROR);
5643       RPC_CALL1(vgDestroyImage_impl,
5644                 thread,
5645                 VGDESTROYIMAGE_ID,
5646                 RPC_HANDLE(vg_handle));
5647       return VG_INVALID_HANDLE;
5648    }
5649 
5650    platform_mutex_acquire(&state->shared_state->mutex);
5651    if (!insert_object(state, vg_handle, image)) {
5652       set_error(VG_OUT_OF_MEMORY_ERROR);
5653       platform_mutex_release(&state->shared_state->mutex);
5654       image_free(image);
5655       RPC_CALL1(vgDestroyImage_impl,
5656                 thread,
5657                 VGDESTROYIMAGE_ID,
5658                 RPC_HANDLE(vg_handle));
5659       return VG_INVALID_HANDLE;
5660    }
5661    platform_mutex_release(&state->shared_state->mutex);
5662 
5663    return vg_handle;
5664 }
5665 
5666 #endif
5667