mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Merge pull request #1107 from NiLuJe/master
Revamp the waveform mode selection logic
This commit is contained in:
@@ -7,7 +7,7 @@ local ReaderActivityIndicator = EventListener:new{}
|
||||
|
||||
function ReaderActivityIndicator:init()
|
||||
local dev_mod = Device.model
|
||||
if dev_mod == "KindlePaperWhite" or dev_mod == "KindlePaperWhite2" or dev_mod == "KindleTouch" then
|
||||
if dev_mod == "KindlePaperWhite" or dev_mod == "KindlePaperWhite2" or dev_mod == "KindleVoyage" or dev_mod == "KindleBasic" or dev_mod == "KindleTouch" then
|
||||
require "liblipclua"
|
||||
self.lipc_handle = lipc.init("com.github.koreader.activityindicator")
|
||||
end
|
||||
|
||||
@@ -53,6 +53,21 @@ local KindlePaperWhite2 = Kindle:new{
|
||||
touch_dev = "/dev/input/event1",
|
||||
}
|
||||
|
||||
local KindleBasic = Kindle:new{
|
||||
model = "KindleBasic",
|
||||
isTouchDevice = yes,
|
||||
-- FIXME!
|
||||
touch_dev = "/dev/input/event0",
|
||||
}
|
||||
|
||||
local KindleVoyage = Kindle:new{
|
||||
model = "KindleVoyage",
|
||||
isTouchDevice = yes,
|
||||
hasFrontlight = yes,
|
||||
display_dpi = 300,
|
||||
touch_dev = "/dev/input/event1",
|
||||
}
|
||||
|
||||
function Kindle2:init()
|
||||
self.screen = require("device/screen"):new{device = self}
|
||||
self.input = require("device/input"):new{
|
||||
@@ -140,8 +155,8 @@ function KindlePaperWhite2:init()
|
||||
self.powerd = require("device/kindle/powerd"):new{
|
||||
device = self,
|
||||
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
|
||||
batt_capacity_file = "/sys/devices/system/yoshi_battery/yoshi_battery0/battery_capacity",
|
||||
is_charging_file = "/sys/devices/platform/aplite_charger.0/charging",
|
||||
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
||||
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
||||
}
|
||||
|
||||
Kindle.init(self)
|
||||
@@ -149,6 +164,35 @@ function KindlePaperWhite2:init()
|
||||
self.input.open("/dev/input/event1")
|
||||
end
|
||||
|
||||
function KindleBasic:init()
|
||||
self.screen = require("device/screen"):new{device = self}
|
||||
self.powerd = require("device/kindle/powerd"):new{
|
||||
device = self,
|
||||
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
||||
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
||||
}
|
||||
|
||||
Kindle.init(self)
|
||||
|
||||
-- FIXME!
|
||||
self.input.open("/dev/input/event0")
|
||||
end
|
||||
|
||||
function KindleVoyage:init()
|
||||
self.screen = require("device/screen"):new{device = self}
|
||||
self.powerd = require("device/kindle/powerd"):new{
|
||||
device = self,
|
||||
fl_intensity_file = "/sys/class/backlight/max77696-bl/brightness",
|
||||
batt_capacity_file = "/sys/devices/system/wario_battery/wario_battery0/battery_capacity",
|
||||
is_charging_file = "/sys/devices/system/wario_charger/wario_charger0/charging",
|
||||
}
|
||||
|
||||
Kindle.init(self)
|
||||
|
||||
self.input.open("/dev/input/event1")
|
||||
-- TODO: Handle the page turn 'buttons'! (/dev/input/event2)
|
||||
end
|
||||
|
||||
--[[
|
||||
Test if a kindle device has Special Offers
|
||||
--]]
|
||||
@@ -188,6 +232,8 @@ function KindleTouch:exit()
|
||||
end
|
||||
KindlePaperWhite.exit = KindleTouch.exit
|
||||
KindlePaperWhite2.exit = KindleTouch.exit
|
||||
KindleBasic.exit = KindleTouch.exit
|
||||
KindleVoyage.exit = KindleTouch.exit
|
||||
|
||||
function Kindle3:exit()
|
||||
-- send double menu key press events to trigger screen refresh
|
||||
@@ -223,6 +269,8 @@ local touch_set = Set { "0F", "11", "10", "12" }
|
||||
local pw_set = Set { "24", "1B", "1D", "1F", "1C", "20" }
|
||||
local pw2_set = Set { "D4", "5A", "D5", "D6", "D7", "D8", "F2", "17",
|
||||
"60", "F4", "F9", "62", "61", "5F" }
|
||||
local kt2_set = Set { "C6" }
|
||||
local kv_set = Set { "13", "54", "2A", "4F", "52", "53" }
|
||||
|
||||
if k2_set[kindle_devcode] then
|
||||
return Kindle2
|
||||
@@ -240,6 +288,10 @@ elseif pw_set[kindle_devcode] then
|
||||
return KindlePaperWhite
|
||||
elseif pw2_set[kindle_devcode] then
|
||||
return KindlePaperWhite2
|
||||
elseif kt2_set[kindle_devcode] then
|
||||
return KindleBasic
|
||||
elseif kv_set[kindle_devcode] then
|
||||
return KindleVoyage
|
||||
end
|
||||
|
||||
error("unknown Kindle model "..kindle_devcode)
|
||||
|
||||
@@ -78,13 +78,13 @@ function Screen:setViewport(viewport)
|
||||
self.viewport.w, self.viewport.h)
|
||||
end
|
||||
|
||||
function Screen:refresh(refresh_type, waveform_mode, x, y, w, h)
|
||||
function Screen:refresh(refresh_type, waveform_mode, wait_for_marker, x, y, w, h)
|
||||
if self.viewport and x and y then
|
||||
-- adapt to viewport
|
||||
x = x + self.viewport.x
|
||||
y = y + self.viewport.y
|
||||
end
|
||||
self.fb:refresh(refresh_type, waveform_mode, x, y, w, h)
|
||||
self.fb:refresh(refresh_type, waveform_mode, wait_for_marker, x, y, w, h)
|
||||
end
|
||||
|
||||
function Screen:getSize()
|
||||
|
||||
@@ -6,6 +6,10 @@ local util = require("ffi/util")
|
||||
local DEBUG = require("dbg")
|
||||
local _ = require("gettext")
|
||||
|
||||
-- cf. koreader-base/ffi-cdecl/include/mxcfb-kindle.h (UPDATE_MODE_* applies to Kobo, too)
|
||||
local UPDATE_MODE_PARTIAL = 0x0
|
||||
local UPDATE_MODE_FULL = 0x1
|
||||
|
||||
-- NOTE: Those have been confirmed on Kindle devices. Might be completely different on Kobo (except for AUTO)!
|
||||
local WAVEFORM_MODE_INIT = 0x0 -- Screen goes to white (clears)
|
||||
local WAVEFORM_MODE_DU = 0x1 -- Grey->white/grey->black
|
||||
@@ -20,16 +24,25 @@ local WAVEFORM_MODE_DU4 = 0x7 -- Medium fidelity 4 level of gray dire
|
||||
-- Kindle PW2
|
||||
local WAVEFORM_MODE_REAGL = 0x8 -- Ghost compensation waveform
|
||||
local WAVEFORM_MODE_REAGLD = 0x9 -- Ghost compensation waveform with dithering
|
||||
-- Kindle Basic/Kindle Voyage
|
||||
local WAVEFORM_MODE_GL4 = 0xA -- 2-bit from white transition
|
||||
-- TODO: Use me in night mode on those devices?
|
||||
local WAVEFORM_MODE_GL16_INV = 0xB -- High fidelity for black transition
|
||||
|
||||
local WAVEFORM_MODE_AUTO = 0x101
|
||||
|
||||
-- Kobo's headers suck, so invent something to avoid magic numbers...
|
||||
local WAVEFORM_MODE_KOBO_REGAL = 0x7
|
||||
|
||||
|
||||
-- there is only one instance of this
|
||||
local UIManager = {
|
||||
default_refresh_type = 0, -- 0 for partial refresh, 1 for full refresh
|
||||
default_refresh_type = UPDATE_MODE_PARTIAL,
|
||||
default_waveform_mode = WAVEFORM_MODE_GC16, -- high fidelity waveform
|
||||
fast_waveform_mode = WAVEFORM_MODE_A2,
|
||||
fast_waveform_mode = WAVEFORM_MODE_A2, -- FIXME: Is this OK on Kobo?
|
||||
full_refresh_waveform_mode = WAVEFORM_MODE_GC16,
|
||||
partial_refresh_waveform_mode = WAVEFORM_MODE_GC16,
|
||||
wait_for_every_marker = false,
|
||||
-- force to repaint all the widget is stack, will be reset to false
|
||||
-- after each ui loop
|
||||
repaint_all = false,
|
||||
@@ -89,6 +102,20 @@ function UIManager:init()
|
||||
if KOBO_LIGHT_ON_START and tonumber(KOBO_LIGHT_ON_START) > -1 then
|
||||
Device:getPowerDevice():setIntensity( math.max( math.min(KOBO_LIGHT_ON_START,100) ,0) )
|
||||
end
|
||||
-- Emulate the stock reader's refresh behavior...
|
||||
self.full_refresh_waveform_mode = WAVEFORM_MODE_GC16
|
||||
-- Request REGAL waveform mode on devices that support it (Aura & H2O)
|
||||
if Device.model == "Kobo_phoenix" or Device.model == "Kobo_dahlia" then
|
||||
self.partial_refresh_waveform_mode = WAVEFORM_MODE_KOBO_REGAL
|
||||
-- Since Kobo doesn't have MXCFB_WAIT_FOR_UPDATE_SUBMISSION, enabling this currently has no effect :).
|
||||
self.wait_for_every_marker = true
|
||||
else
|
||||
-- See the note in the Kindle code path later, the stock reader might be using AUTO
|
||||
self.partial_refresh_waveform_mode = WAVEFORM_MODE_GC16
|
||||
self.wait_for_every_marker = false
|
||||
end
|
||||
-- Let the driver decide what to do with PARTIAL, regional updates...
|
||||
self.default_waveform_mode = WAVEFORM_MODE_AUTO
|
||||
elseif Device:isKindle() then
|
||||
self.event_handlers["IntoSS"] = function()
|
||||
self:sendEvent(Event:new("FlushSettings"))
|
||||
@@ -105,24 +132,34 @@ function UIManager:init()
|
||||
Device:usbPlugOut()
|
||||
self:sendEvent(Event:new("NotCharging"))
|
||||
end
|
||||
-- Emulate the stock reader refresh behavior...
|
||||
-- Emulate the stock reader's refresh behavior...
|
||||
--[[
|
||||
NOTE: For ref, on a Touch (debugPaint is my new best friend):
|
||||
UI: gc16_fast
|
||||
Reader: When flash: if to/from img: gc16, else gc16_fast; when non-flash: auto (seems to prefer gl16_fast); Waiting for marker only on flash
|
||||
NOTE: For ref, on a Touch (debugPaint & a patched strace are your friend!):
|
||||
UI: flash: GC16_FAST, non-flash: AUTO (prefers GC16_FAST)
|
||||
Reader: When flash: if to/from img: GC16, else GC16_FAST; when non-flash: AUTO (seems to prefer GL16_FAST); Waiting for marker only on flash
|
||||
On a PW2:
|
||||
Same as Touch, except reader uses reagl on non-flash, non-flash lasts longer (12 pgs); Always waits for marker
|
||||
UI: flash: GC16_FAST, non-flash: AUTO (prefers GC16_FAST)
|
||||
Reader: When flash: if to/from img: GC16, else GC16_FAST; when non-flash: REAGL (w/ UPDATE_MODE_FULL!); Always waits for marker
|
||||
Note that the bottom status bar region is refreshed separately, right after the screen, as a PARTIAL, AUTO (GC16_FAST) update, and it's this marker that's waited after...
|
||||
Non flash lasts longer (dual timeout: 14pgs / 7mins).
|
||||
--]]
|
||||
-- We don't really have an easy way to know if we're refreshing the UI, or a page, or if said page contains an image, so go with the highest fidelity option
|
||||
-- We spend much more time in the reader than the UI, and our UI isn't very graphic anyway, so we'll follow the reader's behaviour above all
|
||||
self.full_refresh_waveform_mode = WAVEFORM_MODE_GC16
|
||||
-- We spend much more time in the reader than the UI, and our UI isn't very graphic anyway, so go with the reader behavior
|
||||
if Device.model == "KindlePaperWhite2" then
|
||||
-- Request REAGL waveform mode on devices that support it (PW2, KT2, KV) [FIXME: Is that actually true of the KT2?]
|
||||
if Device.model == "KindlePaperWhite2" or Device.model == "KindleBasic" or Device.model == "KindleVoyage" then
|
||||
self.partial_refresh_waveform_mode = WAVEFORM_MODE_REAGL
|
||||
-- We need to wait for every update marker when using REAGL waveform modes. That mostly means we always use MXCFB_WAIT_FOR_UPDATE_SUBMISSION.
|
||||
self.wait_for_every_marker = true
|
||||
else
|
||||
self.partial_refresh_waveform_mode = WAVEFORM_MODE_GL16_FAST
|
||||
-- NOTE: Or we could go back to what KOReader did before fa55acc in koreader-base, which was also use WAVEFORM_MODE_AUTO ;). I have *no* idea how the driver makes its choice though...
|
||||
-- NOTE: Or we could go back to what KOReader did before fa55acc in koreader-base, which was also to use AUTO ;). I have *no* idea how the driver makes its choice though...
|
||||
--self.partial_refresh_waveform_mode = WAVEFORM_MODE_AUTO
|
||||
-- Only wait for update markers on FULL updates
|
||||
self.wait_for_every_marker = false
|
||||
end
|
||||
-- Default to GC16_FAST (will be used for PARTIAL, regional updates)
|
||||
self.default_waveform_mode = WAVEFORM_MODE_GC16_FAST
|
||||
end
|
||||
end
|
||||
|
||||
@@ -383,14 +420,15 @@ function UIManager:run()
|
||||
|
||||
local refresh_type = self.default_refresh_type
|
||||
local waveform_mode = self.default_waveform_mode
|
||||
local wait_for_marker = self.wait_for_every_marker
|
||||
if dirty then
|
||||
if force_partial_refresh or force_fast_refresh then
|
||||
refresh_type = 0
|
||||
refresh_type = UPDATE_MODE_PARTIAL
|
||||
elseif force_full_refresh or self.refresh_count == self.FULL_REFRESH_COUNT - 1 then
|
||||
refresh_type = 1
|
||||
refresh_type = UPDATE_MODE_FULL
|
||||
end
|
||||
-- Handle the waveform mode selection...
|
||||
if refresh_type == 1 then
|
||||
if refresh_type == UPDATE_MODE_FULL then
|
||||
waveform_mode = self.full_refresh_waveform_mode
|
||||
else
|
||||
waveform_mode = self.partial_refresh_waveform_mode
|
||||
@@ -398,18 +436,29 @@ function UIManager:run()
|
||||
if force_fast_refresh then
|
||||
waveform_mode = self.fast_waveform_mode
|
||||
end
|
||||
-- If the device is REAGL-aware, and we're doing a reader refresh (i.e., PARTIAL, but not regional), apply some trickery to match the stock reader's behavior (REAGL updates are always FULL, but there's no black flash)
|
||||
if not self.update_regions_func and refresh_type == UPDATE_MODE_PARTIAL and (waveform_mode == WAVEFORM_MODE_REAGL or waveform_mode == WAVEFORM_MODE_KOBO_REGAL) then
|
||||
refresh_type = UPDATE_MODE_FULL
|
||||
end
|
||||
-- If we truly asked for a PARTIAL, regional update, it's likely for an UI element, so fall back to the default waveform mode, which is tailored per-device to hopefully be more appropriate than the one we use in the reader
|
||||
if self.update_regions_func and refresh_type == UPDATE_MODE_PARTIAL and not force_fast_refresh then
|
||||
-- NOTE: Using default_waveform_mode might seem counter-intuitive when we have partial_refresh_waveform_mode, but partial_refresh_waveform_mode is mostly there as a means to flag REAGL-aware devices ;).
|
||||
-- Here, we're actually interested in handling regional updates (which happen to be PARTIAL by definition), and not 'PARTIAL' updates that actually refresh the whole screen.
|
||||
waveform_mode = self.default_waveform_mode
|
||||
end
|
||||
if self.update_regions_func then
|
||||
local update_regions = self.update_regions_func()
|
||||
for _, update_region in ipairs(update_regions) do
|
||||
-- in some rare cases update region has 1 pixel offset
|
||||
Screen:refresh(refresh_type, waveform_mode,
|
||||
Screen:refresh(refresh_type, waveform_mode, wait_for_marker,
|
||||
update_region.x-1, update_region.y-1,
|
||||
update_region.w+2, update_region.h+2)
|
||||
end
|
||||
else
|
||||
Screen:refresh(refresh_type, waveform_mode)
|
||||
Screen:refresh(refresh_type, waveform_mode, wait_for_marker)
|
||||
end
|
||||
if self.refresh_type == 1 then
|
||||
-- REAGL refreshes are always FULL (but without a black flash), but we want to keep our black flash timeout working, so don't reset the counter on FULL REAGL refreshes...
|
||||
if refresh_type == UPDATE_MODE_FULL and waveform_mode ~= WAVEFORM_MODE_REAGL and waveform_mode ~= WAVEFORM_MODE_KOBO_REGAL then
|
||||
self.refresh_count = 0
|
||||
elseif not force_partial_refresh and not force_full_refresh then
|
||||
self.refresh_count = (self.refresh_count + 1)%self.FULL_REFRESH_COUNT
|
||||
|
||||
Reference in New Issue
Block a user