В этой главе будет продемонстрировано использование слоёв, поверхностей и контекстов библиотеки Graphics Framework
Подразделы:
После подключения к дисплею появляется возможность получить дескрипторы слоёв конкретного дисплея. Для этого используется функция gf_layer_attach(), которой передается индекс интересующего слоя. При подключении к дисплею с помощью gf_display_attach() будет заполнена структура gf_display_info_t. Некоторые ее поля содержат информацию о поддерживаемых слоях:
После подключения к слою следует запросить перечень доступных пиксельных форматов через gf_layer_query(). Эта информация требуется для создания и последующего подключения к слою поверхности (области отображаемой памяти) поддерживаемого формата. Пример запроса этой информации:
static int find_rgb_format( gf_layer_t layer ){gf_layer_info_t info;int i;for ( i = 0; gf_layer_query( layer, i, &info ) == GF_ERR_OK; ++i ){switch ( info.format ){case GF_FORMAT_PKLE_ARGB1555:case GF_FORMAT_PKLE_RGB565:case GF_FORMAT_BGR888:case GF_FORMAT_BGRA8888:return info.format;default:continue;}}return (-1);}
Все возможные форматы охватывает тип gf_format_t. Упакованные форматы в структуре gf_layer_info_t, заполняемой функцией gf_layer_query(), являются не endian-специфичными. Где это возможно, следует придерживаться отсутствия этой специфичности (например, при создании поверхностей через gf_surface_create()). Единственным исключением является функция gf_surface_attach(), которая получает на вход уже выделенный блок памяти.
![]() | Речь идет об упакованных форматах. Endian-специфичные варианты других форматов отсутствуют. |
Структура gf_layer_info_t, заполненная функцией gf_layer_query(), также содержит сведения о возможностях слоёв, включая:
После создания поддерживаемой поверхности ее можно ассоциировать со слоем, используя gf_layer_set_surfaces(). Для некоторых пиксельных форматов может требоваться несколько одновременно используемых поверхностей, например, для YUV.
По умолчанию видимым является только основной слой дисплея. Слоя можно скрыть и отобразить используя gf_layer_disable() и gf_layer_enable() соответственно. Основной слой, однако, скрыть нельзя.
Проверить поддерживают ли слои регулировку видимости можно, проанализировав наличие флага GF_LAYER_CAP_DISABLE
в поле caps структуры gf_layer_info_t.
Регулирование указанных параметров для YUV слоёв осуществляется при использовании функций gf_layer_set_brightness(), gf_layer_set_contrast(), gf_layer_set_saturation(), и gf_layer_set_hue(). Они принимают на вход целочисленное значение в диапазоне от -128
до 127
, где 0
является состоянием слоя по умолчанию. Если регулировка параметров не поддерживается, последующий вызов gf_layer_update() вернет отличное от GF_ERR_OK
значение.
Проверить поддерживают ли слои регулировку яркости, контрасти, насыщенности и оттенка можно, проанализировав наличие флагов GF_LAYER_CAP_SET_BRIGHTNESS
, GF_LAYER_CAP_SET_CONTRAST
, GF_LAYER_CAP_SET_SATURATION
и GF_LAYER_CAP_SET_HUE
в поле caps структуры gf_layer_info_t.
Окном обзора называется часть поверхности (прямоугольная область), отображаемая в слое. Функция gf_layer_set_src_viewport() устанавливает область поверхности, которая подлежит отображению и характеризует исходное окно отображение. Функция gf_layer_set_dst_viewport() характеризует результирующее окно отображения — область дисплея, куда будет выводиться изображение области поверхности.
Окна обзора - штатный механизм организации прокрутки, панорамирования и создания эффекта "картинка в картинке". Отличие размера результирующего окна обзора от исходного позволяет задействовать масштабирование в слое (только если оборудование поддерживает это). Для прокрутки и панорамирования осуществляется изменение позиции исходного окна обзора относительно ассоциированной со слоем поверхности.
![]() |
|
Проверить поддерживают ли слои различные операции с окнами обзора можно по наличию следующих флагов в поле caps структуры gf_layer_info_t:
GF_LAYER_CAP_PAN_SOURCE
— возможно регулирование положения исходного окна обзора. GF_LAYER_CAP_PAN_DEST
— возможно регулирование положения результирующего окна обзора. GF_LAYER_CAP_SIZE_DEST
— возможно регулирование положения и размера результирующего окна обзора.
Настройка режимов аппаратного смешивания в слое осуществляется при использовании следующих функций:
![]() | Оборудование должно поддерживать слои и соответствующие аппаратные операции для использования данных вызовов. |
В некоторых случаях смешивание на уровне слоёв может быть более эффективным, нежели смешивание при операциях рендеринга изображения (см. функцию gf_context_set_alpha()). Например, в некоторых приложениях HMI и контент рендерятся различными процессами. В общем случае они могут адресоваться к различным аппаратным слоям, дабы исключить проблемы синхронизации доступа к поверхностям. Объединяя слои средствами контроллер дисплеев достижима простейшая композиция графических окружений. Обратный пример — однократный рендеринг нескольких статических объектов. В этом случае не требуется повторное выполнение операций смешивания с частотой обновления экрана и, соответственно, смешивание на уровне слоев будет являться не эффективным выбором.
Натсройка смешивания в операциях рендеринга рассмотрена ниже в разделе Контексты -> Альфа-смешивание.
Поверхностью является область памяти (преимущественно графической), доступная для рендеринга через GF
API. Поверхность может быть как ассоциирована со слоем (в общем случае весь контент поверхности становится видимым в слое), так и являться самостоятельным объектом рендеринга. В последнем случае имеют место offscreen-рендеринг и одноименные поверхности.
Регион памяти, в котором размещаются данные поверхности сильно зависит от возможностей оборудования и набора флагов, использованных при создании поверхности. Если установлен флаг GF_SURFACE_CREATE_CPU_FAST_ACCESS
при вызове gf_surface_create(), библиотека произведет попытку оптимизации поверхности по доступу со стороны CPU, что в основном означает использование для поверхности системной памяти (RAM). По умолчанию библиотека стремится оптимизировать поверхности исключительно для аппаратного доступа и акселерации. Это, в свою очередь, эквивалентно использованию видео памяти (VRAM).
Данные функции позволяют создавать поверхности:
![]() | Для создания поверхностей, являющихся альфа-картами (см. gf_alpha_t structure), используется вызов gf_surface_create() с флагом GF_SURFACE_CREATE_ALPHA_MAP . Формат данных такой поверхности должен соответствовать GF_FORMAT_BYTE . |
Все поверхности освобождаются менеджером io-display при завершении приложения. Хорошим тоном, однако, является использование функции gf_surface_free() для освобождения ресурсов.
![]() | Обратите внимание, что библиотека GF не освобождает память, ассоциированную с поверхностью черех gf_surface_attach(). |
Для определения параметров поверхности может использоваться функция gf_surface_get_info(). Она заполняет структуру gf_surface_info_t следующей информацией:
GF_SURFACE_PHYS_CONTIG
при создании поверхности) GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE
при создании поверхности) Для получения дескриптора графического устройства, к которому относится поверхность, можно использовать функйию gf_surface_get_dev().
Контекстом является структура, обслуживающая совокупность параметров рендеринга. Параметры назначаются контексту, а не поверхности, в которую будет осуществляться рендеринг.
Для создания контекста используется функция gf_context_create(). После создания следует ассоциировать с ним поверхность, используя gf_context_set_surface(). После того, как контекст утрачивает значимость его следует удалить, используя gf_context_free(), или повторно инициализировать исходными параметрами (см. gf_context_init()).
У контекстов масса параметров, которые будут детально рассматриваться ниже.
![]() | Многие функции с префиксом “set” имеют соответствующие вызовы “disable”. Например, gf_context_set_alpha() и gf_context_disable_alpha(). |
Настройка альфа-смешивания для последующих операций рендеринга осуществляется функцией gf_context_set_alpha(). На фход функции передается структура gf_alpha_t, определяющая параметры смешивания.
Альфа-канал содержит дополнительную информацию, используемую для изменения выводимого пикселя. В основном для достижения различных эффектов полупрозрачности. У канала есть три аспекта:
1555
под альфа-канал отводится только один бит (включен/выключен) и по пять бит на канал цвета RGB. В 32-битном формате 8888
все каналы, включая альфа, имеют восеми-битное кодирование. Также существуют source и destination факторы, укзаанные для определения способа корректировки данных исходного и результирующего пикселей при смешивании.
Рассмотрим типичную операцию смешивания: смешивание исходного пикселя с результирующим, используя альфа-канал пикселя. Для простоты нормализуем 8-битные каналы цвета ARGB формата (альфа и-канал и компоненты цвета) в диапазоне от 0
до 1
. Допустим, что исходный и результирующий пиксели имеют данные (.5, 0, 1, 0)
и (1, 1, 0, 0)
соответственно. Исходный пиксель является зеленым и наполовину прозрачным, а результирующий красный и абсолютно непрозрачный. В нашем случае нужно использовать альфа-канал исходного пикселя для регулирования полупрозрачности. Это соовтетствует флагу GF_ALPHA_M1_SRC_PIXEL_ALPHA
поля gf_alpha_t.mode. Поскольку нам нужно мультиплицировать исходный пиксель лишь с его альфа-компонентом, установим следующий фактор для исходного пикселя: GF_BLEND_SRC_M1
. При простейшем блендинге объем смешивания каждого пикселя должен равняться 1
(или 100%
). Таким образом фактор результирующего пикселя есть GF_BLEND_DST_1mM1
. В результате каждый канал цвета исходного пикселя (включая альфа) умножается на значение его альфа-канала (0.5
), что приводит к: (.25, 0, .5, 0)
. Каждый канал цвета исходного пикселя результирующего пикселя умножается на 1 - 0.5
: (.5, .5, 0, 0)
. На место результирующего пикселя записыватеся сумма этих значений: (.75, .5, .5, 0)
.
Код, имплементирующий эту операцию:
gf_alpha_t alpha = { 0 };alpha.mode = GF_ALPHA_M1_SRC_PIXEL_ALPHA | GF_BLEND_SRC_M1 | GF_BLEND_DST_1mM1;gf_context_set_alpha( context, &alpha );/* do rendering here */gf_context_disable_alpha( context );
Пример, затрагивающий импортирование изображение с полупрозрачностью. Данный код реализует загрузку изображения через библиотеку Image и последующий вывод средствами Graphics
Framework:
if ( img.flags & IMG_TRANSPARENCY ){gf_chroma_t chroma;memset( &chroma, 0, sizeof chroma );chroma.mode = GF_CHROMA_OP_SRC_MATCH | GF_CHROMA_OP_NO_DRAW;if ( img.format & IMG_FMT_PALETTE )chroma.color0 = img.palette[img.transparency.index];elseif ( IMG_FMT_BPP(img.format ) < 24)chroma.color0 = img.transparency.rgb16;elsechroma.color0 = img.transparency.rgb32;gf_context_set_chroma( setup.context, &chroma );}if ( img.format & IMG_FMT_ALPHA ){gf_alpha_t alpha;memset( &alpha, 0, sizeof alpha );alpha.mode = GF_ALPHA_M1_SRC_PIXEL_ALPHA | GF_BLEND_SRC_M1 | GF_BLEND_DST_1mM1;gf_context_set_alpha( setup.context, &alpha );}/* render the loaded image */gf_draw_blit2( setup.context, img_surf, NULL, 0, 0,img.w - 1, img.h - 1, setup.x1, setup.y1 );
Настройка операций с хрома-ключем осуществляется при использовании gf_context_set_chroma(). Функция принимает стурктуру gf_chroma_t с информацией о желаемом режиме смешивания.
Хрома-ключ подразумевает сравнение цвета пикселя с некоторым эталоном для принятия решения о последующем выводе данных в слой. Тип gf_chroma_t позволяет задать комбинацию из двух флагов:
GF_CHROMA_OP_SRC_MATCH
— тестирование пикселей исходного изображения GF_CHROMA_OP_DST_MATCH
— тестирование пикселей результирующего изображения и одного из:
GF_CHROMA_OP_DRAW
— рендеринг осуществляется если параметр color0 соответствует цвету тестируемого пикселя GF_CHROMA_OP_NO_DRAW
— рендеринг не осуществляется если параметр color0 соответствует цвету тестируемого пикселя Для того, что бы запретить вывод белых исходных пикселей (0x00FFFFFF
) или сделать их прозрачными, дсотаточно установить gf_chroma_t.color0 = 0x00FFFFFF
и gf_chroma_t.mode = GF_CHROMA_OP_SRC_MATCH
| GF_CHROMA_OP_NO_DRAW:
gf_chroma_t chroma = { 0 };...chroma.mode = GF_CHROMA_OP_SRC_MATCH | GF_CHROMA_OP_NO_DRAW;chroma.color0 = 0x00FFFFFF;gf_context_set_chroma( context, &chroma );gf_draw_blit2( context, img_surface, surface, 0, 0,w - 1, h - 1, 5 + w + 5, 30 );
Другой пример. Отображение изображения только поверх тех пикселей результирующего изображения, которые соовтетствуют color0: gf_chroma_t.mode = GF_CHROMA_OP_DRAW
| GF_CHROMA_OP_DST_MATCH
.
Основной цвет рисования применяется для большинства поддерживаемых примитивов, включая прямоугольники, полигоны, битовые карты и полилинии. Он устанавливается с помощью gf_context_set_fgcolor(). Фоновый цвет рендеринга настраивается функцией gf_context_set_bgcolor() и применяется как вторичный цвет заполнения, например, как дополнительный цвет для штрихованной линии.
Кроме цветов полилинии также имеют такие атрибуты, как ширина, стиль соединения сегментов, стиль штриховки.
Ширина задается в gf_context_set_penwidth(). Следует учитывать, что широкие линии поддерживаются только в случае, если их поддерживает графический контроллер. Предел ширины также является параметром оборудования. При установке значения 0
будет принудительно использоваться ширина пера в 1
пиксель.
Стиль соединения сегментов полилинии задается с помощью функции gf_context_set_linejoin():
Пунктир придает полилиниям эффект штриховки. Для этого имеется функция gf_context_set_linedash(). Пример:
gf_point_t p[] = {{50, 250},{w - 100, 250}};gf_context_set_fgcolor( context, 0x00ffff );gf_context_set_bgcolor( context, 0xffffff );gf_context_set_linedash( context, 0x000ffff, 0, 32, GF_CONTEXT_LINEDASH_BACKFILL );gf_context_set_penwidth( context, 10 );gf_draw_polyline( context, p, 2, 0 );
Область обрезки ограничивает доступный для рендеринга прямоугольник в пределах размера поверхности, ассоциированной с контекстом. Все операции, выполняемые вне границ данной области не будут отображены. Область обрезки регулируется при помощи gf_context_set_clipping(). Пример:
gf_context_set_fgcolor( context, 0xffff00 );gf_draw_rect( context, 0, 0, w, h );gf_context_set_clipping( context, 50, 50, 400, 400 );{gf_point_t p[][4] = {{80, 8, 150, 150, 80, 80, 40, 160},{240, 8, 290, 80, 360, 10, 290, 160},{40, 190, 150, 270, 50, 320, 90, 270},{210, 260, 450, 190, 370, 260, 450, 340}};gf_context_set_fgcolor( context, 0x0000ff );gf_context_set_penwidth( context, 1 );gf_draw_poly_fill( context, &p[0][0], 4 );gf_context_set_fgcolor( context, 0x00ff00 );gf_context_set_penwidth( context, 5 );gf_draw_polyline( context, &p[1][0], 4, GF_DRAW_POLYLINE_CLOSED );gf_context_set_fgcolor( context, 0xf00f00 );gf_context_set_penwidth( context, 10 );gf_draw_poly_fill( context, &p[2][0], 4 );gf_context_set_fgcolor( context, 0x00ffff );gf_context_set_penwidth( context, 20 );gf_draw_polyline( context, &p[3][0], 4, 0 );}
Растровые операции (ROP) настраиваются при помощи следующих функций:
uint8_t pattern[] = {0x00, 0x01, 0x03, 0x07,0x0f, 0x1f, 0x3f, 0x7f};unsigned short rop = GF_ROP_PDSnaon;gf_context_set_fgcolor( context, 0xff0000 );gf_context_set_bgcolor( context, 0x0000ff );gf_context_set_pattern( context, pattern, 0, 0, GF_CONTEXT_PATTERN_BACKFILL );gf_context_set_rop( context, rop );gf_draw_rect( context, 50, 50, 200, 200 );gf_draw_flush( context);
Сглаживание позволяет сделать отображаемое изображение более плавным, избавляя от различимых резких переходов в сегментах изображения. Достигается это алгоритмически, путем вычисления цвета граничных пикселей с использованием полутонов. За включение этих алгоритмов отвечает функция gf_context_set_antialias().
![]() | Данная опция не применяется к изображениям и шрифтам. Для шрифтов следует применять альфа-смешивание. |
Существует возможность задать смещение в виде параметров x и y, добавляемое к координатам вершин полигонов, линий и полилиний непосредственно перед их рендерингом. Матрица трансформации представляет собой двумерную матрицу, перемножаемую с координатами вершин полигонов, линий и полилиний непосредственно перед их рендерингом. Изменение этих характеристик позволяет достигать эффектов поворота, масштабирования, отражения и параллельного переноса. Осуществить это можно с помощью функций gf_context_set_transform() и gf_context_set_translation().
Пример ниже использует обе функции. Настройка окружения GF
выполянется в подразумеваемой функции gf_setup(), чей код не представлен.
int main( int argc, char *argv[] ){gf_setup_t setup;bool rotate = TRUE,translate = TRUE;unsigned dispno = 0,fc = 0;const char *dev_name = NULL;int layer_idx = GF_SETUP_LAYER_MAIN,rc;float c, s;int theta = 0,dtheta = 1,tx = 0,dx = 1,ty = 0,dy = 1;gf_fixed_t xform[] = {1 << 16, 0, 0, 1 << 16};const gf_point_t points[] = {{ 0, -100},{ 59, 81},{-95, -31},{ 95, -31},{-59, 81}};while ( (rc = getopt(argc, argv, "d:D:l:rtx:y:")) != -1 ){switch ( rc ){case 'd':if ( isdigit( *optarg ) )dev_name = GF_DEVICE_INDEX( atoi( optarg ) );elsedev_name = optarg;break;case 'D':dispno = atoi( optarg );break;case 'l':layer_idx = atoi( optarg );break;case 'r':rotate = FALSE;break;case 't':translate = FALSE;break;case 'x':tx = atoi( optarg );break;case 'y':ty = atoi( optarg );break;}}if ( (rc = gf_setup( &setup, dev_name, dispno, layer_idx, GF_SETUP_FLAG_DBLBUFFER )) != GF_ERR_OK ){fprintf( stderr, "gf_setup() failed: %d\n", rc );return (-1);}gf_context_set_penwidth( setup.context, 3 );gf_context_set_antialias( setup.context, GF_CONTEXT_ANTIALIAS_LINES );for ( ; ; ){gf_surface_t surface = (fc++ & 1) ? setup.surface2 : setup.surface1;gf_context_set_surface( setup.context, surface );if ( gf_draw_begin( setup.context ) == GF_ERR_OK ){gf_context_set_fgcolor( setup.context, 0xffffff );gf_draw_rect( setup.context, 0, 0, INT_MAX, INT_MAX );gf_context_set_fgcolor( setup.context, 0x000000 );gf_draw_polyline( setup.context, points, 5, GF_DRAW_POLYLINE_CLOSED );gf_draw_end( setup.context );}gf_layer_set_surfaces( setup.layer, &surface, 1 );gf_layer_update( setup.layer, 0 );tx += dx;ty += dy;if ( tx >= setup.display_info.xres ){dx = -dx;tx = (setup.display_info.xres << 1) - tx;} elseif ( tx < 0 ){dx = -dx;tx = -tx;}if ( ty >= setup.display_info.yres ){dy = -dy;ty = (setup.display_info.yres << 1) - ty;} elseif ( ty < 0 ){dy = -dy;ty = -ty;}theta += dtheta;if ( theta >= 360 )theta -= 360;s = sinf( theta * 2 * M_PI / 360 );c = cosf( theta * 2 * M_PI / 360 );xform[0] = c * 0x10000;xform[1] = s * 0x10000;xform[2] = -s * 0x10000;xform[3] = xform[0];if ( rotate )gf_context_set_transform( setup.context, xform );if ( translate )gf_context_set_translation( setup.context, tx, ty );}return (0);}
Предыдущий раздел: Библиотека Graphics Framework