文中的"显存"还没有找到合适的中文翻译,它的英文名称是texture, 在应用开发者来看,texture是一个名词,在物理上指的是 GPU显存中一段连续的空间。
弃用 writeonly_texture_view
在 Visual Studio 2013 中,C++ AMP 针对采样和 mipmap 等硬件显存功能引入了更好的支持,但 writeonly_texture_view 类无法支持这些功能。 新引入的 texture_view 类支持 writeonly_texture_view 中功能的超集;因此,writeonly_texture_view 已被弃用。
我们建议(至少在新代码中)使用 texture_view 来访问之前由 writeonly_texture_view 提供的功能。 请比较下面两个代码示例,这两个示例均会写入具有 2 个组件的显存对象 (int_2)。 请注意,在这两种情况下,都必须通过 lambda 表达式中的值来捕获视图 wo_tv4。 以下是采用新 texture_view 类的示例:
void write2ComponentTexture() {
texture<int_2, 1> tex4(16);
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));
});
}
以下是已弃用的 writeonly_texture_view 类:
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));
});
}
你可以看到,如果只是写入主 mipmap 级别,则两个代码示例几乎完全相同。 如果已在现有代码中使用 writeonly_texture_view 并且不打算改进该代码,则不必进行更改。 但是,如果你考虑改进该代码,则我们建议你重写代码以便使用 texture_view,因为它的一些改进支持一些新硬件显存功能。
实例化显存视图对象
声明 texture_view 类似于声明与 array 关联的 array_view。 下面的代码示例声明了多个texture对象以及与之关联的 texture_view 对象。
#include <amp.h>
#include <amp_graphics.h>
using namespace concurrency;
using namespace concurrency::graphics;
void declareTextureViews()
{
// Create a 16-texel texture of int, with associated texture_views.
texture<int, 1> intTexture(16);
texture_view<const int, 1> intTextureViewRO(intTexture); // read-only
texture_view<int, 1> intTextureViewRW(intTexture); // read-write
// Create a 16 x 32 texture of float_2, with associated texture_views.
texture<float_2, 2> floatTexture(16, 32);
texture_view<const float_2, 2> floatTextureViewRO(floatTexture); // read-only
texture_view<float_2, 2> floatTextureViewRO(floatTexture); // write-only
// Create a 2 x 4 x 8 texture of uint_4, with associated texture_views.
texture<uint_4, 3> uintTexture(2, 4, 8);
texture_view<const uint_4, 3> uintTextureViewRO(uintTexture); // read-only
texture_view<uint_4, 3> uintTextureViewWO(uintTexture); // write-only
}
请注意,为何元素类型为非常量且具有一个组件的纹理视图为读写属性,而元素类型为非常量但具有多个组件的纹理视图却是只写属性。 常量元素类型的纹理视图始终是只读属性,但如果元素类型为非常量,则元素中的组件数量决定了视图为读写(1 个组件)视图还是只写(多个组件)视图。
在决定视图是否支持纹理采样以及 mipmap 级别的访问方式时,texture_view 的元素类型(其常量性及其组件数)也会发挥一定的作用:
通过此表,你可以看到只读显存视图完全支持新功能,以此换取不能写入视图。 可写显存视图的限制在于它们只能访问一个 mipmap 级别。 读写显存视图的专用性甚至高于可写显存视图,因为它们增加了一项要求,即显存视图的元素类型应只有一个组件。 请注意,可写显存视图不支持采样,因为采样是面向读取的操作。
读取显存视图对象
通过显存视图读取未采样的显存数据类似于从显存本身读取数据,只是显存是通过引用来捕获,而显存视图则是通过值来捕获。 下面两个代码示例进行了演示;首先,仅使用 texture:
void write2ComponentTexture() {
texture<int_2, 1> text_data(16);
parallel_for_each(extent<1>(16), [&] (index<1> idx) restrict(amp) {
tex_data.set(idx, int_2(1, 1));
});
}
以下是同一个示例,只是现在使用 texture_view 类:
void write2ComponentTexture() {
texture<int_2, 1> tex_data(16);
texture_view<int_2, 1> tex_view(tex_data);
parallel_for_each(extent<1>(16), [=] (index<1> idx) restrict(amp) {
tex_view.set(idx, int_2(1, 1));
});
}
元素基于浮点类型(例如,float、float_2 或 float_4)的显存视图也可以使用显存采样来读取,以便利用对各种筛选模式和寻址模式的硬件支持。 C++ AMP 支持计算情景下两种最常见的筛选模式,即点筛选(最近邻域)和线性筛选(加权平均),同时支持四种寻址模式,即重叠寻址、镜像寻址、钳位寻址和边框寻址。
除了 C++ AMP 直接支持的模式外,你还可以访问底层平台的其他筛选模式和寻址模式,方法是使用互操作 API 采用通过平台 API 直接创建的显存采样器。 例如,Direct3D 支持各向异性筛选等其他筛选模式,并可以对显存的各个维度应用不同的寻址模式。 通过使用 Direct3D API,你可以创建一个坐标为纵向重叠、横向镜像并进行各向异性筛选采样的显存采样器,然后通过 make_sampler 互操作 API 利用 C++ AMP 代码中的采样器。
显存视图还支持读取 mipmap。 只读显存视图(具有常量元素类型的视图)可以提供最大的灵活性,原因在于可对实例化时确定的一系列 mip 级别进行动态采样,而且支持具有 1、2 或 4 个组件的元素。 元素仅具有一个组件的读写显存视图也支持 mipmap,但仅限实例化时确定的一个 mipmap 级别。
写入显存视图对象
使用 texture_view::get 方法可通过 texture_view 对象写入基础 texture。 显存视图可以为只读、读写或只写视图。 显存视图若要可写,则必须具有非常量元素类型;显存视图若要可读写,则其元素类型还必须只有一个组件。 否则,显存视图为只读视图。 通过显存视图一次只能访问一个显存 mipmap 级别,此级别将在实例化视图时指定。
此示例演示如何写入显存(具有 4 个 mipmap 级别)的第二详细 mipmap 级别。 最详细的 mipmap 级别为级别 0。
// Create a texture that has 4 mipmap levels : 16x16, 8x8, 4x4, 2x2
texture<int, 2> tex(extent<2>(16, 16), 16U, 4);
// Create a writable texture view to the second mipmap level :4x4
texture_view<int, 2> w_view(tex, 1);
parallel_for_each(w_view.extent, [=](index<2> idx) restrict(amp)
{
w_view.set(idx, 123);
});
互操作性
C++ AMP 运行时支持 texture<T,1> 与 ID3D11Texture1D 接口、texture<T,2> 与 ID3D11Texture2D 接口,以及 texture<T,3> 与 ID3D11Texture3D 接口之间的互操作。 get_texture 方法采用 texture 对象,并返回 IUnknown 接口。 make_texture 方法采用 IUnknown 接口和 accelerator_view 对象,并返回 texture 对象。