<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/centaur/procedures/hwp/perv/cen_chiplet_init.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file cen_chiplet_init.C
/// @brief: identify good chiplets MBA01, MBA23 (tbd)
///         define multicast groups
///         setup chiplet pervasive within the chiplets
///

///
/// @author Peng Fei GOU <shgoupf@cn.ibm.com>
///

//
// *HWP HWP Owner: Peng Fei GOU <shgoupf@cn.ibm.com>
// *HWP FW Owner: Thi Tran <thi@us.ibm.com>
// *HWP Team: Perv
// *HWP Level: 2
// *HWP Consumed by: HB
//

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <cen_chiplet_init.H>
#include <cen_common_funcs.H>

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

fapi2::ReturnCode
cen_chiplet_init(const fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>& i_target)
{
    FAPI_DBG("Start");
    fapi2::buffer<uint64_t> l_tp_mcgr1_data   = 0xE0001C0000000000;
    fapi2::buffer<uint64_t> l_tp_mcgr2_data   = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_tp_mcgr3_data   = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_tp_mcgr4_data   = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr1_data = 0xE0001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr2_data = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr3_data = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr4_data = 0xEC001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr1_data  = 0xE0001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr2_data  = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr3_data  = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr4_data  = 0xEC001C0000000000;
    fapi2::buffer<uint64_t> l_write_all_func_gp3_data = 0;
    fapi2::buffer<uint64_t> l_write_all_pcb_slave_errreg_data = ~0;
    fapi2::buffer<uint64_t> l_mem_gp0_data = 0;
    fapi2::buffer<uint64_t> l_ecid_part_1 = 0;
    fapi2::buffer<uint64_t> l_nest_clk_scansel_data = 0;
    fapi2::buffer<uint64_t> l_nest_clk_scandata0_data = 0;
    uint64_t l_nest_clk_scansel_addr = get_scom_addr(SCAN_CHIPLET_NEST, CEN_GENERIC_CLK_SCANSEL);
    uint64_t l_nest_clk_scandata0_addr = get_scom_addr(SCAN_CHIPLET_NEST, CEN_GENERIC_CLK_SCANDATA0);
    fapi2::ATTR_CENTAUR_EC_FEATURE_SWITCH_REPAIR_COMMAND_VALIDATION_ENTRIES_Type
    l_repair_command_validation_entries;

    FAPI_DBG("*** Initialize good chiplets "
             "and setup multicast registers ***" );

    // Set up groups 0 and 3 multicast groups for Centaur
    // Multicast Group 0:   All functional chiplets (PRV NST MEM)
    // Multicast Group 3:   All functional chiplets, except PRV
    FAPI_DBG("Initializing multicast group0 (all) and "
             "group3 (all except PRV)");
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_1_PCB,   l_tp_mcgr1_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_1_PCB, l_nest_mcgr1_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_1_PCB,  l_mem_mcgr1_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_4_PCB, l_nest_mcgr4_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_4_PCB,  l_mem_mcgr4_data));

    FAPI_DBG("Set unused group registers to broadcast, Group 7");
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_2_PCB,   l_tp_mcgr2_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_3_PCB,   l_tp_mcgr3_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_4_PCB,   l_tp_mcgr4_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_2_PCB, l_nest_mcgr2_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_3_PCB, l_nest_mcgr3_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_2_PCB,  l_mem_mcgr2_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_3_PCB,  l_mem_mcgr3_data));

    FAPI_DBG( "Done initializing centaur multicast group0, group3" );

    //  Chiplet Init (all other pervasive endpoints within the different chiplets)
    FAPI_DBG( "Start pervasive initialization of other chiplets" );

    FAPI_DBG( "Reset GP3 for all chiplets" );
    l_write_all_func_gp3_data.setBit<1>().setBit<11>().setBit<13, 2>().setBit<18>();
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_FUNC_GP3,  l_write_all_func_gp3_data));

    FAPI_DBG( "Release endpoint reset for PCB" );
    l_write_all_func_gp3_data = 0;
    l_write_all_func_gp3_data.setBit<1>().invert();
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_FUNC_GP3_AND,  l_write_all_func_gp3_data));

    FAPI_DBG( "Partial good setting GP3(00)='1'" );
    l_write_all_func_gp3_data = 0;
    l_write_all_func_gp3_data.setBit<0>();
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_FUNC_GP3_OR,  l_write_all_func_gp3_data));

    FAPI_DBG( "DEBUG: clear force_to_known_2 (fencing for partial good) " );
    FAPI_TRY(fapi2::getScom(i_target, CEN_TCM_GP0_PCB, l_mem_gp0_data));
    l_mem_gp0_data.clearBit<16>();
    FAPI_TRY(fapi2::putScom(i_target, CEN_TCM_GP0_PCB, l_mem_gp0_data));

    FAPI_DBG( "PCB slave error reg reset" );
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_PCB_SLAVE_ERRREG, l_write_all_pcb_slave_errreg_data));

    // call cen_scan0_module( SCAN_CHIPLET_ALL, GPTR_TIME_REP )
    FAPI_TRY(cen_scan0_module(i_target, SCAN_CHIPLET_GROUP3, SCAN_ALLREGIONEXVITAL, SCAN_GPTR_TIME_REP));
    // call cen_scan0_module( SCAN_CHIPLET_ALL, ALLSCANEXPRV )
    FAPI_TRY(cen_scan0_module(i_target, SCAN_CHIPLET_GROUP3, SCAN_ALLREGIONEXVITAL, SCAN_ALLSCANEXPRV));

    //  Repair Loader (exclude TP)
    FAPI_DBG("Invoking repair loader...");

    // DD1 is not allowed for repair command validation entries.
    FAPI_TRY(FAPI_ATTR_GET(fapi2::ATTR_CENTAUR_EC_FEATURE_SWITCH_REPAIR_COMMAND_VALIDATION_ENTRIES,
                           i_target, l_repair_command_validation_entries));

    FAPI_ASSERT(l_repair_command_validation_entries,
                fapi2::CEN_CHIPLET_INIT_REPAIR_NOT_ALLOWED_IN_DD1().set_TARGET(i_target),
                "DD1 is not supported by repair command!");

    FAPI_TRY(cen_repair_loader(i_target, REPAIR_COMMAND_VALIDATION_ENTRIES_DD2, REPAIR_COMMAND_START_ADDRESS));

    // skip load if no repairs are present
    FAPI_TRY(fapi2::getScom(i_target, CEN_OTPROM0_ECID_PART1_REGISTER_RO, l_ecid_part_1));

    if (l_ecid_part_1.getBit<0>())
    {
        FAPI_DBG("SCANNING tcn_refr_time");
        // inject header and rotate ring to position where repair loader will write data from OTPROM
        // scan 0..210
        l_nest_clk_scansel_data.setBit<10>().setBit<27>();
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scansel_addr, l_nest_clk_scansel_data));
        l_nest_clk_scandata0_data = 0xA5A55A5A00000000;
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scandata0_addr, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x6E, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x65, l_nest_clk_scandata0_data));
        // data 211..3006
        FAPI_TRY(cen_repair_loader(i_target, REPAIR_COMMAND_VALIDATION_ENTRY_TCN_REFR_TIME_DD2, REPAIR_COMMAND_START_ADDRESS));
        // scan 3007..3208
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scansel_addr, l_nest_clk_scansel_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x6E, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x5C, l_nest_clk_scandata0_data));
        // data 3209..6004
        FAPI_TRY(cen_repair_loader(i_target, REPAIR_COMMAND_VALIDATION_ENTRY_TCN_REFR_TIME_DD2, REPAIR_COMMAND_START_ADDRESS));
        // scan 6005..6151
        // check header
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scansel_addr, l_nest_clk_scansel_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x6E, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x25, l_nest_clk_scandata0_data));

        FAPI_ASSERT((l_nest_clk_scandata0_data == 0xA5A55A5A00000000),
                    fapi2::CEN_CHIPLET_INIT_HEADER_MISMATCH().set_TARGET(i_target),
                    "Error rotating tcn_refr_time ring -- header mismatch!"
                   );
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}

<commit_msg>Centaur istep 11 support<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/centaur/procedures/hwp/perv/cen_chiplet_init.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2017                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file cen_chiplet_init.C
/// @brief: identify good chiplets MBA01, MBA23 (tbd)
///         define multicast groups
///         setup chiplet pervasive within the chiplets
///

///
/// @author Peng Fei GOU <shgoupf@cn.ibm.com>
///

//
// *HWP HWP Owner: Peng Fei GOU <shgoupf@cn.ibm.com>
// *HWP FW Owner: Thi Tran <thi@us.ibm.com>
// *HWP Team: Perv
// *HWP Level: 2
// *HWP Consumed by: HB
//

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <cen_chiplet_init.H>
#include <cen_common_funcs.H>

//------------------------------------------------------------------------------
// Function definitions
//------------------------------------------------------------------------------

fapi2::ReturnCode
cen_chiplet_init(const fapi2::Target<fapi2::TARGET_TYPE_MEMBUF_CHIP>& i_target)
{
    FAPI_DBG("Start");
    fapi2::buffer<uint64_t> l_tp_mcgr1_data   = 0xE0001C0000000000;
    fapi2::buffer<uint64_t> l_tp_mcgr2_data   = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_tp_mcgr3_data   = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_tp_mcgr4_data   = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr1_data = 0xE0001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr2_data = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr3_data = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_nest_mcgr4_data = 0xEC001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr1_data  = 0xE0001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr2_data  = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr3_data  = 0xFC001C0000000000;
    fapi2::buffer<uint64_t> l_mem_mcgr4_data  = 0xEC001C0000000000;
    fapi2::buffer<uint64_t> l_write_all_func_gp3_data = 0;
    fapi2::buffer<uint64_t> l_write_all_pcb_slave_errreg_data = ~0;
    fapi2::buffer<uint64_t> l_mem_gp0_data = 0;
    fapi2::buffer<uint64_t> l_ecid_part_1 = 0;
    fapi2::buffer<uint64_t> l_nest_clk_scansel_data = 0;
    fapi2::buffer<uint64_t> l_nest_clk_scandata0_data = 0;
    uint64_t l_nest_clk_scansel_addr = get_scom_addr(SCAN_CHIPLET_NEST, CEN_GENERIC_CLK_SCANSEL);
    uint64_t l_nest_clk_scandata0_addr = get_scom_addr(SCAN_CHIPLET_NEST, CEN_GENERIC_CLK_SCANDATA0);

    FAPI_DBG("*** Initialize good chiplets "
             "and setup multicast registers ***" );

    // Set up groups 0 and 3 multicast groups for Centaur
    // Multicast Group 0:   All functional chiplets (PRV NST MEM)
    // Multicast Group 3:   All functional chiplets, except PRV
    FAPI_DBG("Initializing multicast group0 (all) and "
             "group3 (all except PRV)");
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_1_PCB,   l_tp_mcgr1_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_1_PCB, l_nest_mcgr1_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_1_PCB,  l_mem_mcgr1_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_4_PCB, l_nest_mcgr4_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_4_PCB,  l_mem_mcgr4_data));

    FAPI_DBG("Set unused group registers to broadcast, Group 7");
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_2_PCB,   l_tp_mcgr2_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_3_PCB,   l_tp_mcgr3_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLPERV_MULTICAST_GROUP_4_PCB,   l_tp_mcgr4_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_2_PCB, l_nest_mcgr2_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLNEST_MULTICAST_GROUP_3_PCB, l_nest_mcgr3_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_2_PCB,  l_mem_mcgr2_data));
    FAPI_TRY(fapi2::putScom(i_target, CEN_PCBSLMEM_MULTICAST_GROUP_3_PCB,  l_mem_mcgr3_data));

    FAPI_DBG( "Done initializing centaur multicast group0, group3" );

    //  Chiplet Init (all other pervasive endpoints within the different chiplets)
    FAPI_DBG( "Start pervasive initialization of other chiplets" );

    FAPI_DBG( "Reset GP3 for all chiplets" );
    l_write_all_func_gp3_data.setBit<1>().setBit<11>().setBit<13, 2>().setBit<18>();
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_FUNC_GP3,  l_write_all_func_gp3_data));

    FAPI_DBG( "Release endpoint reset for PCB" );
    l_write_all_func_gp3_data = 0;
    l_write_all_func_gp3_data.setBit<1>().invert();
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_FUNC_GP3_AND,  l_write_all_func_gp3_data));

    FAPI_DBG( "Partial good setting GP3(00)='1'" );
    l_write_all_func_gp3_data = 0;
    l_write_all_func_gp3_data.setBit<0>();
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_FUNC_GP3_OR,  l_write_all_func_gp3_data));

    FAPI_DBG( "DEBUG: clear force_to_known_2 (fencing for partial good) " );
    FAPI_TRY(fapi2::getScom(i_target, CEN_TCM_GP0_PCB, l_mem_gp0_data));
    l_mem_gp0_data.clearBit<16>();
    FAPI_TRY(fapi2::putScom(i_target, CEN_TCM_GP0_PCB, l_mem_gp0_data));

    FAPI_DBG( "PCB slave error reg reset" );
    FAPI_TRY(fapi2::putScom(i_target, CEN_WRITE_ALL_PCB_SLAVE_ERRREG, l_write_all_pcb_slave_errreg_data));

    // call cen_scan0_module( SCAN_CHIPLET_ALL, GPTR_TIME_REP )
    FAPI_TRY(cen_scan0_module(i_target, SCAN_CHIPLET_GROUP3, SCAN_ALLREGIONEXVITAL, SCAN_GPTR_TIME_REP));
    // call cen_scan0_module( SCAN_CHIPLET_ALL, ALLSCANEXPRV )
    FAPI_TRY(cen_scan0_module(i_target, SCAN_CHIPLET_GROUP3, SCAN_ALLREGIONEXVITAL, SCAN_ALLSCANEXPRV));

    //  Repair Loader (exclude TP)
    FAPI_DBG("Invoking repair loader...");

    FAPI_TRY(cen_repair_loader(i_target, REPAIR_COMMAND_VALIDATION_ENTRIES_DD2, REPAIR_COMMAND_START_ADDRESS));

    // skip load if no repairs are present
    FAPI_TRY(fapi2::getScom(i_target, CEN_OTPROM0_ECID_PART1_REGISTER_RO, l_ecid_part_1));

    if (l_ecid_part_1.getBit<0>())
    {
        FAPI_DBG("SCANNING tcn_refr_time");
        // inject header and rotate ring to position where repair loader will write data from OTPROM
        // scan 0..210
        l_nest_clk_scansel_data.setBit<10>().setBit<27>();
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scansel_addr, l_nest_clk_scansel_data));
        l_nest_clk_scandata0_data = 0xA5A55A5A00000000;
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scandata0_addr, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x6E, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x65, l_nest_clk_scandata0_data));
        // data 211..3006
        FAPI_TRY(cen_repair_loader(i_target, REPAIR_COMMAND_VALIDATION_ENTRY_TCN_REFR_TIME_DD2, REPAIR_COMMAND_START_ADDRESS));
        // scan 3007..3208
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scansel_addr, l_nest_clk_scansel_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x6E, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x5C, l_nest_clk_scandata0_data));
        // data 3209..6004
        FAPI_TRY(cen_repair_loader(i_target, REPAIR_COMMAND_VALIDATION_ENTRY_TCN_REFR_TIME_DD2, REPAIR_COMMAND_START_ADDRESS));
        // scan 6005..6151
        // check header
        FAPI_TRY(fapi2::putScom(i_target, l_nest_clk_scansel_addr, l_nest_clk_scansel_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x6E, l_nest_clk_scandata0_data));
        FAPI_TRY(fapi2::getScom(i_target, l_nest_clk_scandata0_addr + 0x25, l_nest_clk_scandata0_data));

        FAPI_ASSERT((l_nest_clk_scandata0_data == 0xA5A55A5A00000000),
                    fapi2::CEN_CHIPLET_INIT_HEADER_MISMATCH().set_TARGET(i_target),
                    "Error rotating tcn_refr_time ring -- header mismatch!"
                   );
    }

fapi_try_exit:
    FAPI_DBG("End");
    return fapi2::current_err;
}

<|endoftext|>


<commit_before>#include "calibration_impl.h"
#include "system.h"
#include "global_include.h"
#include "px4_custom_mode.h"
#include <functional>
#include <string>
#include <sstream>

namespace dronecode_sdk {

using namespace std::placeholders;

CalibrationImpl::CalibrationImpl(System &system) : PluginImplBase(system)
{
    _parent->register_plugin(this);
}

CalibrationImpl::~CalibrationImpl()
{
    _parent->unregister_plugin(this);
}

void CalibrationImpl::init()
{
    _parent->register_mavlink_message_handler(
        MAVLINK_MSG_ID_STATUSTEXT, std::bind(&CalibrationImpl::process_statustext, this, _1), this);
}

void CalibrationImpl::deinit()
{
    _parent->unregister_all_mavlink_message_handlers(this);
}

void CalibrationImpl::enable()
{
    // The calibration check should eventually be better than this.
    // For now, we just do the same as QGC does.
    _parent->get_param_int_async(std::string("CAL_GYRO0_ID"),
                                 std::bind(&CalibrationImpl::receive_param_cal_gyro, this, _1, _2));

    _parent->get_param_int_async(
        std::string("CAL_ACC0_ID"),
        std::bind(&CalibrationImpl::receive_param_cal_accel, this, _1, _2));

    _parent->get_param_int_async(std::string("CAL_MAG0_ID"),
                                 std::bind(&CalibrationImpl::receive_param_cal_mag, this, _1, _2));
}

void CalibrationImpl::disable() {}

void CalibrationImpl::calibrate_gyro_async(const Calibration::calibration_callback_t &callback)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_parent->is_armed()) {
        report_failed("System is armed.");
        return;
    }

    if (_state != State::NONE) {
        if (callback) {
            _parent->call_user_callback(
                [callback]() { callback(Calibration::Result::BUSY, NAN, ""); });
        }
        return;
    }

    _state = State::GYRO_CALIBRATION;
    _calibration_callback = callback;

    MAVLinkCommands::CommandLong command{};
    command.command = MAV_CMD_PREFLIGHT_CALIBRATION;
    MAVLinkCommands::CommandLong::set_as_reserved(command.params, 0.0f);
    command.params.param1 = 1.0f; // Gyro
    command.target_component_id = MAV_COMP_ID_AUTOPILOT1;
    _parent->send_command_async(command,
                                std::bind(&CalibrationImpl::command_result_callback, this, _1, _2));
}

void CalibrationImpl::calibrate_accelerometer_async(
    const Calibration::calibration_callback_t &callback)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_parent->is_armed()) {
        report_failed("System is armed.");
        return;
    }

    if (_state != State::NONE) {
        if (callback) {
            _parent->call_user_callback(
                [callback]() { callback(Calibration::Result::BUSY, NAN, ""); });
        }
        return;
    }

    _state = State::ACCELEROMETER_CALIBRATION;
    _calibration_callback = callback;

    MAVLinkCommands::CommandLong command{};
    command.command = MAV_CMD_PREFLIGHT_CALIBRATION;
    MAVLinkCommands::CommandLong::set_as_reserved(command.params, 0.0f);
    command.params.param5 = 1.0f; // Accel
    command.target_component_id = MAV_COMP_ID_AUTOPILOT1;
    _parent->send_command_async(command,
                                std::bind(&CalibrationImpl::command_result_callback, this, _1, _2));
}

void CalibrationImpl::calibrate_magnetometer_async(
    const Calibration::calibration_callback_t &callback)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_parent->is_armed()) {
        report_failed("System is armed.");
        return;
    }

    if (_state != State::NONE) {
        if (callback) {
            _parent->call_user_callback(
                [callback]() { callback(Calibration::Result::BUSY, NAN, ""); });
        }
        return;
    }

    _state = State::MAGNETOMETER_CALIBRATION;
    _calibration_callback = callback;

    MAVLinkCommands::CommandLong command{};
    command.command = MAV_CMD_PREFLIGHT_CALIBRATION;
    MAVLinkCommands::CommandLong::set_as_reserved(command.params, 0.0f);
    command.params.param2 = 1.0f; // Mag
    command.target_component_id = MAV_COMP_ID_AUTOPILOT1;
    _parent->send_command_async(command,
                                std::bind(&CalibrationImpl::command_result_callback, this, _1, _2));
}

bool CalibrationImpl::is_gyro_calibration_ok() const
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    return _is_gyro_ok;
}

bool CalibrationImpl::is_accelerometer_calibration_ok() const
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    return _is_accelerometer_ok;
}

bool CalibrationImpl::is_magnetometer_calibration_ok() const
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    return _is_magnetometer_ok;
}

void CalibrationImpl::command_result_callback(MAVLinkCommands::Result command_result,
                                              float progress)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_state == State::NONE) {
        // It might be someone else like a ground station trying to do a
        // calibration. We silently ignore it.
        return;
    }

    // If we get a progress result here, it is the new interface and we can
    // use the progress info. If we get an ack, we need to translate that to
    // a first progress update, and then parse the statustexts for progress.
    switch (command_result) {
        case MAVLinkCommands::Result::SUCCESS:
            // Silently ignore.
            break;

        case MAVLinkCommands::Result::NO_SYSTEM:
            // FALLTHROUGH
        case MAVLinkCommands::Result::CONNECTION_ERROR:
            // FALLTHROUGH
        case MAVLinkCommands::Result::BUSY:
            // FALLTHROUGH
        case MAVLinkCommands::Result::COMMAND_DENIED:
            // FALLTHROUGH
        case MAVLinkCommands::Result::UNKNOWN_ERROR:
            // FALLTHROUGH
        case MAVLinkCommands::Result::TIMEOUT:
            // Report all error cases.
            if (_calibration_callback) {
                auto calibration_callback_tmp = _calibration_callback;
                _parent->call_user_callback([calibration_callback_tmp, command_result]() {
                    calibration_callback_tmp(
                        calibration_result_from_command_result(command_result), NAN, "");
                });
            }
            _calibration_callback = nullptr;
            _state = State::NONE;
            break;

        case MAVLinkCommands::Result::IN_PROGRESS:
            if (_calibration_callback) {
                auto calibration_callback_tmp = _calibration_callback;
                _parent->call_user_callback([calibration_callback_tmp, command_result, progress]() {
                    calibration_callback_tmp(
                        calibration_result_from_command_result(command_result), progress, "");
                });
            }
            break;
    };
}

Calibration::Result
CalibrationImpl::calibration_result_from_command_result(MAVLinkCommands::Result result)
{
    switch (result) {
        case MAVLinkCommands::Result::SUCCESS:
            return Calibration::Result::SUCCESS;
        case MAVLinkCommands::Result::NO_SYSTEM:
            return Calibration::Result::NO_SYSTEM;
        case MAVLinkCommands::Result::CONNECTION_ERROR:
            return Calibration::Result::CONNECTION_ERROR;
        case MAVLinkCommands::Result::BUSY:
            return Calibration::Result::BUSY;
        case MAVLinkCommands::Result::COMMAND_DENIED:
            return Calibration::Result::COMMAND_DENIED;
        case MAVLinkCommands::Result::TIMEOUT:
            return Calibration::Result::TIMEOUT;
        case MAVLinkCommands::Result::IN_PROGRESS:
            return Calibration::Result::IN_PROGRESS;
        default:
            return Calibration::Result::UNKNOWN;
    }
}

void CalibrationImpl::receive_param_cal_gyro(bool success, int value)
{
    if (!success) {
        LogErr() << "Error: Param for gyro cal failed.";
        return;
    }

    bool ok = (value != 0);
    set_gyro_calibration(ok);
}

void CalibrationImpl::receive_param_cal_accel(bool success, int value)
{
    if (!success) {
        LogErr() << "Error: Param for accel cal failed.";
        return;
    }

    bool ok = (value != 0);
    set_accelerometer_calibration(ok);
}

void CalibrationImpl::receive_param_cal_mag(bool success, int value)
{
    if (!success) {
        LogErr() << "Error: Param for mag cal failed.";
        return;
    }

    bool ok = (value != 0);
    set_magnetometer_calibration(ok);
}

void CalibrationImpl::set_gyro_calibration(bool ok)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    _is_gyro_ok = ok;
}

void CalibrationImpl::set_accelerometer_calibration(bool ok)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    _is_accelerometer_ok = ok;
}

void CalibrationImpl::set_magnetometer_calibration(bool ok)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    _is_magnetometer_ok = ok;
}

void CalibrationImpl::process_statustext(const mavlink_message_t &message)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    if (_state == State::NONE) {
        return;
    }

    mavlink_statustext_t statustext;
    mavlink_msg_statustext_decode(&message, &statustext);

    _parser.reset();
    _parser.parse(statustext.text);

    switch (_parser.get_status()) {
        case CalibrationStatustextParser::Status::NONE:
            // Ignore it.
            break;
        case CalibrationStatustextParser::Status::STARTED:
            report_started();
            break;
        case CalibrationStatustextParser::Status::DONE:
            report_done();
            break;
        case CalibrationStatustextParser::Status::FAILED:
            report_failed(_parser.get_failed_message());
            break;
        case CalibrationStatustextParser::Status::CANCELLED:
            report_cancelled();
            break;
        case CalibrationStatustextParser::Status::PROGRESS:
            report_progress(_parser.get_progress());
            break;
        case CalibrationStatustextParser::Status::INSTRUCTION:
            report_instruction(_parser.get_instruction());
            break;
    }

    switch (_parser.get_status()) {
        case CalibrationStatustextParser::Status::DONE:
            // FALLTHROUGH
        case CalibrationStatustextParser::Status::FAILED:
            // FALLTHROUGH
        case CalibrationStatustextParser::Status::CANCELLED:
            _calibration_callback = nullptr;
            _state == State::NONE;
            break;
        default:
            break;
    }
}

void CalibrationImpl::report_started()
{
    report_progress(0.0f);
}

void CalibrationImpl::report_done()
{
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp]() {
            calibration_callback_tmp(Calibration::Result::SUCCESS, NAN, "");
        });
    }
}

void CalibrationImpl::report_failed(const std::string &failed)
{
    LogErr() << "Calibration failed: " << failed;
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp]() {
            calibration_callback_tmp(Calibration::Result::FAILED, NAN, "");
        });
    }
}

void CalibrationImpl::report_cancelled()
{
    LogWarn() << "Calibration was cancelled";
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp]() {
            calibration_callback_tmp(Calibration::Result::CANCELLED, NAN, "");
        });
    }
}

void CalibrationImpl::report_progress(float progress)
{
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp, progress]() {
            calibration_callback_tmp(Calibration::Result::IN_PROGRESS, progress, "");
        });
    }
}

void CalibrationImpl::report_instruction(const std::string &instruction)
{
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp, instruction]() {
            calibration_callback_tmp(Calibration::Result::INSTRUCTION, NAN, instruction);
        });
    }
}

} // namespace dronecode_sdk
<commit_msg>calibration: fix warning statement had no effect<commit_after>#include "calibration_impl.h"
#include "system.h"
#include "global_include.h"
#include "px4_custom_mode.h"
#include <functional>
#include <string>
#include <sstream>

namespace dronecode_sdk {

using namespace std::placeholders;

CalibrationImpl::CalibrationImpl(System &system) : PluginImplBase(system)
{
    _parent->register_plugin(this);
}

CalibrationImpl::~CalibrationImpl()
{
    _parent->unregister_plugin(this);
}

void CalibrationImpl::init()
{
    _parent->register_mavlink_message_handler(
        MAVLINK_MSG_ID_STATUSTEXT, std::bind(&CalibrationImpl::process_statustext, this, _1), this);
}

void CalibrationImpl::deinit()
{
    _parent->unregister_all_mavlink_message_handlers(this);
}

void CalibrationImpl::enable()
{
    // The calibration check should eventually be better than this.
    // For now, we just do the same as QGC does.
    _parent->get_param_int_async(std::string("CAL_GYRO0_ID"),
                                 std::bind(&CalibrationImpl::receive_param_cal_gyro, this, _1, _2));

    _parent->get_param_int_async(
        std::string("CAL_ACC0_ID"),
        std::bind(&CalibrationImpl::receive_param_cal_accel, this, _1, _2));

    _parent->get_param_int_async(std::string("CAL_MAG0_ID"),
                                 std::bind(&CalibrationImpl::receive_param_cal_mag, this, _1, _2));
}

void CalibrationImpl::disable() {}

void CalibrationImpl::calibrate_gyro_async(const Calibration::calibration_callback_t &callback)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_parent->is_armed()) {
        report_failed("System is armed.");
        return;
    }

    if (_state != State::NONE) {
        if (callback) {
            _parent->call_user_callback(
                [callback]() { callback(Calibration::Result::BUSY, NAN, ""); });
        }
        return;
    }

    _state = State::GYRO_CALIBRATION;
    _calibration_callback = callback;

    MAVLinkCommands::CommandLong command{};
    command.command = MAV_CMD_PREFLIGHT_CALIBRATION;
    MAVLinkCommands::CommandLong::set_as_reserved(command.params, 0.0f);
    command.params.param1 = 1.0f; // Gyro
    command.target_component_id = MAV_COMP_ID_AUTOPILOT1;
    _parent->send_command_async(command,
                                std::bind(&CalibrationImpl::command_result_callback, this, _1, _2));
}

void CalibrationImpl::calibrate_accelerometer_async(
    const Calibration::calibration_callback_t &callback)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_parent->is_armed()) {
        report_failed("System is armed.");
        return;
    }

    if (_state != State::NONE) {
        if (callback) {
            _parent->call_user_callback(
                [callback]() { callback(Calibration::Result::BUSY, NAN, ""); });
        }
        return;
    }

    _state = State::ACCELEROMETER_CALIBRATION;
    _calibration_callback = callback;

    MAVLinkCommands::CommandLong command{};
    command.command = MAV_CMD_PREFLIGHT_CALIBRATION;
    MAVLinkCommands::CommandLong::set_as_reserved(command.params, 0.0f);
    command.params.param5 = 1.0f; // Accel
    command.target_component_id = MAV_COMP_ID_AUTOPILOT1;
    _parent->send_command_async(command,
                                std::bind(&CalibrationImpl::command_result_callback, this, _1, _2));
}

void CalibrationImpl::calibrate_magnetometer_async(
    const Calibration::calibration_callback_t &callback)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_parent->is_armed()) {
        report_failed("System is armed.");
        return;
    }

    if (_state != State::NONE) {
        if (callback) {
            _parent->call_user_callback(
                [callback]() { callback(Calibration::Result::BUSY, NAN, ""); });
        }
        return;
    }

    _state = State::MAGNETOMETER_CALIBRATION;
    _calibration_callback = callback;

    MAVLinkCommands::CommandLong command{};
    command.command = MAV_CMD_PREFLIGHT_CALIBRATION;
    MAVLinkCommands::CommandLong::set_as_reserved(command.params, 0.0f);
    command.params.param2 = 1.0f; // Mag
    command.target_component_id = MAV_COMP_ID_AUTOPILOT1;
    _parent->send_command_async(command,
                                std::bind(&CalibrationImpl::command_result_callback, this, _1, _2));
}

bool CalibrationImpl::is_gyro_calibration_ok() const
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    return _is_gyro_ok;
}

bool CalibrationImpl::is_accelerometer_calibration_ok() const
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    return _is_accelerometer_ok;
}

bool CalibrationImpl::is_magnetometer_calibration_ok() const
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    return _is_magnetometer_ok;
}

void CalibrationImpl::command_result_callback(MAVLinkCommands::Result command_result,
                                              float progress)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    if (_state == State::NONE) {
        // It might be someone else like a ground station trying to do a
        // calibration. We silently ignore it.
        return;
    }

    // If we get a progress result here, it is the new interface and we can
    // use the progress info. If we get an ack, we need to translate that to
    // a first progress update, and then parse the statustexts for progress.
    switch (command_result) {
        case MAVLinkCommands::Result::SUCCESS:
            // Silently ignore.
            break;

        case MAVLinkCommands::Result::NO_SYSTEM:
            // FALLTHROUGH
        case MAVLinkCommands::Result::CONNECTION_ERROR:
            // FALLTHROUGH
        case MAVLinkCommands::Result::BUSY:
            // FALLTHROUGH
        case MAVLinkCommands::Result::COMMAND_DENIED:
            // FALLTHROUGH
        case MAVLinkCommands::Result::UNKNOWN_ERROR:
            // FALLTHROUGH
        case MAVLinkCommands::Result::TIMEOUT:
            // Report all error cases.
            if (_calibration_callback) {
                auto calibration_callback_tmp = _calibration_callback;
                _parent->call_user_callback([calibration_callback_tmp, command_result]() {
                    calibration_callback_tmp(
                        calibration_result_from_command_result(command_result), NAN, "");
                });
            }
            _calibration_callback = nullptr;
            _state = State::NONE;
            break;

        case MAVLinkCommands::Result::IN_PROGRESS:
            if (_calibration_callback) {
                auto calibration_callback_tmp = _calibration_callback;
                _parent->call_user_callback([calibration_callback_tmp, command_result, progress]() {
                    calibration_callback_tmp(
                        calibration_result_from_command_result(command_result), progress, "");
                });
            }
            break;
    };
}

Calibration::Result
CalibrationImpl::calibration_result_from_command_result(MAVLinkCommands::Result result)
{
    switch (result) {
        case MAVLinkCommands::Result::SUCCESS:
            return Calibration::Result::SUCCESS;
        case MAVLinkCommands::Result::NO_SYSTEM:
            return Calibration::Result::NO_SYSTEM;
        case MAVLinkCommands::Result::CONNECTION_ERROR:
            return Calibration::Result::CONNECTION_ERROR;
        case MAVLinkCommands::Result::BUSY:
            return Calibration::Result::BUSY;
        case MAVLinkCommands::Result::COMMAND_DENIED:
            return Calibration::Result::COMMAND_DENIED;
        case MAVLinkCommands::Result::TIMEOUT:
            return Calibration::Result::TIMEOUT;
        case MAVLinkCommands::Result::IN_PROGRESS:
            return Calibration::Result::IN_PROGRESS;
        default:
            return Calibration::Result::UNKNOWN;
    }
}

void CalibrationImpl::receive_param_cal_gyro(bool success, int value)
{
    if (!success) {
        LogErr() << "Error: Param for gyro cal failed.";
        return;
    }

    bool ok = (value != 0);
    set_gyro_calibration(ok);
}

void CalibrationImpl::receive_param_cal_accel(bool success, int value)
{
    if (!success) {
        LogErr() << "Error: Param for accel cal failed.";
        return;
    }

    bool ok = (value != 0);
    set_accelerometer_calibration(ok);
}

void CalibrationImpl::receive_param_cal_mag(bool success, int value)
{
    if (!success) {
        LogErr() << "Error: Param for mag cal failed.";
        return;
    }

    bool ok = (value != 0);
    set_magnetometer_calibration(ok);
}

void CalibrationImpl::set_gyro_calibration(bool ok)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    _is_gyro_ok = ok;
}

void CalibrationImpl::set_accelerometer_calibration(bool ok)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    _is_accelerometer_ok = ok;
}

void CalibrationImpl::set_magnetometer_calibration(bool ok)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);

    _is_magnetometer_ok = ok;
}

void CalibrationImpl::process_statustext(const mavlink_message_t &message)
{
    std::lock_guard<std::mutex> lock(_calibration_mutex);
    if (_state == State::NONE) {
        return;
    }

    mavlink_statustext_t statustext;
    mavlink_msg_statustext_decode(&message, &statustext);

    _parser.reset();
    _parser.parse(statustext.text);

    switch (_parser.get_status()) {
        case CalibrationStatustextParser::Status::NONE:
            // Ignore it.
            break;
        case CalibrationStatustextParser::Status::STARTED:
            report_started();
            break;
        case CalibrationStatustextParser::Status::DONE:
            report_done();
            break;
        case CalibrationStatustextParser::Status::FAILED:
            report_failed(_parser.get_failed_message());
            break;
        case CalibrationStatustextParser::Status::CANCELLED:
            report_cancelled();
            break;
        case CalibrationStatustextParser::Status::PROGRESS:
            report_progress(_parser.get_progress());
            break;
        case CalibrationStatustextParser::Status::INSTRUCTION:
            report_instruction(_parser.get_instruction());
            break;
    }

    switch (_parser.get_status()) {
        case CalibrationStatustextParser::Status::DONE:
            // FALLTHROUGH
        case CalibrationStatustextParser::Status::FAILED:
            // FALLTHROUGH
        case CalibrationStatustextParser::Status::CANCELLED:
            _calibration_callback = nullptr;
            _state = State::NONE;
            break;
        default:
            break;
    }
}

void CalibrationImpl::report_started()
{
    report_progress(0.0f);
}

void CalibrationImpl::report_done()
{
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp]() {
            calibration_callback_tmp(Calibration::Result::SUCCESS, NAN, "");
        });
    }
}

void CalibrationImpl::report_failed(const std::string &failed)
{
    LogErr() << "Calibration failed: " << failed;
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp]() {
            calibration_callback_tmp(Calibration::Result::FAILED, NAN, "");
        });
    }
}

void CalibrationImpl::report_cancelled()
{
    LogWarn() << "Calibration was cancelled";
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp]() {
            calibration_callback_tmp(Calibration::Result::CANCELLED, NAN, "");
        });
    }
}

void CalibrationImpl::report_progress(float progress)
{
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp, progress]() {
            calibration_callback_tmp(Calibration::Result::IN_PROGRESS, progress, "");
        });
    }
}

void CalibrationImpl::report_instruction(const std::string &instruction)
{
    if (_calibration_callback) {
        auto calibration_callback_tmp = _calibration_callback;
        _parent->call_user_callback([calibration_callback_tmp, instruction]() {
            calibration_callback_tmp(Calibration::Result::INSTRUCTION, NAN, instruction);
        });
    }
}

} // namespace dronecode_sdk
<|endoftext|>


<commit_before>/**
 * @file max_variance_new_cluster_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of MaxVarianceNewCluster class.
 */
#ifndef __MLPACK_METHODS_KMEANS_MAX_VARIANCE_NEW_CLUSTER_IMPL_HPP
#define __MLPACK_METHODS_KMEANS_MAX_VARIANCE_NEW_CLUSTER_IMPL_HPP

// Just in case it has not been included.
#include "max_variance_new_cluster.hpp"

namespace mlpack {
namespace kmeans {

/**
 * Take action about an empty cluster.
 */
template<typename MetricType, typename MatType>
size_t MaxVarianceNewCluster::EmptyCluster(const MatType& data,
                                           const size_t emptyCluster,
                                           const arma::mat& oldCentroids,
                                           arma::mat& newCentroids,
                                           arma::Col<size_t>& clusterCounts,
                                           MetricType& metric,
                                           const size_t iteration)
{
  // If necessary, calculate the variances and assignments.
  if (iteration != this->iteration || assignments.n_elem != data.n_cols)
    Precalculate(data, oldCentroids, clusterCounts, metric);
  this->iteration = iteration;

  // Now find the cluster with maximum variance.
  arma::uword maxVarCluster;
  variances.max(maxVarCluster);

  // Now, inside this cluster, find the point which is furthest away.
  size_t furthestPoint = data.n_cols;
  double maxDistance = -DBL_MAX;
  for (size_t i = 0; i < data.n_cols; ++i)
  {
    if (assignments[i] == maxVarCluster)
    {
      const double distance = std::pow(metric.Evaluate(data.col(i),
          newCentroids.col(maxVarCluster)), 2.0);

      if (distance > maxDistance)
      {
        maxDistance = distance;
        furthestPoint = i;
      }
    }
  }

  // Take that point and add it to the empty cluster.
  newCentroids.col(maxVarCluster) *= (double(clusterCounts[maxVarCluster]) /
      double(clusterCounts[maxVarCluster] - 1));
  newCentroids.col(maxVarCluster) -= (1.0 / (clusterCounts[maxVarCluster] - 1.0)) *
      arma::vec(data.col(furthestPoint));
  clusterCounts[maxVarCluster]--;
  clusterCounts[emptyCluster]++;
  newCentroids.col(emptyCluster) = arma::vec(data.col(furthestPoint));
  assignments[furthestPoint] = emptyCluster;

  // Modify the variances, as necessary.
  variances[emptyCluster] = 0;
  // One has already been subtracted from clusterCounts[maxVarCluster].
  variances[maxVarCluster] = (1.0 / (clusterCounts[maxVarCluster])) *
      ((clusterCounts[maxVarCluster] + 1) * variances[maxVarCluster] - maxDistance);

  // Output some debugging information.
  Log::Debug << "Point " << furthestPoint << " assigned to empty cluster " <<
      emptyCluster << ".\n";

  return 1; // We only changed one point.
}

//! Serialize the object.
template<typename Archive>
void MaxVarianceNewCluster::Serialize(Archive& /* ar */,
                                      const unsigned int /* version */)
{
  // Serialization is useless here, because the only thing we store is
  // precalculated quantities, and if we're serializing, our precalculations are
  // likely to be useless when we deserialize (because the user will be running
  // a different clustering, probably).  So there is no need to store anything,
  // and if we are loading, we just reset the assignments array so
  // precalculation will happen next time EmptyCluster() is called.
  if (Archive::is_loading::value)
    assignments.set_size(0);
}

template<typename MetricType, typename MatType>
void MaxVarianceNewCluster::Precalculate(const MatType& data,
                                         const arma::mat& oldCentroids,
                                         arma::Col<size_t>& clusterCounts,
                                         MetricType& metric)
{
  // We have to calculate the variances of each cluster and the assignments of
  // each point.  This is most easily done by iterating through the entire
  // dataset.
  variances.zeros(oldCentroids.n_cols);
  assignments.set_size(data.n_cols);

  // Add the variance of each point's distance away from the cluster.  I think
  // this is the sensible thing to do.
  for (size_t i = 0; i < data.n_cols; ++i)
  {
    // Find the closest centroid to this point.
    double minDistance = std::numeric_limits<double>::infinity();
    size_t closestCluster = oldCentroids.n_cols; // Invalid value.

    for (size_t j = 0; j < oldCentroids.n_cols; j++)
    {
      const double distance = metric.Evaluate(data.col(i), oldCentroids.col(j));

      if (distance < minDistance)
      {
        minDistance = distance;
        closestCluster = j;
      }
    }

    assignments[i] = closestCluster;
    variances[closestCluster] += std::pow(metric.Evaluate(data.col(i),
        oldCentroids.col(closestCluster)), 2.0);
  }

  // Divide by the number of points in the cluster to produce the variance,
  // unless the cluster is empty or contains only one point, in which case we
  // set the variance to 0.
  for (size_t i = 0; i < clusterCounts.n_elem; ++i)
    if (clusterCounts[i] <= 1)
      variances[i] = 0;
    else
      variances[i] /= clusterCounts[i];
}

}; // namespace kmeans
}; // namespace mlpack

#endif
<commit_msg>kmeans: small fix with inf variance<commit_after>/**
 * @file max_variance_new_cluster_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of MaxVarianceNewCluster class.
 */
#ifndef __MLPACK_METHODS_KMEANS_MAX_VARIANCE_NEW_CLUSTER_IMPL_HPP
#define __MLPACK_METHODS_KMEANS_MAX_VARIANCE_NEW_CLUSTER_IMPL_HPP

// Just in case it has not been included.
#include "max_variance_new_cluster.hpp"

namespace mlpack {
namespace kmeans {

/**
 * Take action about an empty cluster.
 */
template<typename MetricType, typename MatType>
size_t MaxVarianceNewCluster::EmptyCluster(const MatType& data,
                                           const size_t emptyCluster,
                                           const arma::mat& oldCentroids,
                                           arma::mat& newCentroids,
                                           arma::Col<size_t>& clusterCounts,
                                           MetricType& metric,
                                           const size_t iteration)
{
  // If necessary, calculate the variances and assignments.
  if (iteration != this->iteration || assignments.n_elem != data.n_cols)
    Precalculate(data, oldCentroids, clusterCounts, metric);
  this->iteration = iteration;

  // Now find the cluster with maximum variance.
  arma::uword maxVarCluster;
  variances.max(maxVarCluster);

  // Now, inside this cluster, find the point which is furthest away.
  size_t furthestPoint = data.n_cols;
  double maxDistance = -DBL_MAX;
  for (size_t i = 0; i < data.n_cols; ++i)
  {
    if (assignments[i] == maxVarCluster)
    {
      const double distance = std::pow(metric.Evaluate(data.col(i),
          newCentroids.col(maxVarCluster)), 2.0);

      if (distance > maxDistance)
      {
        maxDistance = distance;
        furthestPoint = i;
      }
    }
  }

  // Take that point and add it to the empty cluster.
  newCentroids.col(maxVarCluster) *= (double(clusterCounts[maxVarCluster]) /
      double(clusterCounts[maxVarCluster] - 1));
  newCentroids.col(maxVarCluster) -= (1.0 / (clusterCounts[maxVarCluster] - 1.0)) *
      arma::vec(data.col(furthestPoint));
  clusterCounts[maxVarCluster]--;
  clusterCounts[emptyCluster]++;
  newCentroids.col(emptyCluster) = arma::vec(data.col(furthestPoint));
  assignments[furthestPoint] = emptyCluster;

  // Modify the variances, as necessary.
  variances[emptyCluster] = 0;
  // One has already been subtracted from clusterCounts[maxVarCluster].
  if (clusterCounts[maxVarCluster] <= 1)
    variances[maxVarCluster] = 0;
  else
    variances[maxVarCluster] = (1.0 / clusterCounts[maxVarCluster]) *
      ((clusterCounts[maxVarCluster] + 1) * variances[maxVarCluster] - maxDistance);

  // Output some debugging information.
  Log::Debug << "Point " << furthestPoint << " assigned to empty cluster " <<
      emptyCluster << ".\n";

  return 1; // We only changed one point.
}

//! Serialize the object.
template<typename Archive>
void MaxVarianceNewCluster::Serialize(Archive& /* ar */,
                                      const unsigned int /* version */)
{
  // Serialization is useless here, because the only thing we store is
  // precalculated quantities, and if we're serializing, our precalculations are
  // likely to be useless when we deserialize (because the user will be running
  // a different clustering, probably).  So there is no need to store anything,
  // and if we are loading, we just reset the assignments array so
  // precalculation will happen next time EmptyCluster() is called.
  if (Archive::is_loading::value)
    assignments.set_size(0);
}

template<typename MetricType, typename MatType>
void MaxVarianceNewCluster::Precalculate(const MatType& data,
                                         const arma::mat& oldCentroids,
                                         arma::Col<size_t>& clusterCounts,
                                         MetricType& metric)
{
  // We have to calculate the variances of each cluster and the assignments of
  // each point.  This is most easily done by iterating through the entire
  // dataset.
  variances.zeros(oldCentroids.n_cols);
  assignments.set_size(data.n_cols);

  // Add the variance of each point's distance away from the cluster.  I think
  // this is the sensible thing to do.
  for (size_t i = 0; i < data.n_cols; ++i)
  {
    // Find the closest centroid to this point.
    double minDistance = std::numeric_limits<double>::infinity();
    size_t closestCluster = oldCentroids.n_cols; // Invalid value.

    for (size_t j = 0; j < oldCentroids.n_cols; j++)
    {
      const double distance = metric.Evaluate(data.col(i), oldCentroids.col(j));

      if (distance < minDistance)
      {
        minDistance = distance;
        closestCluster = j;
      }
    }

    assignments[i] = closestCluster;
    variances[closestCluster] += std::pow(metric.Evaluate(data.col(i),
        oldCentroids.col(closestCluster)), 2.0);
  }

  // Divide by the number of points in the cluster to produce the variance,
  // unless the cluster is empty or contains only one point, in which case we
  // set the variance to 0.
  for (size_t i = 0; i < clusterCounts.n_elem; ++i)
    if (clusterCounts[i] <= 1)
      variances[i] = 0;
    else
      variances[i] /= clusterCounts[i];
}

}; // namespace kmeans
}; // namespace mlpack

#endif
<|endoftext|>


<commit_before>/* libs/graphics/ports/SkFontHost_fontconfig.cpp
**
** Copyright 2008, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

// -----------------------------------------------------------------------------
// This file provides implementations of the font resolution members of
// SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
// on Linux systems and handles configuration, parsing and caching issues
// involved with enumerating and matching fonts.
//
// [1] http://fontconfig.org
// -----------------------------------------------------------------------------

#include <map>
#include <string>

#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include "SkFontHost.h"
#include "SkStream.h"
#include "SkFontHost_fontconfig_control.h"
#include "SkFontHost_fontconfig_impl.h"
#include "SkFontHost_fontconfig_direct.h"

static FontConfigInterface* global_fc_impl = NULL;

void SkiaFontConfigUseDirectImplementation() {
    if (global_fc_impl)
      delete global_fc_impl;
    global_fc_impl = new FontConfigDirect;
}

void SkiaFontConfigSetImplementation(FontConfigInterface* font_config) {
    if (global_fc_impl)
      delete global_fc_impl;
    global_fc_impl = font_config;
}

static FontConfigInterface* GetFcImpl() {
  if (!global_fc_impl)
    global_fc_impl = new FontConfigDirect;
  return global_fc_impl;
}

static SkMutex global_fc_map_lock;
static std::map<uint32_t, SkTypeface *> global_fc_typefaces;

static SkMutex global_remote_font_map_lock;
static std::map<uint32_t, std::pair<uint8_t*, size_t> > global_remote_fonts;
static unsigned global_next_remote_font_id;

// This is the maximum size of the font cache.
static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024;  // 2MB

// UniqueIds are encoded as (filefaceid << 8) | style
// For system fonts, filefaceid = (fileid << 4) | face_index.
// For remote fonts, filefaceid = fileid.

static unsigned UniqueIdToFileFaceId(unsigned uniqueid)
{
    return uniqueid >> 8;
}

static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
{
    return static_cast<SkTypeface::Style>(uniqueid & 0xff);
}

static unsigned FileFaceIdAndStyleToUniqueId(unsigned filefaceid,
                                             SkTypeface::Style style)
{
    SkASSERT((style & 0xff) == style);
    return (filefaceid << 8) | static_cast<int>(style);
}

static const unsigned kRemoteFontMask = 0x00800000u;

static bool IsRemoteFont(unsigned filefaceid)
{
    return filefaceid & kRemoteFontMask;
}

class FontConfigTypeface : public SkTypeface {
public:
    FontConfigTypeface(Style style, uint32_t id)
        : SkTypeface(style, id)
    { }

    ~FontConfigTypeface()
    {
        const uint32_t id = uniqueID();
        if (IsRemoteFont(UniqueIdToFileFaceId(id))) {
            SkAutoMutexAcquire ac(global_remote_font_map_lock);
            std::map<uint32_t, std::pair<uint8_t*, size_t> >::iterator iter
                = global_remote_fonts.find(id);
            if (iter != global_remote_fonts.end()) {
                sk_free(iter->second.first);  // remove the font on memory.
                global_remote_fonts.erase(iter);
            }
        }
    }
};

// static
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
                                       const char familyName[],
                                       const void* data, size_t bytelength,
                                       SkTypeface::Style style)
{
    std::string resolved_family_name;

    if (familyFace) {
        // Given the fileid we can ask fontconfig for the familyname of the
        // font.
        const unsigned filefaceid = UniqueIdToFileFaceId(familyFace->uniqueID());
        if (!GetFcImpl()->Match(&resolved_family_name, NULL,
          true /* filefaceid valid */, filefaceid, "",
          NULL, 0, NULL, NULL)) {
            return NULL;
        }
    } else if (familyName) {
        resolved_family_name = familyName;
    }

    bool bold = style & SkTypeface::kBold;
    bool italic = style & SkTypeface::kItalic;
    unsigned filefaceid;
    if (!GetFcImpl()->Match(NULL, &filefaceid,
                            false, -1, /* no filefaceid */
                            resolved_family_name, data, bytelength,
                            &bold, &italic)) {
        return NULL;
    }
    const SkTypeface::Style resulting_style = static_cast<SkTypeface::Style>(
        (bold ? SkTypeface::kBold : 0) |
        (italic ? SkTypeface::kItalic : 0));

    const unsigned id = FileFaceIdAndStyleToUniqueId(filefaceid,
                                                     resulting_style);
    SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (resulting_style, id));

    {
        SkAutoMutexAcquire ac(global_fc_map_lock);
        global_fc_typefaces[id] = typeface;
    }

    return typeface;
}

// static
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
{
    if (!stream)
        return NULL;

    const size_t length = stream->read(0, 0);
    if (!length)
        return NULL;
    if (length >= 1024 * 1024 * 1024)
        return NULL;  // don't accept too large fonts (>= 1GB) for safety.

    uint8_t* font = (uint8_t*)sk_malloc_throw(length);
    if (stream->read(font, length) != length) {
        sk_free(font);
        return NULL;
    }

    SkTypeface::Style style = static_cast<SkTypeface::Style>(0);
    unsigned id = 0;
    {
        SkAutoMutexAcquire ac(global_remote_font_map_lock);
        id = FileFaceIdAndStyleToUniqueId(
            global_next_remote_font_id | kRemoteFontMask, style);

        if (++global_next_remote_font_id >= kRemoteFontMask)
            global_next_remote_font_id = 0;

        if (!global_remote_fonts.insert(
                std::make_pair(id, std::make_pair(font, length))).second) {
            sk_free(font);
            return NULL;
        }
    }

    SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
    return typeface;
}

// static
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
{
    SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
    return NULL;
}

// static
bool SkFontHost::ValidFontID(SkFontID uniqueID) {
    if (IsRemoteFont(UniqueIdToFileFaceId(uniqueID))) {
        // remote font
        SkAutoMutexAcquire ac(global_remote_font_map_lock);
        return global_remote_fonts.find(uniqueID) != global_remote_fonts.end();
    } else {
        // local font
        SkAutoMutexAcquire ac(global_fc_map_lock);
        return global_fc_typefaces.find(uniqueID) != global_fc_typefaces.end();
    }
}

void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
    SkASSERT(!"SkFontHost::Serialize unimplemented");
}

SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    SkASSERT(!"SkFontHost::Deserialize unimplemented");
    return NULL;
}

// static
uint32_t SkFontHost::NextLogicalFont(SkFontID curr, SkFontID orig) {
    // We don't handle font fallback, WebKit does.
    return 0;
}

///////////////////////////////////////////////////////////////////////////////

class SkFileDescriptorStream : public SkStream {
  public:
    SkFileDescriptorStream(int fd) {
        memory_ = NULL;
        offset_ = 0;

        // this ensures that if we fail in the constructor, we will safely
        // ignore all subsequent calls to read() because we will always trim
        // the requested size down to 0
        length_ = 0;

        struct stat st;
        if (fstat(fd, &st))
            return;

        void* memory = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
        close(fd);
        if (memory == MAP_FAILED)
            return;

        memory_ = reinterpret_cast<uint8_t*>(memory);
        length_ = st.st_size;
    }

    ~SkFileDescriptorStream() {
        munmap(const_cast<uint8_t*>(memory_), length_);
    }

    virtual bool rewind() {
        offset_ = 0;
        return true;
    }

    // SkStream implementation.
    virtual size_t read(void* buffer, size_t size) {
        if (!buffer && !size) {
            // This is request for the length of the stream.
            return length_;
        }

        size_t remaining = length_ - offset_;
        if (size > remaining)
            size = remaining;
        if (buffer)
            memcpy(buffer, memory_ + offset_, size);

        offset_ += size;
        return size;
    }

    virtual const void* getMemoryBase() {
        return memory_;
    }

  private:
    const uint8_t* memory_;
    size_t offset_, length_;
};

///////////////////////////////////////////////////////////////////////////////

// static
SkStream* SkFontHost::OpenStream(uint32_t id)
{
    const unsigned filefaceid = UniqueIdToFileFaceId(id);

    if (IsRemoteFont(filefaceid)) {
      // remote font
      SkAutoMutexAcquire ac(global_remote_font_map_lock);
      std::map<uint32_t, std::pair<uint8_t*, size_t> >::const_iterator iter
          = global_remote_fonts.find(id);
      if (iter == global_remote_fonts.end())
          return NULL;
      return SkNEW_ARGS(
          SkMemoryStream, (iter->second.first, iter->second.second));
    }

    // system font
    const int fd = GetFcImpl()->Open(filefaceid);
    if (fd < 0)
        return NULL;

    return SkNEW_ARGS(SkFileDescriptorStream, (fd));
}

// static
size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
                               int32_t* index) {
    const unsigned filefaceid = UniqueIdToFileFaceId(fontID);

    if (IsRemoteFont(filefaceid))
        return 0;

    if (index) {
        *index = filefaceid & 0xfu;
        // 1 is a bogus return value.
        // We had better change the signature of this function in Skia
        // to return bool to indicate success/failure and have another
        // out param for fileName length.
        if (!path)
          return 1;
    }

    if (path)
        SkASSERT(!"SkFontHost::GetFileName does not support the font path "
                  "retrieval.");

    return 0;
}
<commit_msg>Remove ValidFontID.<commit_after>/* libs/graphics/ports/SkFontHost_fontconfig.cpp
**
** Copyright 2008, Google Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

// -----------------------------------------------------------------------------
// This file provides implementations of the font resolution members of
// SkFontHost by using the fontconfig[1] library. Fontconfig is usually found
// on Linux systems and handles configuration, parsing and caching issues
// involved with enumerating and matching fonts.
//
// [1] http://fontconfig.org
// -----------------------------------------------------------------------------

#include <map>
#include <string>

#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include "SkFontHost.h"
#include "SkStream.h"
#include "SkFontHost_fontconfig_control.h"
#include "SkFontHost_fontconfig_impl.h"
#include "SkFontHost_fontconfig_direct.h"

static FontConfigInterface* global_fc_impl = NULL;

void SkiaFontConfigUseDirectImplementation() {
    if (global_fc_impl)
      delete global_fc_impl;
    global_fc_impl = new FontConfigDirect;
}

void SkiaFontConfigSetImplementation(FontConfigInterface* font_config) {
    if (global_fc_impl)
      delete global_fc_impl;
    global_fc_impl = font_config;
}

static FontConfigInterface* GetFcImpl() {
  if (!global_fc_impl)
    global_fc_impl = new FontConfigDirect;
  return global_fc_impl;
}

static SkMutex global_fc_map_lock;
static std::map<uint32_t, SkTypeface *> global_fc_typefaces;

static SkMutex global_remote_font_map_lock;
static std::map<uint32_t, std::pair<uint8_t*, size_t> > global_remote_fonts;
static unsigned global_next_remote_font_id;

// This is the maximum size of the font cache.
static const unsigned kFontCacheMemoryBudget = 2 * 1024 * 1024;  // 2MB

// UniqueIds are encoded as (filefaceid << 8) | style
// For system fonts, filefaceid = (fileid << 4) | face_index.
// For remote fonts, filefaceid = fileid.

static unsigned UniqueIdToFileFaceId(unsigned uniqueid)
{
    return uniqueid >> 8;
}

static SkTypeface::Style UniqueIdToStyle(unsigned uniqueid)
{
    return static_cast<SkTypeface::Style>(uniqueid & 0xff);
}

static unsigned FileFaceIdAndStyleToUniqueId(unsigned filefaceid,
                                             SkTypeface::Style style)
{
    SkASSERT((style & 0xff) == style);
    return (filefaceid << 8) | static_cast<int>(style);
}

static const unsigned kRemoteFontMask = 0x00800000u;

static bool IsRemoteFont(unsigned filefaceid)
{
    return filefaceid & kRemoteFontMask;
}

class FontConfigTypeface : public SkTypeface {
public:
    FontConfigTypeface(Style style, uint32_t id)
        : SkTypeface(style, id)
    { }

    ~FontConfigTypeface()
    {
        const uint32_t id = uniqueID();
        if (IsRemoteFont(UniqueIdToFileFaceId(id))) {
            SkAutoMutexAcquire ac(global_remote_font_map_lock);
            std::map<uint32_t, std::pair<uint8_t*, size_t> >::iterator iter
                = global_remote_fonts.find(id);
            if (iter != global_remote_fonts.end()) {
                sk_free(iter->second.first);  // remove the font on memory.
                global_remote_fonts.erase(iter);
            }
        }
    }
};

// static
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
                                       const char familyName[],
                                       const void* data, size_t bytelength,
                                       SkTypeface::Style style)
{
    std::string resolved_family_name;

    if (familyFace) {
        // Given the fileid we can ask fontconfig for the familyname of the
        // font.
        const unsigned filefaceid = UniqueIdToFileFaceId(familyFace->uniqueID());
        if (!GetFcImpl()->Match(&resolved_family_name, NULL,
          true /* filefaceid valid */, filefaceid, "",
          NULL, 0, NULL, NULL)) {
            return NULL;
        }
    } else if (familyName) {
        resolved_family_name = familyName;
    }

    bool bold = style & SkTypeface::kBold;
    bool italic = style & SkTypeface::kItalic;
    unsigned filefaceid;
    if (!GetFcImpl()->Match(NULL, &filefaceid,
                            false, -1, /* no filefaceid */
                            resolved_family_name, data, bytelength,
                            &bold, &italic)) {
        return NULL;
    }
    const SkTypeface::Style resulting_style = static_cast<SkTypeface::Style>(
        (bold ? SkTypeface::kBold : 0) |
        (italic ? SkTypeface::kItalic : 0));

    const unsigned id = FileFaceIdAndStyleToUniqueId(filefaceid,
                                                     resulting_style);
    SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (resulting_style, id));

    {
        SkAutoMutexAcquire ac(global_fc_map_lock);
        global_fc_typefaces[id] = typeface;
    }

    return typeface;
}

// static
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream)
{
    if (!stream)
        return NULL;

    const size_t length = stream->read(0, 0);
    if (!length)
        return NULL;
    if (length >= 1024 * 1024 * 1024)
        return NULL;  // don't accept too large fonts (>= 1GB) for safety.

    uint8_t* font = (uint8_t*)sk_malloc_throw(length);
    if (stream->read(font, length) != length) {
        sk_free(font);
        return NULL;
    }

    SkTypeface::Style style = static_cast<SkTypeface::Style>(0);
    unsigned id = 0;
    {
        SkAutoMutexAcquire ac(global_remote_font_map_lock);
        id = FileFaceIdAndStyleToUniqueId(
            global_next_remote_font_id | kRemoteFontMask, style);

        if (++global_next_remote_font_id >= kRemoteFontMask)
            global_next_remote_font_id = 0;

        if (!global_remote_fonts.insert(
                std::make_pair(id, std::make_pair(font, length))).second) {
            sk_free(font);
            return NULL;
        }
    }

    SkTypeface* typeface = SkNEW_ARGS(FontConfigTypeface, (style, id));
    return typeface;
}

// static
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[])
{
    SkASSERT(!"SkFontHost::CreateTypefaceFromFile unimplemented");
    return NULL;
}

void SkFontHost::Serialize(const SkTypeface*, SkWStream*) {
    SkASSERT(!"SkFontHost::Serialize unimplemented");
}

SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
    SkASSERT(!"SkFontHost::Deserialize unimplemented");
    return NULL;
}

// static
uint32_t SkFontHost::NextLogicalFont(SkFontID curr, SkFontID orig) {
    // We don't handle font fallback, WebKit does.
    return 0;
}

///////////////////////////////////////////////////////////////////////////////

class SkFileDescriptorStream : public SkStream {
  public:
    SkFileDescriptorStream(int fd) {
        memory_ = NULL;
        offset_ = 0;

        // this ensures that if we fail in the constructor, we will safely
        // ignore all subsequent calls to read() because we will always trim
        // the requested size down to 0
        length_ = 0;

        struct stat st;
        if (fstat(fd, &st))
            return;

        void* memory = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
        close(fd);
        if (memory == MAP_FAILED)
            return;

        memory_ = reinterpret_cast<uint8_t*>(memory);
        length_ = st.st_size;
    }

    ~SkFileDescriptorStream() {
        munmap(const_cast<uint8_t*>(memory_), length_);
    }

    virtual bool rewind() {
        offset_ = 0;
        return true;
    }

    // SkStream implementation.
    virtual size_t read(void* buffer, size_t size) {
        if (!buffer && !size) {
            // This is request for the length of the stream.
            return length_;
        }

        size_t remaining = length_ - offset_;
        if (size > remaining)
            size = remaining;
        if (buffer)
            memcpy(buffer, memory_ + offset_, size);

        offset_ += size;
        return size;
    }

    virtual const void* getMemoryBase() {
        return memory_;
    }

  private:
    const uint8_t* memory_;
    size_t offset_, length_;
};

///////////////////////////////////////////////////////////////////////////////

// static
SkStream* SkFontHost::OpenStream(uint32_t id)
{
    const unsigned filefaceid = UniqueIdToFileFaceId(id);

    if (IsRemoteFont(filefaceid)) {
      // remote font
      SkAutoMutexAcquire ac(global_remote_font_map_lock);
      std::map<uint32_t, std::pair<uint8_t*, size_t> >::const_iterator iter
          = global_remote_fonts.find(id);
      if (iter == global_remote_fonts.end())
          return NULL;
      return SkNEW_ARGS(
          SkMemoryStream, (iter->second.first, iter->second.second));
    }

    // system font
    const int fd = GetFcImpl()->Open(filefaceid);
    if (fd < 0)
        return NULL;

    return SkNEW_ARGS(SkFileDescriptorStream, (fd));
}

// static
size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
                               int32_t* index) {
    const unsigned filefaceid = UniqueIdToFileFaceId(fontID);

    if (IsRemoteFont(filefaceid))
        return 0;

    if (index) {
        *index = filefaceid & 0xfu;
        // 1 is a bogus return value.
        // We had better change the signature of this function in Skia
        // to return bool to indicate success/failure and have another
        // out param for fileName length.
        if (!path)
          return 1;
    }

    if (path)
        SkASSERT(!"SkFontHost::GetFileName does not support the font path "
                  "retrieval.");

    return 0;
}
<|endoftext|>


<commit_before>
#include "iaxclient.h"

// For compilers that supports precompilation , includes  wx/wx.h
#include  "wx/wxprec.h"

#ifndef WX_PRECOMP
#include  "wx/wx.h"
#endif

#include  "wx.h"

IMPLEMENT_APP(IAXClient)

static int inputLevel = 0;
static int outputLevel = 0;

static char *buttonlabels[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#" };

class IAXTimer : public wxTimer
{
  public:
    void IAXTimer::Notify();
};

class DialPad : public wxPanel
{
public:
    DialPad(wxFrame *parent, wxPoint pos, wxSize size);

    void ButtonHandler(wxEvent &evt);

    wxButton *buttons[12];

protected:
    DECLARE_EVENT_TABLE()
};

class IAXFrame : public wxFrame
{
public:
    IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height);

    ~IAXFrame();

    void IAXFrame::ButtonHandler(wxEvent &evt);

    wxGauge *input;
    wxGauge *output;
    DialPad *dialPad;
    IAXTimer *timer;
    wxTextCtrl *iaxDest;
    wxButton *dialButton, *quitButton;

protected:
    DECLARE_EVENT_TABLE()

};

static IAXFrame *theFrame;

void IAXTimer::Notify()
{
    iaxc_process_calls();
}

DialPad::DialPad(wxFrame *parent, wxPoint pos, wxSize size)
  : wxPanel(parent, -1, pos, size, wxTAB_TRAVERSAL, wxString("dial pad"))
{
    int x=0 ,y=0;

    int dX = size.GetWidth()/3;
    int dY = size.GetHeight()/4;

#if 0
    wxGauge *w = new wxGauge(this, -1, 50, wxPoint(0,0), wxSize(10,200),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("test level"));
#endif
    for(int i=0; i<12;)
    {
	fprintf(stderr, "creating button at %d,%d, %d by %d\n", x,y,dX,dY);
	buttons[i] = new wxButton(this, i, wxString(buttonlabels[i]),
	    wxPoint(x,y), wxSize(dX-5,dY-5),
	    0, wxDefaultValidator, wxString(buttonlabels[i]));

	i++;
	if(i%3 == 0) {
	    x=0; y+=dY;
	} else {
	    x+=dX;
	}
    }
}

void DialPad::ButtonHandler(wxEvent &evt)
{
	int buttonNo = evt.m_id;
	char *button = buttonlabels[buttonNo];
	fprintf(stderr, "got Button Event for button %s\n", button);
	iaxc_send_dtmf(*button);
}

BEGIN_EVENT_TABLE(DialPad, wxPanel)
	EVT_BUTTON(0,DialPad::ButtonHandler)
	EVT_BUTTON(1,DialPad::ButtonHandler)
	EVT_BUTTON(2,DialPad::ButtonHandler)
	EVT_BUTTON(3,DialPad::ButtonHandler)
	EVT_BUTTON(4,DialPad::ButtonHandler)
	EVT_BUTTON(5,DialPad::ButtonHandler)
	EVT_BUTTON(6,DialPad::ButtonHandler)
	EVT_BUTTON(7,DialPad::ButtonHandler)
	EVT_BUTTON(8,DialPad::ButtonHandler)
	EVT_BUTTON(9,DialPad::ButtonHandler)
	EVT_BUTTON(10,DialPad::ButtonHandler)
	EVT_BUTTON(11,DialPad::ButtonHandler)
END_EVENT_TABLE()

IAXFrame::IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height)
  : wxFrame((wxFrame *) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height))
{
    dialPad = new DialPad(this, wxPoint(0,0), wxSize(100,120));

    input  = new wxGauge(this, -1, 50, wxPoint(100,0), wxSize(10,120),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("input level"));
    output  = new wxGauge(this, -1, 50, wxPoint(110,0), wxSize(10,120),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("output level"));

    iaxDest = new wxTextCtrl(this, -1, wxString("guest@server"),
	wxPoint(0,120), wxSize(110,20) /*, wxTE_MULTILINE */);

    dialButton = new wxButton(this, 100, wxString("Dial"),
	    wxPoint(0,150), wxSize(55,25));

    quitButton = new wxButton(this, 101, wxString("Quit"),
	    wxPoint(60,150), wxSize(55,25));

    timer = new IAXTimer();
    timer->Start(10);
    //output = new wxGauge(this, -1, 100);
}

void IAXFrame::ButtonHandler(wxEvent &evt)
{
	int buttonNo = evt.m_id;

	fprintf(stderr, "got Button Event for button %d\n", buttonNo);

	switch(buttonNo) {
		case 100:
			// dial the number
			iaxc_call(stderr,
			   (char *)(theFrame->iaxDest->GetValue().c_str()));
			break;
		case 101:
			exit(0);
			break;
		default:
			break;
	}
}

BEGIN_EVENT_TABLE(IAXFrame, wxFrame)
	EVT_BUTTON(100,IAXFrame::ButtonHandler)
	EVT_BUTTON(101,IAXFrame::ButtonHandler)
END_EVENT_TABLE()

IAXFrame::~IAXFrame()
{
}

bool IAXClient::OnInit()
{
	theFrame = new IAXFrame("IAXTest", 0,0,120,300);
	theFrame->CreateStatusBar();
	theFrame->SetStatusText("Hello World");

	theFrame->Show(TRUE);
	SetTopWindow(theFrame);

	doTestCall(0,NULL);

	return true;

}

extern "C" {
   int levels_callback(float input, float output)
   {
      if (input < -50)
	inputLevel=0;
      else
	inputLevel=(int)input+50;

      if (output < -50)
	outputLevel=0;
      else
	outputLevel=(int)output+50;

      theFrame->input->SetValue(inputLevel);
      theFrame->output->SetValue(outputLevel);
   }
}
<commit_msg>change level meter range<commit_after>
#include "iaxclient.h"

// For compilers that supports precompilation , includes  wx/wx.h
#include  "wx/wxprec.h"

#ifndef WX_PRECOMP
#include  "wx/wx.h"
#endif

#include  "wx.h"

#define LEVEL_MAX -10
#define LEVEL_MIN -50

IMPLEMENT_APP(IAXClient)

static int inputLevel = 0;
static int outputLevel = 0;

static char *buttonlabels[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "0", "#" };

class IAXTimer : public wxTimer
{
  public:
    void IAXTimer::Notify();
};

class DialPad : public wxPanel
{
public:
    DialPad(wxFrame *parent, wxPoint pos, wxSize size);

    void ButtonHandler(wxEvent &evt);

    wxButton *buttons[12];

protected:
    DECLARE_EVENT_TABLE()
};

class IAXFrame : public wxFrame
{
public:
    IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height);

    ~IAXFrame();

    void IAXFrame::ButtonHandler(wxEvent &evt);

    wxGauge *input;
    wxGauge *output;
    DialPad *dialPad;
    IAXTimer *timer;
    wxTextCtrl *iaxDest;
    wxButton *dialButton, *quitButton;

protected:
    DECLARE_EVENT_TABLE()

};

static IAXFrame *theFrame;

void IAXTimer::Notify()
{
    iaxc_process_calls();
}

DialPad::DialPad(wxFrame *parent, wxPoint pos, wxSize size)
  : wxPanel(parent, -1, pos, size, wxTAB_TRAVERSAL, wxString("dial pad"))
{
    int x=0 ,y=0;

    int dX = size.GetWidth()/3;
    int dY = size.GetHeight()/4;

#if 0
    wxGauge *w = new wxGauge(this, -1, 50, wxPoint(0,0), wxSize(10,200),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("test level"));
#endif
    for(int i=0; i<12;)
    {
	fprintf(stderr, "creating button at %d,%d, %d by %d\n", x,y,dX,dY);
	buttons[i] = new wxButton(this, i, wxString(buttonlabels[i]),
	    wxPoint(x,y), wxSize(dX-5,dY-5),
	    0, wxDefaultValidator, wxString(buttonlabels[i]));

	i++;
	if(i%3 == 0) {
	    x=0; y+=dY;
	} else {
	    x+=dX;
	}
    }
}

void DialPad::ButtonHandler(wxEvent &evt)
{
	int buttonNo = evt.m_id;
	char *button = buttonlabels[buttonNo];
	fprintf(stderr, "got Button Event for button %s\n", button);
	iaxc_send_dtmf(*button);
}

BEGIN_EVENT_TABLE(DialPad, wxPanel)
	EVT_BUTTON(0,DialPad::ButtonHandler)
	EVT_BUTTON(1,DialPad::ButtonHandler)
	EVT_BUTTON(2,DialPad::ButtonHandler)
	EVT_BUTTON(3,DialPad::ButtonHandler)
	EVT_BUTTON(4,DialPad::ButtonHandler)
	EVT_BUTTON(5,DialPad::ButtonHandler)
	EVT_BUTTON(6,DialPad::ButtonHandler)
	EVT_BUTTON(7,DialPad::ButtonHandler)
	EVT_BUTTON(8,DialPad::ButtonHandler)
	EVT_BUTTON(9,DialPad::ButtonHandler)
	EVT_BUTTON(10,DialPad::ButtonHandler)
	EVT_BUTTON(11,DialPad::ButtonHandler)
END_EVENT_TABLE()

IAXFrame::IAXFrame(const wxChar *title, int xpos, int ypos, int width, int height)
  : wxFrame((wxFrame *) NULL, -1, title, wxPoint(xpos, ypos), wxSize(width, height))
{
    dialPad = new DialPad(this, wxPoint(0,0), wxSize(100,120));

    input  = new wxGauge(this, -1, LEVEL_MAX-LEVEL_MIN, wxPoint(100,0), wxSize(10,120),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("input level"));
    output  = new wxGauge(this, -1, LEVEL_MAX-LEVEL_MIN, wxPoint(110,0), wxSize(10,120),
	  wxGA_VERTICAL,  wxDefaultValidator, wxString("output level"));

    iaxDest = new wxTextCtrl(this, -1, wxString("guest@ast1/8068"),
	wxPoint(0,120), wxSize(110,20) /*, wxTE_MULTILINE */);

    dialButton = new wxButton(this, 100, wxString("Dial"),
	    wxPoint(0,150), wxSize(55,25));

    quitButton = new wxButton(this, 101, wxString("Quit"),
	    wxPoint(60,150), wxSize(55,25));

    timer = new IAXTimer();
    timer->Start(10);
    //output = new wxGauge(this, -1, 100);
}

void IAXFrame::ButtonHandler(wxEvent &evt)
{
	int buttonNo = evt.m_id;

	fprintf(stderr, "got Button Event for button %d\n", buttonNo);

	switch(buttonNo) {
		case 100:
			// dial the number
			iaxc_call(stderr,
			   (char *)(theFrame->iaxDest->GetValue().c_str()));
			break;
		case 101:
			exit(0);
			break;
		default:
			break;
	}
}

BEGIN_EVENT_TABLE(IAXFrame, wxFrame)
	EVT_BUTTON(100,IAXFrame::ButtonHandler)
	EVT_BUTTON(101,IAXFrame::ButtonHandler)
END_EVENT_TABLE()

IAXFrame::~IAXFrame()
{
}

bool IAXClient::OnInit()
{
	theFrame = new IAXFrame("IAXTest", 0,0,120,300);
	theFrame->CreateStatusBar();
	theFrame->SetStatusText("Hello World");

	theFrame->Show(TRUE);
	SetTopWindow(theFrame);

	doTestCall(0,NULL);

	return true;

}

extern "C" {
   int levels_callback(float input, float output)
   {
      if (input < LEVEL_MIN)
	input = LEVEL_MIN;
      else if (input > LEVEL_MAX)
	input = LEVEL_MAX;
      inputLevel = (int)input - (LEVEL_MIN);

      if (output < LEVEL_MIN)
	output = LEVEL_MIN;
      else if (input > LEVEL_MAX)
	output = LEVEL_MAX;
      outputLevel = (int)output - (LEVEL_MIN);

      theFrame->input->SetValue(inputLevel);
      theFrame->output->SetValue(outputLevel);
   }
}
<|endoftext|>


<commit_before>/*
 * GLShaderBindingLayout.cpp
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015-2019 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "GLShaderBindingLayout.h"
#include "../Ext/GLExtensionRegistry.h"
#include "../Ext/GLExtensions.h"
#include "../../../Core/HelperMacros.h"

namespace LLGL
{

GLShaderBindingLayout::GLShaderBindingLayout(const GLPipelineLayout& pipelineLayout)
{
    /* Gather all uniform bindings */
    for (const auto& binding : pipelineLayout.GetBindings())
    {
        if (!binding.name.empty())
        {
            if (binding.type == ResourceType::Sampler || binding.type == ResourceType::Texture)
            {
                bindings_.push_back({ binding.name, binding.slot });
                ++numUniformBindings_;
            }
        }
    }

    /* Gather all uniform-block bindings */
    for (const auto& binding : pipelineLayout.GetBindings())
    {
        if (!binding.name.empty())
        {
            if (binding.type == ResourceType::Buffer && (binding.bindFlags & BindFlags::ConstantBuffer) != 0)
            {
                bindings_.push_back({ binding.name, binding.slot });
                ++numUniformBlockBindings_;
            }
        }
    }

    /* Gather all shader-storage bindings */
    for (const auto& binding : pipelineLayout.GetBindings())
    {
        if (!binding.name.empty())
        {
            if (binding.type == ResourceType::Buffer && (binding.bindFlags & (BindFlags::Storage | BindFlags::Sampled)) != 0)
            {
                bindings_.push_back({ binding.name, binding.slot });
                ++numShaderStorageBindings_;
            }
        }
    }
}

void GLShaderBindingLayout::BindResourceSlots(GLuint program) const
{
    std::size_t resourceIndex = 0;

    /* Set uniform bindings */
    for (std::uint8_t i = 0; i < numUniformBindings_; ++i)
    {
        const auto& resource = bindings_[resourceIndex++];
        auto blockIndex = glGetUniformLocation(program, resource.name.c_str());
        if (blockIndex != GL_INVALID_INDEX)
            glUniform1i(blockIndex, static_cast<GLint>(resource.slot));
    }

    /* Set uniform-block bindings */
    for (std::uint8_t i = 0; i < numUniformBlockBindings_; ++i)
    {
        const auto& resource = bindings_[resourceIndex++];
        auto blockIndex = glGetUniformBlockIndex(program, resource.name.c_str());
        if (blockIndex != GL_INVALID_INDEX)
            glUniformBlockBinding(program, blockIndex, resource.slot);
    }

    /* Set shader-storage bindings */
    #ifdef LLGL_GLEXT_SHADER_STORAGE_BUFFER_OBJECT
    for (std::uint8_t i = 0; i < numShaderStorageBindings_; ++i)
    {
        const auto& resource = bindings_[resourceIndex++];
        auto blockIndex = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, resource.name.c_str());
        if (blockIndex != GL_INVALID_INDEX)
            glShaderStorageBlockBinding(program, blockIndex, resource.slot);
    }
    #endif
}

int GLShaderBindingLayout::CompareSWO(const GLShaderBindingLayout& rhs) const
{
    const auto& lhs = *this;

    for (std::size_t i = 0, n = bindings_.size(); i < n; ++i)
    {
        LLGL_COMPARE_MEMBER_SWO( bindings_[i].slot );
        LLGL_COMPARE_MEMBER_SWO( bindings_[i].name );
    }

    return 0;
}

bool GLShaderBindingLayout::HasBindings() const
{
    return ((numUniformBindings_ | numUniformBlockBindings_ | numShaderStorageBindings_) != 0);
}

} // /namespace LLGL

// ================================================================================
<commit_msg>Bug fix: "GLShaderBindingLayout::CompareSWO" function did not account for different number of bindings between compared objects.<commit_after>/*
 * GLShaderBindingLayout.cpp
 *
 * This file is part of the "LLGL" project (Copyright (c) 2015-2019 by Lukas Hermanns)
 * See "LICENSE.txt" for license information.
 */

#include "GLShaderBindingLayout.h"
#include "../Ext/GLExtensionRegistry.h"
#include "../Ext/GLExtensions.h"
#include "../../../Core/HelperMacros.h"

namespace LLGL
{

GLShaderBindingLayout::GLShaderBindingLayout(const GLPipelineLayout& pipelineLayout)
{
    /* Gather all uniform bindings */
    for (const auto& binding : pipelineLayout.GetBindings())
    {
        if (!binding.name.empty())
        {
            if (binding.type == ResourceType::Sampler || binding.type == ResourceType::Texture)
            {
                bindings_.push_back({ binding.name, binding.slot });
                ++numUniformBindings_;
            }
        }
    }

    /* Gather all uniform-block bindings */
    for (const auto& binding : pipelineLayout.GetBindings())
    {
        if (!binding.name.empty())
        {
            if (binding.type == ResourceType::Buffer && (binding.bindFlags & BindFlags::ConstantBuffer) != 0)
            {
                bindings_.push_back({ binding.name, binding.slot });
                ++numUniformBlockBindings_;
            }
        }
    }

    /* Gather all shader-storage bindings */
    for (const auto& binding : pipelineLayout.GetBindings())
    {
        if (!binding.name.empty())
        {
            if (binding.type == ResourceType::Buffer && (binding.bindFlags & (BindFlags::Storage | BindFlags::Sampled)) != 0)
            {
                bindings_.push_back({ binding.name, binding.slot });
                ++numShaderStorageBindings_;
            }
        }
    }
}

void GLShaderBindingLayout::BindResourceSlots(GLuint program) const
{
    std::size_t resourceIndex = 0;

    /* Set uniform bindings */
    for (std::uint8_t i = 0; i < numUniformBindings_; ++i)
    {
        const auto& resource = bindings_[resourceIndex++];
        auto blockIndex = glGetUniformLocation(program, resource.name.c_str());
        if (blockIndex != GL_INVALID_INDEX)
            glUniform1i(blockIndex, static_cast<GLint>(resource.slot));
    }

    /* Set uniform-block bindings */
    for (std::uint8_t i = 0; i < numUniformBlockBindings_; ++i)
    {
        const auto& resource = bindings_[resourceIndex++];
        auto blockIndex = glGetUniformBlockIndex(program, resource.name.c_str());
        if (blockIndex != GL_INVALID_INDEX)
            glUniformBlockBinding(program, blockIndex, resource.slot);
    }

    /* Set shader-storage bindings */
    #ifdef LLGL_GLEXT_SHADER_STORAGE_BUFFER_OBJECT
    for (std::uint8_t i = 0; i < numShaderStorageBindings_; ++i)
    {
        const auto& resource = bindings_[resourceIndex++];
        auto blockIndex = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, resource.name.c_str());
        if (blockIndex != GL_INVALID_INDEX)
            glShaderStorageBlockBinding(program, blockIndex, resource.slot);
    }
    #endif
}

int GLShaderBindingLayout::CompareSWO(const GLShaderBindingLayout& rhs) const
{
    const auto& lhs = *this;

    /* Compare number of bindings first; if equal we can use one of the arrays only */
    LLGL_COMPARE_MEMBER_SWO( bindings_.size() );

    for (std::size_t i = 0, n = bindings_.size(); i < n; ++i)
    {
        LLGL_COMPARE_MEMBER_SWO( bindings_[i].slot );
        LLGL_COMPARE_MEMBER_SWO( bindings_[i].name );
    }

    return 0;
}

bool GLShaderBindingLayout::HasBindings() const
{
    return ((numUniformBindings_ | numUniformBlockBindings_ | numShaderStorageBindings_) != 0);
}

} // /namespace LLGL

// ================================================================================
<|endoftext|>