Implement updating of current frame on GPU

This commit is contained in:
Kovid Goyal 2021-01-28 21:41:31 +05:30
parent 4098f2d383
commit b21850dd15
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 55 additions and 8 deletions

View File

@ -780,8 +780,32 @@ grman_update_layers(GraphicsManager *self, unsigned int scrolled_by, float scree
#define _gap z_index
#define _animation_enabled data_width
static inline Frame*
current_frame(Image *img) {
if (img->current_frame_index > img->extra_framecnt) return NULL;
return img->current_frame_index ? img->extra_frames + img->current_frame_index - 1 : &img->root_frame;
}
static void
update_current_frame(GraphicsManager *self, Image *img, void *data) {
bool needs_load = data == NULL;
Frame *f = current_frame(img);
if (f == NULL) return;
if (needs_load) {
size_t data_sz;
if (!read_from_cache(self, (const ImageAndFrame){.image_id=img->internal_id, .frame_id=f->id}, &data, &data_sz)) {
if (PyErr_Occurred()) PyErr_Print();
return;
}
}
if (send_to_gpu) {
send_image_to_gpu(&img->texture_id, data, img->width, img->height, img->is_opaque, img->is_4byte_aligned, false, REPEAT_CLAMP);
}
if (needs_load) free(data);
}
static Image*
handle_animation_frame_load_command(GraphicsManager *self, GraphicsCommand *g, Image *img, const uint8_t *payload) {
handle_animation_frame_load_command(GraphicsManager *self, GraphicsCommand *g, Image *img, const uint8_t *payload, bool *is_dirty) {
uint32_t frame_number = g->_frame_number, fmt = g->format ? g->format : RGBA;
if (!frame_number || frame_number > img->extra_framecnt + 2) frame_number = img->extra_framecnt + 2;
bool is_new_frame = frame_number == img->extra_framecnt + 2;
@ -822,6 +846,7 @@ handle_animation_frame_load_command(GraphicsManager *self, GraphicsCommand *g, I
void *base_data = NULL;
size_t data_sz = 0;
bool needs_send_to_gpu = false;
ImageAndFrame key = { .image_id = img->internal_id };
if (is_new_frame) {
key.frame_id = ++img->frame_id_counter;
@ -849,6 +874,8 @@ handle_animation_frame_load_command(GraphicsManager *self, GraphicsCommand *g, I
if (!read_from_cache(self, key, &base_data, &data_sz)) {
FAIL("ENODATA", "No data for frame with number: %u found in image: %u", frame_number, img->client_id);
}
Frame *f = current_frame(img);
if (f && f->id == key.frame_id) needs_send_to_gpu = true;
}
if (data_sz != expected_data_sz) {
free(base_data);
@ -871,6 +898,10 @@ handle_animation_frame_load_command(GraphicsManager *self, GraphicsCommand *g, I
free_load_data(&img->load_data);
bool added = add_to_cache(self, key, base_data, data_sz);
if (needs_send_to_gpu) {
update_current_frame(self, img, base_data);
*is_dirty = true;
}
free(base_data);
if (!added) {
PyErr_Print();
@ -893,7 +924,7 @@ handle_animation_frame_load_command(GraphicsManager *self, GraphicsCommand *g, I
#undef ABRT
static Image*
handle_delete_frame_command(GraphicsManager *self, const GraphicsCommand *g, bool *is_dirty UNUSED) {
handle_delete_frame_command(GraphicsManager *self, const GraphicsCommand *g, bool *is_dirty) {
if (!g->id && !g->image_number) {
REPORT_ERROR("Delete frame data command without image id or number");
return NULL;
@ -906,6 +937,7 @@ handle_delete_frame_command(GraphicsManager *self, const GraphicsCommand *g, boo
uint32_t frame_number = MIN(img->extra_framecnt + 1, g->_frame_number);
if (!frame_number) frame_number = 1;
if (!img->extra_framecnt) return g->delete_action == 'F' ? img : NULL;
*is_dirty = true;
ImageAndFrame key = {.image_id=img->internal_id};
bool remove_root = frame_number == 1;
if (remove_root) {
@ -914,19 +946,26 @@ handle_delete_frame_command(GraphicsManager *self, const GraphicsCommand *g, boo
if (PyErr_Occurred()) PyErr_Print();
img->root_frame = img->extra_frames[0];
}
unsigned idx = remove_root ? 0 : frame_number - 2;
unsigned removed_idx = remove_root ? 0 : frame_number - 2;
if (!remove_root) {
key.frame_id = img->extra_frames[idx].id;
key.frame_id = img->extra_frames[removed_idx].id;
remove_from_cache(self, key);
}
if (PyErr_Occurred()) PyErr_Print();
if (idx < img->extra_framecnt - 1) memmove(img->extra_frames + idx, img->extra_frames + idx + 1, sizeof(img->extra_frames[0]) * img->extra_framecnt - 1 - idx);
if (removed_idx < img->extra_framecnt - 1) memmove(img->extra_frames + removed_idx, img->extra_frames + removed_idx + 1, sizeof(img->extra_frames[0]) * img->extra_framecnt - 1 - removed_idx);
img->extra_framecnt--;
if (img->current_frame_index > img->extra_framecnt) {
img->current_frame_index = img->extra_framecnt;
update_current_frame(self, img, NULL);
return NULL;
}
if (removed_idx == img->current_frame_index) update_current_frame(self, img, NULL);
else if (removed_idx < img->current_frame_index) img->current_frame_index--;
return NULL;
}
static void
handle_animation_control_command(bool *is_dirty, const GraphicsCommand *g, Image *img) {
handle_animation_control_command(GraphicsManager *self, bool *is_dirty, const GraphicsCommand *g, Image *img) {
if (g->_frame_number) {
uint32_t frame_idx = g->_frame_number - 1;
if (frame_idx <= img->extra_framecnt) {
@ -939,6 +978,7 @@ handle_animation_control_command(bool *is_dirty, const GraphicsCommand *g, Image
if (frame_idx != img->current_frame_index && frame_idx <= img->extra_framecnt) {
img->current_frame_index = frame_idx;
*is_dirty = true;
update_current_frame(self, img, NULL);
}
}
if (g->_animation_enabled) {
@ -1201,10 +1241,10 @@ grman_handle_command(GraphicsManager *self, const GraphicsCommand *g, const uint
} else {
GraphicsCommand ag = *g;
if (ag.action == 'f') {
img = handle_animation_frame_load_command(self, &ag, img, payload);
img = handle_animation_frame_load_command(self, &ag, img, payload, is_dirty);
ret = finish_command_response(&ag, img != NULL);
} else if (ag.action == 'a') {
handle_animation_control_command(is_dirty, &ag, img);
handle_animation_control_command(self, is_dirty, &ag, img);
}
}
break;

View File

@ -663,21 +663,28 @@ class TestGraphics(BaseTest):
{'gap': 101, 'id': 3, 'data': b'444444333333444444333333333333333333'},
{'gap': 40, 'id': 4, 'data': b'5' * 36},
))
self.assertEqual(img['current_frame_index'], 1)
self.assertIsNone(li(a='d', d='f', i=1, r=1))
img = g.image_for_client_id(1)
self.assertEqual(img['current_frame_index'], 0)
self.assertEqual(img['data'], b'3' * 36)
self.assertEqual(img['extra_frames'], (
{'gap': 101, 'id': 3, 'data': b'444444333333444444333333333333333333'},
{'gap': 40, 'id': 4, 'data': b'5' * 36},
))
self.assertIsNone(li(a='a', i=1, c=3))
img = g.image_for_client_id(1)
self.assertEqual(img['current_frame_index'], 2)
self.assertIsNone(li(a='d', d='f', i=1, r=2))
img = g.image_for_client_id(1)
self.assertEqual(img['current_frame_index'], 1)
self.assertEqual(img['data'], b'3' * 36)
self.assertEqual(img['extra_frames'], (
{'gap': 40, 'id': 4, 'data': b'5' * 36},
))
self.assertIsNone(li(a='d', d='f', i=1))
img = g.image_for_client_id(1)
self.assertEqual(img['current_frame_index'], 0)
self.assertEqual(img['data'], b'5' * 36)
self.assertFalse(img['extra_frames'])
self.assertIsNone(li(a='d', d='f', i=1))