Графика (C++ AMP)
C++ AMP содержит несколько интерфейсов API в пространстве имен Concurrency::graphics, которые можно использовать для доступа к поддержке текстур на GPU.Ниже описываются наиболее типичные скрипты применения.
Класс texture может использоваться как контейнер данных для вычислений, использующий пространственную локальность кэша и размещения текстур на GPU.Пространственная локальность — свойство элементов данных, заключающееся в их близком физическом расположении друг к другу.
Среда выполнения предоставляет эффективное взаимодействие с невычисляемыми шейдерами.Шейдеры пикселя, вершины, тесселяции и оболочки часто используют или создают текстуры, которые можно использовать в вычислениях C++ AMP.
Графический API в C++ AMP предоставляет альтернативные способы доступа к буферам, упакованным в подслова.Текстуры, имеющие форматы, которые представляют тексели (элементы текстуры), состоящие из 8 или 16-разрядных скалярных величин, имеют возможность доступа к данным, упакованным таким образом.
Примечание |
---|
API C++ AMP не предоставляет функционал фильтрации и выборки текстуры.Необходимо использовать возможности взаимодействия C++ AMP, а затем написать код на DirectCompute и HLSL. |
Типы norm и unorm
Типы norm и unorm — скалярные типы, которые ограничивают диапазон значений float; это называется сжатием.Эти типы могут быть созданы из других скалярных типов явным образом.При приведении типов значение сначала приводится к float, а затем сжимается до соответствующих границ, разрешенных типом norm [- 1.0… 1.0] или unorm [0,0… 1.0].Приведение от +/- бесконечности возвращает +/-1.Приведение от NaN не определено.Тип norm может быть неявно создан из unorm без потери данных.В этих типах определен неявный оператор приведения к float.Определены бинарные операторы между этими типами и другими встроенными скалярными типами, такими как float и int: +, -, *,/, ==! =, >, <, >=, <=.Составные операторы присваивания также поддерживаются: +=,-=, * =, / =.Для типов norm определен унарный оператор отрицания (-).
Библиотека коротких векторов
Библиотека коротких векторов предоставляет некоторую функциональность типа Vector, определенного в HLSL и, как правило, используемого для определения текселей.Короткий вектор — это структура данных, которая содержит от одного до четырех значений одного типа.Поддерживаемые типы: double, float, int, norm, uint, и unorm.В следующей таблице показаны имена типов.Для каждого типа также существует определение typedef без символа подчеркивания в имени.Типы, которые содержат подчеркивания, находятся в Пространство имен Concurrency::graphics.Типы, которые не содержат подчеркивания, находятся в Пространство имен Concurrency::graphics::direct3d, так что они четко отделены от фундаментальных типов с похожими названиями, таких как __int8 и __int16.
Длина 2 |
Длина 3 |
Длина 4 |
|
---|---|---|---|
double |
double_2 double2 |
double_3 double3 |
double_4 double4 |
float |
float_2 float2 |
float_3 float3 |
float_4 float4 |
Целочисленное значение. |
int_2 int2 |
int_3 int3 |
int_4 int4 |
norm |
norm_2 norm2 |
norm_3 norm3 |
norm_4 norm4 |
uint |
uint_2 uint2 |
uint_3 uint3 |
uint_4 uint4 |
unorm |
unorm_2 unorm2 |
unorm_3 unorm3 |
unorm_4 unorm4 |
Операторы
Если оператор определен между двумя короткими векторами, то он также определен между коротким вектором и скаляром.Кроме того, одно из следующих утвержлений должно быть верно:
Тип скаляра должен быть тем же, что и тип элемента короткого вектора.
Тип скаляра может быть неявно преобразован в тип элемента вектора с помощью только одного определенного пользователем преобразования.
Операция проводится покомпонентно между каждым компонентом короткого вектора и скаляром.Ниже приведены допустимые операторы:
Тип оператора |
Допустимые типы |
---|---|
Бинарные операторы |
Допустимы для всех типов: +, -, *, /, Допустимы для целочисленных типов: %, ^, |, &, <<, >>, Два вектора должны иметь одинаковый размер, а результат — вектор того же размера. |
Операторы сравнения |
Допустимы для всех типов: == и != |
Составной оператор присваивания |
Допустимы для всех типов: +=, -=, *=, /= Допустимы для целочисленных типов: %=, ^=, |=, &=, <<=, >>= |
Операторы инкремента и декремента |
Допустимы для всех типов: ++, -- И префиксная, и постфиксная формы являются допустимыми. |
Оператор побитового НЕ (~) |
Допустим для целочисленных типов. |
Унарный оператор - |
Допустим для всех типов, за исключением unorm и uint. |
Группирующие выражения
Библиотека коротких векторов поддерживает конструкции метода доступа вида vector_type.identifier для доступа к компонентам короткого вектора.Идентификатор identifier, известный как группирующее выражение, указывает компоненты вектора.Выражение может быть l-значением или r-значением.Отдельные символы в идентификаторе могут быть: x, y, z и w; или r, g, b и a."x" и "r" обозначают нулевой компонент, "y" и "g" — первый компонент и т.д.(Обратите внимание, что "x" и "r" не могут быть использованы в одном и том же идентификаторе). Поэтому «rgba» и «xyzw» возвращают одинаковый результат.Методы доступа из одного компонента, такие как «x» и «y», являются скалярными типами значения.Многокомпонентные методы доступа — типы короткого вектора.Например, если есть вектор int_4 с именем fourInts и значениями 2, 4, 6 и 8, то fourInts.y возвращает целое число 4, а fourInts.rg — объект int_2 со значениями 2 и 4.
Классы текстуры
Множество графических процессоров имеют оборудование и кэши, оптимизированные для выборки пикселов и текселей и визуализации изображений и текстур.Класс texture<T,N>, являющийся контейнером для объектов текселей, предоставляет функциональные возможности для работы с текстурами на таких GPU.Тексель может быть:
Скаляром типа int, uint, float, double, norm или unorm.
Коротким вектором, который содержит 2 или 4 компонента.Единственное исключение — тип double_4, который не разрешен.
Объект texture может иметь ранг 1, 2 или 3.Объект texture может быть перехвачен только по ссылке в лямбда-выражении в вызове метода parallel_for_each.Текстура хранится на GPU как объекты текстуры Direct3D.Дополнительные сведения о текстурах и текселях в Direct3d см. в разделе Введение в текстуры в Direct3D 11.
Тип текселя может быть одним из множества различных форматов текстуры, которые используются при программировании графики.Например, формат RGBA может использовать 32 бита, по 8 бит на каждый из скалярных элементов R, G, B и A.Текстурное оборудование видеокарты может получать доступ к отдельным элементам в зависимости от формата.Например, если используется формат RGBA, то текстурное оборудование может извлечь каждый 8-битный элемент в 32-битное представление.В C++ AMP можно задать количество бит на один скалярный элемент пользовательского текселя, что позволяет автоматически получать доступ к отдельным скалярным элементам в коде без использования битовых сдвигов.
Создание объектов текстуры
Можно объявить объект текстуры без инициализации.В следующем примере объявляется несколько объектов текстуры.
#include <amp.h>
#include <amp_graphics.h>
using namespace concurrency;
using namespace concurrency::graphics;
void declareTextures() {
// Create a 16-texel texture of int.
texture<int, 1> intTexture1(16);
texture<int, 1> intTexture2(extent<1>(16));
// Create a 16 x 32 texture of float_2.
texture<float_2, 2> floatTexture1(16, 32);
texture<float_2, 2> floatTexture2(extent<2>(16, 32));
// Create a 2 x 4 x 8 texture of uint_4.
texture<uint_4, 3> uintTexture1(2, 4, 8);
texture<uint_4, 3> uintTexture2(extent<3>(2, 4, 8));
}
Можно также использовать конструктор для объявления и инициализации объекта texture.Следующий пример кода создает объект texture из вектора объектов float_4.Количество битов на один скалярный элемент установлено по умолчанию.Нельзя использовать этот конструктор с norm, unorm или короткими векторами norm и unorm, поскольку они не имеют количества бит по умолчанию на один скалярный элемент.
#include <amp.h>
#include <amp_graphics.h>
#include <vector>
using namespace concurrency;
using namespace concurrency::graphics;
void initializeTexture() {
std::vector<int_4> texels;
for (int i = 0; i < 768 * 1024; i++) {
int_4 i4(i, i, i, i);
texels.push_back(i4);
}
texture<int_4, 2> aTexture(768, 1024, texels.begin(), texels.end());
}
Можно также объявить и инициализировать объект texture с использованием перегрузки конструктора, которая принимает указатель на исходные данные, размер исходных данных в байтах и количество бит на один скалярный элемент.
void createTextureWithBPC() {
// Create the source data.
float source[1024 * 2];
for (int i = 0; i < 1024 * 2; i++) {
source[i] = (float)i;
}
// Initialize the texture by using the size of source in bytes
// and bits per scalar element.
texture<float_2, 1> floatTexture(1024, source, (unsigned int)sizeof(source), 32U);
}
Текстуры в этих примерах созданы в представлении по умолчанию ускорителя по умолчанию.Можно использовать другие перегрузки конструктора, если нужно определить объект accelerator_view.Нельзя создать объект текстуры на ускорителе ЦП.
Существуют ограничения на размер каждого измерения объекта texture, как показано в следующей таблице.Если пределы превышены, то возникает ошибка времени выполнения.
Текстура |
Ограничение размера |
---|---|
texture<T,1> |
16384 |
texture<T,2> |
16384 |
texture<T,2> |
2048 |
Чтение из объектов текстуры
Можно читать из объекта texture с помощью Оператор texture::operator[], Оператор texture::operator() или Метод texture::get.Оператор texture::operator[] и Оператор texture::operator() возвращают значение, а не ссылки.Следовательно, нельзя записать в объект texture с помощью Оператор texture::operator[].
void readTexture() {
std::vector<int_2> src;
for (int i = 0; i < 16 *32; i++) {
int_2 i2(i, i);
src.push_back(i2);
}
std::vector<int_2> dst(16 * 32);
array_view<int_2, 2> arr(16, 32, dst);
arr.discard_data();
const texture<int_2, 2> tex9(16, 32, src.begin(), src.end());
parallel_for_each(tex9.extent, [=, &tex9] (index<2> idx) restrict(amp) {
// Use the subscript operator.
arr[idx].x += tex9[idx].x;
// Use the function () operator.
arr[idx].x += tex9(idx).x;
// Use the get method.
arr[idx].y += tex9.get(idx).y;
// Use the function () operator.
arr[idx].y += tex9(idx[0], idx[1]).y;
});
arr.synchronize();
}
В следующем примере кода показано, как сохранить каналы текстуры в коротком векторе, а затем получить доступ к отдельным скалярным элементам как к свойствам короткого вектора.
void UseBitsPerScalarElement() {
// Create the image data.
// Each unsigned int (32-bit) represents four 8-bit scalar elements(r,g,b,a values).
const int image_height = 16;
const int image_width = 16;
std::vector<unsigned int> image(image_height * image_width);
extent<2> image_extent(image_height, image_width);
// By using uint_4 and 8 bits per channel, each 8-bit channel in the data source is
// stored in one 32-bit component of a uint_4.
texture<uint_4, 2> image_texture(image_extent, image.data(), image_extent.size() * 4U, 8U);
// Use can access the RGBA values of the source data by using swizzling expressions of the uint_4.
parallel_for_each(image_extent,
[&image_texture](index<2> idx) restrict(amp)
{
// 4 bytes are automatically extracted when reading.
uint_4 color = image_texture[idx];
unsigned int r = color.r;
unsigned int g = color.g;
unsigned int b = color.b;
unsigned int a = color.a;
});
}
В следующей таблице перечислено допустимое количество бит на канал для каждой разновидности типа вектора.
Тип данных текстуры |
Допустимое количество бит на скалярный элемент |
---|---|
int, int_2, int_4 uint, uint_2, uint_4 |
8, 16, 32 |
float, float_2, float_4 |
16, 32 |
double, double_2 |
64 |
norm, norm_2, norm_4 unorm, unorm_2, unorm_4 |
8, 16 |
Запись в объекты текстуры
Метод texture::set используется для записи в объекты texture.Объект текстуры может быть доступен только для чтения или для чтения и записи.Для объекта текстуры, который должен быть доступен для чтения и записи, должны выполняться следующие условия:
T имеет только один скалярный компонент.(Нельзя использовать короткие векторы).
T не является double, norm или unorm.
Значение свойства texture::bits_per_scalar_element — 32.
Если все три условия не выполняются, то объект texture будет доступен только для чтения.Первые два условия проверяются во время компиляции.Генерируется ошибка компиляции, если имеется код, который пытается писать в readonly-объект текстуры.Условие для texture::bits_per_scalar_element обнаруживается во время выполнения, и среда выполнения создает исключение unsupported_feature при попытке записи в объект texture, доступный только для чтения.
В следующем примере кода выполняется запись значений в объект текстуры.
void writeTexture() {
texture<int, 1> tex1(16);
parallel_for_each(tex1.extent, [&tex1] (index<1> idx) restrict(amp) {
tex1.set(idx, 0);
});
}
Использование объекта writeonly_texture_view
Класс writeonly_texture_view предоставляет представление объекта текстуры, доступное только для чтения.Объект writeonly_texture_view должен быть перехвачен по значению в лямбда-выражении.Следующий пример кода использует объект writeonly_texture_view для записи в объект texture, который имеет 2 компонента (int_2).
void write2ComponentTexture() {
texture<int_2, 1> tex4(16);
writeonly_texture_view<int_2, 1> wo_tv4(tex4);
parallel_for_each(extent<1>(16), [=] (index<1> idx) restrict(amp) {
wo_tv4.set(idx, int_2(1, 1));
});
}
Копирование объектов текстуры
Можно производить копирование объектов текстуры с помощью функции copy или функции copy_async, как показано в следующем примере кода.
void copyHostArrayToTexture() {
// Copy from source array to texture object by using the copy function.
float floatSource[1024 * 2];
for (int i = 0; i < 1024 * 2; i++) {
floatSource[i] = (float)i;
}
texture<float_2, 1> floatTexture(1024);
copy(floatSource, (unsigned int)sizeof(floatSource), floatTexture);
// Copy from source array to texture object by using the copy function.
char charSource[16 * 16];
for (int i = 0; i < 16 * 16; i++) {
charSource[i] = (char)i;
}
texture<int, 2> charTexture(16, 16, 8U);
copy(charSource, (unsigned int)sizeof(charSource), charTexture);
// Copy from texture object to source array by using the copy function.
copy(charTexture, charSource, (unsigned int)sizeof(charSource));
}
Также можно скопировать одну текстуру в другую с помощью метода texture::copy_to.Две текстуры могут находиться на разных объектах accelerator_view.При копировании в объект writeonly_texture_view, данные копируются в нижележащий объект texture.Количество бит на один скалярный элемент и размер должны быть одинаковыми на объектах texture источника и назначения.Если эти требования не выполнены, то генерируется исключение.
Взаимодействие
Среда выполнения C++ AMP поддерживает взаимодействие между texture<T,1> и интерфейсом ID3D11Texture1D, между texture<T,2> и интерфейсом ID3D11Texture2D, а также между texture<T,3> и интерфейсом ID3D11Texture3D.Метод get_texture принимает объект texture и возвращает интерфейс IUnknown.Метод make_texture принимает интерфейс IUnknown и объект accelerator_view, а возвращает объект texture.