Не получается разогнать процедуру

Раздел посвящен программированию с использованием Power Basic.
sh2ezo
Начинающий
Начинающий
 
Сообщения: 9
Зарегистрирован: 05.09.2011 (Пн) 17:04
Откуда: НН обл.,г. Дзержинск

Не получается разогнать процедуру

Сообщение sh2ezo » 09.05.2012 (Ср) 13:10

Было мне нечего делать и решил написать графическую либу, т.к. DirectX'ы и OpenGL'ы учить до ужасного влом. Полноэкранный режим получился сразу нормальным, после долго кипел над оконным. В итоге, получилась поддержка того и другого. Рисовать научил только прямоугольники любых размеров. Решил проверить шустрость и написал тестер, который рисует в окошке 1000 квадратов 32*32 пикселя. FPS всего 30, что мне кажется оооочень медленным, т.к. процедура рисования написана почти полностью на АСМе. Решил сделать процедуру более шустрой. Все умножения заменил сложениями, убрал лишние строчки, но FPS поднялось всего на 1. У меня больше нет идей насчет того, как можно еще больше ускорить процедуру. Есть у кого идеи? Вот код:
Код: Выделить всё
FUNCTION gRect ALIAS "gRect" (BYVAL hDev AS LONG, _
                              BYVAL x1 AS LONG, _
                              BYVAL y1 AS LONG, _
                              BYVAL x2 AS LONG, _
                              BYVAL y2 AS LONG, _
                              BYVAL borderWidth AS LONG, _
                              BYVAL borderColor AS DWORD, _
                              BYVAL IsFilled AS LONG, _
                              BYVAL FillColor AS DWORD _
                               ) EXPORT AS LONG

    LOCAL x AS LONG
    LOCAL y AS LONG
    LOCAL gDev AS LONG PTR
    'LOCAL clr AS DWORD
    LOCAL offs AS DWORD PTR
    LOCAL ddsd AS DDSURFACEDESC PTR
    gDev=mmSectionPointer(hDev)

    IF y1<=0 THEN y1=1
    'if x<0 then x=0
   
    gRect_ok1:
    '=================================
    offs=@gDev[%lpWidth]            '=
                                    '=
    'Нулим EAX и ECX                '=
    ! xor ECX,ECX                   '=
    ! xor EAX,EAX                   '=
                                    '=
    gRect_loop3:                    '=
    ! add EAX,offs                  '=
    ! inc ECX                       '=
    ! cmp ECX,y1                    '=
    ! jne gRect_loop3               '==\
    ! add EAX,x1                    '===> этот участок является заменой для кода: offs=(@gDev[%lpWidth]*y1+x1)*4+@gDev[%lpSCREENBUFFER]
    ! mov EBX,EAX                   '==/
    ! add EAX,EBX                   '=
    ! add EAX,EBX                   '=
    ! add EAX,EBX                   '=
    ! mov offs,EAX                  '=
    offs=offs+@gDev[%lpSCREENBUFFER]'=
    '=================================

    LOCAL newline AS DWORD
    newline=(@gDev[%lpWidth]-(x2-x1+1))
    ! mov EAX,newline '\
    ! add EAX,newline ' \
    ! add EAX,newline '  умножение newline на 4
    ! add EAX,newline ' /
    ! mov newline,EAX '/

    ! mov ECX,y1 '----------------------------------------[Цикл 1: For y=y1 To y2]--------------------------------------------
    gRect_loop1:                                                                                                             '|
                ! mov y,ECX 'Сохраним значение счетчика                                                                      '|
                ! mov ECX,x1 '----------------------------[Цикл 2: For x=x1 To x2]------------------------------------        |
                gRect_loop2:                                                                                         '|       |
                            ! mov x,ECX 'Сохраним значение счетчика                                                   |       |
                            'точка за пределами рисуемой области?                                                     |       |
                            IF x>=0 AND y>=0 AND x<@gDev[%lpWidth] AND y<@gDev[%lpHeight] THEN                       '|       |
                                'Нет - рисуем                                                                        '|       |
                                'Рисуем границу прямоугольника?                                                      '|       |
                                IF x<x1+borderWidth OR x>x2-borderWidth OR y<y1+borderWidth OR y>y2-borderWidth THEN '|       |
                                    ! mov EAX,offs                                                                   '|       |
                                    ! mov EBX,borderColor                                                            '|       |
                                    ! mov [EAX],EBX                                                                  '|       |
                                ELSE 'Нет, это не граница                                                            '|       |
                                    ! cmp isFilled,0 'Применять заливку?                                             '|       |
                                    ! je RectNotFilled 'Нет? Идем отседава                                           '|       |
                                    ! mov EAX,offs                                                                   '|       |
                                    ! mov EBX,FillColor                                                              '|       |
                                    ! mov [EAX],EBX                                                                  '|       |
                                    RectNotFilled:                                                                   '|       |
                                END IF                                                                               '|       |
                            END IF                                                                                   '|       |
                            ! add offs,4 'сместим указатель на 4 байта(DWORD)                                        '|       |
                            ! mov ECX,x  'Вытащим значение счетчика                                                  '|       |
                            ! inc ECX    'Увеличим на 1                                                              '|       |
                            ! cmp ECX,x2 'Проверим, не достигли ли конца по X                                        '|       |
                            ! jna gRect_loop2 'Достигли - уходим------------------------------------------------------|       |
                                                                                                                             '|
                ! mov EAX,newline 'Рисование строки закончено                                                                '|
                ! add offs,EAX    'Переходим на следующую                                                                    '|
                ! mov ECX,y       'Вытащим значение счетчика                                                                 '|
                ! inc ECX         'Увеличим на 1                                                                             '|
                ! cmp ECX,y2      'Если это была последняя строка,                                                           '|
                ! jna gRect_loop1 'Уйдем отседа-------------------------------------------------------------------------------|


END FUNCTION             

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: Не получается разогнать процедуру

Сообщение iGrok » 09.05.2012 (Ср) 14:13

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

А ничего, что для DX и OGL есть аппаратная поддержка в видеокартах, и твоё наколенное произведение искусства по определению будет медленнее?
label:
cli
jmp label

sh2ezo
Начинающий
Начинающий
 
Сообщения: 9
Зарегистрирован: 05.09.2011 (Пн) 17:04
Откуда: НН обл.,г. Дзержинск

Re: Не получается разогнать процедуру

Сообщение sh2ezo » 09.05.2012 (Ср) 15:14

Чет не подумал об этом. Спс. Посмотрим, что другие скажут. Сейчас оптимизирую процедуру очистки экрана и рендеринга. Попробую засчет них еще что-нибудь выжать

DarkMachine
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 51
Зарегистрирован: 24.02.2012 (Пт) 15:58

Re: Не получается разогнать процедуру

Сообщение DarkMachine » 10.05.2012 (Чт) 10:06

Выложи рабочий исходник, посмотрим...

Debugger
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1667
Зарегистрирован: 17.06.2006 (Сб) 15:11

Re: Не получается разогнать процедуру

Сообщение Debugger » 10.05.2012 (Чт) 10:20

iGrok писал(а):медленнее?

У Mikle получилось довольно быстро рисовать всё.

iGrok
Артефакт VBStreets
Артефакт VBStreets
 
Сообщения: 4272
Зарегистрирован: 10.05.2007 (Чт) 16:11
Откуда: Сетевое сознание

Re: Не получается разогнать процедуру

Сообщение iGrok » 10.05.2012 (Чт) 14:49

Debugger писал(а):
iGrok писал(а):медленнее?

У Mikle получилось довольно быстро рисовать всё.

Точно, что-то я подзабыл про его sr2d.
label:
cli
jmp label

sh2ezo
Начинающий
Начинающий
 
Сообщения: 9
Зарегистрирован: 05.09.2011 (Пн) 17:04
Откуда: НН обл.,г. Дзержинск

Re: Не получается разогнать процедуру

Сообщение sh2ezo » 10.05.2012 (Чт) 21:06

Забыл сказать. Разогнал до 50 FPS, но периодически по неизвестным причинам падает до 37, но не ниже,что радует.

Есть еще одна проблема. Я не рисую напрямую в графический контекст целевого окна, т.к. не понял, как грамотно приделать к нему DIBSection(приделал к DC в памяти и делаю BitBlt при рендеринге), поэтому прошу просветить.

В прилагающемся архиве имеются:
1) исходник
2) скомпиленная либа
3) TESTER.EXE для теста "шустрости"
4) Инклуды

пока нету вывода текста, поэтому тест только в оконном режиме
Вложения
gDLL.rar
(34.55 Кб) Скачиваний: 195

DarkMachine
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 51
Зарегистрирован: 24.02.2012 (Пт) 15:58

Re: Не получается разогнать процедуру

Сообщение DarkMachine » 11.05.2012 (Пт) 15:08

Разогнал до 68 (падает до 53 если загрузить что то тяжёлое)
Оптимизировал кеширование некоторых переменных, в том числе и повторные вычисления.
Можно ещё оптимизировать, используя только ММХ если знать какой алгоритм ты заложил туда.
Слабое место в программе это длинные условия и преобразования из DWORD в LONG. Поэтому пришлось все переделать в LONG.
Код: Выделить всё
FUNCTION gRect ALIAS "gRect" (BYVAL hDev AS LONG, _
                              BYVAL x1 AS LONG, _
                              BYVAL y1 AS LONG, _
                              BYVAL x2 AS LONG, _
                              BYVAL y2 AS LONG, _
                              BYVAL borderWidth AS LONG, _
                              BYVAL borderColor AS LONG, _
                              BYVAL IsFilled AS LONG, _
                              BYVAL FillColor AS LONG _
                               ) EXPORT AS LONG
    #REGISTER NONE
    REGISTER x AS LONG
    REGISTER y AS LONG

    LOCAL gDev AS LONG PTR

    LOCAL offs AS LONG PTR
    LOCAL ddsd AS DDSURFACEDESC PTR

    LOCAL dvX, NewLine AS LONG   '
    LOCAL x1B, x2B, y1B, y2B AS LONG
    x1B  = x1+borderWidth
    x2B  = x2-borderWidth
    y1B  = y1+borderWidth
    y2B  = y2-borderWidth
    gDev = mmSectionPointer(hDev)
    dvX  = @gDev[%lpWidth] - (x2-x1+1)
    IF y1<=0 THEN y1=1
    '=================================

    offs = @gDev[%lpWidth]            '=

    ! align 8
    'Нулим EAX и ECX                '=
    ! xor ECX,ECX                   '=
    ! xor EAX,EAX                   '=
                                    '=
    gRect_loop3:                    '=
    ! add EAX, offs                  '=
    ! inc ECX                       '=
    ! cmp ECX,y1                    '=
    ! jne gRect_loop3               '==\
    ! add EAX,x1                    '===> этот участок является заменой для кода: offs=(@gDev[%lpWidth]*y1+x1)*4+@gDev[%lpSCREENBUFFER]
    ! mov EBX,EAX                   '==/
    ! add EAX,EBX                   '=
    ! add EAX,EBX                   '=
    ! add EAX,EBX                   '=
    ! mov offs,EAX                  '=

    ! mov eax, gDev[%lpSCREENBUFFER] ' offs = offs + @gDev[%lpSCREENBUFFER]'=
    ! mov eax, [eax]
    ! add offs, eax

    ! mov eax, dvX
    ! lea eax, [eax*4]                ' mult newline by 4
    ! mov newline, eax

    ! mov ECX,y1 '----------------------------------------[Цикл 1: For y=y1 To y2]--------------------------------------------
    gRect_loop1:                                                                                                             '|
                ! mov y,ECX 'Сохраним значение счетчика                                                                      '|
                ! mov ECX,x1 '----------------------------[Цикл 2: For x=x1 To x2]------------------------------------        |
                gRect_loop2:                                                                                         '|       |
                            ! mov x,ECX 'Сохраним значение счетчика                                                   |       |
                            'точка за пределами рисуемой области?
                            IF x>=0 AND y>=0 AND x<@gDev[%lpWidth] AND y<@gDev[%lpHeight] THEN                       '|       |
                                'Нет - рисуем                                                                        '|       |
                                'Рисуем границу прямоугольника?
                                IF x<x1b OR x>x2b OR y<y1b OR y>y2b THEN '|       |
                                    ! mov EAX,offs                                                                   '|       |
                                    ! mov EBX,borderColor                                                            '|       |
                                    ! mov [EAX],EBX
                                ELSE 'Нет, это не граница
                                    ! cmp isFilled,0 'Применять заливку?                                             '|       |
                                    ! je RectNotFilled 'Нет? Идем отседава                                           '|       |

                                    ! mov EAX,offs                                                                   '|       |
                                    ! mov EBX,FillColor                                                              '|       |
                                    ! mov [EAX],EBX
                                END IF                                                                               '|       |
                            END IF
                     RectNotFilled:                                                                   '|       |
                            ! add offs,4 'сместим указатель на 4 байта(DWORD)                                        '|       |
                            ! mov ECX,x  'Вытащим значение счетчика                                                  '|       |
                            ! inc ECX    'Увеличим на 1                                                              '|       |
                            ! cmp ECX,x2 'Проверим, не достигли ли конца по X                                        '|       |
                            ! jna gRect_loop2 'Достигли - уходим------------------------------------------------------|       |
                ! mov EAX,newline 'Рисование строки закончено                                                                '|
                ! add offs,EAX    'Переходим на следующую                                                                    '|

                ! mov ECX,y       'Вытащим значение счетчика                                                                 '|
                ! inc ECX         'Увеличим на 1                                                                             '|
                ! cmp ECX,y2      'Если это была последняя строка,                                                           '|
                ! jna gRect_loop1 'Уйдем отседа-------------------------------------------------------------------------------|

DarkMachine
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 51
Зарегистрирован: 24.02.2012 (Пт) 15:58

Re: Не получается разогнать процедуру

Сообщение DarkMachine » 11.05.2012 (Пт) 15:20

По поводу DIBSection вот ссылка http://www.powerbasic.com/support/forum ... 01849.html (Hi-Octane DrawDIB)
и код от Valor - двойная буферизация ДХ.

Код: Выделить всё
Here is a snippet to double buffer using DX and PB:
'----------------------------------------------------
  FUNCTION DD_CREATEPRIMARYSURFACEDOUBLEBUFFER ALIAS "DD_CREATEPRIMARYSURFACEDOUBLEBUFFER" (BYVAL lpdd AS LONG, BYVAL ddps AS LONG, BYVAL ddbs AS LONG, BYVAL ddsf AS LONG) EXPORT AS LONG
             
    'function takes
    ' lpdd        - direct draw object
    ' ddps        - long pointer to variable that will receive the ddraw
    '               primary surface object pointer on success.
    ' ddbs        - long pointer to variable that will receive the ddraw
    '               back buffer object pointer on success.
    ' ddsf        - this is an optional variable that will allow for
    '               additional flags to be specified for the surface.
    '               this flag can be NULL or any one of the numerous
    '               additional flags for directx surfaces.
    '
    'function returns
    ' long        - %DD_OK = 0 on success or error code on error
    '
    'notes:         call this function to create a primary ddraw
    '               double buffer flipping chain
   
    LOCAL l AS LONG
    LOCAL lp AS LONG PTR
    LOCAL ddsd AS DDSURFACEDESC2                      ' direct draw surface descriptor structure

    ' set the appropriate members for creating the primary surface
    ddsd.dwSize = SIZEOF(DDSURFACEDESC2)
    ddsd.dwFlags = %DDSD_CAPS OR %DDSD_BACKBUFFERCOUNT
    ddsd.dwBackBufferCount = 1&                       ' one back buffer
   
    ddsd.ddssurfCaps.dwCaps = %DDSCAPS_PRIMARYSURFACE OR %DDSCAPS_COMPLEX OR %DDSCAPS_FLIP OR ddsf
   
    ' create the primary double buffer surface                                                                                 
    l = M_CALL(lpdd, %DDCreateSurface, VARPTR(ddsd), ddps, 0)
    IF l <> %DD_OK THEN
      FUNCTION = l : EXIT FUNCTION
    END IF
   
    ' get the object pointer for the back buffer surface
    lp = ddps                                         ' set pointer to primary surface pointer
    ddsd.ddssurfCaps.dwCaps = %DDSCAPS_BACKBUFFER OR ddsf
    l = M_CALL(@lp, %DDSGetAttachedSurface, VARPTR(ddsd.ddssurfCaps), ddbs)   
    FUNCTION = l                                      ' return

  END FUNCTION

sh2ezo
Начинающий
Начинающий
 
Сообщения: 9
Зарегистрирован: 05.09.2011 (Пн) 17:04
Откуда: НН обл.,г. Дзержинск

Re: Не получается разогнать процедуру

Сообщение sh2ezo » 11.05.2012 (Пт) 16:16

Благодарю за рекомендации и пример оптимизации)) у меня не так шустро летает, но шустрее, чем было) надо будет почитать про MMX. Сам попробую оптимизировать. За ссылки тоже спс))

Если возникнут еще проблемы, буду писать сюда)


Вернуться в Power Basic

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 40

    TopList