前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DAY20:阅读Surface Memory

DAY20:阅读Surface Memory

作者头像
GPUS Lady
发布2018-06-22 18:15:42
1.4K0
发布2018-06-22 18:15:42
举报
文章被收录于专栏:GPUS开发者

3.2.11.2. Surface Memory

For devices of compute capability 2.0 and higher, a CUDA array (described in Cubemap Surfaces), created with the cudaArraySurfaceLoadStore flag, can be read and written via a surface object or surface reference using the functions described in Surface Functions.

Table 14 lists the maximum surface width, height, and depth depending on the compute capability of the device.

(二维码扫描可以看到Table 14的图)

3.2.11.2.1. Surface Object API

A surface object is created using cudaCreateSurfaceObject() from a resource description of type struct cudaResourceDesc.

The following code sample applies some simple transformation kernel to a texture.

3.2.11.2.2. Surface Reference API

A surface reference is declared at file scope as a variable of type surface:

surface<void, Type> surfRef;

where Type specifies the type of the surface reference and is equal to cudaSurfaceType1D, cudaSurfaceType2D, cudaSurfaceType3D, cudaSurfaceTypeCubemap,cudaSurfaceType1DLayered, cudaSurfaceType2DLayered, or cudaSurfaceTypeCubemapLayered; Type is an optional argument which defaults to cudaSurfaceType1D. A surface reference can only be declared as a static global variable and cannot be passed as an argument to a function.

Before a kernel can use a surface reference to access a CUDA array, the surface reference must be bound to the CUDA array using cudaBindSurfaceToArray().

The following code samples bind a surface reference to a CUDA array cuArray:

· Using the low-level API:

· Using the high-level API:

A CUDA array must be read and written using surface functions of matching dimensionality and type and via a surface reference of matching dimensionality; otherwise, the results of reading and writing the CUDA array are undefined.

Unlike texture memory, surface memory uses byte addressing. This means that the x-coordinate used to access a texture element via texture functions needs to be multiplied by the byte size of the element to access the same element via a surface function. For example, the element at texture coordinate x of a one-dimensional floating-point CUDA array bound to a texture reference texRef and a surface reference surfRef is read using tex1d(texRef, x) via texRef, but surf1Dread(surfRef, 4*x) via surfRef. Similarly, the element at texture coordinate x and y of a two-dimensional floating-point CUDA array bound to a texture reference texRef and a surface reference surfRef is accessed using tex2d(texRef, x, y) via texRef, but surf2Dread(surfRef, 4*x, y) via surfRef (the byte offset of the y-coordinate is internally calculated from the underlying line pitch of the CUDA array).

The following code sample applies some simple transformation kernel to a texture.

本文备注/经验分享:

Surface Memory——

如同之前我们说过的, surface等于非常简化版本的texture,texture具有的特殊功能它都没有。例如texture的坐标变换,插值,高级边界处理之类的。还有图形学用的mipmap,lod啥的,但Surface同样可以绑定CUDA Array,同时可以写入。而普通指针读写只能应付普通的线性内存(显存)。以及,surface只有简单的边界处理,例如越界返回0(读取)或者越界写入忽略之类的。你应当将它当成一个极度简化版本的texture,或者当成只有存储读写功能,但没有采样器(sampler,也就是之前你看到的那些texture的高级特性)的简化版本texture。能写入这个非常重要——在以前没有写入功能的时候,更新CUDA Array非常麻烦,现在只需要在kernel上启动一个surface更新写入即可。这个是个很好的功能,否则以前需要从host端折腾,现在可以直接从device上启动kernel处理了。其他的都一样。

Surface Object API——

在这段演示的代码里面, 你会看到这个kernel很简化了,没有旋转功能了,只是简单的复制一张图片:读取原图,写入目标图。因为之前的那个旋转kernel的很多特性,例如从归一化的坐标进行插值这些,surface没有。所以这个kernel只是一个简化的什么都不干的kernel,但演示了surface可以直接写入的特性。

(1)更新CUDA Array的时候,texture是只读的,但这个可以对后备存储(CUDA Array)写入。可以用来更新一个CUDA Array给texture用,但需要注意的是,surface写入和texture读取不维持一致性,只有在下次kernel启动的时候才能生效,所以你往往能见到这种风格的代码——stream中:surface写入kernel---->texture读取kernel 这么一个顺序。

(2)你不需要复杂的texture功能,而只需要简单的越界处理(只有两种最简单的边界处理);

(3) 你可能需要surface访问CUDA Array,以便使用里面的特殊的,对用户不透明,但可能对程序性能有提升的存储方式。 大致这三种情况。

还有一点,就是纹理在不使用归一化坐标的时候,坐标的含义是点/元素/纹元。而surface的坐标是字节。里面有个元素大小的倍数差别。从texture改成surface的时候,需要注意这个坐标问题(假设surface能满足要求),其他应当都一样了。以及,刚才说过的不维持读写一致性这个很重要。写入surface必须在下次kernel启动才能生效。立刻读取将导致未定义的结果。

还有一点。surface必须绑定到Cuda array,

struct cudaResourceDesc resDesc; memset(&resDesc, 0, sizeof(resDesc)); resDesc.resType = cudaResourceTypeArray;

这三行代码中的resType,必须是cudaResourceTypeArray。手册没说,但是用线性内存这里会失败的。其实也很好理解。本身surface功能就少。如果再不使用CUDA Array,那就和普通的指针读写普通内存(显存)毫无区别了。(除了唯一剩下的防止越界)。那样的话又何必要用它了。所以这里要求必须的,这里不能使用cudaResourceTypeLinear,而必须是TypeArray。

Surface Reference API——

上面说的这些对object和reference都有效的。他们只是一个是老API,一个是新API而已。无本质区别的,类似texture reference和texture object的关系,纹理的特性是通用的,只是形式不同。surface同理。surface reference就比surface object早出了fermi这一代,从Fermi开始有的surface reference,但从Kepler就立刻更新了, 有了surface object。而texture reference是从一开头有CUDA就有的,不过它们两个都是从Kepler(3.0)开始,更新有了texture object和surface object,所以texture refernce独立存在的时间更长。老代码涉及texture reference的可能要远比surface reference的多。

The following code sample applies some simple transformation kernel to a texture.; 后面的代码没有什么特别的,但需要注意的是,从inputSurfRef读取后,没有经过任何处理,就写入了outputSurfRef。以前texture那段是有个旋转的。这个是原图,完全没转动。但:

(1)虽然没转动,但结果直接写入了一个输出的cuda array, 以后可以直接给需要该cuda array内容的texture用。而之前的例子只能写入普通内存。(因为texture无写入能力)

(2)这里没有使用outputSurfRef。如果要使用的话,必须在下次的kernel中才能使用它,本次如果使用了会导致未定义的结果。

(3)注意x坐标是一个乘以了4(元素大小)的整数。因为单位是字节。 而之前的texture坐标不需要*4, 同时是归一化的浮点值[0.0, 1.0)。

归一化的浮点坐标,这个属于texture独有的高级特性。不能使用的。(但可以自行用代码实现坐标变换,等效的实现这一点,只是不能自动免费实现了)

有不明白的地方,请在本文后留言

或者在我们的技术论坛bbs.gpuworld.cn上发帖

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GPUS开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3.2.11.2. Surface Memory
  • 3.2.11.2.1. Surface Object API
  • 3.2.11.2.2. Surface Reference API
  • Surface Memory——
  • 有不明白的地方,请在本文后留言
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档