diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-04-20 16:48:26 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-04-20 16:48:26 +0300 |
commit | 4bd016cf3125b8341d0c690e9e3ecace582f54d7 (patch) | |
tree | 7ab51f846c7608f17bcfa9363266753a377631c7 /src/ui/documentwidget.c | |
parent | 4f840655fcb69f151c73121d790344296f6b43e6 (diff) |
DocumentWidget: Pre-rendering finetuning
Ensure there is more buffered content available in the current scrolling direction, and also make sure that all buffers get pre-rendered after a short delay with the view being stationary.
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r-- | src/ui/documentwidget.c | 138 |
1 files changed, 84 insertions, 54 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 42018e19..2229b7f7 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -157,14 +157,14 @@ struct Impl_DrawBufs { | |||
157 | int flags; | 157 | int flags; |
158 | SDL_Texture * sideIconBuf; | 158 | SDL_Texture * sideIconBuf; |
159 | iTextBuf * timestampBuf; | 159 | iTextBuf * timestampBuf; |
160 | iRangei lastVis; | 160 | uint32_t lastRenderTime; |
161 | }; | 161 | }; |
162 | 162 | ||
163 | static void init_DrawBufs(iDrawBufs *d) { | 163 | static void init_DrawBufs(iDrawBufs *d) { |
164 | d->flags = 0; | 164 | d->flags = 0; |
165 | d->sideIconBuf = NULL; | 165 | d->sideIconBuf = NULL; |
166 | d->timestampBuf = NULL; | 166 | d->timestampBuf = NULL; |
167 | iZap(d->lastVis); | 167 | d->lastRenderTime = 0; |
168 | } | 168 | } |
169 | 169 | ||
170 | static void deinit_DrawBufs(iDrawBufs *d) { | 170 | static void deinit_DrawBufs(iDrawBufs *d) { |
@@ -794,14 +794,6 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
794 | !isSuccess_GmStatusCode(d->sourceStatus)); | 794 | !isSuccess_GmStatusCode(d->sourceStatus)); |
795 | const iRangei visRange = visibleRange_DocumentWidget_(d); | 795 | const iRangei visRange = visibleRange_DocumentWidget_(d); |
796 | const iRect bounds = bounds_Widget(as_Widget(d)); | 796 | const iRect bounds = bounds_Widget(as_Widget(d)); |
797 | if (!equal_Rangei(visRange, d->drawBufs->lastVis)) { | ||
798 | /* After scrolling/resizing stops, begin prendering the visbuf contents. | ||
799 | `Periodic` is used for detecting when the visible range has been modified. */ | ||
800 | removeTicker_App(prerender_DocumentWidget_, d); | ||
801 | remove_Periodic(periodic_App(), d); | ||
802 | add_Periodic(periodic_App(), d, | ||
803 | format_CStr("document.render from:%d to:%d", visRange.start, visRange.end)); | ||
804 | } | ||
805 | setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) }); | 797 | setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) }); |
806 | const int docSize = size_GmDocument(d->doc).y; | 798 | const int docSize = size_GmDocument(d->doc).y; |
807 | setThumb_ScrollWidget(d->scroll, | 799 | setThumb_ScrollWidget(d->scroll, |
@@ -829,6 +821,11 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
829 | recent->normScrollY = normScrollPos_DocumentWidget_(d); | 821 | recent->normScrollY = normScrollPos_DocumentWidget_(d); |
830 | } | 822 | } |
831 | } | 823 | } |
824 | /* After scrolling/resizing stops, begin pre-rendering the visbuf contents. */ { | ||
825 | removeTicker_App(prerender_DocumentWidget_, d); | ||
826 | remove_Periodic(periodic_App(), d); | ||
827 | add_Periodic(periodic_App(), d, "document.render"); | ||
828 | } | ||
832 | } | 829 | } |
833 | 830 | ||
834 | static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | 831 | static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { |
@@ -1763,10 +1760,9 @@ static iBool handlePinch_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
1763 | 1760 | ||
1764 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 1761 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
1765 | iWidget *w = as_Widget(d); | 1762 | iWidget *w = as_Widget(d); |
1766 | if (equal_Command(cmd, "document.render")) { | 1763 | if (equal_Command(cmd, "document.render")) /* Periodic makes direct dispatch to here */ { |
1767 | const iRangei vis = { argLabel_Command(cmd, "from"), argLabel_Command(cmd, "to") }; | 1764 | // printf("%u: document.render\n", SDL_GetTicks()); |
1768 | const iRangei current = visibleRange_DocumentWidget_(d); | 1765 | if (SDL_GetTicks() - d->drawBufs->lastRenderTime > 150) { |
1769 | if (equal_Rangei(vis, current)) { | ||
1770 | remove_Periodic(periodic_App(), d); | 1766 | remove_Periodic(periodic_App(), d); |
1771 | /* Scrolling has stopped, begin filling up the buffer. */ | 1767 | /* Scrolling has stopped, begin filling up the buffer. */ |
1772 | if (d->visBuf->buffers[0].texture) { | 1768 | if (d->visBuf->buffers[0].texture) { |
@@ -1824,6 +1820,8 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1824 | updateWindowTitle_DocumentWidget_(d); | 1820 | updateWindowTitle_DocumentWidget_(d); |
1825 | allocVisBuffer_DocumentWidget_(d); | 1821 | allocVisBuffer_DocumentWidget_(d); |
1826 | animateMedia_DocumentWidget_(d); | 1822 | animateMedia_DocumentWidget_(d); |
1823 | remove_Periodic(periodic_App(), d); | ||
1824 | removeTicker_App(prerender_DocumentWidget_, d); | ||
1827 | return iFalse; | 1825 | return iFalse; |
1828 | } | 1826 | } |
1829 | else if (equal_Command(cmd, "tab.created")) { | 1827 | else if (equal_Command(cmd, "tab.created")) { |
@@ -3704,6 +3702,13 @@ static void drawPin_(iPaint *p, iRect rangeRect, int dir) { | |||
3704 | init1_I2(gap_UI * 2)), pinColor); | 3702 | init1_I2(gap_UI * 2)), pinColor); |
3705 | } | 3703 | } |
3706 | 3704 | ||
3705 | static void extend_GmRunRange_(iGmRunRange *runs) { | ||
3706 | if (runs->start) { | ||
3707 | runs->start--; | ||
3708 | runs->end++; | ||
3709 | } | ||
3710 | } | ||
3711 | |||
3707 | static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, iBool prerenderExtra) { | 3712 | static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, iBool prerenderExtra) { |
3708 | iBool didDraw = iFalse; | 3713 | iBool didDraw = iFalse; |
3709 | const iRect bounds = bounds_Widget(constAs_Widget(d)); | 3714 | const iRect bounds = bounds_Widget(constAs_Widget(d)); |
@@ -3712,6 +3717,7 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
3712 | const iRangei full = { 0, size_GmDocument(d->doc).y }; | 3717 | const iRangei full = { 0, size_GmDocument(d->doc).y }; |
3713 | const iRangei vis = ctx->vis; | 3718 | const iRangei vis = ctx->vis; |
3714 | iVisBuf *visBuf = d->visBuf; /* will be updated now */ | 3719 | iVisBuf *visBuf = d->visBuf; /* will be updated now */ |
3720 | d->drawBufs->lastRenderTime = SDL_GetTicks(); | ||
3715 | /* Swap buffers around to have room available both before and after the visible region. */ | 3721 | /* Swap buffers around to have room available both before and after the visible region. */ |
3716 | allocVisBuffer_DocumentWidget_(d); | 3722 | allocVisBuffer_DocumentWidget_(d); |
3717 | reposition_VisBuf(visBuf, vis); | 3723 | reposition_VisBuf(visBuf, vis); |
@@ -3721,11 +3727,11 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
3721 | iForIndices(i, visBuf->buffers) { | 3727 | iForIndices(i, visBuf->buffers) { |
3722 | iVisBufTexture *buf = &visBuf->buffers[i]; | 3728 | iVisBufTexture *buf = &visBuf->buffers[i]; |
3723 | iVisBufMeta * meta = buf->user; | 3729 | iVisBufMeta * meta = buf->user; |
3724 | const iRangei bufRange = bufferRange_VisBuf(visBuf, i); | 3730 | const iRangei bufRange = intersect_Rangei(bufferRange_VisBuf(visBuf, i), full); |
3725 | const iRangei bufVisRange = intersect_Rangei(bufRange, vis); | 3731 | const iRangei bufVisRange = intersect_Rangei(bufRange, vis); |
3726 | ctx->widgetBounds = moved_Rect(ctxWidgetBounds, init_I2(0, -buf->origin)); | 3732 | ctx->widgetBounds = moved_Rect(ctxWidgetBounds, init_I2(0, -buf->origin)); |
3727 | ctx->viewPos = init_I2(left_Rect(ctx->docBounds) - left_Rect(bounds), -buf->origin); | 3733 | ctx->viewPos = init_I2(left_Rect(ctx->docBounds) - left_Rect(bounds), -buf->origin); |
3728 | //printf(" buffer %zu: invalid range %d...%d\n", i, invalidRange[i].start, invalidRange[i].end); | 3734 | // printf(" buffer %zu: buf vis range %d...%d\n", i, bufVisRange.start, bufVisRange.end); |
3729 | if (!prerenderExtra && !isEmpty_Range(&bufVisRange)) { | 3735 | if (!prerenderExtra && !isEmpty_Range(&bufVisRange)) { |
3730 | didDraw = iTrue; | 3736 | didDraw = iTrue; |
3731 | if (isEmpty_Rangei(buf->validRange)) { | 3737 | if (isEmpty_Rangei(buf->validRange)) { |
@@ -3737,10 +3743,7 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
3737 | iZap(ctx->runsDrawn); | 3743 | iZap(ctx->runsDrawn); |
3738 | render_GmDocument(d->doc, bufVisRange, drawRun_DrawContext_, ctx); | 3744 | render_GmDocument(d->doc, bufVisRange, drawRun_DrawContext_, ctx); |
3739 | meta->runsDrawn = ctx->runsDrawn; | 3745 | meta->runsDrawn = ctx->runsDrawn; |
3740 | if (meta->runsDrawn.start) { | 3746 | extend_GmRunRange_(&meta->runsDrawn); |
3741 | meta->runsDrawn.start--; | ||
3742 | meta->runsDrawn.end++; | ||
3743 | } | ||
3744 | buf->validRange = bufVisRange; | 3747 | buf->validRange = bufVisRange; |
3745 | // printf(" buffer %zu valid %d...%d\n", i, bufRange.start, bufRange.end); | 3748 | // printf(" buffer %zu valid %d...%d\n", i, bufRange.start, bufRange.end); |
3746 | } | 3749 | } |
@@ -3750,19 +3753,19 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
3750 | if (meta->runsDrawn.start) { | 3753 | if (meta->runsDrawn.start) { |
3751 | beginTarget_Paint(p, buf->texture); | 3754 | beginTarget_Paint(p, buf->texture); |
3752 | meta->runsDrawn.start = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start, | 3755 | meta->runsDrawn.start = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start, |
3753 | -1, iInvalidSize, | 3756 | -1, iInvalidSize, |
3754 | bufVisRange, | 3757 | bufVisRange, |
3755 | drawRun_DrawContext_, | 3758 | drawRun_DrawContext_, |
3756 | ctx); | 3759 | ctx); |
3757 | buf->validRange.start = bufVisRange.start; | 3760 | buf->validRange.start = bufVisRange.start; |
3758 | } | 3761 | } |
3759 | if (meta->runsDrawn.end) { | 3762 | if (meta->runsDrawn.end) { |
3760 | beginTarget_Paint(p, buf->texture); | 3763 | beginTarget_Paint(p, buf->texture); |
3761 | meta->runsDrawn.end = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end, | 3764 | meta->runsDrawn.end = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end, |
3762 | +1, iInvalidSize, | 3765 | +1, iInvalidSize, |
3763 | bufVisRange, | 3766 | bufVisRange, |
3764 | drawRun_DrawContext_, | 3767 | drawRun_DrawContext_, |
3765 | ctx); | 3768 | ctx); |
3766 | buf->validRange.end = bufVisRange.end; | 3769 | buf->validRange.end = bufVisRange.end; |
3767 | } | 3770 | } |
3768 | } | 3771 | } |
@@ -3770,38 +3773,62 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
3770 | /* Progressively draw the rest of the buffer if it isn't fully valid. */ | 3773 | /* Progressively draw the rest of the buffer if it isn't fully valid. */ |
3771 | if (prerenderExtra && !equal_Rangei(bufRange, buf->validRange)) { | 3774 | if (prerenderExtra && !equal_Rangei(bufRange, buf->validRange)) { |
3772 | const iGmRun *next; | 3775 | const iGmRun *next; |
3773 | if (meta->runsDrawn.start) { | 3776 | // printf("%zu: prerenderExtra (start:%p end:%p)\n", i, meta->runsDrawn.start, meta->runsDrawn.end); |
3774 | const iRangei upper = intersect_Rangei(bufRange, (iRangei){ full.start, buf->validRange.start }); | 3777 | if (meta->runsDrawn.start == NULL) { |
3775 | if (upper.end > upper.start) { | 3778 | /* Haven't drawn anything yet in this buffer, so let's try seeding it. */ |
3776 | beginTarget_Paint(p, buf->texture); | 3779 | const int rh = lineHeight_Text(paragraph_FontId); |
3777 | next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start, | 3780 | const int y = i >= iElemCount(visBuf->buffers) / 2 ? bufRange.start : (bufRange.end - rh); |
3778 | -1, 1, upper, | 3781 | beginTarget_Paint(p, buf->texture); |
3779 | drawRun_DrawContext_, | 3782 | fillRect_Paint(p, (iRect){ zero_I2(), visBuf->texSize }, tmBackground_ColorId); |
3780 | ctx); | 3783 | buf->validRange = (iRangei){ y, y + rh }; |
3781 | if (meta->runsDrawn.start != next) { | 3784 | iZap(ctx->runsDrawn); |
3782 | meta->runsDrawn.start = next; | 3785 | render_GmDocument(d->doc, buf->validRange, drawRun_DrawContext_, ctx); |
3783 | didDraw = iTrue; | 3786 | meta->runsDrawn = ctx->runsDrawn; |
3787 | extend_GmRunRange_(&meta->runsDrawn); | ||
3788 | // printf("%zu: seeded, next %p:%p\n", i, meta->runsDrawn.start, meta->runsDrawn.end); | ||
3789 | didDraw = iTrue; | ||
3790 | } | ||
3791 | else { | ||
3792 | if (meta->runsDrawn.start) { | ||
3793 | const iRangei upper = intersect_Rangei(bufRange, (iRangei){ full.start, buf->validRange.start }); | ||
3794 | if (upper.end > upper.start) { | ||
3795 | beginTarget_Paint(p, buf->texture); | ||
3796 | next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.start, | ||
3797 | -1, 1, upper, | ||
3798 | drawRun_DrawContext_, | ||
3799 | ctx); | ||
3800 | if (next && meta->runsDrawn.start != next) { | ||
3801 | meta->runsDrawn.start = next; | ||
3802 | buf->validRange.start = bottom_Rect(next->visBounds); | ||
3803 | didDraw = iTrue; | ||
3804 | } | ||
3805 | else { | ||
3806 | buf->validRange.start = bufRange.start; | ||
3807 | } | ||
3784 | } | 3808 | } |
3785 | buf->validRange.start = bufRange.start; | ||
3786 | } | 3809 | } |
3787 | } | 3810 | if (!didDraw && meta->runsDrawn.end) { |
3788 | if (meta->runsDrawn.end) { | 3811 | const iRangei lower = intersect_Rangei(bufRange, (iRangei){ buf->validRange.end, full.end }); |
3789 | const iRangei lower = intersect_Rangei(bufRange, (iRangei){ buf->validRange.end, full.end }); | 3812 | if (lower.end > lower.start) { |
3790 | if (lower.end > lower.start) { | 3813 | beginTarget_Paint(p, buf->texture); |
3791 | beginTarget_Paint(p, buf->texture); | 3814 | next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end, |
3792 | next = renderProgressive_GmDocument(d->doc, meta->runsDrawn.end, | 3815 | +1, 1, lower, |
3793 | +1, 1, lower, | 3816 | drawRun_DrawContext_, |
3794 | drawRun_DrawContext_, | 3817 | ctx); |
3795 | ctx); | 3818 | if (next && meta->runsDrawn.end != next) { |
3796 | if (meta->runsDrawn.end != next) { | 3819 | meta->runsDrawn.end = next; |
3797 | meta->runsDrawn.end = next; | 3820 | buf->validRange.end = top_Rect(next->visBounds); |
3798 | didDraw = iTrue; | 3821 | didDraw = iTrue; |
3822 | } | ||
3823 | else { | ||
3824 | buf->validRange.end = bufRange.end; | ||
3825 | } | ||
3799 | } | 3826 | } |
3800 | buf->validRange.end = bufRange.end; | ||
3801 | } | 3827 | } |
3802 | } | 3828 | } |
3803 | } | 3829 | } |
3804 | /* Draw any invalidated runs that fall within this buffer. */ { | 3830 | /* Draw any invalidated runs that fall within this buffer. */ |
3831 | if (!prerenderExtra) { | ||
3805 | const iRangei bufRange = { buf->origin, buf->origin + visBuf->texSize.y }; | 3832 | const iRangei bufRange = { buf->origin, buf->origin + visBuf->texSize.y }; |
3806 | /* Clear full-width backgrounds first in case there are any dynamic elements. */ { | 3833 | /* Clear full-width backgrounds first in case there are any dynamic elements. */ { |
3807 | iConstForEach(PtrSet, r, d->invalidRuns) { | 3834 | iConstForEach(PtrSet, r, d->invalidRuns) { |
@@ -3826,6 +3853,9 @@ static iBool render_DocumentWidget_(const iDocumentWidget *d, iDrawContext *ctx, | |||
3826 | } | 3853 | } |
3827 | } | 3854 | } |
3828 | endTarget_Paint(p); | 3855 | endTarget_Paint(p); |
3856 | if (prerenderExtra && didDraw) { | ||
3857 | return iTrue; | ||
3858 | } | ||
3829 | } | 3859 | } |
3830 | clear_PtrSet(d->invalidRuns); | 3860 | clear_PtrSet(d->invalidRuns); |
3831 | } | 3861 | } |