| |
Строка 6: | Строка 6: |
| http://topsailnet.com/#39145 buy ambien - buy ambien no prescription http://www.americanindependentwriters.net/#35827 buy ativan online - buy ativan without a prescription | | http://topsailnet.com/#39145 buy ambien - buy ambien no prescription http://www.americanindependentwriters.net/#35827 buy ativan online - buy ativan without a prescription |
| | | |
− | == Основные понятия и начало работы ==
| + | http://lifeofpis.com/#75709 alternatives to lamisil - lamisil tablet side effect http://www.corasyndicate.com/#59342 phentermine - phentermine |
− | | |
− | API драйвера напоминает интерфейсом обычные графические библиотеки, как например GDI. Рассмотрим основные понятия и приёмы работы с AHI в применении к эльфописанию.
| |
− | | |
− | AHI разрабатывался отдельно от программных продуктов, где он используется, поэтому был спроектирован максимально универсальным. Одно из следствий такой универсальности является возможность драйвера распараллеливать работу с железом между различными "клиентами", а именно - между приложениями операционной системы и самой ОС.
| |
− | | |
− | Для обеспечения такой возможности используется специальный объект, с которым разработчику [[ELF|эльфа]] под драйвер придётся сталкиваться постоянно - это ''контекст устройства''.
| |
− | | |
− | | |
− | === Контекст устройства ===
| |
− | | |
− | '''Контекст устройства''' ({{lang-en|Device Context}}) — структура данных, обеспечивающая эксклюзивный доступ к устройству вывода для приложения, использующего эту структуру и предотвращающая влияние других приложений на процесс работы с устройством. В ней хранятся все данные о текущем состоянии устройства, устанавливаемом приложением - владельцем контекста.
| |
− | | |
− | Чтобы лучше разъяснить как это работает, рассмотрим ситуацию на упрощенном примере:
| |
− | :'''Приложения A''' и '''B''' работают параллельно, и хотят получить доступ к '''Устройству''', для чего каждый из них создаёт с помощью AHI новый '''контекст''' для собственного пользования.
| |
− | :'''Приложение A''' пытается изменить состояние '''Устройства''', скажем, меняет основной цвет "кисти" на <font color="red">красный</font>. А на самом деле, информация о цвете кисти попадает не сразу в '''Устройство''', а сохраняется в '''контексте приложения A'''.
| |
− | :'''Приложение B''' тоже меняет (в своём '''контексте''') цвет кисти, но на <font color="blue">синий</font>.
| |
− | :Теперь, '''Приложение B''' пытается вывести линию <font color="blue">синим</font> цветом. Для этого драйвер отсылает '''контекст приложения B''' (вместе с информацией о цвете) '''Устройств'''у и подаёт команду на рисование линии текущим (<font color="blue">синим</font>) цветом.
| |
− | :После этого, если '''Приложение A''' тоже решит нарисовать линию, ему не придётся "задумываться" о том, что '''Приложение B''' что-то там проделало с '''Устройством''', а просто вызовет функцию рисования линии, и драйвер нарисует её <font color="red">красным</font> цветом, выполнив те же процедуры с контекстом.
| |
− | | |
− | Если бы небыло системы контекстов, и данные сразу попадали в устройство, то после установки '''Приложением B''' цвета в <font color="blue">синий</font>, '''Приложение A''' тоже бы получало <font color="blue">синие</font> линии вместо желаемых <font color="red">красных</font>.
| |
− | | |
− | | |
− | В коде контекст описывается как тип <tt>'''AHIDEVCONTEXT_T'''</tt> и является первым параметром почти у всех функций AHI.
| |
− | В ОС [[P2K]] напрямую функции драйвера не используются (кроме [[JVM|Java-машины]]), а Функции графики предоставляются через промежуточную надстройку над AHI - [[DAL]], поэтому все приложения ОС (а точнее, система [[UIS]]), так же как и сама ОС, используют единственный системный контекст.
| |
− | | |
− | Для эльфов есть выбор, как получить контекст:
| |
− | <ol>
| |
− | <li>Можно получить системный контекст, который использует ОС, с помощью функции [[DAL_GetDeviceContext]]:
| |
− | <pre>
| |
− | // Это будет наш контекст. Удобнее всего объявить его глобальным
| |
− | AHIDEVCONTEXT_T dCtx;
| |
− | | |
− | // Получаем системный контекст
| |
− | dCtx = DAL_GetDeviceContext(0);
| |
− | </pre>
| |
− | Недостаток этого способа - необходимо помнить, что приложение не является единственным клиентом драйвера, и делать необходимые установки перед каждой операцией вывода. А так же есть вероятность появления искажений в прорисовке экрана самой системой (UIS).
| |
− | </li>
| |
− | <li>Либо можно создать новый контекст только для нужд приложения, с помощью функций [[ldrGetAhiDevice]] и [[AhiDevOpen]]:
| |
− | <pre>
| |
− | // Это будет наш контекст. Удобнее всего объявить его глобальным
| |
− | AHIDEVCONTEXT_T dCtx;
| |
− | | |
− | // Информация об устройстве
| |
− | AHIDEVICE_T device;
| |
− | | |
− | // В EP2 уже есть вспомогательная функция для получения информации об устройстве
| |
− | device = ldrGetAhiDevice();
| |
− | | |
− | // Создаём контекст
| |
− | sts = AhiDevOpen( &dCtx, device, "Matrix", 0 );
| |
− | </pre>
| |
− | Недостаток этого способа - если функции драйвера используются несколькими клиентами одновременно, они работают медленнее из-за необходимости постоянно переключаться между контекстами.
| |
− | </li>
| |
− | </ol>
| |
− | | |
− | | |
− | === Поверхности ===
| |
− | | |
− | Прежде чем переходить к рассмотрению непосредственно программирования под AHI, необходимо ознакомиться с ещё одним важнейшим понятием - "поверхностями".
| |
− | | |
− | Поверхность ({{lang-en|Surface}}, "Сурфейс") — логически выделенный участок [[Видеопамять|видеопамяти]] чипа ATI.
| |
− | | |
− | Как многим из вас известно, у видеочипов часто есть собственная видеопамять, причём эта видеопамять не обязательно доступна [[MCU|процессору]] напрмяую. В телефонах [[Motorola]] с чипами ATI именно такой случай.
| |
− | | |
− | Размер внутренней видеопамяти (располагается прямо на чипе) на [[W2250]] и [[W2260]] одинаков и составляет ''192Kb'', однако к [[W2260]] подключен внешний модуль для расширения внутренней видеопамяти. Последняя работает медленнее внутренней, что отчасти компенсируется её значительно большим объёмом.
| |
− | | |
− | [[MCU]] может обращаться к видеопамяти двумя способами - через [[DMAC]] (только запись), либо через [[QSPI]] (чтение и запись).
| |
− | | |
− | Все растровые операции AHI производятся с участием поверхностей. Есть четыре наиболее важные поверхности, используемые в работе драйвера. Однако, последняя фраза не означает, что поверхностей именно четыре, скорее следует понимать это как статусы, присваиваемые определённым поверхностям, и при этом одна и та же поверхность(участок памяти) может принимать одновременно несколько таких статусов:
| |
− | *'''Отображаемая поверхность ("Display Surface", "Экранная поверхность", она же "Экранный буфер")
| |
− | *:Это та поверхность, из которой в данный момент чип берёт информацию для непосредственного вывода на экран.
| |
− | *:Устанавливается с помощью функции [[AhiDispSurfSet]], а получить можно с помощью [[AhiDispSurfGet]]
| |
− | *'''Поверхность назначения ("Destination Surface", "Поверхность-приёмник")
| |
− | *:Эта поверхность является целевой для функций рисования, тоесть в неё будет попадать результат операции.
| |
− | *:Устанавливается функцией [[AhiDrawSurfDstSet]]
| |
− | *'''Поверхность-источник ("Source Surface")
| |
− | *:Эта поверхность является источником данных для функций рисования, например картинка спрайта, который мы хотим нарисовать.
| |
− | *:Устанавливается функцией [[AhiDrawSurfSrcSet]]
| |
− | *'''Поверхность кисти ("Brush Surface")
| |
− | *:С этой поверхностью приложения никогда не работают напрямую, но о её существовании нужно знать, чтобы проще было понимать принцип работы некоторых функций рисования - она является важным вспомогательным инструментом. Всегда монохромная (однобитная), и используется как параметр PATTERN в [[ROP|растровых операциях]].
| |
− | *:Устанавливается самим драйвером, а настраивается с помощью функции [[AhiDrawBrushSet]].
| |
− | | |
− | Иногда требуется создать собственную поверхность в видеопамяти, например, чтобы закешировать спрайт (вывод графики из внутренней памяти намного быстрее, чем из системной). Для этого можно использовать функции [[AhiSurfAlloc]], [[AhiSurfFree]], [[AhiSurfReuse]].
| |
− | | |
− | === Координаты ===
| |
− | | |
− | Ещё одна вещь, с которой придётся постоянно иметь дело - это точки и области экрана и их координаты.
| |
− | | |
− | Координатная система экрана (да и всякой поверхности, тоже!) с точки зрения чипа ATI имеет следующую конфигурацию:
| |
− | *Начало отсчёта - в левом верхнем углу, отсчёт начинается с нуля
| |
− | *Ось X направлена вправо
| |
− | *Ось Y направлена вниз
| |
− | | |
− | Два основных объекта для описания координатных положений - это <tt>AHIPOINT_T</tt> и <tt>AHIRECT_T</tt>:
| |
− | <pre>
| |
− | typedef struct
| |
− | {
| |
− | INT32 x, y;
| |
− | | |
− | } AHIPOINT_T;
| |
− | | |
− | typedef struct
| |
− | {
| |
− | INT32 x1, y1, x2, y2;
| |
− | | |
− | } AHIRECT_T;
| |
− | </pre>
| |
− | | |
− | Если с первым всё понятно - просто задаёт координаты точки по x и y, то <tt>AHIRECT_T</tt>, который задаёт прямоугольную область экрана, стоит рассмотреть чуть подробнее:
| |
− | *<tt>x1, y1</tt> - координаты левого верхнего угла прямоугольника
| |
− | *<tt>x2, y2</tt> - правого нижнего
| |
− | Важное замечание: в отличие от используемой в [[UIS]] системе задания такой области, здесь координаты правого нижнего угла задаются '''не включительно'''!
| |
− | Например, если x1 = 0, x2 = 32 - это означает, что в область попадут точки с координатами x от 0 до 31.
| |
− | | |
− | | |
− | Чаще всего эти две структуры используются в функциях AHI примерно так:
| |
− | <pre>
| |
− | UINT32 AhiDrawBitBlt( AHIDEVCONTEXT_T devCx, AHIRECT_T *dstRect, AHIPOINT_T *srcPt );
| |
− | </pre>
| |
− | *<tt>AHIRECT_T</tt> указывает область на целевой поверхности, куда попадёт картинка из поверхности-источника, и именно он задаёт размер картинки.
| |
− | *<tt>AHIPOINT_T</tt> указывает координаты левого верхнего угла на поверхности-источнике, откуда будет скопирована область, размерами равная размерам прямоугольника <tt>AHIRECT_T</tt>.
| |
− | | |
− | | |
− | === Цвет ===
| |
− | | |
− | Как многие знают, во многих телефонах используются дисплеи с глубиной цвета 16 бит (Покомпонентно: 5 бит на красный, 6 бит на зелёный и 5 - на синий, "RGB565"), а в настольных компьютерах - с глубиной цвета в 24 бита (по 8 бит на каждую компоненту цвета, "RGB888"). Многие привыкли к заданию цвета в 24-битном формате на настольных компьютерах, да и это намного легче, стоит только рассмотреть пример: 0xFACE8D - в 24bpp сразу видно, какая интенсивность цвета на каждой компоненте, а на 16bpp это будет 0xFE71, и ничего не понятно... Вебдизайнеры поймут.
| |
− | | |
− | Для облегчения задачи, предусмотрен макрос, который получает из привычного RGB888 цвета - RGB565, например:
| |
− | <pre>
| |
− | ATI_565RGB(0xFA, 0xCE, 0x8D);
| |
− | </pre>
| |
− | Конечно, пользоваться им необязательно для случаев "чёрного" и "белого" - это 0x0 и 0xFFFF соответственно.
| |
− | {{Внимание|Нетрудно однако подсчитать, что "белый"(0xFFFF) в RGB565 при переводе обратно в RGB888 будет уже не очень "белым", далеко не 0xFFFFFF. Это полезно иметь в виду, когда работаете с картинками в формате RGB565}}
| |
− | | |
− | Возможно, у Вас уже назрел вопрос ещё с первых строк этого раздела, "А как же 18-битные дисплеи, которые ставили, например, на E1?"
| |
− | | |
− | Так вот по крайней мере [[W2250]] не имеет поддержки 18-битных поверхностей, чтобы обеспечить использование возможностей такого дисплея, так что это был не более чем маркетинговый ход. Впрочем, это же судя по всему касается и [[LTE2]] телефонов, так как для графики там опять же используются 16-битные поверхности.
| |
− | | |
− | Во многих графических адаптерах прошлого (хотя, и по сей день нередко используется, например, в консолях) основным режимом был 8-битный цвет с палитрой. К моему великому сожалению, портативные чипы ATI не имеют аппаратной поддержки 8-битных палитр (8-битный цвет - возможно, только в формате RGB322, но не проверено), но есть особенность, которую можно назвать однобитной палитрой.
| |
− | | |
− | Однобитные поверхности занимают особое место среди прочих. А именно, при выводе однобитной картинки, мы можем задавать 16-битный цвет, который будет представлять "1", "цвет переднего плана", и цвет, представляющий "0", "цвет фона", либо сделать один из них прозрачным. Фактически, получаем палитру для однобитного изображения.
| |
− | | |
− | Эти два цвета также задаются отдельно для кисти (а она, как мы узнали из предыдущих разделов, тоже однобитная поверхность!) - с помощью функций [[AhiDrawBrushFgColorSet]] и [[AhiDrawBrushBgColorSet]], и для остальных однобитных изображений - функциями [[AhiDrawFgColorSet]] и [[AhiDrawBgColorSet]].
| |
− | | |
− | | |
− | === Инициализация ===
| |
− | | |
− | Итак, у нас теперь есть контекст, полученный одним из двух способов, указанных выше. Что дальше?
| |
− | | |
− | Вне зависимости от того, собственный у нас контекст или нет, нужно провести его инициализацию. Различие лишь в том, что в случае собственного контекста её достаточно провести один раз, а в случае использования системного - почти каждый раз перед вызовом какой-либо функции рисования AHI.
| |
− | | |
− | Перед тем, как вызвать какую-либо функцию рисования, мы должны установить необходимые для её работы параметры:
| |
− | <ol>
| |
− | <li>'''Установить поверхность-приёмник<br>
| |
− | Часто для этого используется отображаемая поверхность, если не планируется вывод с использованием [[Двойная буферизация|двойной буферизации]].
| |
− | <pre>
| |
− | // Наш контекст, полученный ранее
| |
− | AHIDEVCONTEXT_T dCtx;
| |
− | | |
− | // Наша отображаемая поверхность
| |
− | AHISURFACE_T sDisp;
| |
− | | |
− | // Получим отображаемую поверхность. Достаточно сделать это один раз, ведь врядли она поменяется.
| |
− | AhiDispSurfGet( dCtx, &sDisp );
| |
− | | |
− | // Устанавливаем поверхность-приёмник
| |
− | AhiDrawSurfDstSet( dCtx, sDisp, 0 );
| |
− | </pre>
| |
− | </li>
| |
− | | |
− | <li>'''Установить поверхность-источник<br>
| |
− | Обычно для этой роли используют либо пользовательскую поверхность с нужной к выводу картинкой, либо системную внеэкранную поверхность (см. [[Двойная буферизация]]).
| |
− | <pre>
| |
− | // Сохраним сюда системную внеэкранную поверхность
| |
− | AHISURFACE_T sDraw;
| |
− | | |
− | // Получим системную внеэкранную поверхность
| |
− | sDraw = DAL_GetDrawingSurface( DISPLAY_MAIN );
| |
− | | |
− | // Устанавливаем поверхность-источник
| |
− | AhiDrawSurfSrcSet( dCtx, sDraw, 0 );
| |
− | </pre>
| |
− | </li>
| |
− | | |
− | <li>'''Установить [[Clipping|области вырезания]] для приёмника и источника<br>
| |
− | Пока что выключим их, и для этого передадим в функции [[AhiDrawClipDstSet]] и [[AhiDrawClipSrcSet]] - <tt>NULL</tt>:
| |
− | <pre>
| |
− | // Выключаем области вырезания для приёмника и источника
| |
− | AhiDrawClipDstSet( dCtx, NULL );
| |
− | AhiDrawClipSrcSet( dCtx, NULL );
| |
− | </pre>
| |
− | </li>
| |
− | | |
− | <li>'''Установить [[Raster Operations|растровую операцию]]<br>
| |
− | Чтобы не углубляться в рамках этой статьи в растровые операции, ограничимся пока что простым правилом:
| |
− | | |
− | Для вывода растровых изображений устанавливаем <tt>AHIROP_SRCCOPY</tt>, а для рисования цветом - <tt>AHIROP_PATCOPY</tt>.
| |
− | Отсановимся на последнем, так как пригодится в последующем примере.
| |
− | <pre>
| |
− | // Устанавливаем растровую операцию на применение кисти
| |
− | AhiDrawRopSet( dCtx, AHIROP3(AHIROP_PATCOPY) );
| |
− | </pre>
| |
− | </li>
| |
− | | |
− | <li>'''Настроить кисть<br>
| |
− | Это делать не обязательно, если мы не собираемся рисовать графические примитивы. Но так как мы собираемся, то...
| |
− | <pre>
| |
− | // Установим кисть на самую обычную, сплошную (SOLID)
| |
− | AhiDrawBrushSet(devCx, NULL, NULL, 0x0, AHIFLAG_BRUSH_SOLID);
| |
− | </pre>
| |
− | </li>
| |
− | </ol>
| |
− | | |
− | Конечно, некоторые из этих операций понадобится повторить перед вызовом определённых функций, с другими установками, но надеюсь это уже не составит для Вас проблем.
| |
| | | |
| == Примеры == | | == Примеры == |
AHI англ. ATI Handheld Interface — драйвер для чипов ATI. Присутствует в каждой прошивке для телефонов, где есть чип ATI, а это - все телефоны на базе LTE и LTE2.
yZfgLO <a href="http://ejdjudbgakhl.com/">ejdjudbgakhl</a>, [url=http://fevoeukacthf.com/]fevoeukacthf[/url], [link=http://mebvchxotgxg.com/]mebvchxotgxg[/link], http://hkksxkbsltie.com/
http://topsailnet.com/#39145 buy ambien - buy ambien no prescription http://www.americanindependentwriters.net/#35827 buy ativan online - buy ativan without a prescription
http://lifeofpis.com/#75709 alternatives to lamisil - lamisil tablet side effect http://www.corasyndicate.com/#59342 phentermine - phentermine
Примеры
Наконец, уже можно что-нибудь да и нарисовать!
Не будем здесь заострять внимание на таких тривиальных вещах, как размещение последующих примеров в коде и инициализация приложения. Пускай, например, рисовать мы будем в вызове по таймеру.
Первый пример
Для первого раза нарисуем цветной графический примитив.
// Вспомогательная переменная для указания области экрана
AHIRECT_T rect;
// Установим цвет кисти. Этим цветом будут выводиться наши графические примитивы
AhiDrawBrushFgColorSet(devCx, ATI_565RGB(0,0,255)); // Ярко-синий
// Зададим прямоугольник на экране, который будет залит нашим цветом
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = 64;
rect.y2 = 64;
// Нарисуем прямоугольник rect
AhiDrawSpans( dCtx, &rect, 1, 0);
References: AhiDrawSpans, AhiDrawBrushFgColorSet
После этого мы получим на экране синий квадрат в левом верхнем углу. Не больно-то и сложно, не так ли?
Второй пример
Теперь мы попытаемся решить задачу чуть посложнее, а именно - выведем какую-нибдь картинку. Код для загрузки картинок можно взять из библиотеки AHG, написанной tim apple, а саму картинку нужно будет подготовить особым образом.
/* Проведём инициализацию при загрузке эльфа: */
// Сюда будет загружена наша картинка. Не забудьте освободить память bitmap.image по завершению!
AHIBITMAP_T bitmap;
// Загружаем картинку!
BMP_LoadFromFile(L"file://b/image.bmp", &bitmap);
/* Теперь нарисуем картинку на экране средствами ATI */
AHIPOINT_T point;
AHIRECT_T rect;
// Пусть мы хотим вывести картинку в левом верхнем углу, задаём область как в предыдущем примере
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = bitmap.width;
rect.y2 = bitmap.height;
// И ещё - точку на исходной картинке. Мы выводим целиком, так что нули.
point.x = 0;
point.y = 0;
// Не забываем, что в прошлый раз мы установили операцию PATCOPY, но она не подходит для вывода растра!
AhiDrawRopSet( dCtx, AHIROP3(AHIROP_SRCCOPY) );
// Осталось собственно вывести картинку!
AhiDrawBitmapBlt( dCtx, &rect, &point, &bitmap, NULL, 0 );
References: AhiDrawBitmapBlt, AhiDrawRopSet
Третий пример
В третьем, заключительном примере мы создадим собственную поверхность, перенесём её в видеопамять и будем работать уже из неё.
Пример во многом повторяет предыдущий, но смотрите внимательнее - есть значительные отличия!
/* Проведём инициализацию при загрузке эльфа: */
// Сюда будет загружена наша картинка. Не забудьте освободить память bitmap.image по завершению!
AHIBITMAP_T bitmap;
// Это - размер новой поверхности
AHIPOINT_T size;
// Сюда мы сохраним указатель на новую поверхность
AHISURFACE_T surface;
// Загружаем картинку!
BMP_LoadFromFile(L"file://b/image.bmp", &bitmap);
/* Создадим новую поверхность - surface, по размеру картинки*/
size.x = bitmap.width;
size.y = bitmap.height;
AhiSurfAlloc( dCtx, &surface, &size, AHIFMT_16BPP_565, 0 );
/* Перенесём картинку на нашу новую поверхность, просто нарисовав её из системной памяти */
AHIPOINT_T point;
AHIRECT_T rect;
// Задаём область вывода
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = bitmap.width;
rect.y2 = bitmap.height;
// И точку на исходной картинке
point.x = 0;
point.y = 0;
// Не забываем, что в прошлый раз мы установили операцию PATCOPY, но она не подходит для вывода растра!
AhiDrawRopSet( dCtx, AHIROP3(AHIROP_SRCCOPY) );
// Сейчас мы хотим вывести картинку на новую поверхность.
AhiDrawSurfDstSet( dCtx, surface, 0 );
// Так как выводить будем из системной памяти, поверхность-источник нам не важна.
// Выводим картинку
AhiDrawBitmapBlt( dCtx, &rect, &point, &bitmap, NULL, 0 );
/* Теперь мы можем работать с этой картинкой в видеопамяти */
AHIPOINT_T point;
AHIRECT_T rect;
// Сейчас мы хотим вывести картинку из новой поверхности на экран.
AhiDrawSurfSrcSet( dCtx, surface, 0 );
AhiDrawSurfDstSet( dCtx, sDisp, 0 );
point.x = 0;
point.y = 0;
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = bitmap.width;
rect.y2 = bitmap.height;
// Для вывода из видеопамяти используется эта функция
AhiDrawBitBlt( dCtx, &rect, &point );
References: AhiDrawBitBlt, AhiSurfAlloc, AhiDrawSurfSrcSet, AhiDrawSurfDstSet, AhiDrawBitmapBlt, AhiDrawRopSet
Заключение
Итак, рассмотрев основные моменты работы с драйвером ATI и даже несколько конкретных примеров, у вас не должно возникнуть больших проблем с разработкой эльфов с его использованием.
Тем более, что уже существует несколько подобных эльфов, с исходным кодом которых можно ознакомиться.
Если эта статья вам чем-то помогла - пожалуйста, отпишитесь на форуме! --Andy51 19:13, 29 августа 2009 (MSD)