-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PROTO: Create text_objects and use them for rendering to improve text rendering performance #773
base: master
Are you sure you want to change the base?
Conversation
3e6dc77
to
ae81038
Compare
@@ -411,6 +416,11 @@ void menu_set_padding(component *c, int padding) { | |||
m->padding = padding; | |||
} | |||
|
|||
void menu_invalidate_help_text_cache(component *c) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does anything use this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
game_menu_return should be calling it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I goofed the rebase?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also be I missed it in the original PROTO submit.
@@ -212,6 +213,7 @@ static void textinput_free(component *c) { | |||
textinput *tb = widget_get_obj(c); | |||
surface_free(&tb->sur); | |||
str_free(&tb->text); | |||
text_objects_free(tb->text_cache, (sizeof(tb->text_cache) / sizeof(tb->text_cache[0]))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why isn't the second parameter an integer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t is an unsigned int, but will be 64bit or 32bit based on your architecture. And it's not a signed int because I never expect to have a negative amount of objects to destroy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean why not just pass the number of text objects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
size_t is fine, but the arraysize magic should probably be replaced with a named constant (same as the [0]'s, [1]'s, [2]'s and [3]'s, as pointed out in a different conversation)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should become a macro called ARRAY_SIZE(tb->text_cache).
That makes it forward compatible, when someone expands or reduces the array, they won't need to change this instance.
src/game/gui/textinput.c
Outdated
@@ -27,6 +27,7 @@ typedef struct { | |||
|
|||
textinput_done_cb done_cb; | |||
void *userdata; | |||
text_object text_cache[3]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be 2 not 3 here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These text_caches should seriously be named variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't disagree, or at least used named indices
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
@@ -312,73 +319,83 @@ void vs_render(scene *scene) { | |||
char text[256]; | |||
char money[16]; | |||
fight_stats *fight_stats = &scene->gs->fight_stats; | |||
static int force_redraw = 1; | |||
if(force_redraw) { | |||
// TODO: Find out why this caching doesn't work. The cache is built before the stats are correct. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: investigate this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This problem can be seen when bringing up the in-game menu the second time through, it will show an empty spot where the "explanation" is on the N64 branch indicating that the text object wasn't correctly dirtied.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a game menu on the 'vs' screen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhhh, that's interesting. I didn't realize I left this comment in the VS, it probably needs to be in arena somewhere.
@@ -38,6 +39,8 @@ vec2i interpolate(vec2i start, vec2i end, float fraction) { | |||
} | |||
|
|||
void chr_score_create(chr_score *score) { | |||
score->text_cache[0].dynamic = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unclear why this needs to be dynamic. Only the x/y position changes, maybe those should not be cached?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dynamic means something special, it means that the frame-over-frame rendering of the text object cannot be guaranteed to be the same. As the object may get occluded and require a re-render. Unfortunately I couldn't figure out a way to track this, so I resorted to hand picking objects that were NOT-SAFE to copy from the previous frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only really matters on the N64, where we can copy from the previous frame buffer, instead of allocating an intermediate texture.
The fallback would be to allocate the intermediate texture on the N64.
And can be completely ignored on the PC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, ok, maybe we can have a better name than dynamic, or have a comment that explains it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other names I've considered: not_copy_safe, needs_intermediate_texture, not_static_composition,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is uncachable
or changes_frequently
appropriate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's more of a hint to the renderer telling it not to 2nd level optimize.
0th lvl - render each letter.
1st lvl - allocate a new texture, render each letter to texture on dirty bit, use the allocated texture on all invocations without the dirty bit.
2nd lvl - render each letter to FB on dirty bit, copy from FB without dirty bit.
@@ -246,3 +248,10 @@ void video_draw_remap(const surface *src_surface, int x, int y, int remap_offset | |||
dst.y = y; | |||
draw_args(src_surface, &dst, remap_offset, remap_rounds, 0, 255, 255, 0, options); | |||
} | |||
|
|||
void video_render_text_block(text_object *text) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this belongs in video.c
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea here was that the video plugin can decide what to do with a text object.
For instance the N64 side doesn't traverse the letters if the object is not marked dirty. The code in here for video.c (PC) is unchanged from the original call pattern. If there is a better place that would allow the renderer to decide how to handle the text objects, I'm open to suggestions. This really seemed like the correct place. For instance the NULL renderer will just do nothing here too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is why we discussed the possible pluggable text renderer backend earlier. The plugin backend would decide how to call the video renderer instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, but maybe we can do something intermediate for now, before we go to the "solves all the problems" pluggable text renderer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I WANT IT NOW! We should throw in kubernetes too somehow ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@katajakasa Would this be something you could rework later, after this change goes in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is. Let's get this part merged first.
@@ -55,7 +57,7 @@ component *label_create_with_width(const text_settings *tconf, const char *text, | |||
widget_set_obj(c, local); | |||
widget_set_render_cb(c, label_render); | |||
widget_set_free_cb(c, label_free); | |||
|
|||
// local->text_cache[0].dynamic = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove
@@ -110,7 +110,11 @@ static void menu_render(component *c) { | |||
if(m->help_bg2) { | |||
video_draw(m->help_bg2, m->help_x - 8, m->help_y - 8); | |||
} | |||
text_render(&m->help_text_conf, TEXT_DEFAULT, m->help_x, m->help_y, m->help_w, m->help_h, (*tmp)->help); | |||
// TODO: The text_cache should move into inner component. In this case the one of the s->objs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this comment is wrong and it's not invalidated every frame
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what I ran into was that the menu didn't animate, so I marked all these dynamic.
src/game/gui/text_render.h
Outdated
int offset; | ||
int limit; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int offset; | |
int limit; | |
int palette_offset; | |
int palette_limit; |
Might also be possible to make these a smaller (8-bit) integer type, but that sounds like work for another PR.
src/game/gui/text_render.h
Outdated
int y; | ||
int offset; | ||
int limit; | ||
surface *sur; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
surface *sur; | |
surface const *sur; |
Since this is not an owned surface, and we do not plan to modify the surface via this pointer.
if(cached_text->max_letters < (text_len * 4)) { | ||
size_t size = (text_len * sizeof(letter) * 4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is magic number 4?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like 4 is the number of draw calls per letter.
At the very least, it should be a named constant.
Perhaps all four draw calls should be stored in one struct letter
? This would increase the number of fields in struct letter
/struct text_object
, but should decrease overall memory usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the shadows, we support up to 3 shadows per letter, including the letter itself. Actually per the code we support 4 shadows per letter (+letter). But I've never seen more than 3 being used.
render_char_surface(settings, state, sur, x, y); | ||
return sur->w; | ||
void letter_set_parameters(text_object *cached_text, surface *sur, int x, int y, int offset, int limit) { | ||
cached_text->cur_letter->x = x; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add an assert that checks that cached_text->cur_letter < cached_text->letter + cached_text->max_letters
24a2118
to
ead6221
Compare
Ok, I think I've gained some familiarity with this PR now, and I'd like to suggest some changes:
As long as that doesn't unnecessarily extend the bounds of the text object. |
My idea would be that if we were flowing several chunks of text into the same text_object, then we could 'finish' the flow that would allow any underlying texture allocation stuff to happen, with the final set of bounds? |
This is a cherry-pick/rework of the commit from the n64 branch. It builds and works but it needs more work/cleanups.
EDIT(Nopey): Closes #677