Вход

Просмотр полной версии : Помощь с оптимизацией кода



moroz1999
10.11.2007, 15:33
Буду очень благодарен, если кто-нибудь придумает, как можно ускорить этот код без кардинальных изменений в способе вывода.

Это - вывод монохромного спрайта с маской на произвольную координату экрана. Сам спрайт имеет произвольную высоту/ширину (в байтах, не в пикселях).
Байты не смещаются на ходу, а используется предварительно рассчитанная таблица всех вариантов смещений для всех возможных вариантов байта (4кб).


SPRXCO DB 4
SPRYCO DB 0
SPRXLEN DB 3
SPRYLEN DB 48
SPRITESRC EQU #9B00



DRAWSPRITE
;check if sprite should be displayed without shifting
LD A,(SPRXCO)
AND 7
JP Z,DRAWNOX

;--------------------------------------------------
;---------------INITIALISATION---------------------
;--------------------------------------------------

ADD A,#B0
LD (RIGHTSIDE1+1),A
LD (RIGHTSIDE2+1),A
LD (RIGHTSIDE3+1),A
LD (RIGHTSIDE4+1),A
ADD A,8
LD (LEFTSIDE1+1),A
LD (LEFTSIDE2+1),A
LD (LEFTSIDE3+1),A
LD (LEFTSIDE4+1),A

LD BC,(SPRADR) ;BC = destination address on screen
LD DE,SPRITESRC ;DE = source address in memory
LD A,(SPRYLEN)
LD IXL,A ;ixl = sprite's height

LD A,(SPRXLEN)
DEC A
LD (DRAWSPRITEITELINE+2), A ;HARDCODED SPRITE'S WIDTH

;----------------------------------------------
;---------------MAIN CYCLE---------------------
;----------------------------------------------

DRAWSPRITEITELINE
LD IXH,0 ;ixh = sprite's width, HERE GOES A HARDCODE FROM INIT
PUSH BC

;-------START DRAWING RIGHT SIDE OF LEFT BYTE--------

LD A,(DE) ;READ COPY BYTE OF MASK FOR NEXT SCREEN BYTE
EX AF,AF'
LD A,(DE) ;READ BYTE OF MASK

RIGHTSIDE1
LD H,00
LD L,A ;HL = BYTE ADDRESS IN RIGHTSIDE PRESHIFTED TABLE

LD A,(BC) ;READ BYTE FROM SCREEN
OR (HL)
XOR (HL) ;APPLY PRESHIFTED MASK FROM TABLE

LD H,A ;SAVE TEMPORARY RESULT IN H

INC DE
LD A,(DE) ;READ BYTE OF SPRITE
LD L,A

LD A,H

RIGHTSIDE2
LD H,00 ;HL = BYTE ADDRESS IN RIGHTSIDE PRESHIFTED TABLE
OR (HL) ;APPLY PRESHIFTED SPRITE FROM TABLE

LD (BC),A ;LEFT HALFBYTE OF LEFT SIDE OF SPRITE IS DONE, PLACE IT BACK ON SCREEN

INC BC

;-------START DRAWING LEFT SIDE OF CENTER BYTE--------
DRAWSPRITEITECENTER

LD A,L ;SAVE LEFT SPRITE BYTE IN A
EX AF,AF' ;A = SAVED LEFT BYTE OF MASK

LEFTSIDE1
LD H,00
LD L,A ;HL = BYTE ADDRESS IN LEFTSIDE PRESHIFTED TABLE

LD A,(BC) ;READ FROM SCREEN

OR (HL)
XOR (HL) ;APPLY LEFT MASK BYTE FROM TABLE

LD H,A ;SAVE TEMPORARY RESULT IN H

EX AF,AF' ;A = SAVED LEFT BYTE OF SPRITE
LD L,A

LD A,H ;RESTORE TEMPORARY RESULT

LEFTSIDE2
LD H,00 ;HL = BYTE ADDRESS IN LEFTSIDE PRESHIFTED TABLE

OR (HL) ;APPLY LEFT SPRITE BYTE FROM TABLE

LD H,A ;SAVE TEMPORARY RESULT (READY LEFT SIDE OF ONSCREEN BYTE) IN H

INC DE
;-------START DRAWING RIGHT SIDE OF CENTER BYTE--------

LD A,(DE) ;READ COPY BYTE OF MASK FOR NEXT SCREEN BYTE
EX AF,AF'

LD A,(DE) ;READ BYTE OF MASK
LD L,A

LD A,H ;RESTORE TEMPORARY RESULT FROM H

RIGHTSIDE3
LD H,00 ;HL = BYTE ADDRESS IN RIGHTSIDE PRESHIFTED TABLE

OR (HL)
XOR (HL) ;APPLY PRESHIFTED MASK FROM TABLE

LD H,A ;SAVE TEMPORARY RESULT IN H

INC DE
LD A,(DE) ;READ BYTE OF SPRITE
LD L,A

LD A,H

RIGHTSIDE4
LD H,00 ;HL = BYTE ADDRESS IN RIGHTSIDE PRESHIFTED TABLE
OR (HL) ;APPLY PRESHIFTED SPRITE FROM TABLE

LD (BC),A ;LEFT HALFBYTE OF LEFT SIDE OF SPRITE IS DONE, PLACE IT BACK ON SCREEN

INC BC

DEC IXH
JR NZ,DRAWSPRITEITECENTER

;-------START DRAWING LEFT SIDE OF RIGHT BYTE--------
LD A,L ;SAVE LEFT SPRITE BYTE IN A
EX AF,AF' ;A = SAVED LEFT BYTE OF MASK

LEFTSIDE3
LD H,00
LD L,A ;HL = BYTE ADDRESS IN LEFTSIDE PRESHIFTED TABLE

LD A,(BC) ;READ FROM SCREEN

OR (HL)
XOR (HL) ;APPLY LEFT MASK BYTE FROM TABLE

LD H,A ;SAVE TEMPORARY RESULT IN H

EX AF,AF' ;A = SAVED LEFT BYTE OF SPRITE
LD L,A

LD A,H ;RESTORE TEMPORARY RESULT

LEFTSIDE4
LD H,00 ;HL = BYTE ADDRESS IN LEFTSIDE PRESHIFTED TABLE

OR (HL) ;APPLY LEFT SPRITE BYTE FROM TABLE

LD (BC),A

INC DE
POP BC

DEC IXL
RET Z

INC B
LD A,B
AND 7

JR NZ,DRAWSPRITEITELINE
LD A,C
ADD A,32
LD C,A
JR C,DRAWSPRITEITELINE
LD A,B
SUB 8
LD B,A

JR DRAWSPRITEITELINE

Добавлено через 7 часов 28 минут
не стану делать новую тему, но вопрос косвенно связан с предыдущим: расскажите пожалуйста в трех словах о выводе спрайтов стеком. параметры те же.
в чем будет выигрыш? всё равно ведь спрайтам надо делать побитовое смещение или пользоваться табличкой, как сверху?

ну, прежде всего, не нужно будет пользоваться downhl, верно? но разве это окупит затраты на переброску результата стеком?

мне кажется, что я чего-то глобально недопонимаю в этом методе, потому что я почти не вижу ему применения при более-менее универсальном использовании.

moroz1999
19.11.2007, 11:01
ну ладно, то, что с кодом помочь ни у кого времени нет - это вполне ожидаемо и норм. но на вопросы-то всяко кто-нибудь может ответить? :D

пока что вижу плюсы использования теневого экрана в следующем:
1. основной: downhl практически не нужен. ни для спрайтов персонажей, ни для тайлов на бэкграунде
2. обрезание экрана по бокам можно не делать. минусы - доп. затраты памяти плюс возникающее ограничение по ширине спрайта

какие еще плюсы есть?

Vitamin
19.11.2007, 11:40
Иногда вместо использования downhl используют табличку адресов. Иногда по ней же бегут стеком (например, в процедуре рисования линии).
Иногда можно совместить вывод через стек и адресацию:



pop hl
dup N
pop bc
ld a,(hl)
and c
xor b
ld (hl),a
inc l
edup


Напрямую выводить на экран через push не всегда эффективно- сказывается необходимость подстройки адресов

Barmaley_m
10.12.2007, 17:59
Есть еще следующие возможности оптимизации:

- вместо хранения таблицы сдвигов (каждый байт сдвинут на n бит) можно хранить каждый спрайт в разных вариантах сдвига. При этом потребуется в 8 раз больше памяти под спрайты, но код вывода может стать эффективнее

- всякий универсальный код будет работать медленнее специализированного. Не следует пытаться получить "самую быструю" универсальную подпрограмму. Вместо этого лучше получить оптимальную подпрограмму для конкретно заданных размеров и конфигурации спрайта. Если спрайт большой, то можно получить некоторый выигрыш, исключив операцию считывания из экранной памяти (так как внутренние области спрайта будут полностью замещать экранные данные).

elfh
11.12.2007, 04:55
я всегда заранее сдвинутые спрайты использую, если надо быстро вывести на экран. еще обычно делаю так:

xlen jr nn
dup max_x_len
;output routine
edup

т.е. чтобы не использовать счетчик в цикле по х, можно один раз рассчитать на какое смещение перескочить в процедуре вывода. это смещение заносится в (xlen+1).

удачи!

DimkaM
28.05.2008, 12:33
moroz1999
Извиняюсь, что поднимаю старую тему.

Что получилось в конечном итоге, можешь поделится процедуркой?

moroz1999
28.05.2008, 20:52
DimkaM, данная конкретная процедура осталась такой же. общие исходники (хоть в них и нет никакой конкретики) за неготовностью в паблик выкладывать пока не хочу.
но, поскольку в обозримом будущем я вряд ли что доделаю, то смотри личные сообщения :)

DimkaM
02.06.2008, 14:19
Спасибо.
Буду исследовать,очень интересно узнать производительность.
Сейчас только начинаю изучать ассемблер.
Моя цель вывод спрайта 4x4знакоместа, с маской и координатами точностью до пикселя.
Я написал процедуру со сдвигом, она кушает от 16500 до 32000 тактов на такой спрайт, но есть перспектива уменьшить до соответственно 16500-24000 тактов.

Может у кого будут ещё предложения.

Хранить в памяти сдвинутые спрайты нереально, у меня спрайтов на 16кб.