<commit_before>#include <algorithm>
#include <unordered_map>

#include <boost/functional/hash.hpp>
#include <noise/noise.h>
#include "noiseutils.h"

#include "asserts.hpp"
#include "engine.hpp"
#include "random.hpp"
#include "surface.hpp"
#include "terrain_generator.hpp"

namespace terrain
{
	namespace
	{
		class tile
		{
		public:
			tile(float threshold, TerrainType tt, const std::string& name, const std::string& image)
				: threshold_(threshold),
				  terrain_type_(tt),
				  name_(name)
			{
				surface_.reset(new graphics::surface(image));
			}
			TerrainType get_terrain_type() const { return terrain_type_; }
			float get_threshold() const { return threshold_; }
			const std::string& get_name() const { return name_; }
			surface_ptr get_surface() { return surface_; }
		private:
			float threshold_;
			TerrainType terrain_type_;
			std::string name_;
			surface_ptr surface_;
		};
		inline bool operator<(const tile& lhs, const tile& rhs) { return lhs.get_threshold() < rhs.get_threshold(); }

		class terrain_data
		{
		public:
			terrain_data() {}
			void add_tile(const tile& gp)
			{
				tiles_.emplace_back(gp);
			}
			void sort_tiles() {
				std::stable_sort(tiles_.begin(), tiles_.end());
			}
			const point& get_tile_size() const { return tile_size_; }
			void set_tile_size(const point& p) { tile_size_ = p; }
			surface_ptr get_surface_at_height(float value) {
				if(value <= tiles_.front().get_threshold()) {
					return tiles_.front().get_surface();
				} else if(value >= tiles_.back().get_threshold()) {
					return tiles_.back().get_surface();
				}
				for(auto& gp : tiles_) {
					if(value < gp.get_threshold()) {
						return gp.get_surface();
					}
				}
				ASSERT_LOG(false, "No valid terrain value found for value: " << value);
				return nullptr;
			}

		private:
			point tile_size_;
			std::vector<tile> tiles_;
		};

		terrain_data& get_terrain_data()
		{
			static terrain_data res;
			return res;
		}
	}

	chunk::chunk(const point&pos, int width, int height)
		: pos_(pos),
		  width_(width),
		  height_(height),
		  texture_(nullptr)
	{
		terrain_.resize(height);
		for(auto& row : terrain_) {
			row.resize(width);
		}
	}

	chunk::~chunk()
	{
		if(texture_) {
			SDL_DestroyTexture(texture_);
			texture_ = nullptr;
		}
	}

	float chunk::get_at(int x, int y)
	{
		ASSERT_LOG(x < width_, "x exceeds width of chunk: " << x << " >= " << width_);
		ASSERT_LOG(y < height_, "y exceeds height of chunk: " << y << " >= " << height_);
		return terrain_[y][x];
	}

	void chunk::set_at(int x, int y, float tt)
	{
		ASSERT_LOG(x < width_, "x exceeds width of chunk: " << x << " >= " << width_);
		ASSERT_LOG(y < height_, "y exceeds height of chunk: " << y << " >= " << height_);
		terrain_[y][x] = tt;
	}

	surface_ptr chunk::make_surface_from_chunk(chunk_ptr chk)
	{
		auto& cache = get_terrain_data();
		auto& tile_size = cache.get_tile_size();
		int w = tile_size.x * chk->width();
		int h = tile_size.y * chk->height();

		surface_ptr dst = std::make_shared<graphics::surface>(w, h);
		for(int y = 0; y != chk->height(); ++y) {
			for(int x = 0; x != chk->width(); ++x) {
				auto height_value = chk->get_at(x, y);
				auto surf = cache.get_surface_at_height(height_value);
				dst->blit_scaled(surf, rect(x * tile_size.x, y * tile_size.y, tile_size.x, tile_size.y));
			}
		}
		return dst;
	}

	void chunk::draw(const engine& eng, const point& cam) const
	{
		if(!texture_) {
			texture_ = SDL_CreateTextureFromSurface(const_cast<SDL_Renderer*>(eng.get_renderer()), chunk_surface_->get());
		}
		ASSERT_LOG(texture_ != nullptr, "No texture found for chunk.");
		// Note camera isn't adjusted for tile size.
		// But it is in the same units as pos_ is;

		SDL_Rect dst = {
			(pos_.x - cam.x) * eng.get_tile_size().x - chunk_surface_->width() / 2 + eng.get_window().width() / 2,
			(pos_.y - cam.y) * eng.get_tile_size().y - chunk_surface_->height() / 2 + eng.get_window().height() / 2,
			chunk_surface_->width(),
			chunk_surface_->height()
		};
		SDL_RenderCopy(const_cast<SDL_Renderer*>(eng.get_renderer()), texture_, NULL, &dst);
	}

	std::size_t point_hash::operator()(const point& p) const
	{
		std::size_t seed = 0;
		boost::hash_combine(seed, boost::hash_value(p.x));
		boost::hash_combine(seed, boost::hash_value(p.y));
		return seed;
	}

	terrain::terrain()
		: chunk_size_w_(16),
		  chunk_size_h_(16)
	{
	}

	void terrain::load_terrain_data(const node& n)
	{
		ASSERT_LOG(n.has_key("tile_size") && n["tile_size"].is_list() && n["tile_size"].num_elements() == 2,
			"'tile_size' attribute in terrain data file must be a two element list.");
		ASSERT_LOG(n.has_key("tiles") && n["tiles"].is_map(),
			"terrain data must have 'tiles' attribute that is a map.");
		auto& td = get_terrain_data();
		auto& tiles = n["tiles"].as_map();

		TerrainType counter = 1;
		td.set_tile_size(point(static_cast<int>(n["tile_size"][0].as_int()), static_cast<int>(n["tile_size"][1].as_int())));
		for(const auto& t : tiles) {
			const auto& name = t.first.as_string();
			ASSERT_LOG(t.second.has_key("image"), "tiles must have 'image' attribute");
			const auto& image = t.second["image"].as_string();
			ASSERT_LOG(t.second.has_key("gradient"), "tiles must have 'gradient' attribute");
			const auto& gradient = t.second["gradient"].as_float();
			td.add_tile(tile(gradient, counter++, name, image));
		}

		td.sort_tiles();
	}

	std::vector<chunk_ptr> terrain::get_chunks_in_area(const rect& r)
	{
		// We assume that chunks are placed on a grid. So that 0,0 is the co-ordinates of the
		// center of the first chunk, the chunk one up/one right would be at chunk_size_w_,chunk_size_h_

		std::vector<chunk_ptr> res;

		// So first step, we create a new rectangle based on our grid that is normalised to cover the rectangle r.
		rect r_norm = rect::from_coordinates((r.x() - chunk_size_w_) / chunk_size_w_,
			(r.y() - chunk_size_h_) / chunk_size_h_,
			(r.x2() + chunk_size_w_) / chunk_size_w_,
			(r.y2() + chunk_size_h_) / chunk_size_h_);
		// Next iterate over the grid positions and get all the relevant chunks
		for(int y = r_norm.y(); y < r_norm.y2(); ++y) {
			for(int x = r_norm.x(); x < r_norm.x2(); ++x) {
				point pos(x * chunk_size_w_, y * chunk_size_h_);
				auto it = chunks_.find(pos);
				if(it == chunks_.end()) {
					auto nchunk = generate_terrain_chunk(pos);
					chunks_[pos] = nchunk;
					res.emplace_back(nchunk);
				} else {
					res.emplace_back(it->second);
				}
			}
		}
		// XXX Need to add some chunk unloading logic.
		return res;
	}

	chunk_ptr terrain::generate_terrain_chunk(const point& pos)
	{
		using namespace noise;
		module::Perlin pnoise;
		const double scale = 4.0;
		pnoise.SetSeed(static_cast<int>(generator::get_seed()));
		chunk_ptr nchunk = std::make_shared<chunk>(pos, chunk_size_w_, chunk_size_h_);
		for(int y = 0; y < chunk_size_h_; ++y) {
			for(int x = 0; x < chunk_size_w_; ++x) {
				auto ns = pnoise.GetValue(
					(x + pos.x - chunk_size_w_ / 2.0) / (chunk_size_w_ * scale),
					(y + pos.y - chunk_size_h_ / 2.0) / (chunk_size_h_ * scale),
					0.0);
				nchunk->set_at(x, y, static_cast<float>(ns));
			}
		}
		nchunk->set_surface(chunk::make_surface_from_chunk(nchunk));
		return nchunk;
	}

	point terrain::get_terrain_size()
	{
		return get_terrain_data().get_tile_size();
	}
}
<commit_msg>Changed the terrain generation scale.<commit_after>#include <algorithm>
#include <unordered_map>

#include <boost/functional/hash.hpp>
#include <noise/noise.h>
#include "noiseutils.h"

#include "asserts.hpp"
#include "engine.hpp"
#include "random.hpp"
#include "surface.hpp"
#include "terrain_generator.hpp"

namespace terrain
{
	namespace
	{
		const double terrain_scale_factor = 8.0;

		class tile
		{
		public:
			tile(float threshold, TerrainType tt, const std::string& name, const std::string& image)
				: threshold_(threshold),
				  terrain_type_(tt),
				  name_(name)
			{
				surface_.reset(new graphics::surface(image));
			}
			TerrainType get_terrain_type() const { return terrain_type_; }
			float get_threshold() const { return threshold_; }
			const std::string& get_name() const { return name_; }
			surface_ptr get_surface() { return surface_; }
		private:
			float threshold_;
			TerrainType terrain_type_;
			std::string name_;
			surface_ptr surface_;
		};
		inline bool operator<(const tile& lhs, const tile& rhs) { return lhs.get_threshold() < rhs.get_threshold(); }

		class terrain_data
		{
		public:
			terrain_data() {}
			void add_tile(const tile& gp)
			{
				tiles_.emplace_back(gp);
			}
			void sort_tiles() {
				std::stable_sort(tiles_.begin(), tiles_.end());
			}
			const point& get_tile_size() const { return tile_size_; }
			void set_tile_size(const point& p) { tile_size_ = p; }
			surface_ptr get_surface_at_height(float value) {
				if(value <= tiles_.front().get_threshold()) {
					return tiles_.front().get_surface();
				} else if(value >= tiles_.back().get_threshold()) {
					return tiles_.back().get_surface();
				}
				for(auto& gp : tiles_) {
					if(value < gp.get_threshold()) {
						return gp.get_surface();
					}
				}
				ASSERT_LOG(false, "No valid terrain value found for value: " << value);
				return nullptr;
			}

		private:
			point tile_size_;
			std::vector<tile> tiles_;
		};

		terrain_data& get_terrain_data()
		{
			static terrain_data res;
			return res;
		}
	}

	chunk::chunk(const point&pos, int width, int height)
		: pos_(pos),
		  width_(width),
		  height_(height),
		  texture_(nullptr)
	{
		terrain_.resize(height);
		for(auto& row : terrain_) {
			row.resize(width);
		}
	}

	chunk::~chunk()
	{
		if(texture_) {
			SDL_DestroyTexture(texture_);
			texture_ = nullptr;
		}
	}

	float chunk::get_at(int x, int y)
	{
		ASSERT_LOG(x < width_, "x exceeds width of chunk: " << x << " >= " << width_);
		ASSERT_LOG(y < height_, "y exceeds height of chunk: " << y << " >= " << height_);
		return terrain_[y][x];
	}

	void chunk::set_at(int x, int y, float tt)
	{
		ASSERT_LOG(x < width_, "x exceeds width of chunk: " << x << " >= " << width_);
		ASSERT_LOG(y < height_, "y exceeds height of chunk: " << y << " >= " << height_);
		terrain_[y][x] = tt;
	}

	surface_ptr chunk::make_surface_from_chunk(chunk_ptr chk)
	{
		auto& cache = get_terrain_data();
		auto& tile_size = cache.get_tile_size();
		int w = tile_size.x * chk->width();
		int h = tile_size.y * chk->height();

		surface_ptr dst = std::make_shared<graphics::surface>(w, h);
		for(int y = 0; y != chk->height(); ++y) {
			for(int x = 0; x != chk->width(); ++x) {
				auto height_value = chk->get_at(x, y);
				auto surf = cache.get_surface_at_height(height_value);
				dst->blit_scaled(surf, rect(x * tile_size.x, y * tile_size.y, tile_size.x, tile_size.y));
			}
		}
		return dst;
	}

	void chunk::draw(const engine& eng, const point& cam) const
	{
		if(!texture_) {
			texture_ = SDL_CreateTextureFromSurface(const_cast<SDL_Renderer*>(eng.get_renderer()), chunk_surface_->get());
		}
		ASSERT_LOG(texture_ != nullptr, "No texture found for chunk.");
		// Note camera isn't adjusted for tile size.
		// But it is in the same units as pos_ is;

		SDL_Rect dst = {
			(pos_.x - cam.x) * eng.get_tile_size().x - chunk_surface_->width() / 2 + eng.get_window().width() / 2,
			(pos_.y - cam.y) * eng.get_tile_size().y - chunk_surface_->height() / 2 + eng.get_window().height() / 2,
			chunk_surface_->width(),
			chunk_surface_->height()
		};
		SDL_RenderCopy(const_cast<SDL_Renderer*>(eng.get_renderer()), texture_, NULL, &dst);
	}

	std::size_t point_hash::operator()(const point& p) const
	{
		std::size_t seed = 0;
		boost::hash_combine(seed, boost::hash_value(p.x));
		boost::hash_combine(seed, boost::hash_value(p.y));
		return seed;
	}

	terrain::terrain()
		: chunk_size_w_(16),
		  chunk_size_h_(16)
	{
	}

	void terrain::load_terrain_data(const node& n)
	{
		ASSERT_LOG(n.has_key("tile_size") && n["tile_size"].is_list() && n["tile_size"].num_elements() == 2,
			"'tile_size' attribute in terrain data file must be a two element list.");
		ASSERT_LOG(n.has_key("tiles") && n["tiles"].is_map(),
			"terrain data must have 'tiles' attribute that is a map.");
		auto& td = get_terrain_data();
		auto& tiles = n["tiles"].as_map();

		TerrainType counter = 1;
		td.set_tile_size(point(static_cast<int>(n["tile_size"][0].as_int()), static_cast<int>(n["tile_size"][1].as_int())));
		for(const auto& t : tiles) {
			const auto& name = t.first.as_string();
			ASSERT_LOG(t.second.has_key("image"), "tiles must have 'image' attribute");
			const auto& image = t.second["image"].as_string();
			ASSERT_LOG(t.second.has_key("gradient"), "tiles must have 'gradient' attribute");
			const auto& gradient = t.second["gradient"].as_float();
			td.add_tile(tile(gradient, counter++, name, image));
		}

		td.sort_tiles();
	}

	std::vector<chunk_ptr> terrain::get_chunks_in_area(const rect& r)
	{
		// We assume that chunks are placed on a grid. So that 0,0 is the co-ordinates of the
		// center of the first chunk, the chunk one up/one right would be at chunk_size_w_,chunk_size_h_

		std::vector<chunk_ptr> res;

		// So first step, we create a new rectangle based on our grid that is normalised to cover the rectangle r.
		rect r_norm = rect::from_coordinates((r.x() - chunk_size_w_) / chunk_size_w_,
			(r.y() - chunk_size_h_) / chunk_size_h_,
			(r.x2() + chunk_size_w_) / chunk_size_w_,
			(r.y2() + chunk_size_h_) / chunk_size_h_);
		// Next iterate over the grid positions and get all the relevant chunks
		for(int y = r_norm.y(); y < r_norm.y2(); ++y) {
			for(int x = r_norm.x(); x < r_norm.x2(); ++x) {
				point pos(x * chunk_size_w_, y * chunk_size_h_);
				auto it = chunks_.find(pos);
				if(it == chunks_.end()) {
					auto nchunk = generate_terrain_chunk(pos);
					chunks_[pos] = nchunk;
					res.emplace_back(nchunk);
				} else {
					res.emplace_back(it->second);
				}
			}
		}
		// XXX Need to add some chunk unloading logic.
		return res;
	}

	chunk_ptr terrain::generate_terrain_chunk(const point& pos)
	{
		using namespace noise;
		module::Perlin pnoise;
		pnoise.SetSeed(static_cast<int>(generator::get_seed()));
		chunk_ptr nchunk = std::make_shared<chunk>(pos, chunk_size_w_, chunk_size_h_);
		for(int y = 0; y < chunk_size_h_; ++y) {
			for(int x = 0; x < chunk_size_w_; ++x) {
				auto ns = pnoise.GetValue(
					(x + pos.x - chunk_size_w_ / 2.0) / (chunk_size_w_ * terrain_scale_factor),
					(y + pos.y - chunk_size_h_ / 2.0) / (chunk_size_h_ * terrain_scale_factor),
					0.0);
				nchunk->set_at(x, y, static_cast<float>(ns));
			}
		}
		nchunk->set_surface(chunk::make_surface_from_chunk(nchunk));
		return nchunk;
	}

	point terrain::get_terrain_size()
	{
		return get_terrain_data().get_tile_size();
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Copyright (c) 2015-2018 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#define BOOST_TEST_MODULE Bitcoin Test Suite

#include "test_bitcoin.h"

#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "crypto/sha256.h"
#include "fs.h"
#include "key.h"
#include "main.h"
#include "miner.h"
#include "parallel.h"
#include "pubkey.h"
#include "random.h"
#include "rpc/register.h"
#include "rpc/server.h"
#include "test/testutil.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include <boost/program_options.hpp>
#include <boost/test/unit_test.hpp>

#include <memory>

#include <boost/thread.hpp>

FastRandomContext insecure_rand_ctx(true);

extern bool fPrintToConsole;
extern void noui_connect();

BasicTestingSetup::BasicTestingSetup(const std::string &chainName)
{
    SHA256AutoDetect();
    ECC_Start();
    SetupEnvironment();
    SetupNetworking();
    fPrintToDebugLog = false; // don't want to write to debug.log file
    fCheckBlockIndex = true;
    SelectParams(chainName);
    noui_connect();
}

BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); }
TestingSetup::TestingSetup(const std::string &chainName) : BasicTestingSetup(chainName)
{
    const CChainParams &chainparams = Params();
    // Ideally we'd move all the RPC tests to the functional testing framework
    // instead of unit tests, but for now we need these here.
    RegisterAllCoreRPCCommands(tableRPC);
    ClearDatadirCache();
    pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(1 << 30)));
    fs::create_directories(pathTemp);
    pblocktree = new CBlockTreeDB(1 << 20, true);
    pcoinsdbview = new CCoinsViewDB(1 << 23, true);
    pcoinsTip = new CCoinsViewCache(pcoinsdbview);
    bool worked = InitBlockIndex(chainparams);
    assert(worked);

    PV.reset(new CParallelValidation(3, &threadGroup));
    RegisterNodeSignals(GetNodeSignals());
}

TestingSetup::~TestingSetup()
{
    UnregisterNodeSignals(GetNodeSignals());
    threadGroup.interrupt_all();
    threadGroup.join_all();
    UnloadBlockIndex();
    delete pcoinsTip;
    delete pcoinsdbview;
    delete pblocktree;
    fs::remove_all(pathTemp);
}

TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
    // Generate a 100-block chain:
    coinbaseKey.MakeNewKey(true);
    CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
    for (int i = 0; i < COINBASE_MATURITY; i++)
    {
        std::vector<CMutableTransaction> noTxns;
        CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
        coinbaseTxns.push_back(*b.vtx[0]);
    }
}

//
// Create a new block with just given transactions, coinbase paying to
// scriptPubKey, and try to add it to the current chain.
//
CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction> &txns,
    const CScript &scriptPubKey)
{
    const CChainParams &chainparams = Params();
    CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
    CBlock &block = pblocktemplate->block;

    // Replace mempool-selected txns with just coinbase plus passed-in txns:
    block.vtx.resize(1);
    for (const CMutableTransaction &tx : txns)
        block.vtx.push_back(MakeTransactionRef(tx));

    // IncrementExtraNonce creates a valid coinbase and merkleRoot
    unsigned int extraNonce = 0;
    IncrementExtraNonce(&block, extraNonce);

    while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus()))
        ++block.nNonce;

    CValidationState state;
    ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false);

    CBlock result = block;
    delete pblocktemplate;
    return result;
}

TestChain100Setup::~TestChain100Setup() {}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool)
{
    CTransaction txn(tx);
    return FromTx(txn, pool);
}

CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool)
{
    bool hasNoDependencies = pool ? pool->HasNoInputsOf(txn) : hadNoDependencies;
    // Hack to assume either its completely dependent on other mempool txs or not at all
    CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;

    CTxMemPoolEntry ret(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight, hasNoDependencies, inChainValue,
        spendsCoinbase, sigOpCount, lp);
    ret.sighashType = SIGHASH_ALL; // For testing, give the transaction any valid sighashtype
    return ret;
}

void Shutdown(void *parg) { exit(0); }
void StartShutdown() { exit(0); }
bool ShutdownRequested() { return false; }
using namespace boost::program_options;

struct StartupShutdown
{
    StartupShutdown()
    {
        options_description optDef("Options");
        optDef.add_options()("testhelp", "program options information")(
            "log_level", "set boost logging (all, test_suite, message, warning, error, ...)")(
            "log_bitcoin", value<std::string>()->required(), "bitcoin logging destination (console, none)");
        variables_map opts;
        store(parse_command_line(boost::unit_test::framework::master_test_suite().argc,
                  boost::unit_test::framework::master_test_suite().argv, optDef),
            opts);

        if (opts.count("testhelp"))
        {
            std::cout << optDef << std::endl;
            exit(0);
        }

        if (opts.count("log_bitcoin"))
        {
            std::string s = opts["log_bitcoin"].as<std::string>();
            if (s == "console")
            {
                fPrintToConsole = true;
                fPrintToDebugLog = false;
            }
            else if (s == "none")
            {
                fPrintToConsole = false;
                fPrintToDebugLog = false;
            }
        }
    }
    ~StartupShutdown() { UnlimitedCleanup(); }
};

BOOST_GLOBAL_FIXTURE(StartupShutdown);
<commit_msg>unittests: Default enable all logging with '--log_bitcoin console'<commit_after>// Copyright (c) 2011-2015 The Bitcoin Core developers
// Copyright (c) 2015-2018 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#define BOOST_TEST_MODULE Bitcoin Test Suite

#include "test_bitcoin.h"

#include "chainparams.h"
#include "consensus/consensus.h"
#include "consensus/validation.h"
#include "crypto/sha256.h"
#include "fs.h"
#include "key.h"
#include "main.h"
#include "miner.h"
#include "parallel.h"
#include "pubkey.h"
#include "random.h"
#include "rpc/register.h"
#include "rpc/server.h"
#include "test/testutil.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include <boost/program_options.hpp>
#include <boost/test/unit_test.hpp>

#include <memory>

#include <boost/thread.hpp>

FastRandomContext insecure_rand_ctx(true);

extern bool fPrintToConsole;
extern void noui_connect();

BasicTestingSetup::BasicTestingSetup(const std::string &chainName)
{
    SHA256AutoDetect();
    ECC_Start();
    SetupEnvironment();
    SetupNetworking();
    fPrintToDebugLog = false; // don't want to write to debug.log file
    fCheckBlockIndex = true;
    SelectParams(chainName);
    noui_connect();
}

BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); }
TestingSetup::TestingSetup(const std::string &chainName) : BasicTestingSetup(chainName)
{
    const CChainParams &chainparams = Params();
    // Ideally we'd move all the RPC tests to the functional testing framework
    // instead of unit tests, but for now we need these here.
    RegisterAllCoreRPCCommands(tableRPC);
    ClearDatadirCache();
    pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(1 << 30)));
    fs::create_directories(pathTemp);
    pblocktree = new CBlockTreeDB(1 << 20, true);
    pcoinsdbview = new CCoinsViewDB(1 << 23, true);
    pcoinsTip = new CCoinsViewCache(pcoinsdbview);
    bool worked = InitBlockIndex(chainparams);
    assert(worked);

    PV.reset(new CParallelValidation(3, &threadGroup));
    RegisterNodeSignals(GetNodeSignals());
}

TestingSetup::~TestingSetup()
{
    UnregisterNodeSignals(GetNodeSignals());
    threadGroup.interrupt_all();
    threadGroup.join_all();
    UnloadBlockIndex();
    delete pcoinsTip;
    delete pcoinsdbview;
    delete pblocktree;
    fs::remove_all(pathTemp);
}

TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
{
    // Generate a 100-block chain:
    coinbaseKey.MakeNewKey(true);
    CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
    for (int i = 0; i < COINBASE_MATURITY; i++)
    {
        std::vector<CMutableTransaction> noTxns;
        CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
        coinbaseTxns.push_back(*b.vtx[0]);
    }
}

//
// Create a new block with just given transactions, coinbase paying to
// scriptPubKey, and try to add it to the current chain.
//
CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction> &txns,
    const CScript &scriptPubKey)
{
    const CChainParams &chainparams = Params();
    CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
    CBlock &block = pblocktemplate->block;

    // Replace mempool-selected txns with just coinbase plus passed-in txns:
    block.vtx.resize(1);
    for (const CMutableTransaction &tx : txns)
        block.vtx.push_back(MakeTransactionRef(tx));

    // IncrementExtraNonce creates a valid coinbase and merkleRoot
    unsigned int extraNonce = 0;
    IncrementExtraNonce(&block, extraNonce);

    while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus()))
        ++block.nNonce;

    CValidationState state;
    ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false);

    CBlock result = block;
    delete pblocktemplate;
    return result;
}

TestChain100Setup::~TestChain100Setup() {}
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool)
{
    CTransaction txn(tx);
    return FromTx(txn, pool);
}

CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool)
{
    bool hasNoDependencies = pool ? pool->HasNoInputsOf(txn) : hadNoDependencies;
    // Hack to assume either its completely dependent on other mempool txs or not at all
    CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;

    CTxMemPoolEntry ret(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight, hasNoDependencies, inChainValue,
        spendsCoinbase, sigOpCount, lp);
    ret.sighashType = SIGHASH_ALL; // For testing, give the transaction any valid sighashtype
    return ret;
}

void Shutdown(void *parg) { exit(0); }
void StartShutdown() { exit(0); }
bool ShutdownRequested() { return false; }
using namespace boost::program_options;

struct StartupShutdown
{
    StartupShutdown()
    {
        options_description optDef("Options");
        optDef.add_options()("testhelp", "program options information")(
            "log_level", "set boost logging (all, test_suite, message, warning, error, ...)")(
            "log_bitcoin", value<std::string>()->required(), "bitcoin logging destination (console, none)");
        variables_map opts;
        store(parse_command_line(boost::unit_test::framework::master_test_suite().argc,
                  boost::unit_test::framework::master_test_suite().argv, optDef),
            opts);

        if (opts.count("testhelp"))
        {
            std::cout << optDef << std::endl;
            exit(0);
        }

        if (opts.count("log_bitcoin"))
        {
            std::string s = opts["log_bitcoin"].as<std::string>();
            if (s == "console")
            {
                /* To enable this, add
                   -- --log_bitcoin console
                   to the end of the test_bitcoin argument list. */
                Logging::LogToggleCategory(Logging::ALL, true);
                fPrintToConsole = true;
                fPrintToDebugLog = false;
            }
            else if (s == "none")
            {
                fPrintToConsole = false;
                fPrintToDebugLog = false;
            }
        }
    }
    ~StartupShutdown() { UnlimitedCleanup(); }
};

BOOST_GLOBAL_FIXTURE(StartupShutdown);
<|endoftext|>


<commit_before>/*
   Copyright (c) 2009-2015, Jack Poulson
   All rights reserved.
   Sayan Ghosh,
   Washington State University

   This file is part of Elemental and is under the BSD 2-Clause License,
   which can be found in the LICENSE file in the root directory, or at
   http://opensource.org/licenses/BSD-2-Clause
*/
#include "El.hpp"
#include "El.h"
using namespace El;

#if MPI_VERSION>=3 && defined(EL_ENABLE_RMA_AXPY) && defined(EL_ENABLE_RMA_GLOBAL_ARRAYS)
extern "C" {
#define GA_BASE(SIG,SIGBASE,T) \
  /* GlobalArrays<T>::GlobalArrays() */ \
  ElError ElGlobalArraysCreate_ ## SIG ( ElGlobalArrays_ ## SIG * A ) \
  { EL_TRY( *A = CReflect( new GlobalArrays<T> ) ) } \
  /* GlobalArrays<T>::~GlobalArrays() */ \
  ElError ElGlobalArraysDestruct_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( delete CReflect(A) ) } \

#define GA_OPS(SIG,SIGBASE,T) \
  /* int GlobalArrays<T>::GA_Create_handle() */ \
  ElError ElGlobalArraysCreateHandle_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt* g_a ) \
  { EL_TRY( *g_a = CReflect(A)->GA_Create_handle() ) } \
  /* void GlobalArrays<T>::GA_Set_data (int g_a, int ndim, int dims[], int type) */ \
  ElError ElGlobalArraysSetData_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt ndim, ElInt dims[], ElInt type ) \
  { EL_TRY( CReflect(A)->GA_Set_data (g_a, ndim, dims, type) ) } \
  /* void GlobalArrays<T>::GA_Allocate (int g_a) */ \
  ElError ElGlobalArraysAllocate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a ) \
  { EL_TRY( CReflect(A)->GA_Allocate (g_a) ) } \
  /* void GlobalArrays<T>::GA_Copy(int g_a, int g_b) */ \
  ElError ElGlobalArraysCopy_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt g_b ) \
  { EL_TRY( CReflect(A)->GA_Copy (g_a, g_b) ) } \
  /* void GlobalArrays<T>::GA_Symmetrize(int g_a) */ \
  ElError ElGlobalArraysSymmetrize_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a ) \
  { EL_TRY( CReflect(A)->GA_Symmetrize (g_a) ) } \
  /* void GlobalArrays<T>::GA_Destroy(int g_a) */ \
  ElError ElGlobalArraysDestroy_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a ) \
  { EL_TRY( CReflect(A)->GA_Destroy (g_a) ) } \
  /* void GlobalArrays<T>::GA_Add(void *alpha, int g_a, void* beta, int g_b, int g_c) */ \
  ElError ElGlobalArraysAdd_ ## SIG ( ElGlobalArrays_ ## SIG A, void* alpha, ElInt g_a, void* beta, ElInt g_b, ElInt g_c ) \
  { EL_TRY( CReflect(A)->GA_Add(alpha, g_a, beta, g_b, g_c) ) } \
  /* void GlobalArrays<T>::GA_Dgemm(char ta, char tb, int m, int n, int k, double alpha, int g_a, int g_b, double beta, int g_c ) */ \
  ElError ElGlobalArraysDgemm_ ## SIG ( ElGlobalArrays_ ## SIG A, char ta, char tb, ElInt m, ElInt n, ElInt k, \
	double alpha, ElInt g_a, ElInt g_b, double beta, ElInt g_c ) \
  { EL_TRY( CReflect(A)->GA_Dgemm(ta, tb, m, n, k, alpha, g_a, g_b, beta, g_c ) ) } \
  /* int GlobalArrays<T>::GA_Duplicate(int g_a, const char* array_name) */ \
  ElError ElGlobalArraysDuplicate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, const char *array_name, ElInt* g_dup ) \
  { EL_TRY( *g_dup = CReflect(A)->GA_Duplicate(g_a, array_name) ) } \
  /* void GlobalArrays<T>::GA_Fill(int g_a, void *value) */ \
  ElError ElGlobalArraysFill_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, void* value ) \
  { EL_TRY( CReflect(A)->GA_Fill(g_a, value) ) } \
  /* void GlobalArrays<T>::GA_Initialize() */ \
  ElError ElGlobalArraysInitialize_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( CReflect(A)->GA_Initialize() ) } \
  /* void GlobalArrays<T>::GA_Sync() */ \
  ElError ElGlobalArraysSync_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( CReflect(A)->GA_Sync() ) } \
  /* void GlobalArrays<T>::GA_Terminate() */ \
  ElError ElGlobalArraysTerminate_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( CReflect(A)->GA_Terminate() ) } \
  /* void GlobalArrays<T>::GA_Transpose(int g_a, int g_b) */ \
  ElError ElGlobalArraysTranspose_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt g_b ) \
  { EL_TRY( CReflect(A)->GA_Transpose(g_a, g_b) ) } \
  /* void GlobalArrays<T>::NGA_Access(int g_a, int lo[], int hi[], void *ptr, int ld[]) */ \
  ElError ElGlobalArraysAccess_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], ElInt hi[], CREFLECT(T)* ptr, ElInt ld[] ) \
  { EL_TRY( CReflect(A)->NGA_Access(g_a, lo, hi, ptr, ld) ) } \
  /* void GlobalArrays<T>::NGA_Distribution(int g_a, int iproc, int lo[], int hi[]) */ \
  ElError ElGlobalArraysDistribute_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt iproc, ElInt lo[], ElInt hi[] ) \
  { EL_TRY( CReflect(A)->NGA_Distribution(g_a, iproc, lo, hi) ) } \
  /* void GlobalArrays<T>::NGA_Acc(int g_a, int lo[], int hi[],void* ptr,int ld[],void* alpha) */ \
  ElError ElGlobalArraysAccumulate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* ptr, ElInt ld[], void* alpha ) \
  { EL_TRY( CReflect(A)->NGA_Acc(g_a, lo, hi, ptr, ld, alpha) ) } \
  /* void GlobalArrays<T>::NGA_Get(int g_a, int lo[], int hi[], void* buf, int ld[]) */ \
  ElError ElGlobalArraysGet_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* buf, ElInt ld[] ) \
  { EL_TRY( CReflect(A)->NGA_Get(g_a, lo, hi, buf, ld) ) } \
  /* void GlobalArrays<T>::NGA_NbAcc(int g_a,int lo[], int hi[],void* ptr,int ld[],void* alpha, ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBAccumulate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* ptr, ElInt ld[], void* alpha, ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbAcc(g_a, lo, hi, ptr, ld, alpha, nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_NbGet(int g_a, int lo[], int hi[], void* buf, int ld[], ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBGet_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* buf, ElInt ld[], ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbGet(g_a, lo, hi, buf, ld, nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_NbPut(int g_a, int lo[], int hi[], void* buf, int ld[], ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBPut_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* ptr, ElInt ld[], ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbPut(g_a, lo, hi, ptr, ld, nbhandle) ) } \
  /* int GlobalArrays<T>::NGA_NbTest(ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBTest_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt* nbhandle, ElInt* status ) \
  { EL_TRY( *status = CReflect(A)->NGA_NbTest(nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_NbWait(ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBWait_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbWait(nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_Put(int g_a, int lo[], int hi[], void* buf, int ld[]) */ \
  ElError ElGlobalArraysPut_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	  ElInt hi[], CREFLECT(T)* ptr, ElInt ld[] ) \
  { EL_TRY( CReflect(A)->NGA_Put(g_a, lo, hi, ptr, ld) ) } \
  /* long GlobalArrays<T>::NGA_Read_inc(int g_a, int subscript[], long inc) */ \
  ElError ElGlobalArraysReadIncrement_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, \
	  ElInt subscript[], ElInt inc, ElInt* prev ) \
  { EL_TRY( *prev = CReflect(A)->NGA_Read_inc(g_a, subscript, inc) ) } \

#define C_PROTO(SIG,SIGBASE,T) \
  GA_BASE(SIG,SIGBASE,T) \
  GA_OPS(SIG,SIGBASE,T) \

#ifndef C_PROTO_INT
# define C_PROTO_INT(SIG,T) C_PROTO(SIG,SIG,T)
#endif

#ifndef C_PROTO_REAL
# define C_PROTO_REAL(SIG,T) C_PROTO(SIG,SIG,T)
#endif
#ifndef C_PROTO_FLOAT
# define C_PROTO_FLOAT C_PROTO_REAL(s,float)
#endif
#ifndef C_PROTO_DOUBLE
# define C_PROTO_DOUBLE C_PROTO_REAL(d,double)
#endif

#ifndef EL_NO_INT_PROTO
C_PROTO_INT(i,Int)
#endif

#ifndef EL_NO_REAL_PROTO
# if !defined(EL_NO_FLOAT_PROTO)
C_PROTO_FLOAT
# endif
# if !defined(EL_NO_DOUBLE_PROTO)
C_PROTO_DOUBLE
# endif
#endif
}
#endif // end of MPI_VERSION>=3 && defined(EL_ENABLE_RMA_AXPY) && defined(EL_ENABLE_RMA_GLOBAL_ARRAYS)
<commit_msg>fixed typo in function name<commit_after>/*
   Copyright (c) 2009-2015, Jack Poulson
   All rights reserved.
   Sayan Ghosh,
   Washington State University

   This file is part of Elemental and is under the BSD 2-Clause License,
   which can be found in the LICENSE file in the root directory, or at
   http://opensource.org/licenses/BSD-2-Clause
*/
#include "El.hpp"
#include "El.h"
using namespace El;

#if MPI_VERSION>=3 && defined(EL_ENABLE_RMA_AXPY) && defined(EL_ENABLE_RMA_GLOBAL_ARRAYS)
extern "C" {
#define GA_BASE(SIG,SIGBASE,T) \
  /* GlobalArrays<T>::GlobalArrays() */ \
  ElError ElGlobalArraysCreate_ ## SIG ( ElGlobalArrays_ ## SIG * A ) \
  { EL_TRY( *A = CReflect( new GlobalArrays<T> ) ) } \
  /* GlobalArrays<T>::~GlobalArrays() */ \
  ElError ElGlobalArraysDestruct_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( delete CReflect(A) ) } \

#define GA_OPS(SIG,SIGBASE,T) \
  /* int GlobalArrays<T>::GA_Create_handle() */ \
  ElError ElGlobalArraysCreateHandle_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt* g_a ) \
  { EL_TRY( *g_a = CReflect(A)->GA_Create_handle() ) } \
  /* void GlobalArrays<T>::GA_Set_data (int g_a, int ndim, int dims[], int type) */ \
  ElError ElGlobalArraysSetData_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt ndim, ElInt dims[], ElInt type ) \
  { EL_TRY( CReflect(A)->GA_Set_data (g_a, ndim, dims, type) ) } \
  /* void GlobalArrays<T>::GA_Allocate (int g_a) */ \
  ElError ElGlobalArraysAllocate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a ) \
  { EL_TRY( CReflect(A)->GA_Allocate (g_a) ) } \
  /* void GlobalArrays<T>::GA_Copy(int g_a, int g_b) */ \
  ElError ElGlobalArraysCopy_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt g_b ) \
  { EL_TRY( CReflect(A)->GA_Copy (g_a, g_b) ) } \
  /* void GlobalArrays<T>::GA_Symmetrize(int g_a) */ \
  ElError ElGlobalArraysSymmetrize_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a ) \
  { EL_TRY( CReflect(A)->GA_Symmetrize (g_a) ) } \
  /* void GlobalArrays<T>::GA_Destroy(int g_a) */ \
  ElError ElGlobalArraysDestroy_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a ) \
  { EL_TRY( CReflect(A)->GA_Destroy (g_a) ) } \
  /* void GlobalArrays<T>::GA_Add(void *alpha, int g_a, void* beta, int g_b, int g_c) */ \
  ElError ElGlobalArraysAdd_ ## SIG ( ElGlobalArrays_ ## SIG A, void* alpha, ElInt g_a, void* beta, ElInt g_b, ElInt g_c ) \
  { EL_TRY( CReflect(A)->GA_Add(alpha, g_a, beta, g_b, g_c) ) } \
  /* void GlobalArrays<T>::GA_Dgemm(char ta, char tb, int m, int n, int k, double alpha, int g_a, int g_b, double beta, int g_c ) */ \
  ElError ElGlobalArraysDgemm_ ## SIG ( ElGlobalArrays_ ## SIG A, char ta, char tb, ElInt m, ElInt n, ElInt k, \
	double alpha, ElInt g_a, ElInt g_b, double beta, ElInt g_c ) \
  { EL_TRY( CReflect(A)->GA_Dgemm(ta, tb, m, n, k, alpha, g_a, g_b, beta, g_c ) ) } \
  /* int GlobalArrays<T>::GA_Duplicate(int g_a, const char* array_name) */ \
  ElError ElGlobalArraysDuplicate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, const char *array_name, ElInt* g_dup ) \
  { EL_TRY( *g_dup = CReflect(A)->GA_Duplicate(g_a, array_name) ) } \
  /* void GlobalArrays<T>::GA_Fill(int g_a, void *value) */ \
  ElError ElGlobalArraysFill_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, void* value ) \
  { EL_TRY( CReflect(A)->GA_Fill(g_a, value) ) } \
  /* void GlobalArrays<T>::GA_Initialize() */ \
  ElError ElGlobalArraysInitialize_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( CReflect(A)->GA_Initialize() ) } \
  /* void GlobalArrays<T>::GA_Sync() */ \
  ElError ElGlobalArraysSync_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( CReflect(A)->GA_Sync() ) } \
  /* void GlobalArrays<T>::GA_Terminate() */ \
  ElError ElGlobalArraysTerminate_ ## SIG ( ElGlobalArrays_ ## SIG A ) \
  { EL_TRY( CReflect(A)->GA_Terminate() ) } \
  /* void GlobalArrays<T>::GA_Transpose(int g_a, int g_b) */ \
  ElError ElGlobalArraysTranspose_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt g_b ) \
  { EL_TRY( CReflect(A)->GA_Transpose(g_a, g_b) ) } \
  /* void GlobalArrays<T>::NGA_Access(int g_a, int lo[], int hi[], void *ptr, int ld[]) */ \
  ElError ElGlobalArraysAccess_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], ElInt hi[], CREFLECT(T)* ptr, ElInt ld[] ) \
  { EL_TRY( CReflect(A)->NGA_Access(g_a, lo, hi, ptr, ld) ) } \
  /* void GlobalArrays<T>::NGA_Distribution(int g_a, int iproc, int lo[], int hi[]) */ \
  ElError ElGlobalArraysDistribution_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt iproc, ElInt lo[], ElInt hi[] ) \
  { EL_TRY( CReflect(A)->NGA_Distribution(g_a, iproc, lo, hi) ) } \
  /* void GlobalArrays<T>::NGA_Acc(int g_a, int lo[], int hi[],void* ptr,int ld[],void* alpha) */ \
  ElError ElGlobalArraysAccumulate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* ptr, ElInt ld[], void* alpha ) \
  { EL_TRY( CReflect(A)->NGA_Acc(g_a, lo, hi, ptr, ld, alpha) ) } \
  /* void GlobalArrays<T>::NGA_Get(int g_a, int lo[], int hi[], void* buf, int ld[]) */ \
  ElError ElGlobalArraysGet_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* buf, ElInt ld[] ) \
  { EL_TRY( CReflect(A)->NGA_Get(g_a, lo, hi, buf, ld) ) } \
  /* void GlobalArrays<T>::NGA_NbAcc(int g_a,int lo[], int hi[],void* ptr,int ld[],void* alpha, ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBAccumulate_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* ptr, ElInt ld[], void* alpha, ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbAcc(g_a, lo, hi, ptr, ld, alpha, nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_NbGet(int g_a, int lo[], int hi[], void* buf, int ld[], ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBGet_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* buf, ElInt ld[], ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbGet(g_a, lo, hi, buf, ld, nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_NbPut(int g_a, int lo[], int hi[], void* buf, int ld[], ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBPut_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	ElInt hi[], CREFLECT(T)* ptr, ElInt ld[], ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbPut(g_a, lo, hi, ptr, ld, nbhandle) ) } \
  /* int GlobalArrays<T>::NGA_NbTest(ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBTest_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt* nbhandle, ElInt* status ) \
  { EL_TRY( *status = CReflect(A)->NGA_NbTest(nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_NbWait(ga_nbhdl_t* nbhandle) */ \
  ElError ElGlobalArraysNBWait_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt* nbhandle ) \
  { EL_TRY( CReflect(A)->NGA_NbWait(nbhandle) ) } \
  /* void GlobalArrays<T>::NGA_Put(int g_a, int lo[], int hi[], void* buf, int ld[]) */ \
  ElError ElGlobalArraysPut_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, ElInt lo[], \
	  ElInt hi[], CREFLECT(T)* ptr, ElInt ld[] ) \
  { EL_TRY( CReflect(A)->NGA_Put(g_a, lo, hi, ptr, ld) ) } \
  /* long GlobalArrays<T>::NGA_Read_inc(int g_a, int subscript[], long inc) */ \
  ElError ElGlobalArraysReadIncrement_ ## SIG ( ElGlobalArrays_ ## SIG A, ElInt g_a, \
	  ElInt subscript[], ElInt inc, ElInt* prev ) \
  { EL_TRY( *prev = CReflect(A)->NGA_Read_inc(g_a, subscript, inc) ) } \

#define C_PROTO(SIG,SIGBASE,T) \
  GA_BASE(SIG,SIGBASE,T) \
  GA_OPS(SIG,SIGBASE,T) \

#ifndef C_PROTO_INT
# define C_PROTO_INT(SIG,T) C_PROTO(SIG,SIG,T)
#endif

#ifndef C_PROTO_REAL
# define C_PROTO_REAL(SIG,T) C_PROTO(SIG,SIG,T)
#endif
#ifndef C_PROTO_FLOAT
# define C_PROTO_FLOAT C_PROTO_REAL(s,float)
#endif
#ifndef C_PROTO_DOUBLE
# define C_PROTO_DOUBLE C_PROTO_REAL(d,double)
#endif

#ifndef EL_NO_INT_PROTO
C_PROTO_INT(i,Int)
#endif

#ifndef EL_NO_REAL_PROTO
# if !defined(EL_NO_FLOAT_PROTO)
C_PROTO_FLOAT
# endif
# if !defined(EL_NO_DOUBLE_PROTO)
C_PROTO_DOUBLE
# endif
#endif
}
#endif // end of MPI_VERSION>=3 && defined(EL_ENABLE_RMA_AXPY) && defined(EL_ENABLE_RMA_GLOBAL_ARRAYS)
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/surface/accelerated_surface_win.h"

#include <windows.h>

#include <list>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/file_path.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/stringprintf.h"
#include "base/threading/thread.h"
#include "base/tracked_objects.h"
#include "base/win/wrapped_window_proc.h"
#include "ipc/ipc_message.h"
#include "ui/base/win/hwnd_util.h"
#include "ui/gfx/gl/gl_switches.h"

namespace {

typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version,
                                                IDirect3D9Ex **d3d);

const wchar_t kD3D9ModuleName[] = L"d3d9.dll";
const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex";

class PresentThreadPool {
 public:
  static const int kNumPresentThreads = 4;

  PresentThreadPool();

  int NextThread();

  void PostTask(int thread,
                const tracked_objects::Location& from_here,
                const base::Closure& task);

 private:
  int next_thread_;
  scoped_ptr<base::Thread> present_threads_[kNumPresentThreads];

  DISALLOW_COPY_AND_ASSIGN(PresentThreadPool);
};

base::LazyInstance<PresentThreadPool>
    g_present_thread_pool = LAZY_INSTANCE_INITIALIZER;

PresentThreadPool::PresentThreadPool() : next_thread_(0) {
  for (int i = 0; i < kNumPresentThreads; ++i) {
    present_threads_[i].reset(new base::Thread(
        base::StringPrintf("PresentThread #%d", i).c_str()));
    present_threads_[i]->Start();
  }
}

int PresentThreadPool::NextThread() {
  next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
  return next_thread_;
}

void PresentThreadPool::PostTask(int thread,
                                 const tracked_objects::Location& from_here,
                                 const base::Closure& task) {
  DCHECK_GE(thread, 0);
  DCHECK_LT(thread, kNumPresentThreads);

  present_threads_[thread]->message_loop()->PostTask(from_here, task);
}

UINT GetPresentationInterval() {
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
    return D3DPRESENT_INTERVAL_IMMEDIATE;
  else
    return D3DPRESENT_INTERVAL_ONE;
}

}  // namespace anonymous

AcceleratedSurface::AcceleratedSurface(HWND parent)
    : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()),
      window_(parent),
      num_pending_resizes_(0) {
}

AcceleratedSurface::~AcceleratedSurface() {
  // Destroy should have been called prior to the last reference going away.
  DCHECK(!device_);
}

void AcceleratedSurface::Initialize() {
  g_present_thread_pool.Pointer()->PostTask(
      thread_affinity_,
      FROM_HERE,
      base::Bind(&AcceleratedSurface::DoInitialize, this));
}

void AcceleratedSurface::Destroy() {
  g_present_thread_pool.Pointer()->PostTask(
      thread_affinity_,
      FROM_HERE,
      base::Bind(&AcceleratedSurface::DoDestroy, this));
}

void AcceleratedSurface::AsyncPresentAndAcknowledge(
    const gfx::Size& size,
    int64 surface_id,
    const base::Closure& completion_task) {
  const int kRound = 64;
  gfx::Size quantized_size(
      std::max(1, (size.width() + kRound - 1) / kRound * kRound),
      std::max(1, (size.height() + kRound - 1) / kRound * kRound));

  if (pending_size_ != quantized_size) {
    pending_size_ = quantized_size;
    base::AtomicRefCountInc(&num_pending_resizes_);

    g_present_thread_pool.Pointer()->PostTask(
        thread_affinity_,
        FROM_HERE,
        base::Bind(&AcceleratedSurface::DoResize, this, quantized_size));
  }

  // This might unnecessarily post to the thread with which the swap chain has
  // affinity. This will only result in potentially delaying the present.
  g_present_thread_pool.Pointer()->PostTask(
      num_pending_resizes_ ?
          thread_affinity_ : g_present_thread_pool.Pointer()->NextThread(),
      FROM_HERE,
      base::Bind(&AcceleratedSurface::DoPresentAndAcknowledge,
                 this,
                 size,
                 surface_id,
                 completion_task));
}

bool AcceleratedSurface::Present() {
  TRACE_EVENT0("surface", "Present");

  HRESULT hr;

  base::AutoLock locked(lock_);

  if (!device_)
    return true;

  RECT rect;
  if (!GetClientRect(window_, &rect))
    return true;

  {
    TRACE_EVENT0("surface", "PresentEx");
    hr = device_->PresentEx(&rect,
                            &rect,
                            NULL,
                            NULL,
                            D3DPRESENT_INTERVAL_IMMEDIATE);

    // If the device hung, force a resize to reset the device.
    if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) {
      base::AtomicRefCountInc(&num_pending_resizes_);
      g_present_thread_pool.Pointer()->PostTask(
          thread_affinity_,
          FROM_HERE,
          base::Bind(&AcceleratedSurface::DoReset, this));

      // A device hang destroys the contents of the back buffer so no point in
      // scheduling a present.
    }

    if (FAILED(hr))
      return false;
  }

  hr = query_->Issue(D3DISSUE_END);
  if (FAILED(hr))
    return true;

  {
    TRACE_EVENT0("surface", "spin");
    do {
      hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);

      if (hr == S_FALSE)
        Sleep(0);
    } while (hr == S_FALSE);
  }

  return true;
}

void AcceleratedSurface::DoInitialize() {
  TRACE_EVENT0("surface", "DoInitialize");

  HRESULT hr;

  d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL));

  Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>(
      d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName));
  if (!create_func)
    return;

  base::win::ScopedComPtr<IDirect3D9Ex> d3d;
  hr = create_func(D3D_SDK_VERSION, d3d.Receive());
  if (FAILED(hr))
    return;

  D3DPRESENT_PARAMETERS parameters = { 0 };
  parameters.BackBufferWidth = 1;
  parameters.BackBufferHeight = 1;
  parameters.BackBufferCount = 1;
  parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
  parameters.hDeviceWindow = window_;
  parameters.Windowed = TRUE;
  parameters.Flags = 0;
  parameters.PresentationInterval = GetPresentationInterval();
  parameters.SwapEffect = D3DSWAPEFFECT_COPY;

  hr = d3d->CreateDeviceEx(
      D3DADAPTER_DEFAULT,
      D3DDEVTYPE_HAL,
      window_,
      D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
          D3DCREATE_MULTITHREADED,
      &parameters,
      NULL,
      device_.Receive());
  if (FAILED(hr))
    return;

  hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
  if (FAILED(hr)) {
    device_ = NULL;
    return;
  }

  return;
}

void AcceleratedSurface::DoDestroy() {
  TRACE_EVENT0("surface", "DoDestroy");

  base::AutoLock locked(lock_);

  query_ = NULL;
  device_ = NULL;
}

void AcceleratedSurface::DoResize(const gfx::Size& size) {
  TRACE_EVENT0("surface", "DoResize");
  size_ = size;
  DoReset();
}

void AcceleratedSurface::DoReset() {
  TRACE_EVENT0("surface", "DoReset");

  HRESULT hr;

  base::AtomicRefCountDec(&num_pending_resizes_);

  base::AutoLock locked(lock_);

  if (!device_)
    return;

  D3DPRESENT_PARAMETERS parameters = { 0 };
  parameters.BackBufferWidth = size_.width();
  parameters.BackBufferHeight = size_.height();
  parameters.BackBufferCount = 1;
  parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
  parameters.hDeviceWindow = window_;
  parameters.Windowed = TRUE;
  parameters.Flags = 0;
  parameters.PresentationInterval = GetPresentationInterval();
  parameters.SwapEffect = D3DSWAPEFFECT_COPY;

  hr = device_->ResetEx(&parameters, NULL);
  if (FAILED(hr))
    return;

  device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
}

void AcceleratedSurface::DoPresentAndAcknowledge(
    const gfx::Size& size,
    int64 surface_id,
    const base::Closure& completion_task) {
  TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id);

  HRESULT hr;

  base::AutoLock locked(lock_);

  // Ensure the task is always run and while the lock is taken.
  base::ScopedClosureRunner scoped_completion_runner(completion_task);

  if (!device_)
    return;

  if (!window_)
    return;

  HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
  if (!handle)
    return;

  base::win::ScopedComPtr<IDirect3DTexture9> source_texture;
  {
    TRACE_EVENT0("surface", "CreateTexture");
    hr = device_->CreateTexture(size.width(),
                                size.height(),
                                1,
                                D3DUSAGE_RENDERTARGET,
                                D3DFMT_A8R8G8B8,
                                D3DPOOL_DEFAULT,
                                source_texture.Receive(),
                                &handle);
    if (FAILED(hr))
      return;
  }

  base::win::ScopedComPtr<IDirect3DSurface9> source_surface;
  hr = source_texture->GetSurfaceLevel(0, source_surface.Receive());
  if (FAILED(hr))
    return;

  base::win::ScopedComPtr<IDirect3DSurface9> dest_surface;
  hr = device_->GetRenderTarget(0, dest_surface.Receive());
  if (FAILED(hr))
    return;

  RECT rect = {
    0, 0,
    size.width(), size.height()
  };

  {
    TRACE_EVENT0("surface", "StretchRect");
    hr = device_->StretchRect(source_surface,
                              &rect,
                              dest_surface,
                              &rect,
                              D3DTEXF_NONE);
    if (FAILED(hr))
      return;
  }

  hr = query_->Issue(D3DISSUE_END);
  if (FAILED(hr))
    return;

  // Flush so the StretchRect can be processed by the GPU while the window is
  // being resized.
  query_->GetData(NULL, 0, D3DGETDATA_FLUSH);

  ::SetWindowPos(
      window_,
      NULL,
      0, 0,
      size.width(), size.height(),
      SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE |SWP_NOOWNERZORDER |
          SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSENDCHANGING |
          SWP_ASYNCWINDOWPOS);

  // Wait for the StretchRect to complete before notifying the GPU process
  // that it is safe to write to its backing store again.
  {
    TRACE_EVENT0("surface", "spin");
    do {
      hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);

      if (hr == S_FALSE)
        Sleep(0);
    } while (hr == S_FALSE);
  }

  scoped_completion_runner.Release();
  if (!completion_task.is_null())
    completion_task.Run();

  {
    TRACE_EVENT0("surface", "Present");
    hr = device_->Present(&rect, &rect, NULL, NULL);

    // If the device hung, force a resize to reset the device.
    if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) {
      base::AtomicRefCountInc(&num_pending_resizes_);
      g_present_thread_pool.Pointer()->PostTask(
          thread_affinity_,
          FROM_HERE,
          base::Bind(&AcceleratedSurface::DoReset, this));

      // A device hang destroys the contents of the back buffer so no point in
      // scheduling a present.
    }
  }
}
<commit_msg>Win AcceleratedSurface does not change z-order when changing compositing window size. Review URL: http://codereview.chromium.org/9076003<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/surface/accelerated_surface_win.h"

#include <windows.h>

#include <list>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/file_path.h"
#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/stringprintf.h"
#include "base/threading/thread.h"
#include "base/tracked_objects.h"
#include "base/win/wrapped_window_proc.h"
#include "ipc/ipc_message.h"
#include "ui/base/win/hwnd_util.h"
#include "ui/gfx/gl/gl_switches.h"

namespace {

typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT sdk_version,
                                                IDirect3D9Ex **d3d);

const wchar_t kD3D9ModuleName[] = L"d3d9.dll";
const char kCreate3D9DeviceExName[] = "Direct3DCreate9Ex";

class PresentThreadPool {
 public:
  static const int kNumPresentThreads = 4;

  PresentThreadPool();

  int NextThread();

  void PostTask(int thread,
                const tracked_objects::Location& from_here,
                const base::Closure& task);

 private:
  int next_thread_;
  scoped_ptr<base::Thread> present_threads_[kNumPresentThreads];

  DISALLOW_COPY_AND_ASSIGN(PresentThreadPool);
};

base::LazyInstance<PresentThreadPool>
    g_present_thread_pool = LAZY_INSTANCE_INITIALIZER;

PresentThreadPool::PresentThreadPool() : next_thread_(0) {
  for (int i = 0; i < kNumPresentThreads; ++i) {
    present_threads_[i].reset(new base::Thread(
        base::StringPrintf("PresentThread #%d", i).c_str()));
    present_threads_[i]->Start();
  }
}

int PresentThreadPool::NextThread() {
  next_thread_ = (next_thread_ + 1) % kNumPresentThreads;
  return next_thread_;
}

void PresentThreadPool::PostTask(int thread,
                                 const tracked_objects::Location& from_here,
                                 const base::Closure& task) {
  DCHECK_GE(thread, 0);
  DCHECK_LT(thread, kNumPresentThreads);

  present_threads_[thread]->message_loop()->PostTask(from_here, task);
}

UINT GetPresentationInterval() {
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableGpuVsync))
    return D3DPRESENT_INTERVAL_IMMEDIATE;
  else
    return D3DPRESENT_INTERVAL_ONE;
}

}  // namespace anonymous

AcceleratedSurface::AcceleratedSurface(HWND parent)
    : thread_affinity_(g_present_thread_pool.Pointer()->NextThread()),
      window_(parent),
      num_pending_resizes_(0) {
}

AcceleratedSurface::~AcceleratedSurface() {
  // Destroy should have been called prior to the last reference going away.
  DCHECK(!device_);
}

void AcceleratedSurface::Initialize() {
  g_present_thread_pool.Pointer()->PostTask(
      thread_affinity_,
      FROM_HERE,
      base::Bind(&AcceleratedSurface::DoInitialize, this));
}

void AcceleratedSurface::Destroy() {
  g_present_thread_pool.Pointer()->PostTask(
      thread_affinity_,
      FROM_HERE,
      base::Bind(&AcceleratedSurface::DoDestroy, this));
}

void AcceleratedSurface::AsyncPresentAndAcknowledge(
    const gfx::Size& size,
    int64 surface_id,
    const base::Closure& completion_task) {
  const int kRound = 64;
  gfx::Size quantized_size(
      std::max(1, (size.width() + kRound - 1) / kRound * kRound),
      std::max(1, (size.height() + kRound - 1) / kRound * kRound));

  if (pending_size_ != quantized_size) {
    pending_size_ = quantized_size;
    base::AtomicRefCountInc(&num_pending_resizes_);

    g_present_thread_pool.Pointer()->PostTask(
        thread_affinity_,
        FROM_HERE,
        base::Bind(&AcceleratedSurface::DoResize, this, quantized_size));
  }

  // This might unnecessarily post to the thread with which the swap chain has
  // affinity. This will only result in potentially delaying the present.
  g_present_thread_pool.Pointer()->PostTask(
      num_pending_resizes_ ?
          thread_affinity_ : g_present_thread_pool.Pointer()->NextThread(),
      FROM_HERE,
      base::Bind(&AcceleratedSurface::DoPresentAndAcknowledge,
                 this,
                 size,
                 surface_id,
                 completion_task));
}

bool AcceleratedSurface::Present() {
  TRACE_EVENT0("surface", "Present");

  HRESULT hr;

  base::AutoLock locked(lock_);

  if (!device_)
    return true;

  RECT rect;
  if (!GetClientRect(window_, &rect))
    return true;

  {
    TRACE_EVENT0("surface", "PresentEx");
    hr = device_->PresentEx(&rect,
                            &rect,
                            NULL,
                            NULL,
                            D3DPRESENT_INTERVAL_IMMEDIATE);

    // If the device hung, force a resize to reset the device.
    if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) {
      base::AtomicRefCountInc(&num_pending_resizes_);
      g_present_thread_pool.Pointer()->PostTask(
          thread_affinity_,
          FROM_HERE,
          base::Bind(&AcceleratedSurface::DoReset, this));

      // A device hang destroys the contents of the back buffer so no point in
      // scheduling a present.
    }

    if (FAILED(hr))
      return false;
  }

  hr = query_->Issue(D3DISSUE_END);
  if (FAILED(hr))
    return true;

  {
    TRACE_EVENT0("surface", "spin");
    do {
      hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);

      if (hr == S_FALSE)
        Sleep(0);
    } while (hr == S_FALSE);
  }

  return true;
}

void AcceleratedSurface::DoInitialize() {
  TRACE_EVENT0("surface", "DoInitialize");

  HRESULT hr;

  d3d_module_.Reset(base::LoadNativeLibrary(FilePath(kD3D9ModuleName), NULL));

  Direct3DCreate9ExFunc create_func = reinterpret_cast<Direct3DCreate9ExFunc>(
      d3d_module_.GetFunctionPointer(kCreate3D9DeviceExName));
  if (!create_func)
    return;

  base::win::ScopedComPtr<IDirect3D9Ex> d3d;
  hr = create_func(D3D_SDK_VERSION, d3d.Receive());
  if (FAILED(hr))
    return;

  D3DPRESENT_PARAMETERS parameters = { 0 };
  parameters.BackBufferWidth = 1;
  parameters.BackBufferHeight = 1;
  parameters.BackBufferCount = 1;
  parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
  parameters.hDeviceWindow = window_;
  parameters.Windowed = TRUE;
  parameters.Flags = 0;
  parameters.PresentationInterval = GetPresentationInterval();
  parameters.SwapEffect = D3DSWAPEFFECT_COPY;

  hr = d3d->CreateDeviceEx(
      D3DADAPTER_DEFAULT,
      D3DDEVTYPE_HAL,
      window_,
      D3DCREATE_FPU_PRESERVE | D3DCREATE_SOFTWARE_VERTEXPROCESSING |
          D3DCREATE_MULTITHREADED,
      &parameters,
      NULL,
      device_.Receive());
  if (FAILED(hr))
    return;

  hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, query_.Receive());
  if (FAILED(hr)) {
    device_ = NULL;
    return;
  }

  return;
}

void AcceleratedSurface::DoDestroy() {
  TRACE_EVENT0("surface", "DoDestroy");

  base::AutoLock locked(lock_);

  query_ = NULL;
  device_ = NULL;
}

void AcceleratedSurface::DoResize(const gfx::Size& size) {
  TRACE_EVENT0("surface", "DoResize");
  size_ = size;
  DoReset();
}

void AcceleratedSurface::DoReset() {
  TRACE_EVENT0("surface", "DoReset");

  HRESULT hr;

  base::AtomicRefCountDec(&num_pending_resizes_);

  base::AutoLock locked(lock_);

  if (!device_)
    return;

  D3DPRESENT_PARAMETERS parameters = { 0 };
  parameters.BackBufferWidth = size_.width();
  parameters.BackBufferHeight = size_.height();
  parameters.BackBufferCount = 1;
  parameters.BackBufferFormat = D3DFMT_A8R8G8B8;
  parameters.hDeviceWindow = window_;
  parameters.Windowed = TRUE;
  parameters.Flags = 0;
  parameters.PresentationInterval = GetPresentationInterval();
  parameters.SwapEffect = D3DSWAPEFFECT_COPY;

  hr = device_->ResetEx(&parameters, NULL);
  if (FAILED(hr))
    return;

  device_->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
}

void AcceleratedSurface::DoPresentAndAcknowledge(
    const gfx::Size& size,
    int64 surface_id,
    const base::Closure& completion_task) {
  TRACE_EVENT1("surface", "DoPresentAndAcknowledge", "surface_id", surface_id);

  HRESULT hr;

  base::AutoLock locked(lock_);

  // Ensure the task is always run and while the lock is taken.
  base::ScopedClosureRunner scoped_completion_runner(completion_task);

  if (!device_)
    return;

  if (!window_)
    return;

  HANDLE handle = reinterpret_cast<HANDLE>(surface_id);
  if (!handle)
    return;

  base::win::ScopedComPtr<IDirect3DTexture9> source_texture;
  {
    TRACE_EVENT0("surface", "CreateTexture");
    hr = device_->CreateTexture(size.width(),
                                size.height(),
                                1,
                                D3DUSAGE_RENDERTARGET,
                                D3DFMT_A8R8G8B8,
                                D3DPOOL_DEFAULT,
                                source_texture.Receive(),
                                &handle);
    if (FAILED(hr))
      return;
  }

  base::win::ScopedComPtr<IDirect3DSurface9> source_surface;
  hr = source_texture->GetSurfaceLevel(0, source_surface.Receive());
  if (FAILED(hr))
    return;

  base::win::ScopedComPtr<IDirect3DSurface9> dest_surface;
  hr = device_->GetRenderTarget(0, dest_surface.Receive());
  if (FAILED(hr))
    return;

  RECT rect = {
    0, 0,
    size.width(), size.height()
  };

  {
    TRACE_EVENT0("surface", "StretchRect");
    hr = device_->StretchRect(source_surface,
                              &rect,
                              dest_surface,
                              &rect,
                              D3DTEXF_NONE);
    if (FAILED(hr))
      return;
  }

  hr = query_->Issue(D3DISSUE_END);
  if (FAILED(hr))
    return;

  // Flush so the StretchRect can be processed by the GPU while the window is
  // being resized.
  query_->GetData(NULL, 0, D3DGETDATA_FLUSH);

  ::SetWindowPos(
      window_,
      NULL,
      0, 0,
      size.width(), size.height(),
      SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE |SWP_NOOWNERZORDER |
          SWP_NOREDRAW | SWP_NOSENDCHANGING | SWP_NOSENDCHANGING |
          SWP_ASYNCWINDOWPOS | SWP_NOZORDER);

  // Wait for the StretchRect to complete before notifying the GPU process
  // that it is safe to write to its backing store again.
  {
    TRACE_EVENT0("surface", "spin");
    do {
      hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH);

      if (hr == S_FALSE)
        Sleep(0);
    } while (hr == S_FALSE);
  }

  scoped_completion_runner.Release();
  if (!completion_task.is_null())
    completion_task.Run();

  {
    TRACE_EVENT0("surface", "Present");
    hr = device_->Present(&rect, &rect, NULL, NULL);

    // If the device hung, force a resize to reset the device.
    if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG) {
      base::AtomicRefCountInc(&num_pending_resizes_);
      g_present_thread_pool.Pointer()->PostTask(
          thread_affinity_,
          FROM_HERE,
          base::Bind(&AcceleratedSurface::DoReset, this));

      // A device hang destroys the contents of the back buffer so no point in
      // scheduling a present.
    }
  }
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <cstdlib>
#include <thread>
#include <iostream>
#include <mutex>
#include <vector>
#include <atomic>
#include "util/debug.h"
#include "util/shared_mutex.h"
using namespace lean;

void foo() {
    static thread_local std::vector<int> v(1024);
    if (v.size() != 1024) {
        std::cerr << "Error\n";
        exit(1);
    }
}

static void tst1() {
    unsigned n = 5;
    for (unsigned i = 0; i < n; i++) {
        std::thread t([](){ foo(); });
        t.join();
    }
}

static void tst2() {
    unsigned N = 10;
    unsigned n = 1;
    lean::shared_mutex mut;
    std::vector<std::thread> threads;
    for (unsigned i = 0; i < N; i++) {
        threads.emplace_back([&]() {
                unsigned sum = 0;
                {
                    lean::shared_lock lock(mut);
                    for (unsigned i = 0; i < 1000000; i++)
                        sum += n;
                }
                {
                   lean::unique_lock lock(mut);
                   std::cout << sum << "\n";
                }
            });
    }
    for (unsigned i = 0; i < N; i++)
        threads[i].join();
}

#ifndef __APPLE__
static void tst3() {
    shared_mutex      mutex;
    std::atomic<bool> t2_started(false);
    std::atomic<bool> t2_done(false);
    std::chrono::milliseconds small_delay(10);

    std::thread t1([&]() {
            while (!t2_started) {
                std::this_thread::sleep_for(small_delay);
            }
            while (!mutex.try_lock()) {
                std::this_thread::sleep_for(small_delay);
            }
            // test recursive try_lock
            lean_verify(mutex.try_lock());
            mutex.unlock();
            // we can only succeed getting the lock if t2 is done
            lean_assert(t2_done);
            mutex.unlock();
        });

    std::thread t2([&]() {
            {
                unique_lock lock(mutex);
                t2_started = true;
                std::this_thread::sleep_for(small_delay);
            }
            t2_done = true;
        });

    t1.join();
    t2.join();
    lean_assert(t2_done);
}

static void tst4() {
    shared_mutex      mutex;
    std::atomic<bool> t2_started(false);
    std::atomic<bool> t2_done(false);
    std::chrono::milliseconds small_delay(10);

    std::thread t1([&]() {
            while (!t2_started) {
                std::this_thread::sleep_for(small_delay);
            }
            while (!mutex.try_lock_shared()) {
                std::this_thread::sleep_for(small_delay);
            }
            // test recursive try_lock_shared
            lean_verify(mutex.try_lock_shared());
            mutex.unlock_shared();
            // we can only succeed getting the lock if t2 is done
            lean_assert(t2_done);
            mutex.unlock_shared();
        });

    std::thread t2([&]() {
            {
                unique_lock lock(mutex);
                t2_started = true;
                std::this_thread::sleep_for(small_delay);
            }
            t2_done = true;
        });

    t1.join();
    t2.join();
    lean_assert(t2_done);
}

static void tst5() {
    shared_mutex      mutex;
    std::atomic<bool> t2_started(false);
    std::atomic<bool> t1_done(false);
    std::chrono::milliseconds small_delay(10);

    std::thread t1([&]() {
            while (!t2_started) {
                std::this_thread::sleep_for(small_delay);
            }
            lean_verify(mutex.try_lock_shared()); // t2 is also using a shared lock
            std::this_thread::sleep_for(small_delay);
            lean_verify(mutex.try_lock_shared());
            std::this_thread::sleep_for(small_delay);
            t1_done = true;
            mutex.unlock_shared();
            std::this_thread::sleep_for(small_delay);
            mutex.unlock_shared();
        });

    std::thread t2([&]() {
            {
                shared_lock lock(mutex);
                t2_started = true;
                while (!t1_done) {
                    std::this_thread::sleep_for(small_delay);
                }
            }
        });

    t1.join();
    t2.join();
}
#else
static void tst3() {}
static void tst4() {}
static void tst5() {}
#endif

int main() {
    tst3();
    return 0;
    tst1();
    tst2();
    tst3();
    tst4();
    tst5();
    return has_violations() ? 1 : 0;
}
<commit_msg>fix(tests/util/thread): typo<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <cstdlib>
#include <thread>
#include <iostream>
#include <mutex>
#include <vector>
#include <atomic>
#include "util/debug.h"
#include "util/shared_mutex.h"
using namespace lean;

void foo() {
    static thread_local std::vector<int> v(1024);
    if (v.size() != 1024) {
        std::cerr << "Error\n";
        exit(1);
    }
}

static void tst1() {
    unsigned n = 5;
    for (unsigned i = 0; i < n; i++) {
        std::thread t([](){ foo(); });
        t.join();
    }
}

static void tst2() {
    unsigned N = 10;
    unsigned n = 1;
    lean::shared_mutex mut;
    std::vector<std::thread> threads;
    for (unsigned i = 0; i < N; i++) {
        threads.emplace_back([&]() {
                unsigned sum = 0;
                {
                    lean::shared_lock lock(mut);
                    for (unsigned i = 0; i < 1000000; i++)
                        sum += n;
                }
                {
                   lean::unique_lock lock(mut);
                   std::cout << sum << "\n";
                }
            });
    }
    for (unsigned i = 0; i < N; i++)
        threads[i].join();
}

#ifndef __APPLE__
static void tst3() {
    shared_mutex      mutex;
    std::atomic<bool> t2_started(false);
    std::atomic<bool> t2_done(false);
    std::chrono::milliseconds small_delay(10);

    std::thread t1([&]() {
            while (!t2_started) {
                std::this_thread::sleep_for(small_delay);
            }
            while (!mutex.try_lock()) {
                std::this_thread::sleep_for(small_delay);
            }
            // test recursive try_lock
            lean_verify(mutex.try_lock());
            mutex.unlock();
            // we can only succeed getting the lock if t2 is done
            lean_assert(t2_done);
            mutex.unlock();
        });

    std::thread t2([&]() {
            {
                unique_lock lock(mutex);
                t2_started = true;
                std::this_thread::sleep_for(small_delay);
            }
            t2_done = true;
        });

    t1.join();
    t2.join();
    lean_assert(t2_done);
}

static void tst4() {
    shared_mutex      mutex;
    std::atomic<bool> t2_started(false);
    std::atomic<bool> t2_done(false);
    std::chrono::milliseconds small_delay(10);

    std::thread t1([&]() {
            while (!t2_started) {
                std::this_thread::sleep_for(small_delay);
            }
            while (!mutex.try_lock_shared()) {
                std::this_thread::sleep_for(small_delay);
            }
            // test recursive try_lock_shared
            lean_verify(mutex.try_lock_shared());
            mutex.unlock_shared();
            // we can only succeed getting the lock if t2 is done
            lean_assert(t2_done);
            mutex.unlock_shared();
        });

    std::thread t2([&]() {
            {
                unique_lock lock(mutex);
                t2_started = true;
                std::this_thread::sleep_for(small_delay);
            }
            t2_done = true;
        });

    t1.join();
    t2.join();
    lean_assert(t2_done);
}

static void tst5() {
    shared_mutex      mutex;
    std::atomic<bool> t2_started(false);
    std::atomic<bool> t1_done(false);
    std::chrono::milliseconds small_delay(10);

    std::thread t1([&]() {
            while (!t2_started) {
                std::this_thread::sleep_for(small_delay);
            }
            lean_verify(mutex.try_lock_shared()); // t2 is also using a shared lock
            std::this_thread::sleep_for(small_delay);
            lean_verify(mutex.try_lock_shared());
            std::this_thread::sleep_for(small_delay);
            t1_done = true;
            mutex.unlock_shared();
            std::this_thread::sleep_for(small_delay);
            mutex.unlock_shared();
        });

    std::thread t2([&]() {
            {
                shared_lock lock(mutex);
                t2_started = true;
                while (!t1_done) {
                    std::this_thread::sleep_for(small_delay);
                }
            }
        });

    t1.join();
    t2.join();
}
#else
static void tst3() {}
static void tst4() {}
static void tst5() {}
#endif

int main() {
    tst1();
    tst2();
    tst3();
    tst4();
    tst5();
    return has_violations() ? 1 : 0;
}
<|endoftext|>


<commit_before>#pragma once
#include "stdafx.h"

#include "texture_baker.h"
#include "font.h"

namespace augs {
	namespace texture_baker {
		void texture::set_uv_unit(double u, double v) {
			x = float(double(rect.x) * u);
			y = float(double(rect.y) * v);
			w = float(double(rect.w) * u);
			h = float(double(rect.h) * v);
		}

		texture::texture() : img(nullptr), ltoa(false) {}
		texture::texture(image* img) : img(img), rect(img->get_size()), ltoa(false) {}

		void texture::set(image* _img) {
			img = _img;
			rect = rects::xywhf<int>(img->get_size());
		}

		void texture::luminosity_to_alpha(bool flag) {
			ltoa = flag;
		}

		rects::xywhf<int> texture::get_rect() const {
			return rect;
		}

		vec2<int> texture::get_size() const {
			return !rect.flipped ? vec2<int>(rect.w, rect.h) : vec2<int>(rect.h, rect.w);
		}

		void texture::get_uv(float u, float v, float& u_out, float& v_out) const {
			if(!rect.flipped) {
				u_out = x + w * u;
				v_out = y + h * v;
			}
			else {
				u_out = x + w * v;
				v_out = y + h * u;
			}
		}

		void texture::get_uv(vec2<float>& texture_space) const {
			auto temp = texture_space;
			get_uv(temp.x, temp.y, texture_space.x, texture_space.y);
		}

		float texture::get_u(int vertex_num_from_cw_rect) const {
			vertex_num_from_cw_rect %= 4;
			float u = 0.f;

			switch(vertex_num_from_cw_rect) {
			case 0: u = 0.f; break;
			case 1: u = rect.flipped ? 0.f : 1.f; break;
			case 2: u = 1.f; break;
			case 3: u = rect.flipped ? 1.f : 0.f; break;
			default: break;
			}

			return x + w * u;
		}

		float texture::get_v(int vertex_num_from_cw_rect) const {
			vertex_num_from_cw_rect %= 4;
			float v = 0.f;

			switch(vertex_num_from_cw_rect) {
			case 0: v = 0.f; break;
			case 1: v = rect.flipped ? 1.f : 0.f; break;
			case 2: v = 1.f; break;
			case 3: v = rect.flipped ? 0.f : 1.f; break;
			default: break;
			}

			return y + h * v;
		}

		void texture::translate_uv(vec2<float> uv) {
			uv *= vec2<float>(w/rect.w, h/rect.h);
			x += uv.x;
			y += uv.y;
		}

		void texture::scale_uv(float u_scalar, float v_scalar) {
			w *= u_scalar;
			h *= v_scalar;
		}

		void texture::get_uv(const rects::texture<float> &uv, rects::texture<float>& out) const {
			get_uv(uv.u1, uv.v1, out.u1, out.v1);
			get_uv(uv.u2, uv.v2, out.u2, out.v2);
		}

		float texture::get_u_unit() const {
			return rect.flipped ? h : w;
		}

		float texture::get_v_unit() const {
			return rect.flipped ? w : h;
		}

		atlas::atlas(int wp) : built(false), rep(true), lin(false), mipmaps(false) {
		}

		atlas::~atlas() {
			destroy();
		}

		unsigned atlas::current = 0;

		bool atlas::gen_packed(std::vector<texture*>& in_textures,
			std::vector<atlas*>& inout_atlases) {
				return true;
		}

		bool atlas::pack() {
			GLint tsize;
			glGetIntegerv(GL_MAX_TEXTURE_SIZE, &tsize);
			return pack(tsize);
		}

		bool atlas::pack(int max_size) {
			int cnt = textures.size();
			ptr_arr.reserve(cnt);

			rects::xywhf<int>** p = ptr_arr.data();

			for(int i = 0; i < cnt; ++i)
				p[i] = &textures[i]->rect;

			int res = rect2D(p, cnt, max_size, b);

			if (res == 1) throw std::runtime_error("not enough space in texture atlas!");
			if (res == 2) throw std::runtime_error("there's a texture larger than maximum atlas size");

			return !res;
		}

		void atlas::create_image(int atlas_channels, bool destroy_images) {
			double u = 1.0 / b.size.w;
			double v = 1.0 / b.size.h;

			for(unsigned i = 0; i < textures.size(); ++i)
				textures[i]->set_uv_unit(u, v);

			unsigned char pixel[] = { 0, atlas_channels == 2 ? 255 : 0, 0, 255 };
			img.create(b.size.w, b.size.h, atlas_channels);
			img.fill(pixel);

			rects::xywhf<int> rc;
			for(unsigned i = 0; i < textures.size(); ++i) {
				rc = textures[i]->get_rect();
				img.blit(*textures[i]->img, rc.x, rc.y, rects::xywhf<int>(0, 0, rc.w, rc.h, rc.flipped), textures[i]->ltoa);

				if(destroy_images)
					textures[i]->img->destroy();
			}
		}

		bool atlas::is_mipmapped() const {
			return mipmaps;
		}

		void atlas::destroy() {
			if(built)
				glDeleteTextures(1, &id);

			rep = true;
			lin = mipmaps = built = false;
		}

		void atlas::build(bool _mipmaps, bool _linear, image* raw_texture) {
			destroy();
			mipmaps = _mipmaps, lin = _linear;

			image& im = raw_texture ? *raw_texture : img;

			glGenTextures(1, &id);
			_bind();

			lin = !lin; if(!lin) linear(); else nearest();

			int format = im.get_channels();
			switch(format) {
			case 1: format = GL_LUMINANCE; break;
			case 2: format = GL_LUMINANCE_ALPHA; break;
			case 3: format = GL_BGR; break;
			case 4: format = GL_BGRA; break;
			}

			glTexImage2D(GL_TEXTURE_2D, 0, im.get_channels(), im.get_size().w, im.get_size().h, 0, format, GL_UNSIGNED_BYTE, im.ptr());

			if(mipmaps) glGenerateMipmap(GL_TEXTURE_2D);

			built = true;

			atlas_texture.set(&im);
			atlas_texture.set_uv_unit(1.0/im.get_size().w, 1.0/im.get_size().h);
		}

		void atlas::default_build() {
			pack();
			create_image(4, true);
			build(false, false);
			/* destroy the raw image as it is already uploaded to GPU */
			img.destroy();
		}

		void atlas::bind() {
			_bind();
		}

		void atlas::_bind() {
			glBindTexture(GL_TEXTURE_2D, current = id);
		}

		void atlas::repeat() {
			if(!rep) {
				rep = true;
				bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
			}
		}

		void atlas::clamp() {
			if(rep) {
				rep = false;
				bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
			}
		}

		void atlas::nearest() {
			bind();
			lin = false;
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
		}

		void atlas::linear() {
			bind();
			lin = true;
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
		}
	}
}<commit_msg>added padding to the atlas<commit_after>#pragma once
#include "stdafx.h"

#include "texture_baker.h"
#include "font.h"

namespace augs {
	namespace texture_baker {
		void texture::set_uv_unit(double u, double v) {
			x = float(double(rect.x) * u);
			y = float(double(rect.y) * v);
			w = float(double(rect.w) * u);
			h = float(double(rect.h) * v);
		}

		texture::texture() : img(nullptr), ltoa(false) {}
		texture::texture(image* img) : img(img), rect(img->get_size()), ltoa(false) {}

		void texture::set(image* _img) {
			img = _img;
			rect = rects::xywhf<int>(img->get_size());
		}

		void texture::luminosity_to_alpha(bool flag) {
			ltoa = flag;
		}

		rects::xywhf<int> texture::get_rect() const {
			return rect;
		}

		vec2<int> texture::get_size() const {
			return !rect.flipped ? vec2<int>(rect.w, rect.h) : vec2<int>(rect.h, rect.w);
		}

		void texture::get_uv(float u, float v, float& u_out, float& v_out) const {
			if(!rect.flipped) {
				u_out = x + w * u;
				v_out = y + h * v;
			}
			else {
				u_out = x + w * v;
				v_out = y + h * u;
			}
		}

		void texture::get_uv(vec2<float>& texture_space) const {
			auto temp = texture_space;
			get_uv(temp.x, temp.y, texture_space.x, texture_space.y);
		}

		float texture::get_u(int vertex_num_from_cw_rect) const {
			vertex_num_from_cw_rect %= 4;
			float u = 0.f;

			switch(vertex_num_from_cw_rect) {
			case 0: u = 0.f; break;
			case 1: u = rect.flipped ? 0.f : 1.f; break;
			case 2: u = 1.f; break;
			case 3: u = rect.flipped ? 1.f : 0.f; break;
			default: break;
			}

			return x + w * u;
		}

		float texture::get_v(int vertex_num_from_cw_rect) const {
			vertex_num_from_cw_rect %= 4;
			float v = 0.f;

			switch(vertex_num_from_cw_rect) {
			case 0: v = 0.f; break;
			case 1: v = rect.flipped ? 1.f : 0.f; break;
			case 2: v = 1.f; break;
			case 3: v = rect.flipped ? 0.f : 1.f; break;
			default: break;
			}

			return y + h * v;
		}

		void texture::translate_uv(vec2<float> uv) {
			uv *= vec2<float>(w/rect.w, h/rect.h);
			x += uv.x;
			y += uv.y;
		}

		void texture::scale_uv(float u_scalar, float v_scalar) {
			w *= u_scalar;
			h *= v_scalar;
		}

		void texture::get_uv(const rects::texture<float> &uv, rects::texture<float>& out) const {
			get_uv(uv.u1, uv.v1, out.u1, out.v1);
			get_uv(uv.u2, uv.v2, out.u2, out.v2);
		}

		float texture::get_u_unit() const {
			return rect.flipped ? h : w;
		}

		float texture::get_v_unit() const {
			return rect.flipped ? w : h;
		}

		atlas::atlas(int wp) : built(false), rep(true), lin(false), mipmaps(false) {
		}

		atlas::~atlas() {
			destroy();
		}

		unsigned atlas::current = 0;

		bool atlas::gen_packed(std::vector<texture*>& in_textures,
			std::vector<atlas*>& inout_atlases) {
				return true;
		}

		bool atlas::pack() {
			GLint tsize;
			glGetIntegerv(GL_MAX_TEXTURE_SIZE, &tsize);
			return pack(tsize);
		}

		bool atlas::pack(int max_size) {
			int cnt = textures.size();
			ptr_arr.reserve(cnt);

			rects::xywhf<int>** p = ptr_arr.data();

			for (int i = 0; i < cnt; ++i)
			{
				p[i] = &textures[i]->rect;
				p[i]->w+=2;
				p[i]->h+=2;
			}

			int res = rect2D(p, cnt, max_size, b);

			for (int i = 0; i < cnt; ++i)
			{
				p[i]->w -= 2;
				p[i]->h -= 2;
			}

			if (res == 1) throw std::runtime_error("not enough space in texture atlas!");
			if (res == 2) throw std::runtime_error("there's a texture larger than maximum atlas size");

			return !res;
		}

		void atlas::create_image(int atlas_channels, bool destroy_images) {
			double u = 1.0 / b.size.w;
			double v = 1.0 / b.size.h;

			for(unsigned i = 0; i < textures.size(); ++i)
				textures[i]->set_uv_unit(u, v);

			unsigned char pixel[] = { 0, atlas_channels == 2 ? 255 : 0, 0, 0 };
			img.create(b.size.w, b.size.h, atlas_channels);
			img.fill(pixel);

			rects::xywhf<int> rc;
			for(unsigned i = 0; i < textures.size(); ++i) {
				rc = textures[i]->get_rect();
				img.blit(*textures[i]->img, rc.x, rc.y, rects::xywhf<int>(0, 0, rc.w, rc.h, rc.flipped), textures[i]->ltoa);

				if(destroy_images)
					textures[i]->img->destroy();
			}
		}

		bool atlas::is_mipmapped() const {
			return mipmaps;
		}

		void atlas::destroy() {
			if(built)
				glDeleteTextures(1, &id);

			rep = true;
			lin = mipmaps = built = false;
		}

		void atlas::build(bool _mipmaps, bool _linear, image* raw_texture) {
			destroy();
			mipmaps = _mipmaps, lin = _linear;

			image& im = raw_texture ? *raw_texture : img;

			glGenTextures(1, &id);
			_bind();

			lin = !lin; if(!lin) linear(); else nearest();

			int format = im.get_channels();
			switch(format) {
			case 1: format = GL_LUMINANCE; break;
			case 2: format = GL_LUMINANCE_ALPHA; break;
			case 3: format = GL_BGR; break;
			case 4: format = GL_BGRA; break;
			}

			glTexImage2D(GL_TEXTURE_2D, 0, im.get_channels(), im.get_size().w, im.get_size().h, 0, format, GL_UNSIGNED_BYTE, im.ptr());

			if(mipmaps) glGenerateMipmap(GL_TEXTURE_2D);

			built = true;

			atlas_texture.set(&im);
			atlas_texture.set_uv_unit(1.0/im.get_size().w, 1.0/im.get_size().h);
		}

		void atlas::default_build() {
			pack();
			create_image(4, true);
			build(false, false);
			/* destroy the raw image as it is already uploaded to GPU */
			img.destroy();
		}

		void atlas::bind() {
			_bind();
		}

		void atlas::_bind() {
			glBindTexture(GL_TEXTURE_2D, current = id);
		}

		void atlas::repeat() {
			if(!rep) {
				rep = true;
				bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
			}
		}

		void atlas::clamp() {
			if(rep) {
				rep = false;
				bind();
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
			}
		}

		void atlas::nearest() {
			bind();
			lin = false;
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
		}

		void atlas::linear() {
			bind();
			lin = true;
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
		}
	}
}<|endoftext|>