• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012-2013 Etnaviv Project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sub license,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the
12  * next paragraph) shall be included in all copies or substantial portions
13  * of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 /* inlined translation functions between gallium and vivante */
24 #ifndef H_TRANSLATE
25 #define H_TRANSLATE
26 
27 #include "pipe/p_defines.h"
28 #include "pipe/p_format.h"
29 #include "pipe/p_state.h"
30 
31 #include "etnaviv_debug.h"
32 #include "etnaviv_format.h"
33 #include "etnaviv_tiling.h"
34 #include "etnaviv_util.h"
35 #include "hw/cmdstream.xml.h"
36 #include "hw/state.xml.h"
37 #include "hw/state_3d.xml.h"
38 
39 #include "util/u_format.h"
40 
41 #include <stdio.h>
42 
43 /* Returned when there is no match of pipe value to etna value */
44 #define ETNA_NO_MATCH (~0)
45 
46 static inline uint32_t
translate_cull_face(unsigned cull_face,unsigned front_ccw)47 translate_cull_face(unsigned cull_face, unsigned front_ccw)
48 {
49    switch (cull_face) {
50    case PIPE_FACE_NONE:
51       return VIVS_PA_CONFIG_CULL_FACE_MODE_OFF;
52    case PIPE_FACE_BACK:
53       return front_ccw ? VIVS_PA_CONFIG_CULL_FACE_MODE_CW
54                        : VIVS_PA_CONFIG_CULL_FACE_MODE_CCW;
55    case PIPE_FACE_FRONT:
56       return front_ccw ? VIVS_PA_CONFIG_CULL_FACE_MODE_CCW
57                        : VIVS_PA_CONFIG_CULL_FACE_MODE_CW;
58    default:
59       DBG("Unhandled cull face mode %i", cull_face);
60       return ETNA_NO_MATCH;
61    }
62 }
63 
64 static inline uint32_t
translate_polygon_mode(unsigned polygon_mode)65 translate_polygon_mode(unsigned polygon_mode)
66 {
67    switch (polygon_mode) {
68    case PIPE_POLYGON_MODE_FILL:
69       return VIVS_PA_CONFIG_FILL_MODE_SOLID;
70    case PIPE_POLYGON_MODE_LINE:
71       return VIVS_PA_CONFIG_FILL_MODE_WIREFRAME;
72    case PIPE_POLYGON_MODE_POINT:
73       return VIVS_PA_CONFIG_FILL_MODE_POINT;
74    default:
75       DBG("Unhandled polygon mode %i", polygon_mode);
76       return ETNA_NO_MATCH;
77    }
78 }
79 
80 static inline uint32_t
translate_stencil_mode(bool enable_0,bool enable_1)81 translate_stencil_mode(bool enable_0, bool enable_1)
82 {
83    if (enable_0) {
84       return enable_1 ? VIVS_PE_STENCIL_CONFIG_MODE_TWO_SIDED
85                       : VIVS_PE_STENCIL_CONFIG_MODE_ONE_SIDED;
86    } else {
87       return VIVS_PE_STENCIL_CONFIG_MODE_DISABLED;
88    }
89 }
90 
91 static inline uint32_t
translate_stencil_op(unsigned stencil_op)92 translate_stencil_op(unsigned stencil_op)
93 {
94    switch (stencil_op) {
95    case PIPE_STENCIL_OP_KEEP:
96       return STENCIL_OP_KEEP;
97    case PIPE_STENCIL_OP_ZERO:
98       return STENCIL_OP_ZERO;
99    case PIPE_STENCIL_OP_REPLACE:
100       return STENCIL_OP_REPLACE;
101    case PIPE_STENCIL_OP_INCR:
102       return STENCIL_OP_INCR;
103    case PIPE_STENCIL_OP_DECR:
104       return STENCIL_OP_DECR;
105    case PIPE_STENCIL_OP_INCR_WRAP:
106       return STENCIL_OP_INCR_WRAP;
107    case PIPE_STENCIL_OP_DECR_WRAP:
108       return STENCIL_OP_DECR_WRAP;
109    case PIPE_STENCIL_OP_INVERT:
110       return STENCIL_OP_INVERT;
111    default:
112       DBG("Unhandled stencil op: %i", stencil_op);
113       return ETNA_NO_MATCH;
114    }
115 }
116 
117 static inline uint32_t
translate_blend(unsigned blend)118 translate_blend(unsigned blend)
119 {
120    switch (blend) {
121    case PIPE_BLEND_ADD:
122       return BLEND_EQ_ADD;
123    case PIPE_BLEND_SUBTRACT:
124       return BLEND_EQ_SUBTRACT;
125    case PIPE_BLEND_REVERSE_SUBTRACT:
126       return BLEND_EQ_REVERSE_SUBTRACT;
127    case PIPE_BLEND_MIN:
128       return BLEND_EQ_MIN;
129    case PIPE_BLEND_MAX:
130       return BLEND_EQ_MAX;
131    default:
132       DBG("Unhandled blend: %i", blend);
133       return ETNA_NO_MATCH;
134    }
135 }
136 
137 static inline uint32_t
translate_blend_factor(unsigned blend_factor)138 translate_blend_factor(unsigned blend_factor)
139 {
140    switch (blend_factor) {
141    case PIPE_BLENDFACTOR_ONE:
142       return BLEND_FUNC_ONE;
143    case PIPE_BLENDFACTOR_SRC_COLOR:
144       return BLEND_FUNC_SRC_COLOR;
145    case PIPE_BLENDFACTOR_SRC_ALPHA:
146       return BLEND_FUNC_SRC_ALPHA;
147    case PIPE_BLENDFACTOR_DST_ALPHA:
148       return BLEND_FUNC_DST_ALPHA;
149    case PIPE_BLENDFACTOR_DST_COLOR:
150       return BLEND_FUNC_DST_COLOR;
151    case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE:
152       return BLEND_FUNC_SRC_ALPHA_SATURATE;
153    case PIPE_BLENDFACTOR_CONST_COLOR:
154       return BLEND_FUNC_CONSTANT_COLOR;
155    case PIPE_BLENDFACTOR_CONST_ALPHA:
156       return BLEND_FUNC_CONSTANT_ALPHA;
157    case PIPE_BLENDFACTOR_ZERO:
158       return BLEND_FUNC_ZERO;
159    case PIPE_BLENDFACTOR_INV_SRC_COLOR:
160       return BLEND_FUNC_ONE_MINUS_SRC_COLOR;
161    case PIPE_BLENDFACTOR_INV_SRC_ALPHA:
162       return BLEND_FUNC_ONE_MINUS_SRC_ALPHA;
163    case PIPE_BLENDFACTOR_INV_DST_ALPHA:
164       return BLEND_FUNC_ONE_MINUS_DST_ALPHA;
165    case PIPE_BLENDFACTOR_INV_DST_COLOR:
166       return BLEND_FUNC_ONE_MINUS_DST_COLOR;
167    case PIPE_BLENDFACTOR_INV_CONST_COLOR:
168       return BLEND_FUNC_ONE_MINUS_CONSTANT_COLOR;
169    case PIPE_BLENDFACTOR_INV_CONST_ALPHA:
170       return BLEND_FUNC_ONE_MINUS_CONSTANT_ALPHA;
171    case PIPE_BLENDFACTOR_SRC1_COLOR:
172    case PIPE_BLENDFACTOR_SRC1_ALPHA:
173    case PIPE_BLENDFACTOR_INV_SRC1_COLOR:
174    case PIPE_BLENDFACTOR_INV_SRC1_ALPHA:
175    default:
176       DBG("Unhandled blend factor: %i", blend_factor);
177       return ETNA_NO_MATCH;
178    }
179 }
180 
181 static inline uint32_t
translate_texture_wrapmode(unsigned wrap)182 translate_texture_wrapmode(unsigned wrap)
183 {
184    switch (wrap) {
185    case PIPE_TEX_WRAP_REPEAT:
186       return TEXTURE_WRAPMODE_REPEAT;
187    case PIPE_TEX_WRAP_CLAMP:
188       return TEXTURE_WRAPMODE_CLAMP_TO_EDGE;
189    case PIPE_TEX_WRAP_CLAMP_TO_EDGE:
190       return TEXTURE_WRAPMODE_CLAMP_TO_EDGE;
191    case PIPE_TEX_WRAP_CLAMP_TO_BORDER:
192       return TEXTURE_WRAPMODE_CLAMP_TO_EDGE; /* XXX */
193    case PIPE_TEX_WRAP_MIRROR_REPEAT:
194       return TEXTURE_WRAPMODE_MIRRORED_REPEAT;
195    case PIPE_TEX_WRAP_MIRROR_CLAMP:
196       return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */
197    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE:
198       return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */
199    case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER:
200       return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */
201    default:
202       DBG("Unhandled texture wrapmode: %i", wrap);
203       return ETNA_NO_MATCH;
204    }
205 }
206 
207 static inline uint32_t
translate_texture_mipfilter(unsigned filter)208 translate_texture_mipfilter(unsigned filter)
209 {
210    switch (filter) {
211    case PIPE_TEX_MIPFILTER_NEAREST:
212       return TEXTURE_FILTER_NEAREST;
213    case PIPE_TEX_MIPFILTER_LINEAR:
214       return TEXTURE_FILTER_LINEAR;
215    case PIPE_TEX_MIPFILTER_NONE:
216       return TEXTURE_FILTER_NONE;
217    default:
218       DBG("Unhandled texture mipfilter: %i", filter);
219       return ETNA_NO_MATCH;
220    }
221 }
222 
223 static inline uint32_t
translate_texture_filter(unsigned filter)224 translate_texture_filter(unsigned filter)
225 {
226    switch (filter) {
227    case PIPE_TEX_FILTER_NEAREST:
228       return TEXTURE_FILTER_NEAREST;
229    case PIPE_TEX_FILTER_LINEAR:
230       return TEXTURE_FILTER_LINEAR;
231    /* What about anisotropic? */
232    default:
233       DBG("Unhandled texture filter: %i", filter);
234       return ETNA_NO_MATCH;
235    }
236 }
237 
238 /* return a RS "compatible" format for use when copying */
239 static inline enum pipe_format
etna_compatible_rs_format(enum pipe_format fmt)240 etna_compatible_rs_format(enum pipe_format fmt)
241 {
242    /* YUYV and UYVY are blocksize 4, but 2 bytes per pixel */
243    if (fmt == PIPE_FORMAT_YUYV || fmt == PIPE_FORMAT_UYVY)
244       return PIPE_FORMAT_B4G4R4A4_UNORM;
245 
246    switch (util_format_get_blocksize(fmt)) {
247    case 2:
248       return PIPE_FORMAT_B4G4R4A4_UNORM;
249    case 4:
250       return PIPE_FORMAT_B8G8R8A8_UNORM;
251    default:
252       return fmt;
253    }
254 }
255 
256 static inline int
translate_rb_src_dst_swap(enum pipe_format src,enum pipe_format dst)257 translate_rb_src_dst_swap(enum pipe_format src, enum pipe_format dst)
258 {
259    return translate_rs_format_rb_swap(src) ^ translate_rs_format_rb_swap(dst);
260 }
261 
262 static inline uint32_t
translate_depth_format(enum pipe_format fmt)263 translate_depth_format(enum pipe_format fmt)
264 {
265    /* Note: Pipe format convention is LSB to MSB, VIVS is MSB to LSB */
266    switch (fmt) {
267    case PIPE_FORMAT_Z16_UNORM:
268       return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D16;
269    case PIPE_FORMAT_X8Z24_UNORM:
270       return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8;
271    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
272       return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8;
273    default:
274       return ETNA_NO_MATCH;
275    }
276 }
277 
278 /* render target format for MSAA */
279 static inline uint32_t
translate_msaa_format(enum pipe_format fmt)280 translate_msaa_format(enum pipe_format fmt)
281 {
282    /* Note: Pipe format convention is LSB to MSB, VIVS is MSB to LSB */
283    switch (fmt) {
284    case PIPE_FORMAT_B4G4R4X4_UNORM:
285       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4;
286    case PIPE_FORMAT_B4G4R4A4_UNORM:
287       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4;
288    case PIPE_FORMAT_B5G5R5X1_UNORM:
289       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5;
290    case PIPE_FORMAT_B5G5R5A1_UNORM:
291       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5;
292    case PIPE_FORMAT_B5G6R5_UNORM:
293       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_R5G6B5;
294    case PIPE_FORMAT_B8G8R8X8_UNORM:
295       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_X8R8G8B8;
296    case PIPE_FORMAT_B8G8R8A8_UNORM:
297       return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A8R8G8B8;
298    /* MSAA with YUYV not supported */
299    default:
300       return ETNA_NO_MATCH;
301    }
302 }
303 
304 /* Return normalization flag for vertex element format */
305 static inline uint32_t
translate_vertex_format_normalize(enum pipe_format fmt)306 translate_vertex_format_normalize(enum pipe_format fmt)
307 {
308    const struct util_format_description *desc = util_format_description(fmt);
309    if (!desc)
310       return VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF;
311 
312    /* assumes that normalization of channel 0 holds for all channels;
313     * this holds for all vertex formats that we support */
314    return desc->channel[0].normalized
315              ? VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON
316              : VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF;
317 }
318 
319 static inline uint32_t
translate_index_size(unsigned index_size)320 translate_index_size(unsigned index_size)
321 {
322    switch (index_size) {
323    case 1:
324       return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR;
325    case 2:
326       return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT;
327    case 4:
328       return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT;
329    default:
330       DBG("Unhandled index size %i", index_size);
331       return ETNA_NO_MATCH;
332    }
333 }
334 
335 static inline uint32_t
translate_draw_mode(unsigned mode)336 translate_draw_mode(unsigned mode)
337 {
338    switch (mode) {
339    case PIPE_PRIM_POINTS:
340       return PRIMITIVE_TYPE_POINTS;
341    case PIPE_PRIM_LINES:
342       return PRIMITIVE_TYPE_LINES;
343    case PIPE_PRIM_LINE_LOOP:
344       return PRIMITIVE_TYPE_LINE_LOOP;
345    case PIPE_PRIM_LINE_STRIP:
346       return PRIMITIVE_TYPE_LINE_STRIP;
347    case PIPE_PRIM_TRIANGLES:
348       return PRIMITIVE_TYPE_TRIANGLES;
349    case PIPE_PRIM_TRIANGLE_STRIP:
350       return PRIMITIVE_TYPE_TRIANGLE_STRIP;
351    case PIPE_PRIM_TRIANGLE_FAN:
352       return PRIMITIVE_TYPE_TRIANGLE_FAN;
353    case PIPE_PRIM_QUADS:
354       return PRIMITIVE_TYPE_QUADS;
355    default:
356       DBG("Unhandled draw mode primitive %i", mode);
357       return ETNA_NO_MATCH;
358    }
359 }
360 
361 /* Get size multiple for size of texture/rendertarget with a certain layout
362  * This is affected by many different parameters:
363  *   - A horizontal multiple of 16 is used when possible as resolve can be used
364  *       at the cost of only a little bit extra memory usage.
365  *   - If the surface is to be used with the resolve engine, set rs_align true.
366  *       If set, a horizontal multiple of 16 will be used for tiled and linear,
367  *       otherwise one of 16.  However, such a surface will be incompatible
368  *       with the samplers if the GPU does hot support the HALIGN feature.
369  *   - If the surface is supertiled, horizontal and vertical multiple is always 64
370  *   - If the surface is multi tiled or supertiled, make sure that the vertical size
371  *     is a multiple of the number of pixel pipes as well.
372  * */
373 static inline void
etna_layout_multiple(unsigned layout,unsigned pixel_pipes,bool rs_align,unsigned * paddingX,unsigned * paddingY,unsigned * halign)374 etna_layout_multiple(unsigned layout, unsigned pixel_pipes, bool rs_align,
375                      unsigned *paddingX, unsigned *paddingY, unsigned *halign)
376 {
377    switch (layout) {
378    case ETNA_LAYOUT_LINEAR:
379       *paddingX = rs_align ? 16 : 4;
380       *paddingY = 1;
381       *halign = rs_align ? TEXTURE_HALIGN_SIXTEEN : TEXTURE_HALIGN_FOUR;
382       break;
383    case ETNA_LAYOUT_TILED:
384       *paddingX = rs_align ? 16 : 4;
385       *paddingY = 4;
386       *halign = rs_align ? TEXTURE_HALIGN_SIXTEEN : TEXTURE_HALIGN_FOUR;
387       break;
388    case ETNA_LAYOUT_SUPER_TILED:
389       *paddingX = 64;
390       *paddingY = 64;
391       *halign = TEXTURE_HALIGN_SUPER_TILED;
392       break;
393    case ETNA_LAYOUT_MULTI_TILED:
394       *paddingX = 16;
395       *paddingY = 4 * pixel_pipes;
396       *halign = TEXTURE_HALIGN_SPLIT_TILED;
397       break;
398    case ETNA_LAYOUT_MULTI_SUPERTILED:
399       *paddingX = 64;
400       *paddingY = 64 * pixel_pipes;
401       *halign = TEXTURE_HALIGN_SPLIT_SUPER_TILED;
402       break;
403    default:
404       DBG("Unhandled layout %i", layout);
405    }
406 }
407 
408 /* return 32-bit clear pattern for color */
409 static inline uint32_t
translate_clear_color(enum pipe_format format,const union pipe_color_union * color)410 translate_clear_color(enum pipe_format format,
411                       const union pipe_color_union *color)
412 {
413    uint32_t clear_value = 0;
414 
415    // XXX util_pack_color
416    switch (format) {
417    case PIPE_FORMAT_B8G8R8A8_UNORM:
418    case PIPE_FORMAT_B8G8R8X8_UNORM:
419       clear_value = etna_cfloat_to_uintN(color->f[2], 8) |
420                     (etna_cfloat_to_uintN(color->f[1], 8) << 8) |
421                     (etna_cfloat_to_uintN(color->f[0], 8) << 16) |
422                     (etna_cfloat_to_uintN(color->f[3], 8) << 24);
423       break;
424    case PIPE_FORMAT_B4G4R4X4_UNORM:
425    case PIPE_FORMAT_B4G4R4A4_UNORM:
426       clear_value = etna_cfloat_to_uintN(color->f[2], 4) |
427                     (etna_cfloat_to_uintN(color->f[1], 4) << 4) |
428                     (etna_cfloat_to_uintN(color->f[0], 4) << 8) |
429                     (etna_cfloat_to_uintN(color->f[3], 4) << 12);
430       clear_value |= clear_value << 16;
431       break;
432    case PIPE_FORMAT_B5G5R5X1_UNORM:
433    case PIPE_FORMAT_B5G5R5A1_UNORM:
434       clear_value = etna_cfloat_to_uintN(color->f[2], 5) |
435                     (etna_cfloat_to_uintN(color->f[1], 5) << 5) |
436                     (etna_cfloat_to_uintN(color->f[0], 5) << 10) |
437                     (etna_cfloat_to_uintN(color->f[3], 1) << 15);
438       clear_value |= clear_value << 16;
439       break;
440    case PIPE_FORMAT_B5G6R5_UNORM:
441       clear_value = etna_cfloat_to_uintN(color->f[2], 5) |
442                     (etna_cfloat_to_uintN(color->f[1], 6) << 5) |
443                     (etna_cfloat_to_uintN(color->f[0], 5) << 11);
444       clear_value |= clear_value << 16;
445       break;
446    default:
447       DBG("Unhandled pipe format for color clear: %i", format);
448    }
449 
450    return clear_value;
451 }
452 
453 static inline uint32_t
translate_clear_depth_stencil(enum pipe_format format,float depth,unsigned stencil)454 translate_clear_depth_stencil(enum pipe_format format, float depth,
455                               unsigned stencil)
456 {
457    uint32_t clear_value = 0;
458 
459    // XXX util_pack_color
460    switch (format) {
461    case PIPE_FORMAT_Z16_UNORM:
462       clear_value = etna_cfloat_to_uintN(depth, 16);
463       clear_value |= clear_value << 16;
464       break;
465    case PIPE_FORMAT_X8Z24_UNORM:
466    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
467       clear_value = (etna_cfloat_to_uintN(depth, 24) << 8) | (stencil & 0xFF);
468       break;
469    default:
470       DBG("Unhandled pipe format for depth stencil clear: %i", format);
471    }
472    return clear_value;
473 }
474 
475 /* Convert MSAA number of samples to x and y scaling factor and
476  * VIVS_GL_MULTI_SAMPLE_CONFIG value.
477  * Return true if supported and false otherwise. */
478 static inline bool
translate_samples_to_xyscale(int num_samples,int * xscale_out,int * yscale_out,uint32_t * config_out)479 translate_samples_to_xyscale(int num_samples, int *xscale_out, int *yscale_out,
480                              uint32_t *config_out)
481 {
482    int xscale, yscale;
483    uint32_t config;
484 
485    switch (num_samples) {
486    case 0:
487    case 1:
488       xscale = 1;
489       yscale = 1;
490       config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE;
491       break;
492    case 2:
493       xscale = 2;
494       yscale = 1;
495       config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X;
496       break;
497    case 4:
498       xscale = 2;
499       yscale = 2;
500       config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X;
501       break;
502    default:
503       return false;
504    }
505 
506    if (xscale_out)
507       *xscale_out = xscale;
508    if (yscale_out)
509       *yscale_out = yscale;
510    if (config_out)
511       *config_out = config;
512 
513    return true;
514 }
515 
516 #endif
517