From 7210fb478d8d0c6aa5bb8e0ae3e0fc67dd730874 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Wed, 27 Mar 2019 22:50:44 +0100 Subject: [PATCH] Faster blitting @ BB8/BBRGB32 when no processing is needed (#4847) * Pickup the eponymous blitting performance tweaks from koreader/koreader-base#878 * Cleanup BitOpts usage (require & cache) * Unify oddness checks (MOD -> AND) * Enforce the native Portrait orientation on Kobo (except @ 16bpp, i.e., KSM w/ 8bpp swap disabled), to allow for faster blitting when unrotted. * Switch CRe BB to 32BPP on color screens * Minor cleanups --- base | 2 +- .../apps/reader/modules/readerrolling.lua | 7 ++- frontend/device/generic/device.lua | 2 +- frontend/document/credocument.lua | 12 +++-- frontend/document/document.lua | 1 + frontend/optmath.lua | 6 ++- frontend/random.lua | 1 + frontend/ui/rendertext.lua | 27 +++++----- frontend/ui/widget/imagewidget.lua | 2 +- frontend/ui/widget/networksetting.lua | 5 +- platform/kobo/koreader.sh | 49 ++++++++----------- plugins/statistics.koplugin/main.lua | 1 + 12 files changed, 64 insertions(+), 51 deletions(-) diff --git a/base b/base index 8660dcd10..5f5df5c00 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 8660dcd10c3a0512ce5144a223e4c4ee34eb0646 +Subproject commit 5f5df5c0091642daed49b09fb1b023c3113b66ed diff --git a/frontend/apps/reader/modules/readerrolling.lua b/frontend/apps/reader/modules/readerrolling.lua index c3c6415e7..a6dc1d264 100644 --- a/frontend/apps/reader/modules/readerrolling.lua +++ b/frontend/apps/reader/modules/readerrolling.lua @@ -1,3 +1,4 @@ +local bit = require("bit") local Blitbuffer = require("ffi/blitbuffer") local ConfirmBox = require("ui/widget/confirmbox") local Device = require("device") @@ -11,6 +12,8 @@ local Input = Device.input local Screen = Device.screen local T = require("ffi/util").template +local band = bit.band + --[[ Rolling is just like paging in page-based documents except that sometimes (in scroll mode) there is no concept of page number to indicate @@ -789,12 +792,12 @@ function ReaderRolling:_gotoPage(new_page, free_first_page) if self.ui.document:getVisiblePageCount() > 1 and not free_first_page then -- Ensure we always have the first of the two pages odd if self.odd_or_even_first_page == 1 then -- odd - if new_page % 2 == 0 then + if band(new_page, 1) == 0 then -- requested page will be shown as the right page new_page = new_page - 1 end elseif self.odd_or_even_first_page == 2 then -- (or 'even' if requested) - if new_page % 2 == 1 then + if band(new_page, 1) == 1 then -- requested page will be shown as the right page new_page = new_page - 1 end diff --git a/frontend/device/generic/device.lua b/frontend/device/generic/device.lua index c659121eb..e334826a9 100644 --- a/frontend/device/generic/device.lua +++ b/frontend/device/generic/device.lua @@ -219,7 +219,7 @@ function Device:onPowerEvent(ev) G_reader_settings:readSetting("screensaver_type") == "random_image" or G_reader_settings:readSetting("screensaver_type") == "image_file" then if not G_reader_settings:isTrue("screensaver_no_background") then - self.screen:clear(self.screen:getScreenWidth(), self.screen:getScreenHeight()) + self.screen:clear() end self.screen:refreshFull() end diff --git a/frontend/document/credocument.lua b/frontend/document/credocument.lua index d16e9f938..7060aaad4 100644 --- a/frontend/document/credocument.lua +++ b/frontend/document/credocument.lua @@ -359,18 +359,20 @@ function CreDocument:drawCurrentView(target, x, y, rect, pos) end if not self.buffer then -- Note about color rendering: - -- If we use TYPE_BBRGB32 (and LVColorDrawBuf drawBuf(..., 32) in cre.cpp), - -- we get inverted Red and Blue in the blitbuffer (could be that - -- crengine/src/lvdrawbuf.cpp treats our 32bits not as RGBA). - -- But it is all fine if we use TYPE_BBRGB16. - self.buffer = Blitbuffer.new(rect.w, rect.h, self.render_color and Blitbuffer.TYPE_BBRGB16 or nil) + -- We use TYPE_BBRGB32 (and LVColorDrawBuf drawBuf(..., 32) in cre.cpp), + -- to match the screen's BB type, allowing us to take shortcuts when blitting. + self.buffer = Blitbuffer.new(rect.w, rect.h, self.render_color and Blitbuffer.TYPE_BBRGB32 or nil) end -- TODO: self.buffer could be re-used when no page/layout/highlights -- change has been made, to avoid having crengine redraw the exact -- same buffer. -- And it could only change when some other methods from here are called + --local start_clock = os.clock() self._drawn_images_count, self._drawn_images_surface_ratio = self._document:drawCurrentPage(self.buffer, self.render_color) + --print(string.format("CreDocument:drawCurrentView: Rendering took %9.3f ms", (os.clock() - start_clock) * 1000)) + --start_clock = os.clock() target:blitFrom(self.buffer, x, y, 0, 0, rect.w, rect.h) + --print(string.format("CreDocument:drawCurrentView: Blitting took %9.3f ms", (os.clock() - start_clock) * 1000)) end function CreDocument:drawCurrentViewByPos(target, x, y, rect, pos) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index 83bb7dad1..fad2f42dd 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -134,6 +134,7 @@ function Document:fastDigest(docsettings) local result = docsettings:readSetting("partial_md5_checksum") if not result then logger.dbg("computing and storing partial_md5_checksum") + local bit = require("bit") local md5 = require("ffi/MD5") local lshift = bit.lshift local step, size = 1024, 1024 diff --git a/frontend/optmath.lua b/frontend/optmath.lua index 8584fd960..e888186d9 100644 --- a/frontend/optmath.lua +++ b/frontend/optmath.lua @@ -2,8 +2,12 @@ Simple math helper functions ]] +local bit = require("bit") + local Math = {} +local band = bit.band + function Math.roundAwayFromZero(num) if num > 0 then return math.ceil(num) @@ -17,7 +21,7 @@ function Math.round(num) end function Math.oddEven(number) - if number % 2 == 1 then + if band(number, 1) == 1 then return "odd" else return "even" diff --git a/frontend/random.lua b/frontend/random.lua index 6c2eb579c..d5ed4580d 100644 --- a/frontend/random.lua +++ b/frontend/random.lua @@ -1,5 +1,6 @@ --- A set of functions to extend math.random and math.randomseed. +local bit = require("bit") local random = {} --- Uses current time as seed to randomize. diff --git a/frontend/ui/rendertext.lua b/frontend/ui/rendertext.lua index f5095652c..284e3d44c 100644 --- a/frontend/ui/rendertext.lua +++ b/frontend/ui/rendertext.lua @@ -2,6 +2,7 @@ Text rendering module. ]] +local bit = require("bit") local Font = require("ui/font") local Cache = require("cache") local CacheItem = require("cacheitem") @@ -9,6 +10,10 @@ local BlitBuffer = require("ffi/blitbuffer") local Device = require("device") local logger = require("logger") +local band = bit.band +local bor = bit.bor +local lshift = bit.lshift + if Device.should_restrict_JIT then require("jit").off(true, true) end @@ -31,23 +36,23 @@ local function utf8Chars(input_text) local function read_next_glyph(input, pos) if string.len(input) < pos then return nil end local value = string.byte(input, pos) - if bit.band(value, 0x80) == 0 then + if band(value, 0x80) == 0 then -- TODO: check valid ranges return pos+1, value, string.sub(input, pos, pos) - elseif bit.band(value, 0xC0) == 0x80 -- invalid, continuation - or bit.band(value, 0xF8) == 0xF8 -- 5-or-more byte sequence, illegal due to RFC3629 + elseif band(value, 0xC0) == 0x80 -- invalid, continuation + or band(value, 0xF8) == 0xF8 -- 5-or-more byte sequence, illegal due to RFC3629 then return pos+1, 0xFFFD, "\xFF\xFD" else local glyph, bytes_left - if bit.band(value, 0xE0) == 0xC0 then - glyph = bit.band(value, 0x1F) + if band(value, 0xE0) == 0xC0 then + glyph = band(value, 0x1F) bytes_left = 1 - elseif bit.band(value, 0xF0) == 0xE0 then - glyph = bit.band(value, 0x0F) + elseif band(value, 0xF0) == 0xE0 then + glyph = band(value, 0x0F) bytes_left = 2 - elseif bit.band(value, 0xF8) == 0xF0 then - glyph = bit.band(value, 0x07) + elseif band(value, 0xF8) == 0xF0 then + glyph = band(value, 0x07) bytes_left = 3 else return pos+1, 0xFFFD, "\xFF\xFD" @@ -57,8 +62,8 @@ local function utf8Chars(input_text) end for i = pos+1, pos + bytes_left do value = string.byte(input, i) - if bit.band(value, 0xC0) == 0x80 then - glyph = bit.bor(bit.lshift(glyph, 6), bit.band(value, 0x3F)) + if band(value, 0xC0) == 0x80 then + glyph = bor(lshift(glyph, 6), band(value, 0x3F)) else -- invalid UTF8 continuation - don't be greedy, just skip -- the initial char of the sequence. diff --git a/frontend/ui/widget/imagewidget.lua b/frontend/ui/widget/imagewidget.lua index 199d30dec..1565aff6b 100644 --- a/frontend/ui/widget/imagewidget.lua +++ b/frontend/ui/widget/imagewidget.lua @@ -168,7 +168,7 @@ function ImageWidget:_loadfile() -- cache this image logger.dbg("cache", hash) cache = ImageCacheItem:new{ bb = self._bb } - cache.size = cache.bb.pitch * cache.bb.h * cache.bb:getBpp() / 8 + cache.size = cache.bb.pitch * cache.bb.h * cache.bb:getBytesPerPixel() ImageCache:insert(hash, cache) end end diff --git a/frontend/ui/widget/networksetting.lua b/frontend/ui/widget/networksetting.lua index 67cc908c7..f153a7c3a 100644 --- a/frontend/ui/widget/networksetting.lua +++ b/frontend/ui/widget/networksetting.lua @@ -30,6 +30,7 @@ Example: ]] +local bit = require("bit") local Blitbuffer = require("ffi/blitbuffer") local CenterContainer = require("ui/widget/container/centercontainer") local Device = require("device") @@ -57,6 +58,8 @@ local _ = require("gettext") local T = require("ffi/util").template local Screen = Device.screen +local band = bit.band + local function obtainIP() -- TODO: check for DHCP result local info = InfoMessage:new{text = _("Obtaining IP address…")} @@ -386,7 +389,7 @@ function NetworkSetting:init() function(l, r) return l.signal_quality > r.signal_quality end) for idx, network in ipairs(self.network_list) do local bg - if idx % 2 == 0 then + if band(idx, 1) == 0 then bg = gray_bg else bg = Blitbuffer.COLOR_WHITE diff --git a/platform/kobo/koreader.sh b/platform/kobo/koreader.sh index 3a5be709d..ddbc6b5e3 100755 --- a/platform/kobo/koreader.sh +++ b/platform/kobo/koreader.sh @@ -135,19 +135,10 @@ if [ -z "${INTERFACE}" ]; then fi # end of value check of PLATFORM -# If we're on a Forma, make sure we start in an orientation we know how to handle (i.e., Portrait, buttons on the Right) -# Because NTX likes mounting panels in weird native rotations, this is actually FB_ROTATE_CCW (3). -# And because shit gets even weirder, we have to echo 1 to get 3 (because the kernel inverts Landscape FB constants, and 3 ^ 2 = 1). -if [ "${PRODUCT}" = "frost" ]; then - # NOTE: We enforce this *everywhere*, because KSM is currently emulating a bogus pickel rotation (UR (0), instead of CCW (3)), - # and current kernels are surreptitiously broken when UR @ 8bpp (especially as far as A2 handling is concerned)... - ORIG_FB_ROTA="$(cat /sys/class/graphics/fb0/rotate)" - # Don't do anything if we're already in the right orientation. - if [ "${ORIG_FB_ROTA}" -ne "3" ]; then - echo 1 >/sys/class/graphics/fb0/rotate - fi -fi -# NOTE: We don't have to restore anything on exit, nickel's startup process will take care of everything (pickel -> nickel). +# We'll want to ensure Portrait rotation to allow us to use faster blitting codepaths @ 8bpp, +# so remember the current one before fbdepth does its thing. +ORIG_FB_ROTA="$(cat /sys/class/graphics/fb0/rotate)" +echo "Original fb rotation is set @ ${ORIG_FB_ROTA}" >>crash.log 2>&1 # In the same vein, swap to 8bpp, # because 16bpp is the worst idea in the history of time, as RGB565 is generally a PITA without hardware blitting, @@ -175,14 +166,21 @@ ko_do_fbdepth() { if grep -q '\["dev_startup_no_fbdepth"\] = true' 'settings.reader.lua' 2>/dev/null; then # Swap back to the original bitdepth (in case this was a restart) if [ -n "${ORIG_FB_BPP}" ]; then - echo "Making sure we're using the original fb bitdepth @ ${ORIG_FB_BPP}bpp" >>crash.log 2>&1 - ./fbdepth -d "${ORIG_FB_BPP}" >>crash.log 2>&1 + # Unless we're a Forma, don't even bother to swap rotation if the fb is @ 16bpp, because RGB565 is terrible anyways, + # so there's no faster codepath to achieve, and running in Portrait @ 16bpp might actually be broken on some setups... + if [ "${ORIG_FB_BPP}" -eq "16" ] && [ "${PRODUCT}" != "frost" ]; then + echo "Making sure we're using the original fb bitdepth @ ${ORIG_FB_BPP}bpp & rotation @ ${ORIG_FB_ROTA}" >>crash.log 2>&1 + ./fbdepth -d "${ORIG_FB_BPP}" -r "${ORIG_FB_ROTA}" >>crash.log 2>&1 + else + echo "Making sure we're using the original fb bitdepth @ ${ORIG_FB_BPP}bpp, and that rotation is set to Portrait" >>crash.log 2>&1 + ./fbdepth -d "${ORIG_FB_BPP}" -r -1 >>crash.log 2>&1 + fi fi else # Swap to 8bpp if things looke sane if [ -n "${ORIG_FB_BPP}" ]; then - echo "Switching fb bitdepth to 8bpp" >>crash.log 2>&1 - ./fbdepth -d 8 >>crash.log 2>&1 + echo "Switching fb bitdepth to 8bpp & rotation to Portrait" >>crash.log 2>&1 + ./fbdepth -d 8 -r -1 >>crash.log 2>&1 fi fi } @@ -210,18 +208,13 @@ while [ $RETURN_VALUE -eq 85 ]; do done # Restore original fb bitdepth if need be... +# Since we also (almost) always enforce Portrait, we also have to restore the original rotation no matter what ;). if [ -n "${ORIG_FB_BPP}" ]; then - echo "Restoring original fb bitdepth @ ${ORIG_FB_BPP}bpp" >>crash.log 2>&1 - ./fbdepth -d "${ORIG_FB_BPP}" >>crash.log 2>&1 -fi - -# Restore original fb rotation on the Forma, for KSM -if [ "${PRODUCT}" = "frost" ]; then - # Only needed for KSM, pickel -> Nickel will restore its own rota properly - if [ "${FROM_NICKEL}" != "true" ]; then - # The Forma kernel inverts odd rotation constants, counteract that, à la Plato, because one-liner ;p. - echo "$(((4 - ORIG_FB_ROTA) % 4))" >/sys/class/graphics/fb0/rotate - fi + echo "Restoring original fb bitdepth @ ${ORIG_FB_BPP}bpp & rotation @ ${ORIG_FB_ROTA}" >>crash.log 2>&1 + ./fbdepth -d "${ORIG_FB_BPP}" -r "${ORIG_FB_ROTA}" >>crash.log 2>&1 +else + echo "Restoring original fb rotation @ ${ORIG_FB_ROTA}" >>crash.log 2>&1 + ./fbdepth -r "${ORIG_FB_ROTA}" >>crash.log 2>&1 fi # Restore original CPUFreq governor if need be... diff --git a/plugins/statistics.koplugin/main.lua b/plugins/statistics.koplugin/main.lua index be530471c..f04882785 100755 --- a/plugins/statistics.koplugin/main.lua +++ b/plugins/statistics.koplugin/main.lua @@ -269,6 +269,7 @@ function ReaderStatistics:partialMd5(file) if file == nil then return nil end + local bit = require("bit") local md5 = require("ffi/MD5") local lshift = bit.lshift local step, size = 1024, 1024