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(); }
// 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; } //-------------------------------------------------------------------------------- }