Цвета можно и без слоев уменьшить, хотя и не очень удобно. Один поток - двухбитный (4 точки в байте), второй - однобитный (8 точек в байте).
Вид для печати
Цвета можно и без слоев уменьшить, хотя и не очень удобно. Один поток - двухбитный (4 точки в байте), второй - однобитный (8 точек в байте).
Что нужно спрямить в dzx0? Ты писал про поточный, но я не совсем понял, ты же уже сделал поточный и я там какие-то мелочи дошлифовывал.
Сейчас dzx0 -- это от начала до конца один цикл. Если я хочу что-то делать с данными по частям, то есть пока этот цикл не завершился, мне приходится встревать в него разными зверскими способами.
Было бы удобно, если бы дополнительно существовал вариант dzx0, который устроен так, что можно вызывать из основной программы типа "call dzx0_stream_getbyte" когда надо. А он бы внутри себя декодировал очередную порцию по мере надобности. В картинках у меня сейчас именно так и сделано, но методом выворачивания цикла наизнанку. Почти так же, как в гигачаде, но попроще, потому что один поток. У этого есть недостатки -- плохая читаемость, необходимость запрещать прерывания пока стеки подменяются, оверхед на все это тоже может быть больше, чем если бы был прямой вызов.
Предполагаемый API такой:
dzx0_stream_init: -- инициализация: d=адрес откуда читаем, b=адрес буфера
dzx0_stream_getbyte: -- очередной байт (допустим Carry=1, если конец потока)
dzx0_stream_getbyte внутри себя вызывает dzx0_decode_chunk, когда исчерпываются данные в буфере
Все это разумеется применимо только к варианту с ограниченным размером буфера. 256 показал себя хорошо.
de, bc (хотя bc будет выровнен по 256)
Алгоритм внутри себя будет декодировать порциями в любом случае. Можно сделать фиксированный размер порции 256 байт. getbyte в обычном случае будет просто брать очередной байт из циклического буфера, если данные уже декодированы, и обращаться к алгоритму за очередной порцией когда буфер истощен.
Для смелых пользователей, кому важна эффективность и не хочется вызывать getbyte для каждого байта, останется возможность вызывать dzx0_decode_chunk напрямую.
256 байт хороший размер с точки зрения эффективности. Но чтобы не блокировать исполнение юзерского когда слишком на долго, хорошо иметь возможность рулить размером порции. Можно условной компиляцией 16/256, например. Или вообще по размеру порции в LDIR-е, правда это усложнит getbyte.
Пока для пробы сделал распаковщик чанками по 256 байт. GetByte можно сделать внешним, как с файловыми буферами: берем байт из буфера, если буфер пуст - распаковываем следующий чанк.
Пример почанковой распаковки всего файла
Код:lxi b,dzx0_Buffer
;DE - откуда
;HL - куда
;BC - буфер
MovLoop2:
push h
call dzx0
pop h
jnc LastMov
MovLoop1:
ldax b
mov m,a
inr c
inx h
jnz MovLoop1
jmp MovLoop2
LastMov:
inr c
dcr c
jz Start
mov e,c
mvi c,0
LastMov1:
ldax b
mov m,a
inr c
inx h
dcr e
jnz LastMov1
jz Start
[свернуть]
Забыл в файле написать - на выходе из dzx0
CY=0 - закончили распаковку
CY=1 - еще не закончили
- - - Добавлено - - -
Отмечу, что учитывая самомодификацию распаковщик однопоточный.
- - - Добавлено - - -
Один чанк распаковывается в среднем за 35000-45000 тактов. Крайние значения, которые видел - от 20000 до 50000 тактов.
Upd 18.09.2022: Примерно на 3% быстрее, сохраняет BC между распаковкой чанков (если убрать сохранение BC, то будет на 7 байт короче).
ivagor, спасибо! Попробовал, работает. Для моего случая годно. По-моему backwards тут не имеет смысла, под себя заменил макросы, потому что prettyasm в них не умеет. Ко всем меткам приставил stream_, чтобы не было конфликтов. А зачем нужна часть, которая подменяет точку входа, почему не просто отдельно инициализация и отдельно распаковка?
Ну что, на этом можно и успокоиться, правда 144 байта еще осталось http://sensi.org/~svo/b/mandrill/progdemo.rom
Ты опять сумел удивить, три картинки (пусть и не полноэкранных)! И музычка хорошо подобрана.
Личное предпочтение, чтобы упростить вызов. Понятно, что это можно вынести наружу, возможно для гитхаба я так и сделаю, надо еще подумать.
Насчет размера чанков. Степени двойки (2-128) можно получить добавив по паре команд перед jnz dzx0_ldir1_3 и jnz dzx0_ldir2_3
mvi a,Mask
ana c
Mask=(16-1) для 16 и т.д.
- - - Добавлено - - -
Ну и для простоты лучше сжимать файлы с размером кратным чанку, тогда хвосты не надо отдельно обрабатывать.
Да ладно, тут я всего-то взял все твои штуки и склеил в одну. Работа редакторская -- подпилить музон под ви53 (vt2 гениальная штука, можно редактировать в vim-е, как нормальный человек), подобрать дизер. А, ну правда тормозная прогрессивная загрузка -- это мое. Надо бы что ли задержку небольшую между картинками вставить.
Про способ вызова -- я быстро адаптировался, потому что сейчас в теме. Но так с ходу это может показаться непонятным.
Размеры чанков 16/256 у меня так и были сделаны. Сейчас, когда декодер не запрещает прерывания, для этой конкретно демы это стало не нужно. Но возможность управлять размером чанка иметь хорошо -- будет другая ситуация, где все будет наоборот.
Немного ускорил вывод и замедлил промежутки между картинками. Выкладываю как есть.
https://github.com/svofski/v06c-progdemo
http://sensi.org/scalar/ware/920
Upd: Забил буфера львом.
rom целиком с -w256 сжимается до 26 с половиной килобайт. Мне кажется, что некоторые резервы есть, пусть и не на 6 килобайт.
- - - Добавлено - - -
Часть ответа нашел. При -w256 сильно ухудшается эффективность сжатия последовательностей одинаковых байт (по крайней мере для absinthe-diag и fille-diag), увеличение хотя бы до -w512 заметно улучшает ситуацию. Альтернативный вариант - обрезать пустоту по бокам и сжать без нее.
Примерно 4К этого резерва -- это буфера гигачада, которые тут оказываются посередине файла -- можно без особых дополнительных ухищрений впихнуть в них одноразовую заставку, которая будет показываться один раз при запуске, потом затираться. Надо придумать, чего бы можно было туда втиснуть.Тигрлев в джунглях Руссо мне нравится, может быть если обрезать джунгли немного и уменьшить, он поместится.
Картинку произвольного размера было бы прикольно уметь. Может быть не для этой демки, а для вообще реюзабельности для чего-нибудь еще. Подумал типа кому нафик нужны такие тормозные картинки 7 Но если они будут маленькими врезками 64х64 или около того, они будут совсем не такие тормозные и это могло бы для чего-нибудь прийтись и кстати.
- - - Добавлено - - -
Это респект музыкантам.
Здесь хватит 11*256=2816 байт (6 - частоты, 1 - микшер, 1 - старший байт огибающей, 3 - громкости), т.е. еще килобайт резерва.
- - - Добавлено - - -
Все же на громкости 3 байта в данном случае расточительство, можно свести в 1 байт. Или даже приплюсовать к микшеру вместо шума.
ivagor, сейчас остается возможность одним движением включить AY, если вдруг захочется (хотя музон немного пережеван для ви53, но совсем чуть-чуть, не так сильно, чтобы совсем испортиться). Или даже сделать неприятный хорус (tm).
Если оставить возможность перенаправить на AY, то есть еще вариант. Композиция довольно компактная, думаю если пережать с -w128 она не сильно увеличится, а буферы сразу в 2 раза меньше.
Кстати, некоторое время пользуюсь сальвадором 1.40, он иногда на 1-2 байта лучше сжимает, мелочь, а приятно.
ivagor, забил буфера львом (вдавил). Пока я об эту демку достаточно потешился, но ты добро пожаловать ускорять, ужимать и добавлять еще конечно ;)
Ссылки те же.
Мне пришлось бы приложить немало усилий, чтобы откомпилировать эту дему, но в принципе потенциал развития есть, тема интересная.
- - - Добавлено - - -
На примере льва хорошо видно, что ограничение размера картинки еще и сильно ускорило бы.
Да, там занудненько так распаковывается и рисуется много-много черных пикселей. Но добавление еще и размера картинки -- это непомерное, непосильное усложнение.
Собрать проще, чем ты думаешь. У тебя python3 стоит? Виндовый.
pip3 install pypng lhafile -- это все зависимости
winbuild.bat
[здесь был первый черновик winbuild.bat, который сейчас в репе]
Ассемблер ты все равно будешь пользовать tasm, поэтому тут про него ничего нет. Для конверсии льва в db у тебя тоже наверняка есть любимый инструмент. Ну или можно исхитриться и обойтись тем же copy/b, но там надо аккуратно подогнать выравнивание, чтобы основной блок картинок не затерся буферами.
Сходу тасм не откомпилирует, надо немного править. Но это не важно, дема интересная и вдохновляющая, появились новые идеи.
ivagor, залил версию, собирающуюся tasm-ом вместе с проверенным батничком winbuild.bat
(ох и цаца этот ваш тасм, строчки ему длинные..)
P.S. пустился во все тяжкие и сделал поддержку обрезанных картинок. Ширина должна быть кратна 16, высота кратна 8. Ссылки все те же.
Ну ты крутой. Под влиянием положительного примера постарался проявить сознательность и убрал тупизну из чанкового распаковщика, стало немного лучше.
Присовокупил dzx0v2, работает, все обновил-перезалил. 3% из одного только распаковщика на глаз конечно не заметишь, но все вместе бесспорно стало как-то бодрее и веселее.
Кстати там просто прорва неиспользованных байт -- 256 это буфер dzx0, который может быть использован один раз при запуске, и 443 в конце. Ну и это без учета того, что это даже не r0m.
- - - Добавлено - - -
P.S. не учел, что bc теперь можно не сохранять, но один раз на 256 байт это совсем не критично.
- - - Добавлено - - -
P.P.S. если убрать push / pop b из picstream_fetch, к концу стрима что-то не так заворачивается. Лень разбираться, пока оставил push/pop, даром, что это ни на что не влияет.
Поздравляю, ты заставил меня откомпилировать прогдему :)
При выходе из dzx0 между чанками c=0, а в последний раз c=индекс последнего байта в буфере+1. Можно убрать push b и pop b из picstream_fetch, если добавить перед picstream_gb_L1 mvi c,0
Оставалось немного места и я заполнил его setpixelями. Выигрыш от 2 до 3.5%
- - - Добавлено - - -
Upd: 4-5.5%
Кажется побыстрее стало (субъективно конечно, там нет ведь замеров скорости.. ну и добавилась картинка какого-то кошака вначале). А это будет демка такая?
BlaireCas, это уже как бы демка такая спонтанно самообразовавшаяся. Не всем демкам суждено звать себя продами и релизами. Бывают же и просто сны (tm). Кошак, кстати, это деталь из "Сна" Анри Руссо ;)
ivagor, спасибо, я попозже сегодня посмотрю и соберу.
Хорошо бы придумать что-то побыстрее, но для вывода отдельных цветных точек это пока похоже на предел (или близко к нему). "Медленный вектор" и все такое.
Все здорово, но желательно бы доработать очистку экрана:
1. Или гасить палитру, потом стирать, потом новая палитра
2. Или очищать как-нибудь не по порядку адресов. По строкам, или чересстрочно и потом навстречу или спиралью и т.п.
- - - Добавлено - - -
Кстати, можно очищать и LFSRом по точкам
LFSR-ом по байтам лучше. И не совсем резко и не надо ждать полчаса. Еще можно фейдить палитру в черное.
Upd: сделал через три строки, получилось просто и симпатично.
По моему впечатлению так лучше.
Что касается предельности сетпикселя. Не обязательно пытаться прошибить лбом этот порог, можно обойти. Нам известна вся картинка, поэтому можно кодировать не абсолютные значения точек, а изменения относительно уже имеющегося в данной позиции цвета. Ускорение за счет того что:
1. Не будет спарок ora c\ xra c, максимум xra c
2. Можно пропускать неизменные плоскости (это главный выигрыш)
Вопрос в том, сожмется ли такой вариант не хуже абсолютного.
Если записывать значение, с которым надо поксорить чтобы получить очередной пиксель, это может получиться. Предсказать про сжатие не могу, но есть опасение, что будет сжиматься заметно хуже.
Опасение подтвердилось, сжимается заметно хуже.
- - - Добавлено - - -
Но я все-таки смог срезать 4 такта на setpixel1 :)
А если картинки сжимать не по пикселям, а по байтам будет хуже сжиматься?
Как известно, одна голова - хорошо, а две - некрасиво. Зато есть эффект.
и вскрываем резерв еще на 16 тактов
Код:setpixel1:
push d
rrc \ rrc \ rrc
mov b, a ; b = saved a, c free
ani 11110b
sta setpixel1setjmp+1
mov a, e
sub m
mov e, a ; update pixel addr
inx h ; hl -> pixel mask
mov c, m ; c = set mask
inx h ; hl -> next in tile sequence
push h ; save hl
setpixel1setjmp:
lhld setpixel1tab
ldax d
ora c
pchl
[свернуть]
- - - Добавлено - - -
Если поменять знак у смещений возьмужек, то еще -4 такта за счет замены
mov a,e
sub m
на
mov a,m
add e
parallelno, картинки заворачиваются в прогрессивную последовательность пикселей-полубайт. Полубайты объединяются в байты, а байты уже потом сжимаются.