Grafika (C++ AMP)
C++ AMP zawiera kilka interfejsów API w przestrzeni nazw Concurrency::graphics, który umożliwia dostęp do obsługi tekstur na GPU.Niektóre typowe przypadki to:
Można użyć klasy texture jako kontener danych dla obliczeń i wykorzystać przestrzenne umiejscowienie w pamięci podręcznej tekstury i układach sprzętowych GPU.Przestrzenne umiejscowienie jest właściwością elementów danych, które są fizycznie blisko siebie.
Środowisko wykonawcze zapewnia skuteczne współdziałanie z modułami cieniującymi wszystkich typów poza obliczeniowymi.Moduły cieniujące pikseli, wierzchołków, teselacji oraz płatów powierzchni często tworzą lub wykorzystują tekstury które można wykorzystać w obliczeniach C++ AMP.
Interfejs graficzny API w C++ AMP zapewnia alternatywne sposoby dostępu buforów z danymi rozmieszczonymi na poziomie niższym niż słowo.Tekstury, które mają formaty reprezentujące teksele (elementy tekstury), które składają się z 8-bitowe lub 16-bitowych skalarów umożliwiają dostęp do danych spakowanych w takiej pamięci.
[!UWAGA]
Interfejsy API C++ AMP nie zapewniają próbkowania tekstur i funkcji filtrowania.Należy użyć funkcji współdziałania C++ AMP i następnie napisać kod z użyciem DirectCompute i HLSL.
Typy norm i unorm
Typy skalarne norm i unorm są typami skalarnymi, które ograniczają zakres wartości float; jest to znane jako obcinanie.Te typy można jawnie zbudować z innych typów skalarnych.Podczas rzutowania, wartość jest najpierw rzutowana na typ float a następnie obcinana do odpowiedniego regionu dozwolonego przez normę [-1.0…1.0] lub normę bez znaku [0.0…1.0].Rzutowanie z +/- nieskończoności zwraca +/- 1.Rzutowanie NaN jest niezdefiniowane.Norma może zostać niejawnie skonstruowana z normy bez znaku bez utraty danych.Operator niejawnej konwersji na typ zmiennoprzecinkowy jest zdefiniowany dla tych typów.Operatory dwuargumentowe są zdefiniowane między podanymi typami i innymi wbudowanymi typami skalarnymi takimi jak float i int: +, -, *, /, ==, !=, >, <, >=, <=.Złożone operatory przypisania są również obsługiwane: +=, -=, *=, /=.Unarny operator negacji (-) jest zdefiniowany dla norm.
Biblioteka Short Vector
Biblioteka Short Vector zawiera niektóre funkcje typu Vector zdefiniowane w HLSL i jest zazwyczaj używana do definiowania tekseli.Krótki wektor jest strukturą danych, zawierającą jedną do czterech wartości tego samego typu.Obsługiwane typy to double, float, int, norm, uint, oraz unorm.Nazwy typów przedstawiono w poniższej tabeli.Dla każdego typu jest również odpowiadające wyrażenie typedef które nie ma znaku podkreślenia w nazwie.Typy, które mają podkreślenia znajdują się w Obszar nazw CONCURRENCY::Graphics.Typy, które nie mają podkreślenia są w znajdują się w Obszar nazw CONCURRENCY::Graphics::Direct3D , dzięki czemu są wyraźnie rozdzielone od podobnie nazwanych typów podstawowych takich jak __int8 i __int16.
Length 2 |
Length 3 |
Length 4 |
|
---|---|---|---|
double |
double_2 double2 |
double_3 double3 |
double_4 double4 |
float |
float_2 float2 |
float_3 float_3 |
float_4 float4 |
int |
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 |
Operatory
Jeśli zdefiniowano operator pomiędzy dwoma krótkimi wektorami, jest on także zdefiniowany pomiędzy krótkim wektorem, a skalarem.Ponadto jeden z poniższych warunków musi być spełniony:
Typ skalara musi być taki sam, jak typ elementu krótkiego wektora.
Typ skalara można niejawnie konwertować na typ elementu wektora za pomocą tylko jednej konwersji zdefiniowanej przez użytkownika.
Operacja jest wykonywana na poziomie składnika dla każdego składnika krótkiego wektora i skalara.Oto prawidłowe operatory:
Typ operatora |
Prawidłowe typy |
---|---|
Operatory dwuargumentowe |
Prawidłowe dla wszystkich typów: +, -, *, / Prawidłowe typów całkowitych: %, ^, |, &, <<, >> Dwa wektory muszą mieć taki sam rozmiar, a wynik jest wektorem tej samej wielkości. |
Operatory relacyjne |
Prawidłowe dla wszystkich typów: == i != |
Złożony operator przypisania |
Prawidłowe dla wszystkich typów: +=, -=, *=, /= Prawidłowe typów całkowitych: %=, ^=, |=, &=, <<=, >>= |
Operatory inkrementacji i dekrementacji |
Ważne na wszystkich typów: ++, -- Zarówno przedrostek jak i przyrostek są prawidłowe. |
Bitowy operator negacji (~) |
Prawidłowy dla typów całkowitych. |
Jednoargumentowy operator - |
Prawidłowe dla wszystkich typów z wyjątkiem unorm i uint. |
Wyrażenia przemieniane
Biblioteka Short Vector obsługuje dostęp do składników krótkiego wektora za pomocą akcesora vector_type.identifier.identifier, który jest znany jako wyrażenie przemieniane, określa składniki wektora.Wyrażenie może być l-wartością lub r-wartością.Pojedyncze znaki w identyfikatorze mogą być jednymi z: x, y, z oraz w lub r, g, b oraz a. "x" oraz "r" oznaczają zerowy składnik, "y" oraz "g" oznaczają pierwszy składnik i tak dalej.Zauważ, że "x" i "r" nie mogą zostać użyte w tym samym identyfikatorze.) "Rgba" i "xyzw" zwracają więc ten sam wynik.Akcesory pojedynczego składnika takie jak "x" i "y" są skalarnymi typami wartości.Akcesory wielu składników są krótkimi wektorami.Na przykład można utworzyć wektor int_4 o nazwie fourInts i zawiera wartości 2, 4, 6 i 8, wówczas fourInts.y zwraca liczbę całkowitą 4, a fourInts.rg zwraca obiekt int_2, który zawiera wartości 2 i 4.
Klasy tekstur
Wiele GPU ma sprzętowe pamięci podręczne, które są zoptymalizowane do pobrania pikseli i tekseli oraz do renderowania obrazów i tekstur.Klasa texture<T,N>, która jest klasą kontenera obiektów texel, eksponuje funkcjonalność GPU dla tekstur.Texel może być:
Skalarem int, uint, float, double, norm, or unorm.
Krótki wektor, który ma dwa lub cztery składniki.Jedynym wyjątkiem jest double_4, który jest niedozwolony.
Obiekt texture może mieć rangi 1, 2 lub 3.Obiekt texture może być przechwytywany jedynie poprzez odwołanie w lambda wywołaniu parallel_for_each.Tekstury są przechowywane na GPU jako obiekty tekstury Direct3D.Aby uzyskać więcej informacji na temat tekstur i tekseli w Direct3d, zobacz Wprowadzenie do tekstur w Direct3D 11.
Typ teksela może być jednym z wielu formatów tekstury, które są używane w programowania grafiki.Na przykład format RGBA może używać 32 bity, po 8 bitów na każdy element skalarny R, G, B oraz A.Sprzęt teksturujący karty graficznej może uzyskać dostęp do poszczególnych elementów w oparciu o format.Na przykład jeśli używasz formatu RGBA sprzęt teksturujący może wyodrębnić każdy element 8-bitowy w formie 32-bitowej.W C++ AMP można ustawić bity po elemencie skalarnym w tekselu tak, aby automatycznie uzyskiwać dostęp do poszczególnych elementów skalarnych w kodzie bez wykorzystywania przesunięć bitowych.
Tworzenie wystąpień obiektów tekstury
Można zadeklarować obiekt tekstury bez inicjalizacji.Poniższy przykład kodu deklaruje kilka obiektów tekstur.
#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));
}
Można także użyć konstruktora do zadeklarowania i zainicjowania obiektu texture.Poniższy przykład kodu tworzy obiekt texture z wektora obiektów float_4.Element bity na skalar jest ustawiony na domyślny.Nie można użyć tego konstruktora z norm, unorm, lub wektorem krótki norm i unorm, ponieważ nie posiadają domyślnej liczby bitów na element skalarny.
#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());
}
Można również zadeklarować i zainicjować obiekt texture za pomocą przeładowania konstruktora, który przyjmuje wskaźnik do danych źródłowych, rozmiar źródła danych w bajtach rozmiar i liczbę bitów na element skalarny.
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);
}
Tekstury w tych przykładach są tworzone w domyślnym widoku akceleratora domyślnego.Można używać innych przeciążeń konstruktora jeśli chcesz określić obiekt accelerator_view.Nie można utworzyć obiektu tekstury na akceleratorze CPU.
Ograniczenia na rozmiar każdego wymiaru obiektu texture obowiązują zgodnie z danymi w poniższej tabeli.Błąd czasu wykonania jest generowany jeśli zakresy zostaną przekroczone.
Tekstura |
Ograniczenie rozmiaru |
---|---|
texture<T,1> |
16384 |
texture<T,2> |
16384 |
texture<T,2> |
2048 |
Czytanie z obiektów tekstur
Można czytać z obiektu texture używając Tekstura::operator[] operatora, Tekstura:: (operator) Operator, lub Metoda Texture::Get.Tekstura::operator[] operatora i Tekstura:: (operator) Operator zwracają wartość, a nie odwołanie.Dlatego nie można zapisywać do obiektu texture za pomocą Tekstura::operator[] operatora.
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();
}
Poniższy przykład kodu demonstruje, jak przechowywać kanały tektsury w krótkim wektorze, a także uzyskiwać dostęp do poszczególnych elementów skalarnych jako właściwości krótkiego wektora.
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;
});
}
Poniższa lista zawiera prawidłowe liczby bitów na kanał, dla każdego typu wektora sortowania.
Typ danych tekstury |
Prawidłowe bity na element skalarny |
---|---|
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 |
Zapisywanie do obiektów tekstury
Użyj metody texture::set, aby zapisywać do obiektów texture.Obiekt tekstury może być tylko do odczytu lub do odczytu i zapisu.Aby do obiektu tekstury można było zapisywać dane i czytać z niego, następujące warunki muszą być spełnione:
T ma tylko jeden składnik skalarny.(Krótkie wektory nie są dozwolone.)
T nie jest typem double, norm, ani unorm.
Właściwość texture::bits_per_scalar_element wynosi 32.
Jeśli którykolwiek z trzech nie jest spełniony, obiekt texture jest tylko do odczytu.Pierwsze dwa warunki są sprawdzane podczas kompilacji.Błąd kompilacji jest generowany, jeśli kod próbuje zapisać do obiektu tekstury, który jest readonly.Warunek dla texture::bits_per_scalar_element jest wykrywany w trakcie wykonania i środowisko wykonawcze zgłasza wyjątek unsupported_feature podczas próby zapisu obiektu texture przeznaczonego tylko do odczytu.
Poniższy przykład kodu zapisuje wartości do obiektu tekstury.
void writeTexture() {
texture<int, 1> tex1(16);
parallel_for_each(tex1.extent, [&tex1] (index<1> idx) restrict(amp) {
tex1.set(idx, 0);
});
}
Za pomocą obiektu writeonly_texture_view
Klasa writeonly_texture_view zawiera widok writeonly obiektu tekstury.Obiekt writeonly_texture_view musi zostać przechwycony przez wartość w wyrażeniu lambda.Następujący przykład kodu wykorzystuje obiekt writeonly_texture_view aby zapisać do obiektu texture, który ma dwa składniki (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));
});
}
Kopiowanie obiektów tekstur
Można kopiować między obiektami tekstur przy użyciu funkcji copy lub copy_async jak pokazano w poniższym przykładzie kodu.
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));
}
Można również skopiować z jednej tekstury do innej za pomocą metody texture::copy_to.Dwie tekstury mogą znajdować się na różnych widokach akceleratora.Przy kopiowaniu obiektu writeonly_texture_view, dane są kopiowane do źródłowych obiektów texture.Bity na element skalarny oraz zakres musi być taka sam dla obiektu źródłowego i docelowego texture.Jeśli te wymagania nie są spełnione, środowisko wykonawcze zgłasza wyjątek.
Współdziałanie
Środowisko wykonawcze C++ AMP obsługuje współdziałanie między texture<T,1> i interfejsem ID3D11Texture1D, między texture<T,2> i interfejsem ID3D11Texture2Di między texture<T,3> i interfejsem ID3D11Texture3D.Metoda get_texture pobiera obiekt texture i zwraca interfejs IUnknown.Metoda make_texture pobiera interfejs IUnknown i obiekt accelerator_view i zwraca obiekt texture.