void zz_manager_texture::unbind_notset ()
{
	zz_hash_table<zz_node*>::iterator it, it_end;
	zz_hash_table<zz_node*> * nodes = get_hash_table();
	zz_texture * tex;

	if (!nodes) return;

	zz_camera * cam = znzin->get_camera();

	if (cam) {
		if (cam->get_speed() > 0) {
			// now, camera is moving, so do not unbind textures
			//ZZ_LOG("manager_texture: camera is moving\n");
			return;
		}
	}

	unsigned int max_tex_mem = znzin->renderer->get_max_texmem() >> 20; // byte -> megabyte
	unsigned int ava_tex_mem = znzin->renderer->get_available_texmem() >> 20;
	const unsigned int suff_tex_mem = 20; // sufficient available texture memory 20 MB
	
#if !defined(UNBIND_ALL)
	if (ava_tex_mem > suff_tex_mem) {
		if ((ava_tex_mem * 3) > max_tex_mem) {
			return;
		}
	}
#endif

	static zz_time s_accum_time = 0; // accumulated time
	const zz_time max_accum_time = ZZ_MSEC_TO_TIME(1000); // default 1000 msec

	s_accum_time += znzin->get_diff_time();

	// we do not unbind in every frame. we do only after some time elapsed
	// and the ratio is (ava_tex_mem / max_tex_mem)
	if (s_accum_time*max_tex_mem < max_accum_time*ava_tex_mem) // s_accum_time < max_accum_time * (ava_tex_mem / max_tex_mem)
		return;

	zz_time current_time = znzin->get_current_time();
	const zz_time MAX_DIFF_TIME = ZZ_MSEC_TO_TIME(10000); // default 10 second

	texlist.clear();

	for (it = nodes->begin(), it_end = nodes->end(); it != it_end; ++it) {
		tex = static_cast<zz_texture*>(*it);

		if (tex->get_lock_texture()) // skip texture that was locked for some reason
			continue;

		if (tex->get_last_settime() == current_time) // skip if it was used in the current frame
			continue;

		if (!tex->get_device_updated()) // skip if it was not device-ready
			continue;

		if (entrance_line.find(tex)) // skip if it is manager-controlled. it will be flushed by manager queue mechanism
			continue;

		if (exit_line.find(tex)) // skip if it is manager-controlled. it will be flushed by manager queue mechanism
			continue;

		texlist.push_back(tex); // insert the texture into the texlist
	}

	if (texlist.empty()) // skip if the texlist is empty
		return;

	texture_settime_compare texture_cf; // declare texture comparision function

	// sort texture list by last_settime
	std::sort(texlist.begin(), texlist.end(), texture_cf);

	tex = *texlist.begin(); // consider only the first
	assert(tex);

	// skip if the texture is recently used.
	if ((current_time - tex->get_last_settime()) < MAX_DIFF_TIME)
		return;

	s_accum_time = 0; // intialize accum_time

	tex->unbind_device();
	tex->update_last_settime();
}
Example #2
0
// If time_to_update is zero, all accumulated time info is ignored. it means *new start*!!.
// When last frame was so heavy, we should refresh it.
// If not, we will get slow frames in a while.
void zz_manager::update (zz_time time_to_update)
{
	if ((exit_line.size() == 0) && (entrance_line.size() == 0)) return;
	
	sort_waitings(); // sort lines

	if (!znzin->get_rs()->use_delayed_loading) {
		exit_line.flush_n_pop((int)exit_line.size());
		entrance_line.flush_n_pop((int)entrance_line.size());
		entrance_time_accumulated = 0;
		exit_time_accumulated = 0;
		return;
	}
	
	if (time_to_update == 0) { // initialize acculumated
		entrance_time_accumulated = 0;
		exit_time_accumulated = 0;
	}
	else {
		// distribute time
		entrance_time_accumulated += 1 + time_to_update/10;
		exit_time_accumulated += 1 + time_to_update/10;
	}
	zz_node * node;
	zz_time t;
	zz_time time_weight;

	//--------------------------------------------------------------------------------
	// for exit
	node = exit_line.back();	
	t = ZZ_TIME_TO_MSEC(exit_time_accumulated);
	time_weight = (!node) ? t : static_cast<zz_time>(node->get_load_weight());

	// not to unload reusing nodes, bound to max_flush
	int max_flush = (exit_line.size() > num_reuse) ? (exit_line.size() - num_reuse) : 0;

	try {
		while ((max_flush-- > 0) && node && (t > time_weight)) {
			//ZZ_LOG("manager: [%s]->update() exit->flush(%s)\n", get_name(), node ? node->get_name() : "(null)");
			exit_line.flush_n_pop(1);
			
			node = exit_line.back();

			if (!node) continue; // skip if no node

			exit_time_accumulated -= ZZ_MSEC_TO_TIME(t);
			t = ZZ_TIME_TO_MSEC(exit_time_accumulated);

			time_weight = static_cast<zz_time>(node->get_load_weight());
		}
	}
	catch (...) {
		if (node) {
			ZZ_LOG("manager: [%s]->update() exit->flush(%s) failed.\n", get_name(), node->get_name());
		}
		else {
			ZZ_LOG("manager: [%s]->update() exit->flush() failed.\n", get_name());
		}
		throw;
	}
	//--------------------------------------------------------------------------------

	//--------------------------------------------------------------------------------
	// for entrance
	node = entrance_line.back();
	t = ZZ_TIME_TO_MSEC(entrance_time_accumulated);
	time_weight = (!node) ? t : static_cast<zz_time>(node->get_load_weight());

	try {
		while (node && (t > time_weight)) {
			//ZZ_LOG("manager: [%s]->update() entrance->flush(%s)\n", get_name(), node ? node->get_name() : "(null)");
			if (entrance_line.flush_node(node)) {
				entrance_time_accumulated -= ZZ_MSEC_TO_TIME(t);
				entrance_line.pop();
			}
			else { // not loaded, so reinsert to front
				entrance_line.pop();
				entrance_line.push(node); // re-insert
			}

			node = entrance_line.back();

			if (!node) continue; // skip if no node

			t = ZZ_TIME_TO_MSEC(entrance_time_accumulated);

			time_weight = static_cast<zz_time>(node->get_load_weight());
		}
	}
	catch (...) {
		if (node) {
			ZZ_LOG("manager: [%s]->update() entrance->flush(%s) failed.\n", get_name(), node->get_name());
		}
		else {
			ZZ_LOG("manager: [%s]->update() entrance->flush() failed.\n", get_name());
		}
		 throw;
	}
	//--------------------------------------------------------------------------------
}