implement load/unload frames

This commit is contained in:
2019-10-22 19:37:55 +02:00
parent 63f8d2f81c
commit 8e4f77333e
11 changed files with 211 additions and 116 deletions

View File

@@ -9,6 +9,7 @@ RTT& Layer::rtt(int i, int frame /*= -1*/)
{
if (frame == -1)
frame = m_frame_index;
assert(m_frames[frame].m_rtt[i].valid());
return m_frames[frame].m_rtt[i];
}
@@ -145,71 +146,22 @@ void Layer::optimize(int frame /*= -1*/)
LOG("optimized %d bytes", saved_bytes);
}
void Layer::restore(const Snapshot& snap, int frame /*= -1*/)
void Layer::restore(const LayerFrame::Snapshot& snap, int frame /*= -1*/)
{
if (frame == -1)
frame = m_frame_index;
clear({ 0, 0, 0, 0 }, frame);
for (int i = 0; i < 6; i++)
{
if (snap.image[i] == nullptr || snap.m_dirty_face[i] == false || box_area(snap.m_dirty_box[i]) <= 0)
{
box(i, frame) = glm::vec4(snap.width, snap.height, 0, 0);
face(i, frame) = false;
continue;
}
box(i, frame) = snap.m_dirty_box[i];
face(i, frame) = snap.m_dirty_face[i];
// TODO: this should not be recreated here!
// Sorry I messed up with this,
// it's just a quick fix DON'T SHIP!!
//m_rtt[i].recreate();
App::I->render_task_async([this, i, &snap, frame]
{
rtt(i, frame).bindTexture();
glm::vec2 box_sz = zw(box(i, frame)) - xy(box(i, frame));
glTexSubImage2D(GL_TEXTURE_2D, 0,
box(i, frame).x, box(i, frame).y,
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
snap.image[i].get());
rtt(i, frame).unbindTexture();
LOG("restore frame %d face %d - %d bytes (%dx%d)", frame, i,
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
});
}
App::I->render_sync();
auto loaded = m_frames[frame].gpu_load();
m_frames[frame].restore(snap);
if (!loaded) m_frames[frame].gpu_unload();
}
Layer::Snapshot Layer::snapshot(int frame /*= -1*/, std::array<glm::vec4, 6>* dirty_box /*= nullptr*/, std::array<bool, 6>* dirty_face /*= nullptr*/)
LayerFrame::Snapshot Layer::snapshot(int frame /*= -1*/, std::array<glm::vec4, 6>* dirty_box /*= nullptr*/, std::array<bool, 6>* dirty_face /*= nullptr*/)
{
if (frame == -1)
frame = m_frame_index;
Snapshot snap;
snap.width = w;
snap.height = h;
for (int i = 0; i < 6; i++)
{
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : box(i, frame);
snap.m_dirty_face[i] = dirty_face ? dirty_face->at(i) : face(i, frame);
if (!snap.m_dirty_face[i])
continue;
snap.image[i] = std::make_unique<uint8_t[]>(rtt(i, frame).bytes());
App::I->render_task_async([this, i, &snap, frame]
{
rtt(i, frame).bindFramebuffer();
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y,
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
rtt(i, frame).unbindFramebuffer();
});
}
App::I->render_sync();
auto loaded = m_frames[frame].gpu_load();
auto snap = m_frames[frame].snapshot(dirty_box, dirty_face);
if (!loaded) m_frames[frame].gpu_unload();
return snap;
}
@@ -229,24 +181,45 @@ bool Layer::create(int width, int height, std::string name)
m_frames.clear();
m_frames.emplace_back();
m_frames.back().create(width, height);
frames_gpu_update();
return true;
}
bool Layer::add_frame()
{
m_frames.emplace_back();
return m_frames.back().create(w, h);
m_frames.back().create(w, h);
frames_gpu_update();
return true;
}
void Layer::remove_frame(int frame)
{
m_frames.erase(m_frames.begin() + frame);
m_frame_index = glm::clamp(m_frame_index, 0, (int)m_frames.size() - 1);
frames_gpu_update();
}
void Layer::duplicate_frame(int frame)
{
m_frames.insert(m_frames.begin() + frame + 1, m_frames[frame].clone());
frames_gpu_update();
}
void Layer::frames_gpu_update()
{
App::I->render_task_async([=]
{
for (int j = 0; j < m_frames.size(); j++)
{
int dist = glm::abs(j - m_frame_index);
int onion = App::I->animation ? App::I->animation->get_onion_size() : 1;
if (dist <= onion)
m_frames[j].gpu_load();
else
m_frames[j].gpu_unload();
}
});
}
int Layer::total_duration() const noexcept
@@ -263,6 +236,8 @@ void Layer::goto_frame(int frame) noexcept
for (i = 0; i < m_frames.size() && frame >= 0; i++)
frame -= m_frames[i].m_duration;
m_frame_index = i - 1;
m_frames[m_frame_index].gpu_load();
frames_gpu_update();
}
void Layer::resize(int width, int height)
@@ -275,7 +250,7 @@ void Layer::resize(int width, int height)
///////////////////////////////////////////////////////////////////////////////////////////
void Layer::Snapshot::create(int w, int h)
void LayerFrame::Snapshot::create(int w, int h)
{
width = w;
height = h;
@@ -288,7 +263,7 @@ void Layer::Snapshot::create(int w, int h)
}
}
void Layer::Snapshot::clear()
void LayerFrame::Snapshot::clear()
{
for (int i = 0; i < 6; i++)
{
@@ -298,7 +273,7 @@ void Layer::Snapshot::clear()
}
}
void Layer::Snapshot::optimize()
void LayerFrame::Snapshot::optimize()
{
for (int i = 0; i < 6; i++)
{
@@ -322,7 +297,7 @@ void Layer::Snapshot::optimize()
}
}
int Layer::Snapshot::memsize() const
int LayerFrame::Snapshot::memsize() const
{
int ret = 0;
for (int i = 0; i < 6; i++)
@@ -372,22 +347,28 @@ LayerFrame& LayerFrame::operator=(LayerFrame&& other)
bool LayerFrame::create(int width, int height, int duration /*= 1*/)
{
bool success = true;
App::I->render_task([&]
//App::I->render_task([&]
//{
// for (int i = 0; i < 6; i++)
// {
// if (!m_rtt[i].create(width, height))
// {
// success = false;
// return;
// }
// m_rtt[i].bindFramebuffer();
// m_rtt[i].clear();
// m_rtt[i].unbindFramebuffer();
// m_dirty_box[i] = glm::vec4(width, height, 0, 0); // reset bounding box
// m_dirty_face[i] = false;
// }
//});
for (int i = 0; i < 6; i++)
{
for (int i = 0; i < 6; i++)
{
if (!m_rtt[i].create(width, height))
{
success = false;
return;
}
m_rtt[i].bindFramebuffer();
m_rtt[i].clear();
m_rtt[i].unbindFramebuffer();
m_dirty_box[i] = glm::vec4(width, height, 0, 0); // reset bounding box
m_dirty_face[i] = false;
}
});
m_dirty_box[i] = glm::vec4(width, height, 0, 0); // reset bounding box
m_dirty_face[i] = false;
}
m_gpu_data = nullptr;
m_duration = duration;
w = width;
h = height;
@@ -396,6 +377,7 @@ bool LayerFrame::create(int width, int height, int duration /*= 1*/)
bool LayerFrame::resize(int width, int height)
{
bool loaded = gpu_load();
glm::vec2 ratio = glm::vec2(width, height) / glm::vec2(w, h);
for (int i = 0; i < 6; i++)
{
@@ -405,6 +387,7 @@ bool LayerFrame::resize(int width, int height)
}
w = width;
h = height;
if (!loaded) gpu_unload();
return true;
}
@@ -442,17 +425,113 @@ void LayerFrame::clear(const glm::vec4& c)
});
}
LayerFrame LayerFrame::clone() const noexcept
LayerFrame LayerFrame::clone() noexcept
{
LayerFrame dup;
dup.m_duration = m_duration;
dup.w = w;
dup.h = h;
bool loaded = gpu_load();
for (int i = 0; i < 6; i++)
{
dup.m_rtt[i] = m_rtt[i].clone();
dup.m_dirty_box[i] = m_dirty_box[i];
dup.m_dirty_face[i] = m_dirty_face[i];
}
if (!loaded) gpu_unload();
return dup;
}
void LayerFrame::restore(const Snapshot& snap)
{
App::I->render_task([this, &snap]
{
clear({ 0, 0, 0, 0 });
for (int i = 0; i < 6; i++)
{
if (!m_rtt[i].valid())
m_rtt[i].create(w, h);
if (snap.image[i] == nullptr || snap.m_dirty_face[i] == false || box_area(snap.m_dirty_box[i]) <= 0)
{
m_dirty_box[i] = glm::vec4(snap.width, snap.height, 0, 0);
m_dirty_face[i] = false;
continue;
}
m_dirty_box[i] = snap.m_dirty_box[i];
m_dirty_face[i] = snap.m_dirty_face[i];
// TODO: this should not be recreated here!
// Sorry I messed up with this,
// it's just a quick fix DON'T SHIP!!
//m_rtt[i].recreate();
m_rtt[i].bindTexture();
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
glTexSubImage2D(GL_TEXTURE_2D, 0,
m_dirty_box[i].x, m_dirty_box[i].y,
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE,
snap.image[i].get());
m_rtt[i].unbindTexture();
LOG("restore face %d - %d bytes (%dx%d)", i,
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
}
});
}
LayerFrame::Snapshot LayerFrame::snapshot(std::array<glm::vec4, 6>* dirty_box /*= nullptr*/, std::array<bool, 6>* dirty_face /*= nullptr*/)
{
Snapshot snap;
snap.width = w;
snap.height = h;
App::I->render_task([this, &snap, dirty_face, dirty_box]
{
for (int i = 0; i < 6; i++)
{
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : m_dirty_box[i];
snap.m_dirty_face[i] = dirty_face ? dirty_face->at(i) : m_dirty_face[i];
if (!snap.m_dirty_face[i] || !m_rtt[i].valid())
continue;
snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes());
m_rtt[i].bindFramebuffer();
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y,
box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
m_rtt[i].unbindFramebuffer();
}
});
return snap;
}
bool LayerFrame::gpu_load() noexcept
{
if (m_gpu_data)
{
restore(*m_gpu_data);
}
else
{
for (auto& rtt : m_rtt)
if (!rtt.valid())
rtt.create(w, h);
}
m_gpu_data.reset();
return true;
}
bool LayerFrame::gpu_unload() noexcept
{
bool ret = false; // already unloaded from gpu
if (!m_gpu_data)
{
m_gpu_data = std::make_unique<Snapshot>(snapshot());
ret = true; // previous state was loaded on gpu
}
for (auto& rtt : m_rtt)
rtt.destroy();
return ret;
}