add multi-threaded precache

Because the lua reader is single threaded on which both user inputloop
and background page rendering is processed. Although there is a pretty
good precache system to save user's time spending on waiting for the
rendering when going to the next page, user input is indeed blocked when
running the precache thing. The situation is even worse in koptreader as
reflowing on page would usually take several second, in this period
users cannot move to the next page view even it's already in the cache.
This patch will let precache run in the background in a seperate thread
so that the koptreader is still responsive when precaching the next
page. Now it only just works. Welcome to find out bugs in it.
chrox 12 years ago
parent 38e75c230e
commit 1d018ee5bf

@ -18,6 +18,7 @@
#include <math.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <libdjvu/miniexp.h>
#include <libdjvu/ddjvuapi.h>
@ -476,7 +477,6 @@ static int reflowPage(lua_State *L) {
DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");
KOPTContext *kctx = (KOPTContext*) luaL_checkudata(L, 2, "koptcontext");
ddjvu_render_mode_t mode = (int) luaL_checkint(L, 3);
WILLUSBITMAP _src, *src;
ddjvu_rect_t prect;
ddjvu_rect_t rrect;
@ -510,7 +510,7 @@ static int reflowPage(lua_State *L) {
dpi *= kctx->shrink_factor;
} while (rrect.w > kctx->read_max_width | rrect.h > kctx->read_max_height);
src = &_src;
WILLUSBITMAP *src = malloc(sizeof(WILLUSBITMAP));
bmp_init(src);
src->width = rrect.w;
src->height = rrect.h;
@ -528,8 +528,13 @@ static int reflowPage(lua_State *L) {
status = ddjvu_page_render(page->page_ref, mode, &prect, &rrect, page->doc->pixelformat,
bmp_bytewidth(src), (char *) src->data);
k2pdfopt_reflow_bmp(kctx, src);
bmp_free(src);
kctx->src = src;
if (kctx->precache) {
pthread_t rf_thread;
pthread_create(&rf_thread, NULL, k2pdfopt_reflow_bmp, (void*) kctx);
} else {
k2pdfopt_reflow_bmp(kctx);
}
return 0;
}

@ -46,6 +46,8 @@ static int newKOPTContext(lua_State *L) {
uint8_t *data = NULL;
BBox bbox = {0, 0, 0, 0};
WILLUSBITMAP *src;
int precache = 0;
KOPTContext *kc = (KOPTContext*) lua_newuserdata(L, sizeof(KOPTContext));
@ -76,6 +78,8 @@ static int newKOPTContext(lua_State *L) {
kc->data = data;
kc->bbox = bbox;
kc->src = src;
kc->precache = precache;
luaL_getmetatable(L, "koptcontext");
lua_setmetatable(L, -2);
@ -216,6 +220,18 @@ static int kcSetWordSpacing(lua_State *L) {
return 0;
}
static int kcSetPreCache(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
kc->precache = 1;
return 0;
}
static int kcIsPreCache(lua_State *L) {
KOPTContext *kc = (KOPTContext*) luaL_checkudata(L, 1, "koptcontext");
lua_pushinteger(L, kc->precache);
return 1;
}
static const struct luaL_Reg koptcontext_meth[] = {
{"setBBox", kcSetBBox},
{"setTrim", kcSetTrim},
@ -239,6 +255,9 @@ static const struct luaL_Reg koptcontext_meth[] = {
{"setDefectSize", kcSetDefectSize},
{"setLineSpacing", kcSetLineSpacing},
{"setWordSpacing", kcSetWordSpacing},
{"setPreCache", kcSetPreCache},
{"isPreCache", kcIsPreCache},
{NULL, NULL}
};

@ -278,6 +278,30 @@ function KOPTReader:drawOrCache(no, preCache)
-- okay, we do not have it in cache yet.
-- so render now.
-- start off with the requested area
if preCache then
Debug("start precache on page", no)
if self.precache_kc ~= nil then
if self.precache_kc:isPreCache() == 1 then
Debug("wait threaded precache to finish.")
return
else
Debug("reflow thread is finished.")
return self:drawAndCache(self.precache_kc, page, pagehash, preCache)
end
else
self.precache_kc = kc
self.precache_kc:setPreCache()
page:reflow(self.precache_kc, self.render_mode)
Debug("threaded reflow is returned.")
end
else
page:reflow(kc, self.render_mode)
return self:drawAndCache(kc, page, pagehash, preCache)
end
end
function KOPTReader:drawAndCache(kc, page, pagehash, preCache)
local tile = { x = offset_x_in_page, y = offset_y_in_page,
w = width, h = height }
-- can we cache the full page?
@ -286,7 +310,6 @@ function KOPTReader:drawOrCache(no, preCache)
max_cache = max_cache - self.cache[self.pagehash].size
end
page:reflow(kc, self.render_mode)
self.fullwidth, self.fullheight = kc:getPageDim()
self.reflow_zoom = kc:getZoom()
Debug("page::reflowPage:", "fullwidth:", self.fullwidth, "fullheight:", self.fullheight)
@ -318,6 +341,10 @@ function KOPTReader:drawOrCache(no, preCache)
page:rfdraw(kc, self.cache[pagehash].bb)
page:close()
if preCache then
self.precache_kc = nil
end
self.min_offset_x = fb.bb:getWidth() - self.cache[pagehash].w
self.min_offset_y = fb.bb:getHeight() - self.cache[pagehash].h
if(self.min_offset_x > 0) then
@ -341,7 +368,7 @@ function KOPTReader:drawOrCache(no, preCache)
offset_x_in_page - tile.x,
offset_y_in_page - tile.y
end
-- get reflow context
function KOPTReader:getContext(page, pnumber, preCache)
local kc = self:makeContext()
@ -351,6 +378,7 @@ function KOPTReader:getContext(page, pnumber, preCache)
-- without it, later check whether to use margins will fail for some documents
pwidth = math.floor(pwidth * 100) / 100
pheight = math.floor(pheight * 100) / 100
Debug("preCache:", preCache and "true" or "false")
Debug("page::getSize",pwidth,pheight)
local x0, y0, x1, y1 = page:getUsedBBox()

21
pdf.c

@ -15,6 +15,11 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <math.h>
#include <stddef.h>
#include <pthread.h>
#include <fitz/fitz-internal.h>
#include "blitbuffer.h"
@ -22,10 +27,6 @@
#include "koptcontext.h"
#include "k2pdfopt.h"
#include "pdf.h"
#include <stdio.h>
#include <math.h>
#include <stddef.h>
typedef struct PdfDocument {
fz_document *xref;
@ -563,7 +564,6 @@ static int reflowPage(lua_State *L) {
fz_rect bounds,bounds2;
fz_matrix ctm;
fz_bbox bbox;
WILLUSBITMAP _src, *src;
pix = NULL;
fz_var(pix);
@ -606,14 +606,19 @@ static int reflowPage(lua_State *L) {
fz_run_page(page->doc->xref, page->page, dev, ctm, NULL);
fz_free_device(dev);
src = &_src;
WILLUSBITMAP *src = malloc(sizeof(WILLUSBITMAP));
bmp_init(src);
int status = bmpmupdf_pixmap_to_bmp(src, page->doc->context, pix);
fz_drop_pixmap(page->doc->context, pix);
k2pdfopt_reflow_bmp(kctx, src);
bmp_free(src);
kctx->src = src;
if (kctx->precache) {
pthread_t rf_thread;
pthread_create( &rf_thread, NULL, k2pdfopt_reflow_bmp, (void*) kctx);
} else {
k2pdfopt_reflow_bmp(kctx);
}
return 0;
}

Loading…
Cancel
Save