Поделиться через


Графика (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

Hh913015.collapse_all(ru-ru,VS.110).gifОператоры

Если оператор определен между двумя короткими векторами, то он также определен между коротким вектором и скаляром.Кроме того, одно из следующих утвержлений должно быть верно:

  • Тип скаляра должен быть тем же, что и тип элемента короткого вектора.

  • Тип скаляра может быть неявно преобразован в тип элемента вектора с помощью только одного определенного пользователем преобразования.

Операция проводится покомпонентно между каждым компонентом короткого вектора и скаляром.Ниже приведены допустимые операторы:

Тип оператора

Допустимые типы

Бинарные операторы

Допустимы для всех типов: +, -, *, /,

Допустимы для целочисленных типов: %, ^, |, &, <<, >>,

Два вектора должны иметь одинаковый размер, а результат — вектор того же размера.

Операторы сравнения

Допустимы для всех типов: == и !=

Составной оператор присваивания

Допустимы для всех типов: +=, -=, *=, /=

Допустимы для целочисленных типов: %=, ^=, |=, &=, <<=, >>=

Операторы инкремента и декремента

Допустимы для всех типов: ++, --

И префиксная, и постфиксная формы являются допустимыми.

Оператор побитового НЕ (~)

Допустим для целочисленных типов.

Унарный оператор -

Допустим для всех типов, за исключением unorm и uint.

Hh913015.collapse_all(ru-ru,VS.110).gifГруппирующие выражения

Библиотека коротких векторов поддерживает конструкции метода доступа вида 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 можно задать количество бит на один скалярный элемент пользовательского текселя, что позволяет автоматически получать доступ к отдельным скалярным элементам в коде без использования битовых сдвигов.

Hh913015.collapse_all(ru-ru,VS.110).gifСоздание объектов текстуры

Можно объявить объект текстуры без инициализации.В следующем примере объявляется несколько объектов текстуры.

#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

Hh913015.collapse_all(ru-ru,VS.110).gifЧтение из объектов текстуры

Можно читать из объекта 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

Hh913015.collapse_all(ru-ru,VS.110).gifЗапись в объекты текстуры

Метод 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); 
    });

}

Hh913015.collapse_all(ru-ru,VS.110).gifИспользование объекта 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)); 
    });
}

Hh913015.collapse_all(ru-ru,VS.110).gifКопирование объектов текстуры

Можно производить копирование объектов текстуры с помощью функции 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.

См. также

Ссылки

Класс double_2

Класс double_3

Класс double_4

Класс float_2

Класс float_3

Класс float_4

Класс int_2

Класс int_3

Класс int_4

Класс norm_2

Класс norm_3

Класс norm_4

Структура short_vector

Структура short_vector_traits

Класс uint_2

Класс uint_3

Класс uint_4

Класс unorm_2

Класс unorm_3

Класс unorm_4