DAY20:阅读Surface Memory

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上发帖

原文发布于微信公众号 - 吉浦迅科技(gpusolution)

原文发表时间:2018-05-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

使用自定义行为扩展 WCF

Windows® Communication Foundation (WCF) 提供了许多扩展点,供开发人员自定义运行时行为,从而实现服务调度和客户代理调用。您...

3057
来自专栏Ldpe2G的个人博客

ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架

这个项目是一次课程作业,要求是写一个并行计算框架,本人本身对openmp比较熟,

1876
来自专栏陈满iOS

iOS开发·runtime原理与实践: 消息转发篇(Message Forwarding) (消息机制,方法未实现+API不兼容奔溃,模拟多继承)

在我们开始使用消息机制之前,我们可以约定我们的术语。例如,很多人不清楚“方法”与“消息”是什么,但这对于理解消息传递系统如何在低级别工作至关重要。

601
来自专栏Golang语言社区

亲身经历的痛--database/sql: Stmt的使用以及坑

前言 众所周知,golang操作数据库,是通过database/sql包,以及第三方的实现了database/sql/driver接口的数据库驱动包来共同完成的...

50010
来自专栏高性能服务器开发

libevent源码深度剖析(五) libevent的核心:事件event

(1)libevent源码深度剖析一 序 (2)libevent源码深度剖析二 Reactor模式 (3)libevent源码深度剖析三 libevent基...

1013
来自专栏数据小魔方

ggplot2学习笔记之——ggplot2主题调整系统

ggplot2绘图系统拥有庞大、健全的图形美化系统,这一套图形美化依赖于图例调整系统、标度调整系统、标签调整系统、主题调整系统以及分面系统。 本节仅从主题调整系...

2875
来自专栏C语言及其他语言

C语言中的宏陷阱 #define SQU(x) x*x

有同学写过或者想写这样的宏定义吗? 求两个或几个数的乘积: #define SQU(x) x*x 我们正常使用没有问题: ? 但如果这样写呢? ? 哎呀,...

3335
来自专栏JAVA高级架构

Netty原理浅析

Netty是JBoss出品的高效的Java NIO开发框架。本文将主要分析Netty实现方面的东西,由于精力有限,本人并没有对其源码做了极细致的研 究。如果下面...

572
来自专栏精讲JAVA

Netty 实现原理浅析

(点击上方公众号,可快速关注) 来源:kafka0102的博客 , www.kafka0102.com/2010/06/167.html Netty是JBoss...

2228
来自专栏平凡文摘

Netty 实现原理浅析

1293

扫码关注云+社区