Home | History | Annotate | Download | only in etnaviv
      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
     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
     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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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