PDA

Просмотр полной версии : Вывод на экран со сдвигом в 4px



NovaStorm
27.01.2013, 18:10
Сейчас сделано так: в (hl) - текущее знакоместо на экране, в bc pop'аем данные для этого знакоместе(что были бы в нём без сдвига), в (de) - данные следующего по горизонтали знакоместа, скролл идёт влево.
По идее нужно 16битное значение [C или B] : (de) сдвинуть влево на 4 бита и загрузить в (hl).
Мой вариант разочаровывает производительностью =(


ld a,(de) ;правый байт
inc de ;для следующей итерации
ld (hl),c ;левый байт
rra
rra
rra
rra
rld

Можно ли сделать это быстрее?

alone
27.01.2013, 19:03
В Silk Worm тупо копировали весь спрайт в буфер, сдвигали его там по RLD и потом уже выводили на экран.

drbars
27.01.2013, 19:59
Я тоже в буфере двигаю. Задача оптимизируется по скорости, когда чётко поставлена.

Процедура сдвигает 2 байта по адресу SPR_MOVE_BUF на полубайт вправо.



LD (SCRL_ST+1),SP
LD SP,SPR_MOVE_BUF
LD HL,ONEBYTE
POP BC
LD (ST_4+1),SP
XOR A
LD (HL),C
RRD
LD C,(HL)
LD (HL),B
RRD
LD B,(HL)
PUSH BC
ST_4 LD SP,0

; тут цикл кол-ва строк можно замутить

LD SP,(SCRL_ST+1)
RET

NovaStorm
27.01.2013, 20:39
Мне тайл вывести в одно знакоместо шириной надо. А если делать это через буфер, добавятся минимум запись/чтение, что будет наверное только хуже.
К слову на два пикселя сделано вот так:


ld a,(de)
inc de
rla
rl c
rla
rl c
ld (hl),c

Можно ли тут что улучшить? Арифметикой, например, или табличкой(кило-другое готов пожертвовать)? Я с такими извратами мало знаком =\
Попалась хорошая страничка про сдвиги http://www.chilliant.com/z80shift.html, но там делается через ADD HL, HL. А это мало того что тормознее, так мне ещё и в другую сторону надо.

drbars
27.01.2013, 20:46
RRD/RLD сам по себе довольно тормозной, я им в исключительных случаях пользуюсь.

Destr
28.01.2013, 12:24
Арифметикой, например, или табличкой
А весь набор спрайтов не продублировать (сдвинутый на нужную величину) ?
Быстрее уже некуда...

alone
29.01.2013, 11:33
POP BC
LD (ST_4+1),SP
XOR A
LD (HL),C
RRD
LD C,(HL)
LD (HL),B
RRD
LD B,(HL)
PUSH BC
ST_4 LD SP,0
А что мешает делать RLD: DEC L или RRD:INC L?

---------- Post added at 11:33 ---------- Previous post was at 11:31 ----------


Мне тайл вывести в одно знакоместо шириной надо.
Лучше используй более крупные тайлы.

NovaStorm
29.01.2013, 14:08
А весь набор спрайтов не продублировать
За килобайт загрызу =Е
У меня 6Кб под тайлы, а вместе с кодом их вывода они должны влезть в страничку.

---------- Post added at 14:08 ---------- Previous post was at 14:04 ----------


Лучше используй более крупные тайлы.
Мне именно в одно знакоместо шириной выводить надо. Случай специфический уж больно.
Потому за сдвиги и взялся, что при не слишком катастрофичных затратах память тайлов экономится в разы.
Это на спрайтах придётся отрываться, храня сдвинутые.

alone
29.01.2013, 16:09
А если вывести строчку тайлов в буфер, а потом оттуда сдвинуть на экран?

NovaStorm
29.01.2013, 18:03
>в буфер
Дык туда сначала записать надо будет, а потом прочитать. А у меня сразу куда надо пишется. Выгоды не будет.
Впрочем сейчас у меня всё равно другие проблемы нарисовались из-за которых всё прахом идёт.
Спрайт из банки во второй экран вывести можно только перебросив сначала вниз?

alone
29.01.2013, 18:22
Ну, у тебя же и так 57 тактов на байт (если inc e).
А будет 16 (pop bc:ld (hl),c/b:inc h) + 22 (rld:dec l) + 16 (pop bc:ld (hl),c/b:inc l) = 54. Сплошная выгода. Если не считать памяти.

Vitamin
29.01.2013, 19:14
Одна идейка (просьба сильно не бить, мог напутать в показаниях):



;алгоритм вывода со сдвигом через две таблицы
*out++ = Hi2Lo[*in];

dup W-2
*out = Lo2Hi[*in++];
*out++ |= Hi2Lo[*in];
edup

*out = Lo2Hi[*in];

;примерный код
;hl - in de- out
;b - 'Hi2Lo

ld c,(hl) ;Hi2Lo + *in 7
ld a,(bc) ;Hi2Lo[*in] 7
ld (de),a ;*out++ 7
inc e ; 4
;=25

dup W-2

inc b ;Lo2Hi + *in 4
inc l ;in++ 4
ld a,(bc) ;Lo2Hi[*in++] 7
ld (de),a ; 7

dec b ; 4
ld c,(hl) ;Hi2Lo + *in 7
ld a,(bc) ;Hi2Lo[*in] 7
ex de,hl ; 4
or (hl) ;*out |= 7
ld (hl),a ; 7
inc l ;out++ 4
ex de,hl ; 4

edup ;=66 per cycle

inc b ;4
ld a,(bc) ;7
ld (de),a ;7
;=18


; E=25+18+66*(W-2) на линию


Затраты памяти- 512 байт на таблички.

NovaStorm
29.01.2013, 20:08
alone, Понял! Берём второй тайл уже сдвинутым. С памятью уже знаю как поступить, целиком дублировать не понадобится, анимированные тайлы сдвигать мне не надо. 4Кб в страничке ещё есть, может и хватит...

---------- Post added at 20:08 ---------- Previous post was at 19:32 ----------

Vitamin,
>на линию
Но мне-то хочется в столбик =)

Vitamin
29.01.2013, 20:48
Но мне-то хочется в столбик =)
Ну модифицируй алгоритм- в чем-то даже проще будет. Суть одна и та же- две таблицы. Причем сдвиг может быть любым, не обязательно 4 пиксела.

Alex Rider
29.01.2013, 20:57
Спрайт из банки во второй экран вывести можно только перебросив сначала вниз?

1) перебросить вниз;
2) щелкать страницами на каждый байт/слово/сколько регистров хватит;
3) хранить спрайт в 7-й банке.

NovaStorm
29.01.2013, 21:16
Vitamin, ну попробую понять, не можешь словами ещё описать? А то для меня асм почти write-only язык =(

Alex Rider,
Под вариант 3 памяти нетЪ.
>2) щелкать страницами
А может ли он быть быстрее переброса через стек?
Может ли вообще существовать такой вариант в разумном исполнении? Потому что переброс стеком - 13 тактов на байт, а попробовал пощёлкать:
ld bc,#7FFD
pop de: ld a,bank: out (c),a: ld a,(hl):and d: or e:ld (hl),a:inc l: ld a,bank: out (c),a
И лишних 19т/б. Может exx как-то можно задействовать?

Vitamin
29.01.2013, 23:22
Vitamin, ну попробую понять, не можешь словами ещё описать? А то для меня асм почти write-only язык =(
Ну я на псевдо-языке вначале описал что делается. В столбик не советую- будут большие накладные расходы.

Alex Rider
30.01.2013, 00:39
И лишних 19т/б. Может exx как-то можно задействовать?

Тут надо считать такты жоско, я ща не в состоянии прикинуть. С exx подстава в том, что адрес второго экрана у тебя в hl, он же тоже переключится на альтернативный... Как вариант - прикинь такие расклады:
-- bc тоже используется для переброски, а #7ffd в него заносится на каждой итерации (или используется альтернативный, например, а в de' хранятся исходная и целевая банки);
-- адрес хранится в ix/iy. Тогда можешь тягать одновременно bc (см. преыдущий пункт), de, hl, bc', de', hl'. Но! Операции с индексными регистрами ну очень меленные :(
-- как более мягкая альтернатива предыдущему пункту - для переброски используются bc, de, ix, iy, в альтернативных - 7ffd и банки.

Пока больше ничего выдумать не могу. Мне тут не так давно надо было крутить спрайт и кидать его на экран - использование альтернативных и индексных регистров сильно ускорило алгоритм. Но там ну очень уж частный случай.

alone
30.01.2013, 12:08
А будет 16 (pop bc:ld (hl),c/b:inc h) + 22 (rld:dec l) + 16 (pop bc:ld (hl),c/b:inc l) = 54.
Даже rld:ldd вместо последних двух. Итого 50.

---------- Post added at 12:04 ---------- Previous post was at 12:02 ----------


alone, Понял! Берём второй тайл уже сдвинутым.
Нет, все тайлы без копий.

---------- Post added at 12:08 ---------- Previous post was at 12:04 ----------


>2) щелкать страницами
А может ли он быть быстрее переброса через стек?
Переброс в буфер сам по себе даёт ускорение. Не вижу смысла от него отказываться и усложнять задачу.

Кстати, на 48К (один экран) спрайты всё равно надо накладывать в буфере. Так что и для 48К это тоже выгодно.

Быструю и не сильно жручую по памяти переброску на экран можно сделать через pop: pop: pop: pop ... push: push: push: push.

NovaStorm
30.01.2013, 14:43
Быструю и не сильно жручую по памяти переброску на экран можно сделать через pop: pop: pop: pop ... push: push: push: push.
Это для одного спрайта, так как адреса фиксированные. Если делать pop hl:ld hl,(nn), то будет 13 тактов вместо 12,5 на байт, но и перемещать в буфер можно будет любой спрайт, а не один =)

---------- Post added at 14:40 ---------- Previous post was at 14:29 ----------


Ну, у тебя же и так 57 тактов на байт (если inc e).
63 у меня =(
С inc e подумаю.

Выводим столбец. В нём есть 4 пикселя от левого и 4 от правого тайлов.
В bc попаются данные левого тайла, из (de) берутся данные правого. В (hl) - экран. Вот полный код на две линии.


pop bc ;10
ld a,(de) ;7
inc de ;6
ld (hl),c ;7
rra
rra
rra
rra ;16
rld ;18
inc h ;4
;;
ld a,(de)
inc de
ld (hl),b
rra
rra
rra
rra
rld
inc h

Мозг в ступоре, пытаюсь осилить примеры.

---------- Post added at 14:43 ---------- Previous post was at 14:40 ----------


Или rld:ld b,(hl):rld:ld c,(hl): push bc - будет 46.5
Куда push? Oo
Одно знакоместо надо же в ширину.

alone
30.01.2013, 14:58
Весь экран в ширину!
Ты сначала готовишь строку тайлов, потом её сдвигаешь и выводишь!
Насчёт вывода через push - невыгодно получается, я же забыл dec l. Надо rld:ldd.

---------- Post added at 14:58 ---------- Previous post was at 14:57 ----------


Это для одного спрайта, так как адреса фиксированные. Если делать pop hl:ld hl,(nn), то будет 13 тактов вместо 12,5 на байт, но и перемещать в буфер можно будет любой спрайт, а не один =)
Если делать pop hl:ld (nn),hl, то будет 12 килобайт кода.

NovaStorm
30.01.2013, 15:24
Да что ж я не могу объяснить-то? =(
Мне не надо весь экран, мне надо один столбик.
А кода на перекидывание спрайтов будет максимум 2*размер. Килобайт-полтора где-то от силы.

alone
30.01.2013, 16:21
Зачем выводить один столбик?
И я не про перекидывание спрайтов, а про перекидывание экранного буфера на экран.

NovaStorm
30.01.2013, 17:21
Буфер я итак кидаю 12kb pop:ld.
А кроме этого столбца у меня всё уже нарисовано.
Я бы конечно мог показать, но спойлерить (если конечно что-то будет) не хочу.

NovaStorm
31.01.2013, 08:54
Поменял inc de на inc e, где можно. 360 тактов-то на экран не лишние =)

alone
31.01.2013, 09:22
Не понимаю, зачем выводить один столб и при этом так загоняться с его оптимизацией... Он же весит всего 5% времени от силы.

NovaStorm
31.01.2013, 10:18
У меня он жрёт до 15-20% от перерисовки(без учёта спрайтов) _всего_ экрана.
Сейчас у меня за два прерывания скроллится экран по 2px и выводятся(из страницы 2го экрана, без переброса) три спрайта с маской 48х48. Ну и ещё остаётся чуток времени.
Проблема в том, что надо сделать вывод этих спрайтов в оба экрана из банок. В нижний-то можно непосредственно, а во второй напрямую и быстро мне способ неизвестен, а с перебросом в буфер нужно будет примерно ещё 7.5-8к тактов на спрайт, что уже не влезет в остаток времени от второго прерывания. Плюс музыка или хотя бы звук и логика ещё тыщи на три-четыре тактов =\.
Кроме вывода этого столбца оптимизировать уже нечего. Остальные алгоритмы предельно дубовы и эффективны =)

alone
31.01.2013, 10:47
Если имеется скролл, то половина знакоместа уже нарисована.
Надо только наложить вторую половину:
1/2*pop bc
ld e,c/b
ld a,(de) ;таблица сдвига на 4
or (hl)
ld (hl),a
inc h

---------- Post added at 10:45 ---------- Previous post was at 10:44 ----------


Плюс музыка или хотя бы звук и логика ещё тыщи на три-четыре тактов =\.
Музыку можно разложить на регистры.

---------- Post added at 10:47 ---------- Previous post was at 10:45 ----------


Сейчас у меня за два прерывания скроллится экран по 2px
Хинт: можно хранить 4 сдвинутых копии экрана и перекидывать их на активный экран по очереди. И никаких битовых сдвигов.

NovaStorm
31.01.2013, 11:04
>Если имеется скролл, то половина знакоместа уже нарисована.
>Хинт: можно хранить 4 сдвинутых копии экрана и перекидывать их на активный экран по очереди. И никаких битовых сдвигов.
Ты меня обижаешь =)
Разумеется так и сделано, поэтому и нарисованной половины знакоместа нету и надо нарисовать его целиком.

---------- Post added at 11:04 ---------- Previous post was at 11:03 ----------

>Музыку можно разложить на регистры.
Всё равно ведь не меньше тыщи-полутора?

alone
31.01.2013, 11:50
Разумеется так и сделано, поэтому и нарисованной половины знакоместа нету и надо нарисовать его целиком.
Какой код переброски? Давай оптимизируем.
Кстати, если выводить спрайты в эти буфера, то второй экран вообще не нужен. Спрайты могут лежать в верхней памяти. Код переброски на экран тоже.


>Музыку можно разложить на регистры.
Всё равно ведь не меньше тыщи-полутора?
Можно и меньше, но это уже будет экономия на спичках :)

NovaStorm
31.01.2013, 14:09
>Какой код переброски? Давай оптимизируем.
12 килов pop:ld, давай попробуем =)
Это в нижний экран. В верхний - пара-тройка килов pop:ld, остальное - цикл по 128 ldi.
В 7й страничке получается экран, переброска в него и вывод спрайта в этот экран(на будущее - из буфера спрайтов). Вниз от #C000 лежат четыре экранных буфера. И 1280 байт остатка, где и получается буфер спрайтов и код переключения страниц.
Почему так сделано... Просто одним экраном не обойтись. Перебросить экран даже c 12.5 тактов на байт(и тем более с 13 при pop:ld) за прерывание не удастся.

alone
31.01.2013, 14:47
А в одно прерывание и не требуется укладываться. Твоя задача начать рисовать сверху позже луча и закончить рисовать снизу до второго прихода луча. Это 113000 тактов.

---------- Post added at 14:47 ---------- Previous post was at 14:46 ----------


12 килов pop:ld, давай попробуем =)
Каким образом они делают циклический сдвиг по X?

NovaStorm
31.01.2013, 15:18
Каким образом они делают циклический сдвиг по X?
Хе-хе, knowhow =)
Хотя мне казалось, что это уже где-то было, даже в worms'ах твоих.
Просто в SP грузится новое начало циклического буфера. Спрайты идут напрямую на экран, в буферах только бэк.
За лучом с буферами без спрайтов гнаться нельзя, отрисовать их не успеешь, тк не знаешь где они. Может с сортировкой по вертикали...
Я уж сколько думал над этим, а ты опять сомнений зародил =)

alone
31.01.2013, 15:42
Спрайты надо рисовать в текущий буфер, а не на экран, тогда не надо ничего следить.

Если у тебя сдвиг нециклический, а тупо смещается начало буфера, то ты можешь копировать на экран через pop: pop: pop...push: push: push... - это должно быть быстрее.

---------- Post added at 15:42 ---------- Previous post was at 15:36 ----------

Хотя надо тогда копировщик для каждого X свой.

NovaStorm
31.01.2013, 16:42
>Хотя надо тогда копировщик для каждого X свой.
Угу, поэтому pop:ld. Сдвиг не циклический, буфер - да.
По поводу одного экрана... Надо подумать ещё. Его переброс - 80к тактов. Начинать его пересылать после начала отрисовки экрана лучом нельзя, тк память экрана неравномерна и мы скорее всего попадём под луч. Надо тогда делать линейный буфер, что сожрёт производительность =\
Плюс нужно хотя бы три спрайта, каждый тысяч на 10т...
К началу вывода спрайтов для п128 луч будет на 37 строке, в верхнюю треть вывести уже не успеем ничего. Рисовать придётся только во второй, а предпочтительней вообще в третьей. А я рисовать тоже по столбикам хотел, чтобы халявный клиппинг поиметь. Фигня какая-то получается =(

alone
31.01.2013, 16:51
Надо тогда делать линейный буфер, что сожрёт производительность =\
Почему?

GriV
05.02.2013, 22:21
НоваШторм от нас что то прячет, хочет сделать из нас программистов :-)
Я вот задачу всё равно не понял, что откуда берётся и какие условия по наложению.
Возможно что можно достигнуть твоей поставленной цели, не решая ту задачу которую ты тут ставишь. АлКо правильно сказал - на спичках экономишь. На музыке - посмотри тему от ТМК (http://zx.pk.ru/showthread.php?t=14307) - можно тыщи 2-3 тактов сэкономить.
С экранами замут тоже не понял.
Держи экраны в основной памяти, в высокой держи перебросчик pop:push:...
Тогда пофигу какая верхняя страничка.
Какие у тебя фазы экранов? Какие фазы спрайтов?