<commit_before>// Copyright (c) 2016-2020 The ZCash developers
// Copyright (c) 2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "wallet/test/wallet_test_fixture.h"

#include "sapling/sapling_util.h"
#include "sapling/address.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#include "util.h"
#include <boost/test/unit_test.hpp>

/**
 * This test covers methods on CWallet
 * GenerateNewZKey()
 * AddZKey()
 * LoadZKey()
 * LoadZKeyMetadata()
 */

BOOST_FIXTURE_TEST_SUITE(wallet_zkeys_tests, WalletTestingSetup)

/**
  * This test covers Sapling methods on CWallet
  * GenerateNewSaplingZKey()
  * AddSaplingZKey()
  * LoadSaplingZKey()
  * LoadSaplingZKeyMetadata()
  */
BOOST_AUTO_TEST_CASE(StoreAndLoadSaplingZkeys) {
    SelectParams(CBaseChainParams::MAIN);

    CWallet wallet;
    LOCK(wallet.cs_wallet);
    // wallet should be empty
    std::set<libzcash::SaplingPaymentAddress> addrs;
    wallet.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(0, addrs.size());

    // No HD seed in the wallet
    BOOST_CHECK_THROW(wallet.GenerateNewSaplingZKey(), std::runtime_error);

    // Random seed
    CKey seed;
    seed.MakeNewKey(true);
    wallet.AddKeyPubKey(seed, seed.GetPubKey());
    wallet.GetSaplingScriptPubKeyMan()->SetHDSeed(seed.GetPubKey(), false, true);

    // wallet should have one key
    auto address = wallet.GenerateNewSaplingZKey();
    wallet.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(1, addrs.size());

    // verify wallet has incoming viewing key for the address
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(address));

    // manually add new spending key to wallet
    HDSeed seed1(seed.GetPrivKey());
    auto m = libzcash::SaplingExtendedSpendingKey::Master(seed1);
    auto sk = m.Derive(0);
    BOOST_CHECK(wallet.AddSaplingZKey(sk));

    // verify wallet did add it
    auto extfvk = sk.ToXFVK();
    BOOST_CHECK(wallet.HaveSaplingSpendingKey(extfvk));

    // verify spending key stored correctly
    libzcash::SaplingExtendedSpendingKey keyOut;
    wallet.GetSaplingSpendingKey(extfvk, keyOut);
    BOOST_CHECK(sk == keyOut);

    // verify there are two keys
    wallet.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(2, addrs.size());
    BOOST_CHECK_EQUAL(1, addrs.count(address));
    BOOST_CHECK_EQUAL(1, addrs.count(sk.DefaultAddress()));

    // Generate a diversified address different to the default
    // If we can't get an early diversified address, we are very unlucky
    blob88 diversifier;
    diversifier.begin()[0] = 10;
    auto dpa = sk.ToXFVK().Address(diversifier).get().second;

    // verify wallet only has the default address
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(sk.DefaultAddress()));
    BOOST_CHECK(!wallet.HaveSaplingIncomingViewingKey(dpa));

    // manually add a diversified address
    auto ivk = extfvk.fvk.in_viewing_key();
    BOOST_CHECK(wallet.AddSaplingIncomingViewingKeyW(ivk, dpa));

    // verify wallet did add it
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(sk.DefaultAddress()));
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(dpa));

    // Load a third key into the wallet
    auto sk2 = m.Derive(1);
    BOOST_CHECK(wallet.LoadSaplingZKey(sk2));

    // attach metadata to this third key
    auto ivk2 = sk2.expsk.full_viewing_key().in_viewing_key();
    int64_t now = GetTime();
    CKeyMetadata meta(now);
    BOOST_CHECK(wallet.LoadSaplingZKeyMetadata(ivk2, meta));

    // check metadata is the same
    BOOST_CHECK_EQUAL(wallet.GetSaplingScriptPubKeyMan()->mapSaplingZKeyMetadata[ivk2].nCreateTime, now);

    // Load a diversified address for the third key into the wallet
    auto dpa2 = sk2.ToXFVK().Address(diversifier).get().second;
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(sk2.DefaultAddress()));
    BOOST_CHECK(!wallet.HaveSaplingIncomingViewingKey(dpa2));
    BOOST_CHECK(wallet.LoadSaplingPaymentAddress(dpa2, ivk2));
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(dpa2));
}

/**
  * This test covers methods on CWalletDB to load/save crypted sapling z keys.
  */
BOOST_AUTO_TEST_CASE(WriteCryptedSaplingZkeyDirectToDb) {
    SelectParams(CBaseChainParams::TESTNET);

    BOOST_CHECK(!pwalletMain->HasSaplingSPKM());
    assert(pwalletMain->SetupSPKM(true));

    // wallet should be empty
    std::set<libzcash::SaplingPaymentAddress> addrs;
    pwalletMain->GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(0, addrs.size());

    // Add random key to the wallet
    auto address = pwalletMain->GenerateNewSaplingZKey();

    // wallet should have one key
    pwalletMain->GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(1, addrs.size());

    // encrypt wallet
    SecureString strWalletPass;
    strWalletPass.reserve(100);
    strWalletPass = "hello";
    BOOST_CHECK(pwalletMain->EncryptWallet(strWalletPass));

    // adding a new key will fail as the wallet is locked
    BOOST_CHECK_THROW(pwalletMain->GenerateNewSaplingZKey(), std::runtime_error);

    // unlock wallet and then add
    pwalletMain->Unlock(strWalletPass);
    libzcash::SaplingPaymentAddress address2 = pwalletMain->GenerateNewSaplingZKey();

    // Create a new wallet from the existing wallet path
    bool fFirstRun;
    CWallet wallet2(pwalletMain->strWalletFile);
    BOOST_CHECK_EQUAL(DB_LOAD_OK, wallet2.LoadWallet(fFirstRun));

    // Confirm it's not the same as the other wallet
    BOOST_CHECK(pwalletMain != &wallet2);
    BOOST_CHECK(wallet2.HasSaplingSPKM());

    // wallet should have two keys
    wallet2.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(2, addrs.size());

    //check we have entries for our payment addresses
    BOOST_CHECK(addrs.count(address));
    BOOST_CHECK(addrs.count(address2));

    // spending key is crypted, so we can't extract valid payment address
    libzcash::SaplingExtendedSpendingKey keyOut;
    BOOST_CHECK(!wallet2.GetSaplingExtendedSpendingKey(address, keyOut));

    // unlock wallet to get spending keys and verify payment addresses
    wallet2.Unlock(strWalletPass);

    BOOST_CHECK(wallet2.GetSaplingExtendedSpendingKey(address, keyOut));
    BOOST_CHECK(address == keyOut.DefaultAddress());

    BOOST_CHECK(wallet2.GetSaplingExtendedSpendingKey(address2, keyOut));
    BOOST_CHECK(address2 == keyOut.DefaultAddress());
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Test: print error if shield diversified address is equal to the default address.<commit_after>// Copyright (c) 2016-2020 The ZCash developers
// Copyright (c) 2020 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "wallet/test/wallet_test_fixture.h"

#include "sapling/sapling_util.h"
#include "sapling/address.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#include "util.h"
#include <boost/test/unit_test.hpp>

/**
 * This test covers methods on CWallet
 * GenerateNewZKey()
 * AddZKey()
 * LoadZKey()
 * LoadZKeyMetadata()
 */

BOOST_FIXTURE_TEST_SUITE(wallet_zkeys_tests, WalletTestingSetup)

/**
  * This test covers Sapling methods on CWallet
  * GenerateNewSaplingZKey()
  * AddSaplingZKey()
  * LoadSaplingZKey()
  * LoadSaplingZKeyMetadata()
  */
BOOST_AUTO_TEST_CASE(StoreAndLoadSaplingZkeys) {
    SelectParams(CBaseChainParams::MAIN);

    CWallet wallet;
    LOCK(wallet.cs_wallet);
    // wallet should be empty
    std::set<libzcash::SaplingPaymentAddress> addrs;
    wallet.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(0, addrs.size());

    // No HD seed in the wallet
    BOOST_CHECK_THROW(wallet.GenerateNewSaplingZKey(), std::runtime_error);

    // Random seed
    CKey seed;
    seed.MakeNewKey(true);
    wallet.AddKeyPubKey(seed, seed.GetPubKey());
    wallet.GetSaplingScriptPubKeyMan()->SetHDSeed(seed.GetPubKey(), false, true);

    // wallet should have one key
    auto address = wallet.GenerateNewSaplingZKey();
    wallet.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(1, addrs.size());

    // verify wallet has incoming viewing key for the address
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(address));

    // manually add new spending key to wallet
    HDSeed seed1(seed.GetPrivKey());
    auto m = libzcash::SaplingExtendedSpendingKey::Master(seed1);
    auto sk = m.Derive(0);
    BOOST_CHECK(wallet.AddSaplingZKey(sk));

    // verify wallet did add it
    auto extfvk = sk.ToXFVK();
    BOOST_CHECK(wallet.HaveSaplingSpendingKey(extfvk));

    // verify spending key stored correctly
    libzcash::SaplingExtendedSpendingKey keyOut;
    wallet.GetSaplingSpendingKey(extfvk, keyOut);
    BOOST_CHECK(sk == keyOut);

    // verify there are two keys
    wallet.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(2, addrs.size());
    BOOST_CHECK_EQUAL(1, addrs.count(address));
    BOOST_CHECK_EQUAL(1, addrs.count(sk.DefaultAddress()));

    // Generate a diversified address different to the default
    // If we can't get an early diversified address, we are very unlucky
    blob88 diversifier;
    diversifier.begin()[0] = 10;
    auto dpa = sk.ToXFVK().Address(diversifier).get().second;

    // verify wallet only has the default address
    libzcash::SaplingPaymentAddress defaultAddr = sk.DefaultAddress();
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(defaultAddr));
    BOOST_CHECK_MESSAGE(!(dpa == defaultAddr), "ERROR: default address is equal to diversified address");
    BOOST_CHECK(!wallet.HaveSaplingIncomingViewingKey(dpa));

    // manually add a diversified address
    auto ivk = extfvk.fvk.in_viewing_key();
    BOOST_CHECK(wallet.AddSaplingIncomingViewingKeyW(ivk, dpa));

    // verify wallet did add it
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(sk.DefaultAddress()));
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(dpa));

    // Load a third key into the wallet
    auto sk2 = m.Derive(1);
    BOOST_CHECK(wallet.LoadSaplingZKey(sk2));

    // attach metadata to this third key
    auto ivk2 = sk2.expsk.full_viewing_key().in_viewing_key();
    int64_t now = GetTime();
    CKeyMetadata meta(now);
    BOOST_CHECK(wallet.LoadSaplingZKeyMetadata(ivk2, meta));

    // check metadata is the same
    BOOST_CHECK_EQUAL(wallet.GetSaplingScriptPubKeyMan()->mapSaplingZKeyMetadata[ivk2].nCreateTime, now);

    // Load a diversified address for the third key into the wallet
    auto dpa2 = sk2.ToXFVK().Address(diversifier).get().second;
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(sk2.DefaultAddress()));
    BOOST_CHECK(!wallet.HaveSaplingIncomingViewingKey(dpa2));
    BOOST_CHECK(wallet.LoadSaplingPaymentAddress(dpa2, ivk2));
    BOOST_CHECK(wallet.HaveSaplingIncomingViewingKey(dpa2));
}

/**
  * This test covers methods on CWalletDB to load/save crypted sapling z keys.
  */
BOOST_AUTO_TEST_CASE(WriteCryptedSaplingZkeyDirectToDb) {
    SelectParams(CBaseChainParams::TESTNET);

    BOOST_CHECK(!pwalletMain->HasSaplingSPKM());
    assert(pwalletMain->SetupSPKM(true));

    // wallet should be empty
    std::set<libzcash::SaplingPaymentAddress> addrs;
    pwalletMain->GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(0, addrs.size());

    // Add random key to the wallet
    auto address = pwalletMain->GenerateNewSaplingZKey();

    // wallet should have one key
    pwalletMain->GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(1, addrs.size());

    // encrypt wallet
    SecureString strWalletPass;
    strWalletPass.reserve(100);
    strWalletPass = "hello";
    BOOST_CHECK(pwalletMain->EncryptWallet(strWalletPass));

    // adding a new key will fail as the wallet is locked
    BOOST_CHECK_THROW(pwalletMain->GenerateNewSaplingZKey(), std::runtime_error);

    // unlock wallet and then add
    pwalletMain->Unlock(strWalletPass);
    libzcash::SaplingPaymentAddress address2 = pwalletMain->GenerateNewSaplingZKey();

    // Create a new wallet from the existing wallet path
    bool fFirstRun;
    CWallet wallet2(pwalletMain->strWalletFile);
    BOOST_CHECK_EQUAL(DB_LOAD_OK, wallet2.LoadWallet(fFirstRun));

    // Confirm it's not the same as the other wallet
    BOOST_CHECK(pwalletMain != &wallet2);
    BOOST_CHECK(wallet2.HasSaplingSPKM());

    // wallet should have two keys
    wallet2.GetSaplingPaymentAddresses(addrs);
    BOOST_CHECK_EQUAL(2, addrs.size());

    //check we have entries for our payment addresses
    BOOST_CHECK(addrs.count(address));
    BOOST_CHECK(addrs.count(address2));

    // spending key is crypted, so we can't extract valid payment address
    libzcash::SaplingExtendedSpendingKey keyOut;
    BOOST_CHECK(!wallet2.GetSaplingExtendedSpendingKey(address, keyOut));

    // unlock wallet to get spending keys and verify payment addresses
    wallet2.Unlock(strWalletPass);

    BOOST_CHECK(wallet2.GetSaplingExtendedSpendingKey(address, keyOut));
    BOOST_CHECK(address == keyOut.DefaultAddress());

    BOOST_CHECK(wallet2.GetSaplingExtendedSpendingKey(address2, keyOut));
    BOOST_CHECK(address2 == keyOut.DefaultAddress());
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ucbserv.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: sb $ $Date: 2000-12-04 17:36:40 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP_
#include <com/sun/star/registry/XRegistryKey.hpp>
#endif

#ifndef _UCB_HXX
#include "ucb.hxx"
#endif
#ifndef _UCBCFG_HXX
#include "ucbcfg.hxx"
#endif
#ifndef _UCBSTORE_HXX
#include "ucbstore.hxx"
#endif
#ifndef _UCBPROPS_HXX
#include "ucbprops.hxx"
#endif
#ifndef _PROVPROX_HXX
#include "provprox.hxx"
#endif

using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;

//=========================================================================
static sal_Bool writeInfo( void * pRegistryKey,
                           const OUString & rImplementationName,
                              Sequence< OUString > const & rServiceNames )
{
    OUString aKeyName( OUString::createFromAscii( "/" ) );
    aKeyName += rImplementationName;
    aKeyName += OUString::createFromAscii( "/UNO/SERVICES" );

    Reference< XRegistryKey > xKey;
    try
    {
        xKey = static_cast< XRegistryKey * >(
                                    pRegistryKey )->createKey( aKeyName );
    }
    catch ( InvalidRegistryException const & )
    {
    }

    if ( !xKey.is() )
        return sal_False;

    sal_Bool bSuccess = sal_True;

    for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n )
    {
        try
        {
            xKey->createKey( rServiceNames[ n ] );
        }
        catch ( InvalidRegistryException const & )
        {
            bSuccess = sal_False;
            break;
        }
    }
    return bSuccess;
}

//=========================================================================
extern "C" void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//=========================================================================
extern "C" sal_Bool SAL_CALL component_writeInfo(
    void * pServiceManager, void * pRegistryKey )
{
    return pRegistryKey &&

    //////////////////////////////////////////////////////////////////////
    // Universal Content Broker.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UniversalContentBroker::getImplementationName_Static(),
               UniversalContentBroker::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCB Configuration.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UcbConfigurationManager::getImplementationName_Static(),
               UcbConfigurationManager::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCB Store.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UcbStore::getImplementationName_Static(),
               UcbStore::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCB PropertiesManager.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UcbPropertiesManager::getImplementationName_Static(),
               UcbPropertiesManager::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCP Proxy Factory.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
       UcbContentProviderProxyFactory::getImplementationName_Static(),
       UcbContentProviderProxyFactory::getSupportedServiceNames_Static() );
}

//=========================================================================
extern "C" void * SAL_CALL component_getFactory(
    const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
    void * pRet = 0;

    Reference< XMultiServiceFactory > xSMgr(
            reinterpret_cast< XMultiServiceFactory * >( pServiceManager ) );
    Reference< XSingleServiceFactory > xFactory;

    //////////////////////////////////////////////////////////////////////
    // Universal Content Broker.
    //////////////////////////////////////////////////////////////////////

    if ( UniversalContentBroker::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UniversalContentBroker::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCB Configuration.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbConfigurationManager::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UcbConfigurationManager::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCB Store.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbStore::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UcbStore::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCB PropertiesManager.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbPropertiesManager::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UcbPropertiesManager::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCP Proxy Factory.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbContentProviderProxyFactory::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory
            = UcbContentProviderProxyFactory::createServiceFactory( xSMgr );
    }

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

    if ( xFactory.is() )
    {
        xFactory->acquire();
        pRet = xFactory.get();
    }

    return pRet;
}

<commit_msg>#83541# - Removed UCB configuration service.<commit_after>/*************************************************************************
 *
 *  $RCSfile: ucbserv.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kso $ $Date: 2001-02-06 10:55:37 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_REGISTRY_XREGISTRYKEY_HPP_
#include <com/sun/star/registry/XRegistryKey.hpp>
#endif

#ifndef _UCB_HXX
#include "ucb.hxx"
#endif
#ifndef _UCBSTORE_HXX
#include "ucbstore.hxx"
#endif
#ifndef _UCBPROPS_HXX
#include "ucbprops.hxx"
#endif
#ifndef _PROVPROX_HXX
#include "provprox.hxx"
#endif

using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;

//=========================================================================
static sal_Bool writeInfo( void * pRegistryKey,
                           const OUString & rImplementationName,
                              Sequence< OUString > const & rServiceNames )
{
    OUString aKeyName( OUString::createFromAscii( "/" ) );
    aKeyName += rImplementationName;
    aKeyName += OUString::createFromAscii( "/UNO/SERVICES" );

    Reference< XRegistryKey > xKey;
    try
    {
        xKey = static_cast< XRegistryKey * >(
                                    pRegistryKey )->createKey( aKeyName );
    }
    catch ( InvalidRegistryException const & )
    {
    }

    if ( !xKey.is() )
        return sal_False;

    sal_Bool bSuccess = sal_True;

    for ( sal_Int32 n = 0; n < rServiceNames.getLength(); ++n )
    {
        try
        {
            xKey->createKey( rServiceNames[ n ] );
        }
        catch ( InvalidRegistryException const & )
        {
            bSuccess = sal_False;
            break;
        }
    }
    return bSuccess;
}

//=========================================================================
extern "C" void SAL_CALL component_getImplementationEnvironment(
    const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv )
{
    *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
}

//=========================================================================
extern "C" sal_Bool SAL_CALL component_writeInfo(
    void * pServiceManager, void * pRegistryKey )
{
    return pRegistryKey &&

    //////////////////////////////////////////////////////////////////////
    // Universal Content Broker.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UniversalContentBroker::getImplementationName_Static(),
               UniversalContentBroker::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCB Store.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UcbStore::getImplementationName_Static(),
               UcbStore::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCB PropertiesManager.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
               UcbPropertiesManager::getImplementationName_Static(),
               UcbPropertiesManager::getSupportedServiceNames_Static() ) &&

    //////////////////////////////////////////////////////////////////////
    // UCP Proxy Factory.
    //////////////////////////////////////////////////////////////////////

    writeInfo( pRegistryKey,
       UcbContentProviderProxyFactory::getImplementationName_Static(),
       UcbContentProviderProxyFactory::getSupportedServiceNames_Static() );
}

//=========================================================================
extern "C" void * SAL_CALL component_getFactory(
    const sal_Char * pImplName, void * pServiceManager, void * pRegistryKey )
{
    void * pRet = 0;

    Reference< XMultiServiceFactory > xSMgr(
            reinterpret_cast< XMultiServiceFactory * >( pServiceManager ) );
    Reference< XSingleServiceFactory > xFactory;

    //////////////////////////////////////////////////////////////////////
    // Universal Content Broker.
    //////////////////////////////////////////////////////////////////////

    if ( UniversalContentBroker::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UniversalContentBroker::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCB Store.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbStore::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UcbStore::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCB PropertiesManager.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbPropertiesManager::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory = UcbPropertiesManager::createServiceFactory( xSMgr );
    }

    //////////////////////////////////////////////////////////////////////
    // UCP Proxy Factory.
    //////////////////////////////////////////////////////////////////////

    else if ( UcbContentProviderProxyFactory::getImplementationName_Static().
                compareToAscii( pImplName ) == 0 )
    {
        xFactory
            = UcbContentProviderProxyFactory::createServiceFactory( xSMgr );
    }

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

    if ( xFactory.is() )
    {
        xFactory->acquire();
        pRet = xFactory.get();
    }

    return pRet;
}

<|endoftext|>


<commit_before>/*!
 * \author David
 * \date 29-Apr-16.
 */

#include <algorithm>
#include <cmath>
#include <easylogging++.h>
#include "texture_manager.h"
#include "../../vulkan/render_context.h"
#include "../../../mc_interface/mc_objects.h"

namespace nova {
    texture_manager::texture_manager(std::shared_ptr<render_context> context) : context(context) {
        LOG(INFO) << "Creating the Texture Manager";
        reset();
        LOG(INFO) << "Texture manager created";
    }

    texture_manager::~texture_manager() {
        // gotta free up all the Vulkan textures
        reset();
    }

    void texture_manager::reset() {
        if(!atlases.empty()) {
            // Nothing to deallocate, let's just return
            return;
        }

        for(auto& tex : atlases) {
            tex.second.destroy();
        }

        atlases.clear();
        locations.clear();

        atlases["lightmap"] = texture2D(vk::Extent2D{16, 16}, vk::Format::eR8G8B8A8Unorm, context);
        atlases["lightmap"].set_name("lightmap");
        LOG(INFO) << "Created lightmap";

        clear_dynamic_textures();
    }

    void texture_manager::add_texture(mc_atlas_texture &new_texture) {
        LOG(INFO) << "Adding texture " << new_texture.name << " (" << new_texture.width << "x" << new_texture.height << ")";
        std::string texture_name = new_texture.name;
        LOG(TRACE) << "Saved texture name";
        auto dimensions = vk::Extent2D{new_texture.width, new_texture.height};
        texture2D texture{dimensions, vk::Format::eR8G8B8A8Unorm, context};
        LOG(TRACE) << "Created texture object";
        texture.set_name(texture_name);

        std::vector<uint8_t> pixel_data((std::size_t) (new_texture.width * new_texture.height * new_texture.num_components));
        for(uint32_t i = 0; i < new_texture.width * new_texture.height * new_texture.num_components; i++) {
            pixel_data[i] = (uint8_t) new_texture.texture_data[i];
        }

        LOG(TRACE) << "Added pixel data to buffer";

        texture.set_data(pixel_data.data(), dimensions);

        LOG(TRACE) << "Sent texture data to GPU";

        atlases[texture_name] = texture;
        LOG(DEBUG) << "Texture atlas " << texture_name << " is Vulkan texture " << texture.get_vk_image();
    }

    void texture_manager::add_texture_location(mc_texture_atlas_location &location) {
        texture_location tex_loc = {
                { location.min_u, location.min_v },
                { location.max_u, location.max_v }
        };

        locations[location.name] = tex_loc;
    }

    const texture_manager::texture_location texture_manager::get_texture_location(const std::string &texture_name) {
        // If we haven't explicitly added a texture location for this texture, let's just assume that the texture isn't
        // in an atlas and thus covers the whole (0 - 1) UV space

        if(locations.find(texture_name) != locations.end()) {
            return locations[texture_name];

        } else {
            return {{0, 0}, {1, 1}};
        }
    }

    texture2D &texture_manager::get_texture(std::string texture_name) {
        if(atlases.find(texture_name) != atlases.end()) {
            return atlases.at(texture_name);
        }

        LOG(INFO) << "Checking if texture " << texture_name << " is in the dynamic textures. There's " << dynamic_tex_name_to_idx.size() << " dynamic textures, it should be one of them";
        if(dynamic_tex_name_to_idx.find(texture_name) != dynamic_tex_name_to_idx.end()) {
            auto idx = dynamic_tex_name_to_idx.at(texture_name);
            if(dynamic_textures.size() > idx) {
                return dynamic_textures.at(idx);
            }
        }

        LOG(ERROR) << "Could not find texture " << texture_name;
        throw std::domain_error("Could not find texture " + texture_name);
    }

    int texture_manager::get_max_texture_size() {
        if(max_texture_size < 0) {
            max_texture_size = context->gpu.props.limits.maxImageDimension2D;

			LOG(DEBUG) << "max texturesize reported by gpu: " << max_texture_size;
        }
        return max_texture_size;
    }

    // Implementation based on RenderGraph::build_aliases from the Granite engine
    void texture_manager::create_dynamic_textures(const std::unordered_map<std::string, texture_resource> &textures,
                                                  const std::vector<render_pass> &passes, std::shared_ptr<swapchain_manager> swapchain) {
        // For each texture in the passes, try to assign it to an existing resource
        // We'll basically create a list of which texture resources can be assigned to each physical resource
        // We want to alias textures. We can alias texture A and B if all reads from A finish before all writes to B AND
        // if A and B have the same format and dimension
        // Maybe we should make a list of things with the same format and dimension?

        clear_dynamic_textures();

        struct range {
            uint32_t first_write_pass = ~0u;
            uint32_t last_write_pass = 0;
            uint32_t first_read_pass = ~0u;
            uint32_t last_read_pass = 0;

            bool has_writer() const
            {
                return first_write_pass <= last_write_pass;
            }

            bool has_reader() const
            {
                return first_read_pass <= last_read_pass;
            }

            bool is_used() const
            {
                return has_writer() || has_reader();
            }

            bool can_alias() const
            {
                // If we read before we have completely written to a resource we need to preserve it, so no alias is possible.
                return !(has_reader() && has_writer() && first_read_pass <= first_write_pass);
            }

            unsigned last_used_pass() const
            {
                unsigned last_pass = 0;
                if (has_writer())
                    last_pass = std::max(last_pass, last_write_pass);
                if (has_reader())
                    last_pass = std::max(last_pass, last_read_pass);
                return last_pass;
            }

            unsigned first_used_pass() const
            {
                unsigned first_pass = ~0u;
                if (has_writer())
                    first_pass = std::min(first_pass, first_write_pass);
                if (has_reader())
                    first_pass = std::min(first_pass, first_read_pass);
                return first_pass;
            }

            bool is_disjoint_with(const range& other) const {
                if (!is_used() || !other.is_used())
                    return false;
                if (!can_alias() || !other.can_alias())
                    return false;

                bool left = last_used_pass() < other.first_used_pass();
                bool right = other.last_used_pass() < first_used_pass();
                return left || right;
            }
        };

        // Look at what range of render passes each resource is used in
        std::unordered_map<std::string, range> resource_used_range;
        std::vector<std::string> resources_in_order;

        uint32_t pass_idx = 0;
        for(const auto& pass : passes) {
            if(pass.texture_inputs) {
                for(const auto &input : pass.texture_inputs.value()) {
                    auto& tex_range = resource_used_range[input];

                    if(pass_idx < tex_range.first_write_pass) {
                        tex_range.first_write_pass = pass_idx;

                    } else if(pass_idx > tex_range.last_write_pass) {
                        tex_range.last_write_pass = pass_idx;
                    }

                    if(std::find(resources_in_order.begin(), resources_in_order.end(), input) == resources_in_order.end()) {
                        resources_in_order.push_back(input);
                    }
                }
            }

            if(pass.texture_outputs) {
                for(const auto &output : pass.texture_outputs.value()) {
                    auto& tex_range = resource_used_range[output];

                    if(pass_idx < tex_range.first_write_pass) {
                        tex_range.first_write_pass = pass_idx;

                    } else if(pass_idx > tex_range.last_write_pass) {
                        tex_range.last_write_pass = pass_idx;
                    }

                    if(std::find(resources_in_order.begin(), resources_in_order.end(), output) == resources_in_order.end()) {
                        resources_in_order.push_back(output);
                    }
                }
            }

            pass_idx++;
        }

        LOG(INFO) << "Ordered resources";

        // Figure out which resources can be aliased
        std::unordered_map<std::string, std::string> aliases;

        for(size_t i = 0; i < resources_in_order.size(); i++) {
            const auto& to_alias_name = resources_in_order[i];
            LOG(INFO) << "Determining if we can alias `" << to_alias_name << "`. Does it exist? " << (textures.find(to_alias_name) != textures.end());
            const auto& to_alias_format = textures.at(to_alias_name).format;

            // Only try to alias with lower-indexed resources
            for(size_t j = 0; j < i; j++) {
                LOG(INFO) << "Trying to alias it with rexource at index " << j << " out of " << resources_in_order.size();
                const auto& try_alias_name = resources_in_order[j];
                if(resource_used_range[to_alias_name].is_disjoint_with(resource_used_range[try_alias_name])) {
                    // They can be aliased if they have the same format
                    const auto& try_alias_format = textures.at(try_alias_name).format;
                    if(to_alias_format == try_alias_format) {
                        aliases[to_alias_name] = try_alias_name;
                    }
                }
            }
        }

        LOG(INFO) << "Figured out which resources can be aliased";

        auto swapchain_dimensions = swapchain->get_swapchain_extent();

        // For each texture:
        //  - If it isn't in the aliases map, create a new texture with its format and add it to the textures map
        //  - If it is in the aliases map, follow its chain of aliases

        for(const auto& named_texture : textures) {
            std::string texture_name = named_texture.first;
            while(aliases.find(texture_name) != aliases.end()) {
                LOG(INFO) << "Resource " << texture_name << " is aliased with " << aliases[texture_name];
                texture_name = aliases[texture_name];
            }

            // We've found the first texture in this alias chain - let's create an actual texture for it if needed
            if(dynamic_tex_name_to_idx.find(texture_name) == dynamic_tex_name_to_idx.end()) {
                LOG(INFO) << "Need to create it";
                // The texture we're all aliasing doesn't have a real texture yet. Let's fix that
                const texture_format& format = textures.at(texture_name).format;

                vk::Extent2D dimensions;
                if(format.dimension_type == texture_dimension_type_enum::Absolute) {
                    dimensions = vk::Extent2D{static_cast<uint32_t>(format.width), static_cast<uint32_t>(format.height)};

                } else {
                    dimensions = swapchain_dimensions;
                    dimensions.width *= format.width;
                    dimensions.height *= format.height;
                }

                auto pixel_format = get_vk_format_from_pixel_format(format.pixel_format);
                auto tex = texture2D{dimensions, pixel_format, context};

                auto new_tex_index = dynamic_textures.size();
                dynamic_textures.push_back(tex);
                dynamic_tex_name_to_idx[texture_name] = new_tex_index;
                //dynamic_tex_name_to_idx[named_texture.first] = new_tex_index;

                LOG(INFO) << "Added texture " << tex.get_name() << " to the dynamic textures";
                LOG(INFO) << "set dynamic_texture_to_idx[" << texture_name << "] = " << new_tex_index;
                //LOG(INFO) << "dynamic_texture_to_idx[" << named_texture.first << "] = " << new_tex_index;

            } else {
                LOG(INFO) << "The physical resource already exists, so we're just gonna use that";
                // The texture we're aliasing already has a real texture behind it - so let's use that
                dynamic_tex_name_to_idx[named_texture.first] = dynamic_tex_name_to_idx[texture_name];
            }
        }
    }

    void texture_manager::clear_dynamic_textures() {
        LOG(INFO) << "Cleared dynamic textures";
        dynamic_textures.resize(0);
        dynamic_tex_name_to_idx.erase(dynamic_tex_name_to_idx.begin(), dynamic_tex_name_to_idx.end());
    }

    bool texture_manager::is_texture_known(const std::string &texture_name) const {
        if(atlases.find(texture_name) != atlases.end()) {
            return true;
        }

        return dynamic_tex_name_to_idx.find(texture_name) != dynamic_tex_name_to_idx.end();

    }

    vk::Format get_vk_format_from_pixel_format(pixel_format_enum format) {
        switch(format) {
            case pixel_format_enum::RGB8:
                return vk::Format::eR8G8B8Unorm;
            case pixel_format_enum::RGBA8:
                return vk::Format::eR8G8B8A8Unorm;
            case pixel_format_enum::RGB16F:
                return vk::Format::eR16G16B16Sfloat;
            case pixel_format_enum::RGBA16F:
                return vk::Format::eR16G16B16A16Sfloat;
            case pixel_format_enum::RGB32F:
                return vk::Format::eR32G32B32Sfloat;
            case pixel_format_enum::RGBA32F:
                return vk::Format::eR32G32B32A32Sfloat;
            case pixel_format_enum::Depth:
                return vk::Format::eD32Sfloat;
            case pixel_format_enum::DepthStencil:
                return vk::Format::eD24UnormS8Uint;
            default:
                LOG(WARNING) << "Could not determine Vulkan format for pixel format " << pixel_format_enum::to_string(format);
                return vk::Format::eR8G8B8Unorm;
        }
    }
}
<commit_msg>No more flickering or bad spelling<commit_after>/*!
 * \author David
 * \date 29-Apr-16.
 */

#include <algorithm>
#include <cmath>
#include <easylogging++.h>
#include "texture_manager.h"
#include "../../vulkan/render_context.h"
#include "../../../mc_interface/mc_objects.h"

namespace nova {
    texture_manager::texture_manager(std::shared_ptr<render_context> context) : context(context) {
        LOG(INFO) << "Creating the Texture Manager";
        reset();
        LOG(INFO) << "Texture manager created";
    }

    texture_manager::~texture_manager() {
        // gotta free up all the Vulkan textures
        reset();
    }

    void texture_manager::reset() {
        if(!atlases.empty()) {
            // Nothing to deallocate, let's just return
            return;
        }

        for(auto& tex : atlases) {
            tex.second.destroy();
        }

        atlases.clear();
        locations.clear();

        atlases["lightmap"] = texture2D(vk::Extent2D{16, 16}, vk::Format::eR8G8B8A8Unorm, context);
        atlases["lightmap"].set_name("lightmap");
        LOG(INFO) << "Created lightmap";

        clear_dynamic_textures();
    }

    void texture_manager::add_texture(mc_atlas_texture &new_texture) {
        LOG(INFO) << "Adding texture " << new_texture.name << " (" << new_texture.width << "x" << new_texture.height << ")";
        std::string texture_name = new_texture.name;
        LOG(TRACE) << "Saved texture name";
        auto dimensions = vk::Extent2D{new_texture.width, new_texture.height};
        texture2D texture{dimensions, vk::Format::eR8G8B8A8Unorm, context};
        LOG(TRACE) << "Created texture object";
        texture.set_name(texture_name);

        std::vector<uint8_t> pixel_data((std::size_t) (new_texture.width * new_texture.height * new_texture.num_components));
        for(uint32_t i = 0; i < new_texture.width * new_texture.height * new_texture.num_components; i++) {
            pixel_data[i] = (uint8_t) new_texture.texture_data[i];
        }

        LOG(TRACE) << "Added pixel data to buffer";

        texture.set_data(pixel_data.data(), dimensions);

        LOG(TRACE) << "Sent texture data to GPU";

        atlases[texture_name] = texture;
        LOG(DEBUG) << "Texture atlas " << texture_name << " is Vulkan texture " << texture.get_vk_image();
    }

    void texture_manager::add_texture_location(mc_texture_atlas_location &location) {
        texture_location tex_loc = {
                { location.min_u, location.min_v },
                { location.max_u, location.max_v }
        };

        locations[location.name] = tex_loc;
    }

    const texture_manager::texture_location texture_manager::get_texture_location(const std::string &texture_name) {
        // If we haven't explicitly added a texture location for this texture, let's just assume that the texture isn't
        // in an atlas and thus covers the whole (0 - 1) UV space

        if(locations.find(texture_name) != locations.end()) {
            return locations[texture_name];

        } else {
            return {{0, 0}, {1, 1}};
        }
    }

    texture2D &texture_manager::get_texture(std::string texture_name) {
        if(atlases.find(texture_name) != atlases.end()) {
            return atlases.at(texture_name);
        }

        LOG(INFO) << "Checking if texture " << texture_name << " is in the dynamic textures. There's " << dynamic_tex_name_to_idx.size() << " dynamic textures, it should be one of them";
        if(dynamic_tex_name_to_idx.find(texture_name) != dynamic_tex_name_to_idx.end()) {
            auto idx = dynamic_tex_name_to_idx.at(texture_name);
            if(dynamic_textures.size() > idx) {
                return dynamic_textures.at(idx);
            }
        }

        LOG(ERROR) << "Could not find texture " << texture_name;
        throw std::domain_error("Could not find texture " + texture_name);
    }

    int texture_manager::get_max_texture_size() {
        if(max_texture_size < 0) {
            max_texture_size = context->gpu.props.limits.maxImageDimension2D;

			LOG(DEBUG) << "max texturesize reported by gpu: " << max_texture_size;
        }
        return max_texture_size;
    }

    // Implementation based on RenderGraph::build_aliases from the Granite engine
    void texture_manager::create_dynamic_textures(const std::unordered_map<std::string, texture_resource> &textures,
                                                  const std::vector<render_pass> &passes, std::shared_ptr<swapchain_manager> swapchain) {
        // For each texture in the passes, try to assign it to an existing resource
        // We'll basically create a list of which texture resources can be assigned to each physical resource
        // We want to alias textures. We can alias texture A and B if all reads from A finish before all writes to B AND
        // if A and B have the same format and dimension
        // Maybe we should make a list of things with the same format and dimension?

        clear_dynamic_textures();

        struct range {
            uint32_t first_write_pass = ~0u;
            uint32_t last_write_pass = 0;
            uint32_t first_read_pass = ~0u;
            uint32_t last_read_pass = 0;

            bool has_writer() const
            {
                return first_write_pass <= last_write_pass;
            }

            bool has_reader() const
            {
                return first_read_pass <= last_read_pass;
            }

            bool is_used() const
            {
                return has_writer() || has_reader();
            }

            bool can_alias() const
            {
                // If we read before we have completely written to a resource we need to preserve it, so no alias is possible.
                return !(has_reader() && has_writer() && first_read_pass <= first_write_pass);
            }

            unsigned last_used_pass() const
            {
                unsigned last_pass = 0;
                if (has_writer())
                    last_pass = std::max(last_pass, last_write_pass);
                if (has_reader())
                    last_pass = std::max(last_pass, last_read_pass);
                return last_pass;
            }

            unsigned first_used_pass() const
            {
                unsigned first_pass = ~0u;
                if (has_writer())
                    first_pass = std::min(first_pass, first_write_pass);
                if (has_reader())
                    first_pass = std::min(first_pass, first_read_pass);
                return first_pass;
            }

            bool is_disjoint_with(const range& other) const {
                if (!is_used() || !other.is_used())
                    return false;
                if (!can_alias() || !other.can_alias())
                    return false;

                bool left = last_used_pass() < other.first_used_pass();
                bool right = other.last_used_pass() < first_used_pass();
                return left || right;
            }
        };

        // Look at what range of render passes each resource is used in
        std::unordered_map<std::string, range> resource_used_range;
        std::vector<std::string> resources_in_order;

        uint32_t pass_idx = 0;
        for(const auto& pass : passes) {
            if(pass.texture_inputs) {
                for(const auto &input : pass.texture_inputs.value()) {
                    auto& tex_range = resource_used_range[input];

                    if(pass_idx < tex_range.first_write_pass) {
                        tex_range.first_write_pass = pass_idx;

                    } else if(pass_idx > tex_range.last_write_pass) {
                        tex_range.last_write_pass = pass_idx;
                    }

                    if(std::find(resources_in_order.begin(), resources_in_order.end(), input) == resources_in_order.end()) {
                        resources_in_order.push_back(input);
                    }
                }
            }

            if(pass.texture_outputs) {
                for(const auto &output : pass.texture_outputs.value()) {
                    auto& tex_range = resource_used_range[output];

                    if(pass_idx < tex_range.first_write_pass) {
                        tex_range.first_write_pass = pass_idx;

                    } else if(pass_idx > tex_range.last_write_pass) {
                        tex_range.last_write_pass = pass_idx;
                    }

                    if(std::find(resources_in_order.begin(), resources_in_order.end(), output) == resources_in_order.end()) {
                        resources_in_order.push_back(output);
                    }
                }
            }

            pass_idx++;
        }

        LOG(INFO) << "Ordered resources";

        // Figure out which resources can be aliased
        std::unordered_map<std::string, std::string> aliases;

        for(size_t i = 0; i < resources_in_order.size(); i++) {
            const auto& to_alias_name = resources_in_order[i];
            LOG(INFO) << "Determining if we can alias `" << to_alias_name << "`. Does it exist? " << (textures.find(to_alias_name) != textures.end());
            const auto& to_alias_format = textures.at(to_alias_name).format;

            // Only try to alias with lower-indexed resources
            for(size_t j = 0; j < i; j++) {
                LOG(INFO) << "Trying to alias it with rexource at index " << j << " out of " << resources_in_order.size();
                const auto& try_alias_name = resources_in_order[j];
                if(resource_used_range[to_alias_name].is_disjoint_with(resource_used_range[try_alias_name])) {
                    // They can be aliased if they have the same format
                    const auto& try_alias_format = textures.at(try_alias_name).format;
                    if(to_alias_format == try_alias_format) {
                        aliases[to_alias_name] = try_alias_name;
                    }
                }
            }
        }

        LOG(INFO) << "Figured out which resources can be aliased";

        auto swapchain_dimensions = swapchain->get_swapchain_extent();

        // For each texture:
        //  - If it isn't in the aliases map, create a new texture with its format and add it to the textures map
        //  - If it is in the aliases map, follow its chain of aliases

        for(const auto& named_texture : textures) {
            std::string texture_name = named_texture.first;
            while(aliases.find(texture_name) != aliases.end()) {
                LOG(INFO) << "Resource " << texture_name << " is aliased with " << aliases[texture_name];
                texture_name = aliases[texture_name];
            }

            // We've found the first texture in this alias chain - let's create an actual texture for it if needed
            if(dynamic_tex_name_to_idx.find(texture_name) == dynamic_tex_name_to_idx.end()) {
                LOG(INFO) << "Need to create it";
                // The texture we're all aliasing doesn't have a real texture yet. Let's fix that
                const texture_format& format = textures.at(texture_name).format;

                vk::Extent2D dimensions;
                if(format.dimension_type == texture_dimension_type_enum::Absolute) {
                    dimensions = vk::Extent2D{static_cast<uint32_t>(format.width), static_cast<uint32_t>(format.height)};

                } else {
                    dimensions = swapchain_dimensions;
                    dimensions.width *= format.width;
                    dimensions.height *= format.height;
                }

                auto pixel_format = get_vk_format_from_pixel_format(format.pixel_format);
                auto tex = texture2D{dimensions, pixel_format, context};

                auto new_tex_index = dynamic_textures.size();
                dynamic_textures.push_back(tex);
                dynamic_tex_name_to_idx[texture_name] = new_tex_index;
                //dynamic_tex_name_to_idx[named_texture.first] = new_tex_index;

                LOG(INFO) << "Added texture " << tex.get_name() << " to the dynamic textures";
                LOG(INFO) << "set dynamic_texture_to_idx[" << texture_name << "] = " << new_tex_index;
                //LOG(INFO) << "dynamic_texture_to_idx[" << named_texture.first << "] = " << new_tex_index;

            } else {
                LOG(INFO) << "The physical resource already exists, so we're just gonna use that";
                // The texture we're aliasing already has a real texture behind it - so let's use that
                dynamic_tex_name_to_idx[named_texture.first] = dynamic_tex_name_to_idx[texture_name];
            }
        }
    }

    void texture_manager::clear_dynamic_textures() {
        LOG(INFO) << "Cleared dynamic textures";
        dynamic_textures.resize(0);
        dynamic_tex_name_to_idx.erase(dynamic_tex_name_to_idx.begin(), dynamic_tex_name_to_idx.end());
    }

    bool texture_manager::is_texture_known(const std::string &texture_name) const {
        if(atlases.find(texture_name) != atlases.end()) {
            return true;
        }

        return dynamic_tex_name_to_idx.find(texture_name) != dynamic_tex_name_to_idx.end();
    }

    vk::Format get_vk_format_from_pixel_format(pixel_format_enum format) {
        switch(format) {
            case pixel_format_enum::RGB8:
                return vk::Format::eR8G8B8Unorm;
            case pixel_format_enum::RGBA8:
                return vk::Format::eR8G8B8A8Unorm;
            case pixel_format_enum::RGB16F:
                return vk::Format::eR16G16B16Sfloat;
            case pixel_format_enum::RGBA16F:
                return vk::Format::eR16G16B16A16Sfloat;
            case pixel_format_enum::RGB32F:
                return vk::Format::eR32G32B32Sfloat;
            case pixel_format_enum::RGBA32F:
                return vk::Format::eR32G32B32A32Sfloat;
            case pixel_format_enum::Depth:
                return vk::Format::eD32Sfloat;
            case pixel_format_enum::DepthStencil:
                return vk::Format::eD24UnormS8Uint;
            default:
                LOG(WARNING) << "Could not determine Vulkan format for pixel format " << pixel_format_enum::to_string(format);
                return vk::Format::eR8G8B8Unorm;
        }
    }
}
<|endoftext|>


<commit_before>#include "include/udata.h"
#include "include/amici_model.h"
#include <cstdio>
#include <cstring>

UserData::UserData()
{
    init();
}

int UserData::unscaleParameters(const Model *model, double *bufferUnscaled) const
{
    switch(pscale) {
        case AMICI_SCALING_LOG10:
            for(int ip = 0; ip < model->np; ++ip) {
                bufferUnscaled[ip] = pow(10, p[ip]);
            }
            break;
        case AMICI_SCALING_LN:
            for(int ip = 0; ip < model->np; ++ip)
                bufferUnscaled[ip] = exp(p[ip]);
            break;
        case AMICI_SCALING_NONE:
            break;
    }

    return AMICI_SUCCESS;
}

UserData::~UserData()
{
    if(qpositivex) delete[] qpositivex;
    if(p) delete[] p;
    if(k) delete[] k;
    if(ts) delete[] ts;
    if(pbar) delete[] pbar;
    if(xbar) delete[] xbar;
    if(x0data) delete[] x0data;
    if(sx0data) delete[] sx0data;
    if(plist) delete[] plist;
}

void UserData::init()
{
    qpositivex = NULL;
    plist = NULL;
    nplist = 0;
    nt = 0;
    p = NULL;
    k = NULL;
    ts = NULL;
    tstart = 0;
    pbar = NULL;
    xbar = NULL;
    sensi = AMICI_SENSI_ORDER_NONE;
    atol = 1e-16;
    rtol = 1e-8;
    maxsteps = 0;
    newton_maxsteps = 0;
    newton_maxlinsteps = 0;
    ism = 1;
    nmaxevent = 10;

    sensi_meth = AMICI_SENSI_FSA;
    linsol = 9;
    interpType = 1;
    lmm = 2;
    iter = 2;
    stldet = true;
    x0data = NULL;

    sx0data = NULL;
    ordering = 0;

}

void UserData::print()
{
    printf("qpositivex: %p\n", qpositivex);
    printf("plist: %p\n", plist);
    printf("nplist: %d\n", nplist);
    printf("nt: %d\n", nt);
    printf("nmaxevent: %d\n", nmaxevent);
    printf("p: %p\n", p);
    printf("k: %p\n", k);
    printf("tstart: %e\n", tstart);
    printf("ts: %p\n", ts);
    printf("pbar: %p\n", pbar);
    printf("xbar: %p\n", xbar);
    printf("sensi: %d\n", sensi);
    printf("atol: %e\n", atol);
    printf("rtol: %e\n", rtol);
    printf("maxsteps: %d\n", maxsteps);
    printf("newton_maxsteps: %d\n", newton_maxsteps);
    printf("newton_maxlinsteps: %d\n", newton_maxlinsteps);
    printf("ism: %d\n", ism);
    printf("sensi_meth: %d\n", sensi_meth);
    printf("linsol: %d\n", linsol);
    printf("interpType: %d\n", interpType);
    printf("lmm: %d\n", lmm);
    printf("iter: %d\n", iter);
    printf("stldet: %d\n", stldet);
    printf("x0data: %p\n", x0data);
    printf("sx0data: %p\n", sx0data);
    printf("ordering: %d\n", ordering);
}
<commit_msg>Fix: parameters were not copied to TempData with AMICI_SCALING_NONE<commit_after>#include "include/udata.h"
#include "include/amici_model.h"
#include <cstdio>
#include <cstring>

UserData::UserData()
{
    init();
}

int UserData::unscaleParameters(const Model *model, double *bufferUnscaled) const
{
    switch(pscale) {
        case AMICI_SCALING_LOG10:
            for(int ip = 0; ip < model->np; ++ip) {
                bufferUnscaled[ip] = pow(10, p[ip]);
            }
            break;
        case AMICI_SCALING_LN:
            for(int ip = 0; ip < model->np; ++ip)
                bufferUnscaled[ip] = exp(p[ip]);
            break;
        case AMICI_SCALING_NONE:
            for(int ip = 0; ip < model->np; ++ip)
                bufferUnscaled[ip] = p[ip];
            break;
    }

    return AMICI_SUCCESS;
}

UserData::~UserData()
{
    if(qpositivex) delete[] qpositivex;
    if(p) delete[] p;
    if(k) delete[] k;
    if(ts) delete[] ts;
    if(pbar) delete[] pbar;
    if(xbar) delete[] xbar;
    if(x0data) delete[] x0data;
    if(sx0data) delete[] sx0data;
    if(plist) delete[] plist;
}

void UserData::init()
{
    qpositivex = NULL;
    plist = NULL;
    nplist = 0;
    nt = 0;
    p = NULL;
    k = NULL;
    ts = NULL;
    tstart = 0;
    pbar = NULL;
    xbar = NULL;
    sensi = AMICI_SENSI_ORDER_NONE;
    atol = 1e-16;
    rtol = 1e-8;
    maxsteps = 0;
    newton_maxsteps = 0;
    newton_maxlinsteps = 0;
    ism = 1;
    nmaxevent = 10;

    sensi_meth = AMICI_SENSI_FSA;
    linsol = 9;
    interpType = 1;
    lmm = 2;
    iter = 2;
    stldet = true;
    x0data = NULL;

    sx0data = NULL;
    ordering = 0;

}

void UserData::print()
{
    printf("qpositivex: %p\n", qpositivex);
    printf("plist: %p\n", plist);
    printf("nplist: %d\n", nplist);
    printf("nt: %d\n", nt);
    printf("nmaxevent: %d\n", nmaxevent);
    printf("p: %p\n", p);
    printf("k: %p\n", k);
    printf("tstart: %e\n", tstart);
    printf("ts: %p\n", ts);
    printf("pbar: %p\n", pbar);
    printf("xbar: %p\n", xbar);
    printf("sensi: %d\n", sensi);
    printf("atol: %e\n", atol);
    printf("rtol: %e\n", rtol);
    printf("maxsteps: %d\n", maxsteps);
    printf("newton_maxsteps: %d\n", newton_maxsteps);
    printf("newton_maxlinsteps: %d\n", newton_maxlinsteps);
    printf("ism: %d\n", ism);
    printf("sensi_meth: %d\n", sensi_meth);
    printf("linsol: %d\n", linsol);
    printf("interpType: %d\n", interpType);
    printf("lmm: %d\n", lmm);
    printf("iter: %d\n", iter);
    printf("stldet: %d\n", stldet);
    printf("x0data: %p\n", x0data);
    printf("sx0data: %p\n", sx0data);
    printf("ordering: %d\n", ordering);
}
<|endoftext|>


<commit_before>/*
 * StochasticReleaseTestProbe.cpp
 *
 *  Created on: Aug 28, 2013
 *      Author: pschultz
 */

#include "StochasticReleaseTestProbe.hpp"

namespace PV {

StochasticReleaseTestProbe::StochasticReleaseTestProbe(const char * name, HyPerCol * hc) {
   initialize_base();
   initStochasticReleaseTestProbe(name, hc);
}

StochasticReleaseTestProbe::StochasticReleaseTestProbe() {
   initialize_base();
}

int StochasticReleaseTestProbe::initialize_base() {
   conn = NULL;
   for (int k=0; k<8; k++) {
      bins[k] = 0;
   }
   sumbins = 0;
   binprobs[0] = 0.00023262907903552502; // erfc(3.5/sqrt(2))/2
   binprobs[1] = 0.005977036246740614; // (erfc(2.5/sqrt(2))-erfc(3.5/sqrt(2)))/2
   binprobs[2] = 0.06059753594308195; // (erfc(1.5/sqrt(2))-erfc(2.5/sqrt(2)))/2
   binprobs[3] = 0.24173033745712885; // (erfc(0.5/sqrt(2))-erfc(1.5/sqrt(2)))/2
   binprobs[4] = 0.3829249225480262; // erf(0.5/sqrt(2)
   binprobs[5] = 0.24173033745712885; // (erfc(0.5/sqrt(2))-erfc(1.5/sqrt(2)))/2
   binprobs[6] = 0.06059753594308195; // (erfc(1.5/sqrt(2))-erfc(2.5/sqrt(2)))/2
   binprobs[7] = 0.005977036246740614; // (erfc(2.5/sqrt(2))-erfc(3.5/sqrt(2)))/2
   binprobs[8] = 0.00023262907903552502; // erfc(3.5/sqrt(2))/2
   return PV_SUCCESS;
}

int StochasticReleaseTestProbe::initStochasticReleaseTestProbe(const char * name, HyPerCol * hc) {
   const char * classkeyword = hc->parameters()->groupKeywordFromName(name);
   HyPerLayer * targetlayer = NULL;
   char * message = NULL;
   const char * filename;
   getLayerFunctionProbeParameters(name, classkeyword, hc, &targetlayer, &message, &filename);
   int status = initStatsProbe(filename, targetlayer, BufActivity, message);

   const int numconns = hc->numberOfConnections();
   for (int c=0; c<numconns; c++) {
      if (!strcmp(hc->getConnection(c)->getPostLayerName(),getTargetLayer()->getName())) {
         assert(conn==NULL);
         conn = hc->getConnection(c);
      }
   }
   assert(conn!=NULL);
   return PV_SUCCESS;
}

int StochasticReleaseTestProbe::outputState(double timed) {
   int status = StatsProbe::outputState(timed);
   assert(status==PV_SUCCESS);

   assert(conn->numberOfAxonalArborLists()==1);
   assert(conn->getNumDataPatches()==1);
   assert(conn->xPatchSize()==1);
   assert(conn->yPatchSize()==1);
   assert(conn->fPatchSize()==1);
   pvdata_t wgt = *conn->get_wDataStart(0);
   HyPerLayer * pre = conn->preSynapticLayer();
   const pvdata_t * preactPtr = pre->getLayerData();
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const int numPreNeurons = pre->getNumNeurons();
   bool found=false;
   pvdata_t preact = 0.0f;
   for (int n=0; n<numPreNeurons; n++) {
      int nExt = kIndexExtended(n, preLoc->nx, preLoc->ny, preLoc->nf, preLoc->nb);
      pvdata_t a = preactPtr[nExt];
      if (a!=0.0f) {
         if (found) {
            assert(preact==a);
         }
         else {
            found = true;
            preact = a;
         }
      }
   }
   if (preact < 0.0f) preact = 0.0f;
   if (preact > 1.0f) preact = 1.0f;

   const int numNeurons = getTargetLayer()->getNumNeurons();
   const PVLayerLoc * loc = getTargetLayer()->getLayerLoc();
   const pvdata_t * activity = getTargetLayer()->getLayerData();
   for (int n=0; n<numNeurons; n++) {
      int nExt = kIndexExtended(n, loc->nx, loc->ny, loc->nf, loc->nb);
      assert(activity[nExt]==0 || activity[nExt]==wgt);
   }
   double mean = preact * numNeurons;
   double stddev = sqrt(numNeurons*preact*(1-preact));
   double numStdDevs = stddev==0.0 && mean==nnz ? 0.0 : (nnz-mean)/stddev;
   HyPerCol * hc = getTargetLayer()->getParent();
   if (timed>0.0 && hc->columnId()==0) {
      fprintf(outputstream->fp, "    t=%f, number of standard deviations = %f\n", timed, numStdDevs);
      int bin = numStdDevs < -3.5 ? 0 :
                numStdDevs < -2.5 ? 1 :
                numStdDevs < -1.5 ? 2 :
                numStdDevs < -0.5 ? 3 :
                numStdDevs <= 0.5 ? 4 :
                numStdDevs <= 1.5 ? 5 :
                numStdDevs <= 2.5 ? 6 :
                numStdDevs <= 3.5 ? 7 : 8;
      bins[bin]++;
      sumbins++;
      if (hc->simulationTime()+hc->getDeltaTime()>=hc->getStopTime()) {
         fprintf(outputstream->fp, "    Histogram:  ");
         for (int k=0; k<9; k++) {
            fprintf(outputstream->fp, " %7d", bins[k]);
         }
         fprintf(outputstream->fp, "\n");

         int minallowed[9];
         int maxallowed[9];

         if (stddev==0) {
            for (int k=0; k<9; k++) {
               minallowed[k] = (k==4 ? sumbins : 0);
               maxallowed[k] = (k==4 ? sumbins : 0);
               assert(bins[k]==(k==4 ? sumbins : 0));
            }
         }
         else {
            assert(preact<1.0f && preact>0.0f);
            for (int k=0; k<9; k++) {
               // find first m for which prob(bins[k]<m) >= 0.005
               double p = binprobs[k];
               double outcomeprob = pow(1-p,sumbins);
               double cumulativeprob = outcomeprob;
               double m=0;
               printf("m=%10.4f, outcomeprob=%.20f, cumulativeprob=%.20f\n", m, outcomeprob, cumulativeprob);
               while(cumulativeprob < 0.005 && m <= sumbins) {
                  m++;
                  outcomeprob *= (sumbins+1-m)/m*p/(1-p);
                  cumulativeprob += outcomeprob;
                  printf("m=%10.4f, outcomeprob=%.20f, cumulativeprob=%.20f\n", m, outcomeprob, cumulativeprob);
               }
               minallowed[k] = m;
               if (bins[k]<minallowed[k]) status = PV_FAILURE;

               // find first m for which prob(bins[k]<m) < 0.995
               while(cumulativeprob <= 0.995 && sumbins) {
                  m++;
                  outcomeprob *= (sumbins+1-m)/m*p/(1-p);
                  cumulativeprob += outcomeprob;
                  printf("m=%10.4f, outcomeprob=%.20f, cumulativeprob=%.20f\n", m, outcomeprob, cumulativeprob);
               }
               maxallowed[k] = m;
               if (bins[k]>maxallowed[k]) status = PV_FAILURE;
            }
            fprintf(outputstream->fp, "    Min allowed:");
            for (int k=0; k<9; k++) {
               fprintf(outputstream->fp, " %7d", minallowed[k]);
            }
            fprintf(outputstream->fp, "\n");
            fprintf(outputstream->fp, "    Max allowed:");
            for (int k=0; k<9; k++) {
               fprintf(outputstream->fp, " %7d", maxallowed[k]);
            }
            fprintf(outputstream->fp, "\n");
            assert(status==PV_SUCCESS);
         }
      }
   }
   return status;
}

StochasticReleaseTestProbe::~StochasticReleaseTestProbe() {
}

} /* namespace PV */
<commit_msg>Fix a bug in StochasticReleaseTestProbe that confused getNumNeurons with getNumGlobalNeurons<commit_after>/*
 * StochasticReleaseTestProbe.cpp
 *
 *  Created on: Aug 28, 2013
 *      Author: pschultz
 */

#include "StochasticReleaseTestProbe.hpp"

namespace PV {

StochasticReleaseTestProbe::StochasticReleaseTestProbe(const char * name, HyPerCol * hc) {
   initialize_base();
   initStochasticReleaseTestProbe(name, hc);
}

StochasticReleaseTestProbe::StochasticReleaseTestProbe() {
   initialize_base();
}

int StochasticReleaseTestProbe::initialize_base() {
   conn = NULL;
   for (int k=0; k<8; k++) {
      bins[k] = 0;
   }
   sumbins = 0;
   binprobs[0] = 0.00023262907903552502; // erfc(3.5/sqrt(2))/2
   binprobs[1] = 0.005977036246740614; // (erfc(2.5/sqrt(2))-erfc(3.5/sqrt(2)))/2
   binprobs[2] = 0.06059753594308195; // (erfc(1.5/sqrt(2))-erfc(2.5/sqrt(2)))/2
   binprobs[3] = 0.24173033745712885; // (erfc(0.5/sqrt(2))-erfc(1.5/sqrt(2)))/2
   binprobs[4] = 0.3829249225480262; // erf(0.5/sqrt(2)
   binprobs[5] = 0.24173033745712885; // (erfc(0.5/sqrt(2))-erfc(1.5/sqrt(2)))/2
   binprobs[6] = 0.06059753594308195; // (erfc(1.5/sqrt(2))-erfc(2.5/sqrt(2)))/2
   binprobs[7] = 0.005977036246740614; // (erfc(2.5/sqrt(2))-erfc(3.5/sqrt(2)))/2
   binprobs[8] = 0.00023262907903552502; // erfc(3.5/sqrt(2))/2
   return PV_SUCCESS;
}

int StochasticReleaseTestProbe::initStochasticReleaseTestProbe(const char * name, HyPerCol * hc) {
   const char * classkeyword = hc->parameters()->groupKeywordFromName(name);
   HyPerLayer * targetlayer = NULL;
   char * message = NULL;
   const char * filename;
   getLayerFunctionProbeParameters(name, classkeyword, hc, &targetlayer, &message, &filename);
   int status = initStatsProbe(filename, targetlayer, BufActivity, message);

   const int numconns = hc->numberOfConnections();
   for (int c=0; c<numconns; c++) {
      if (!strcmp(hc->getConnection(c)->getPostLayerName(),getTargetLayer()->getName())) {
         assert(conn==NULL);
         conn = hc->getConnection(c);
      }
   }
   assert(conn!=NULL);
   return PV_SUCCESS;
}

int StochasticReleaseTestProbe::outputState(double timed) {
   int status = StatsProbe::outputState(timed);
   assert(status==PV_SUCCESS);

   assert(conn->numberOfAxonalArborLists()==1);
   assert(conn->getNumDataPatches()==1);
   assert(conn->xPatchSize()==1);
   assert(conn->yPatchSize()==1);
   assert(conn->fPatchSize()==1);
   pvdata_t wgt = *conn->get_wDataStart(0);
   HyPerLayer * pre = conn->preSynapticLayer();
   const pvdata_t * preactPtr = pre->getLayerData();
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const int numPreNeurons = pre->getNumNeurons();
   bool found=false;
   pvdata_t preact = 0.0f;
   for (int n=0; n<numPreNeurons; n++) {
      int nExt = kIndexExtended(n, preLoc->nx, preLoc->ny, preLoc->nf, preLoc->nb);
      pvdata_t a = preactPtr[nExt];
      if (a!=0.0f) {
         if (found) {
            assert(preact==a);
         }
         else {
            found = true;
            preact = a;
         }
      }
   }
   if (preact < 0.0f) preact = 0.0f;
   if (preact > 1.0f) preact = 1.0f;

   const int numNeurons = getTargetLayer()->getNumNeurons();
   const PVLayerLoc * loc = getTargetLayer()->getLayerLoc();
   const pvdata_t * activity = getTargetLayer()->getLayerData();
   for (int n=0; n<numNeurons; n++) {
      int nExt = kIndexExtended(n, loc->nx, loc->ny, loc->nf, loc->nb);
      assert(activity[nExt]==0 || activity[nExt]==wgt);
   }
   const int numGlobalNeurons = getTargetLayer()->getNumGlobalNeurons();
   double mean = preact * numGlobalNeurons;
   double stddev = sqrt(numGlobalNeurons*preact*(1-preact));
   double numStdDevs = stddev==0.0 && mean==nnz ? 0.0 : (nnz-mean)/stddev;
   HyPerCol * hc = getTargetLayer()->getParent();
   if (timed>0.0 && hc->columnId()==0) {
      fprintf(outputstream->fp, "    t=%f, number of standard deviations = %f\n", timed, numStdDevs);
      int bin = numStdDevs < -3.5 ? 0 :
                numStdDevs < -2.5 ? 1 :
                numStdDevs < -1.5 ? 2 :
                numStdDevs < -0.5 ? 3 :
                numStdDevs <= 0.5 ? 4 :
                numStdDevs <= 1.5 ? 5 :
                numStdDevs <= 2.5 ? 6 :
                numStdDevs <= 3.5 ? 7 : 8;
      bins[bin]++;
      sumbins++;
      if (hc->simulationTime()+hc->getDeltaTime()>=hc->getStopTime()) {
         fprintf(outputstream->fp, "    Histogram:  ");
         for (int k=0; k<9; k++) {
            fprintf(outputstream->fp, " %7d", bins[k]);
         }
         fprintf(outputstream->fp, "\n");

         int minallowed[9];
         int maxallowed[9];

         if (stddev==0) {
            for (int k=0; k<9; k++) {
               minallowed[k] = (k==4 ? sumbins : 0);
               maxallowed[k] = (k==4 ? sumbins : 0);
               assert(bins[k]==(k==4 ? sumbins : 0));
            }
         }
         else {
            assert(preact<1.0f && preact>0.0f);
            for (int k=0; k<9; k++) {
               // find first m for which prob(bins[k]<m) >= 0.005
               double p = binprobs[k];
               double outcomeprob = pow(1-p,sumbins);
               double cumulativeprob = outcomeprob;
               double m=0;
               printf("m=%10.4f, outcomeprob=%.20f, cumulativeprob=%.20f\n", m, outcomeprob, cumulativeprob);
               while(cumulativeprob < 0.005 && m <= sumbins) {
                  m++;
                  outcomeprob *= (sumbins+1-m)/m*p/(1-p);
                  cumulativeprob += outcomeprob;
                  printf("m=%10.4f, outcomeprob=%.20f, cumulativeprob=%.20f\n", m, outcomeprob, cumulativeprob);
               }
               minallowed[k] = m;
               if (bins[k]<minallowed[k]) status = PV_FAILURE;

               // find first m for which prob(bins[k]<m) < 0.995
               while(cumulativeprob <= 0.995 && sumbins) {
                  m++;
                  outcomeprob *= (sumbins+1-m)/m*p/(1-p);
                  cumulativeprob += outcomeprob;
                  printf("m=%10.4f, outcomeprob=%.20f, cumulativeprob=%.20f\n", m, outcomeprob, cumulativeprob);
               }
               maxallowed[k] = m;
               if (bins[k]>maxallowed[k]) status = PV_FAILURE;
            }
            fprintf(outputstream->fp, "    Min allowed:");
            for (int k=0; k<9; k++) {
               fprintf(outputstream->fp, " %7d", minallowed[k]);
            }
            fprintf(outputstream->fp, "\n");
            fprintf(outputstream->fp, "    Max allowed:");
            for (int k=0; k<9; k++) {
               fprintf(outputstream->fp, " %7d", maxallowed[k]);
            }
            fprintf(outputstream->fp, "\n");
            assert(status==PV_SUCCESS);
         }
      }
   }
   return status;
}

StochasticReleaseTestProbe::~StochasticReleaseTestProbe() {
}

} /* namespace PV */
<|endoftext|>


<commit_before>#include "platform_macro.h"
#if defined(TARGET_ARCH_X64)

#include "InstructionRelocation/x64/X64InstructionRelocation.h"

#include <string.h>

#include "dobby_internal.h"

#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h"

#include "core/arch/x64/registers-x64.h"
#include "core/modules/assembler/assembler-x64.h"
#include "core/modules/codegen/codegen-x64.h"

using namespace zz::x64;

static int GenRelocateCodeFixed(void *buffer, AssemblyCodeChunk *origin, AssemblyCodeChunk *relocated) {
  TurboAssembler turbo_assembler_(0);
  // Set fixed executable code chunk address
  turbo_assembler_.SetRealizedAddress((void *)relocated->raw_instruction_start());
#define _ turbo_assembler_.
#define __ turbo_assembler_.GetCodeBuffer()->

  addr64_t curr_orig_ip = origin->raw_instruction_start();
  addr64_t curr_relo_ip = relocated->raw_instruction_start();

  addr_t buffer_cursor = (addr_t)buffer;

  x86_options_t conf = {.mode = 64};

  int predefined_relocate_size = origin->raw_instruction_size();

  while ((buffer_cursor < ((addr_t)buffer + predefined_relocate_size))) {
    int last_relo_offset = turbo_assembler_.GetCodeBuffer()->getSize();

    x86_insn_decode_t insn = {0};
    memset(&insn, 0, sizeof(insn));
    // decode x86 insn
    x86_insn_decode(&insn, (uint8_t *)buffer_cursor, &conf);

    if (insn.primary_opcode >= 0x70 && insn.primary_opcode <= 0x7F) { // jc rel8
      DLOG(1, "[x86 relo] jc rel8, %p", buffer_cursor);

      int8_t orig_offset = insn.immediate;
      int new_offset = (int)(curr_orig_ip + orig_offset - curr_relo_ip);
      uint8_t opcode = 0x80 | (insn.primary_opcode & 0x0f);

      __ Emit8(0x0F);
      __ Emit8(opcode);
      __ Emit32(new_offset);
    } else if (insn.primary_opcode == 0xEB) { // jmp rel8
      DLOG(1, "[x86 relo] jmp rel8, %p", buffer_cursor);

      int8_t orig_offset = insn.immediate;
      int8_t new_offset = (int8_t)(curr_orig_ip + orig_offset - curr_relo_ip);

      __ Emit8(0xE9);
      __ Emit32(new_offset);
    } else if ((insn.flags & X86_INSN_DECODE_FLAG_IP_RELATIVE) && (insn.operands[1].mem.base == RIP)) { // RIP
      DLOG(1, "[x86 relo] rip, %p", buffer_cursor);

      // dword orig_disp = *(dword *)(buffer_cursor + insn.operands[1].mem.disp);
      dword orig_disp = insn.operands[1].mem.disp;
      dword disp = (dword)(curr_orig_ip + orig_disp - curr_relo_ip);

      __ EmitBuffer((void *)buffer_cursor, insn.displacement_offset);
      __ Emit32(disp);
    } else if (insn.primary_opcode == 0xE8 || insn.primary_opcode == 0xE9) { // call or jmp rel32
      DLOG(1, "[x86 relo] jmp or call rel32, %p", buffer_cursor);

      dword orig_offset = insn.immediate;
      dword offset = (dword)(curr_orig_ip + orig_offset - curr_relo_ip);

      __ EmitBuffer((void *)buffer_cursor, insn.immediate_offset);
      __ Emit32(offset);
    } else if (insn.primary_opcode >= 0xE0 && insn.primary_opcode <= 0xE2) { // LOOPNZ/LOOPZ/LOOP/JECXZ
      // LOOP/LOOPcc
      UNIMPLEMENTED();
    } else if (insn.primary_opcode == 0xE3) {
      // JCXZ JCEXZ JCRXZ
      UNIMPLEMENTED();
    } else {
      // Emit the origin instrution
      __ EmitBuffer((void *)buffer_cursor, insn.length);
    }

    // go next
    curr_orig_ip += insn.length;
    buffer_cursor += insn.length;

#if 0
    {
      // 1 orignal instrution => ? relocated instruction
      int relo_offset = turbo_assembler_.GetCodeBuffer()->getSize();
      int relo_len    = relo_offset - last_relo_offset;
      curr_relo_ip += relo_len;
    }
#endif
    curr_relo_ip = relocated->raw_instruction_start() + turbo_assembler_.ip_offset();
  }

  // jmp to the origin rest instructions
  CodeGen codegen(&turbo_assembler_);
  // TODO: 6 == jmp [RIP + disp32] instruction size
  addr64_t stub_addr = curr_relo_ip + 6;
  codegen.JmpNearIndirect(stub_addr);
  turbo_assembler_.GetCodeBuffer()->Emit64(curr_orig_ip);

  // update origin
  int new_origin_len = curr_orig_ip - origin->raw_instruction_start();
  origin->re_init_region_range(origin->raw_instruction_start(), new_origin_len);

  int relo_len = turbo_assembler_.GetCodeBuffer()->getSize();
  if (relo_len > relocated->raw_instruction_size()) {
    DLOG(0, "pre-alloc code chunk not enough");
    return RT_FAILED;
  }

  // Generate executable code
  {
    AssemblyCodeChunk *code = NULL;
    code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_);
    delete code;
  }

  return RT_SUCCESS;
}

void GenRelocateCodeAndBranch(void *buffer, AssemblyCodeChunk *origin, AssemblyCodeChunk *relocated) {
  // pre-alloc code chunk
  AssemblyCodeChunk *cchunk = NULL;

  int relo_code_chunk_size = 32;
  const int chunk_size_step = 16;

x64_try_again:
  if (relocated->raw_instruction_start() == 0) {
    cchunk = MemoryArena::AllocateCodeChunk(relo_code_chunk_size);
    if (cchunk == nullptr) {
      return;
    }
    relocated->re_init_region_range((addr_t)cchunk->address, (int)cchunk->length);
  }

  int ret = GenRelocateCodeFixed(buffer, origin, relocated);
  if (ret != RT_SUCCESS) {
    // free the cchunk
    MemoryArena::Destroy(cchunk);

    relo_code_chunk_size += chunk_size_step;
    relocated->re_init_region_range(0, 0);

    goto x64_try_again;
  }
}

#endif
<commit_msg>[bug-fix] fix x64 relo ip addressing mode less immediate<commit_after>#include "platform_macro.h"
#if defined(TARGET_ARCH_X64)

#include "InstructionRelocation/x64/X64InstructionRelocation.h"

#include <string.h>

#include "dobby_internal.h"

#include "InstructionRelocation/x86/x86_insn_decode/x86_insn_decode.h"

#include "core/arch/x64/registers-x64.h"
#include "core/modules/assembler/assembler-x64.h"
#include "core/modules/codegen/codegen-x64.h"

using namespace zz::x64;

static int GenRelocateCodeFixed(void *buffer, AssemblyCodeChunk *origin, AssemblyCodeChunk *relocated) {
  TurboAssembler turbo_assembler_(0);
  // Set fixed executable code chunk address
  turbo_assembler_.SetRealizedAddress((void *)relocated->raw_instruction_start());
#define _ turbo_assembler_.
#define __ turbo_assembler_.GetCodeBuffer()->

  addr64_t curr_orig_ip = origin->raw_instruction_start();
  addr64_t curr_relo_ip = relocated->raw_instruction_start();

  addr_t buffer_cursor = (addr_t)buffer;

  x86_options_t conf = {.mode = 64};

  int predefined_relocate_size = origin->raw_instruction_size();

  while ((buffer_cursor < ((addr_t)buffer + predefined_relocate_size))) {
    int last_relo_offset = turbo_assembler_.GetCodeBuffer()->getSize();

    x86_insn_decode_t insn = {0};
    memset(&insn, 0, sizeof(insn));
    // decode x86 insn
    x86_insn_decode(&insn, (uint8_t *)buffer_cursor, &conf);

    if (insn.primary_opcode >= 0x70 && insn.primary_opcode <= 0x7F) { // jc rel8
      DLOG(1, "[x86 relo] jc rel8, %p", buffer_cursor);

      int8_t orig_offset = insn.immediate;
      int new_offset = (int)(curr_orig_ip + orig_offset - curr_relo_ip);
      uint8_t opcode = 0x80 | (insn.primary_opcode & 0x0f);

      __ Emit8(0x0F);
      __ Emit8(opcode);
      __ Emit32(new_offset);
    } else if (insn.primary_opcode == 0xEB) { // jmp rel8
      DLOG(1, "[x86 relo] jmp rel8, %p", buffer_cursor);

      int8_t orig_offset = insn.immediate;
      int8_t new_offset = (int8_t)(curr_orig_ip + orig_offset - curr_relo_ip);

      __ Emit8(0xE9);
      __ Emit32(new_offset);
    } else if ((insn.flags & X86_INSN_DECODE_FLAG_IP_RELATIVE) && (insn.operands[1].mem.base == RIP)) { // RIP
      DLOG(1, "[x86 relo] rip, %p", buffer_cursor);

      // dword orig_disp = *(dword *)(buffer_cursor + insn.operands[1].mem.disp);
      dword orig_disp = insn.operands[1].mem.disp;
      dword new_disp = (dword)(curr_orig_ip + orig_disp - curr_relo_ip);

      __ EmitBuffer((void *)buffer_cursor, insn.displacement_offset);
      __ Emit32(new_disp);
      if(insn.immediate_offset) {
        __ EmitBuffer((void *)(buffer_cursor + insn.immediate_offset), insn.length - insn.immediate_offset);
      }
    } else if (insn.primary_opcode == 0xE8 || insn.primary_opcode == 0xE9) { // call or jmp rel32
      DLOG(1, "[x86 relo] jmp or call rel32, %p", buffer_cursor);

      dword orig_offset = insn.immediate;
      dword offset = (dword)(curr_orig_ip + orig_offset - curr_relo_ip);

      __ EmitBuffer((void *)buffer_cursor, insn.immediate_offset);
      __ Emit32(offset);
    } else if (insn.primary_opcode >= 0xE0 && insn.primary_opcode <= 0xE2) { // LOOPNZ/LOOPZ/LOOP/JECXZ
      // LOOP/LOOPcc
      UNIMPLEMENTED();
    } else if (insn.primary_opcode == 0xE3) {
      // JCXZ JCEXZ JCRXZ
      UNIMPLEMENTED();
    } else {
      // Emit the origin instrution
      __ EmitBuffer((void *)buffer_cursor, insn.length);
    }

    // go next
    curr_orig_ip += insn.length;
    buffer_cursor += insn.length;

#if 0
    {
      // 1 orignal instrution => ? relocated instruction
      int relo_offset = turbo_assembler_.GetCodeBuffer()->getSize();
      int relo_len    = relo_offset - last_relo_offset;
      curr_relo_ip += relo_len;
    }
#endif
    curr_relo_ip = relocated->raw_instruction_start() + turbo_assembler_.ip_offset();
  }

  // jmp to the origin rest instructions
  CodeGen codegen(&turbo_assembler_);
  // TODO: 6 == jmp [RIP + disp32] instruction size
  addr64_t stub_addr = curr_relo_ip + 6;
  codegen.JmpNearIndirect(stub_addr);
  turbo_assembler_.GetCodeBuffer()->Emit64(curr_orig_ip);

  // update origin
  int new_origin_len = curr_orig_ip - origin->raw_instruction_start();
  origin->re_init_region_range(origin->raw_instruction_start(), new_origin_len);

  int relo_len = turbo_assembler_.GetCodeBuffer()->getSize();
  if (relo_len > relocated->raw_instruction_size()) {
    DLOG(0, "pre-alloc code chunk not enough");
    return RT_FAILED;
  }

  // Generate executable code
  {
    AssemblyCodeChunk *code = NULL;
    code = AssemblyCodeBuilder::FinalizeFromTurboAssembler(&turbo_assembler_);
    delete code;
  }

  return RT_SUCCESS;
}

void GenRelocateCodeAndBranch(void *buffer, AssemblyCodeChunk *origin, AssemblyCodeChunk *relocated) {
  // pre-alloc code chunk
  AssemblyCodeChunk *cchunk = NULL;

  int relo_code_chunk_size = 32;
  const int chunk_size_step = 16;

x64_try_again:
  if (relocated->raw_instruction_start() == 0) {
    cchunk = MemoryArena::AllocateCodeChunk(relo_code_chunk_size);
    if (cchunk == nullptr) {
      return;
    }
    relocated->re_init_region_range((addr_t)cchunk->address, (int)cchunk->length);
  }

  int ret = GenRelocateCodeFixed(buffer, origin, relocated);
  if (ret != RT_SUCCESS) {
    // free the cchunk
    MemoryArena::Destroy(cchunk);

    relo_code_chunk_size += chunk_size_step;
    relocated->re_init_region_range(0, 0);

    goto x64_try_again;
  }
}

#endif
<|endoftext|>