3D 数组作为纹理在 CUDA 中写入和读取

2024-03-01

由于我正在编程的算法的性质,我需要用一些特定的数学写入/填充 3D 矩阵,然后从该矩阵(在单独的内核中)读取作为 3D 线性插值纹理。

由于纹理是一种读取模式,我假设我可以以某种方式在绑定到纹理的全局内存中写入,并从中单独读取,而不需要双倍内存并将值从写入复制到读取矩阵。但是我似乎不知道如何做到这一点。

  • 如何使用 3D 纹理内存进行读取和写入(在单独的内核中)?

我的问题是我不知道如何定义这个全局读/写数组。在下面的示例中,我创建了一个 3D 纹理,但这是使用带有以下代码的代码cudaExtent and cudaArray。但我似乎无法使用这种类型在它们上书写,我似乎也无法使用创建它们float*或喜欢的。

我可能无法做到这一点并且需要memcpy中间的某个地方,但由于这些数组通常很大,我想节省内存。

示例代码(无法编译,但清楚地定义了我想要做的事情的结构)。默认使用 100x100x100 3D 内存,因为是的。

#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <cuda_runtime_api.h>
#include <cuda.h>

#define MAXTREADS 1024

cudaError_t addWithCuda(int *c, const int *a, const int *b, unsigned int size);
texture<float, cudaTextureType3D, cudaReadModeElementType> tex;

__global__ void readKernel(float* imageend )
{
    int indY = blockIdx.y * blockDim.y + threadIdx.y;
    int indX = blockIdx.x * blockDim.x + threadIdx.x;
    int indZ = blockIdx.z * blockDim.z + threadIdx.z;
    //Make sure we dont go out of bounds
    size_t idx = indZ * 100 * 100 + indY * 100 + indX;
    if (indX >= 100 | indY >= 100 | indZ >= 100)
        return;
    imageend[idx] = tex3D(tex, indX + 0.5, indY + 0.5, indZ + 0.5);

}
__global__ void writeKernel(float* imageaux){
    int indY = blockIdx.y * blockDim.y + threadIdx.y;
    int indX = blockIdx.x * blockDim.x + threadIdx.x;
    int indZ = blockIdx.z * blockDim.z + threadIdx.z;
    //Make sure we dont go out of bounds
    size_t idx = indZ * 100 * 100 + indY * 100 + indX;
    if (indX >= 100 | indY >= 100 | indZ >= 100)
        return;
    imageaux[idx] = (float)idx;

}
int main()
{

    cudaArray *d_image_aux= 0;
    const cudaExtent extent = make_cudaExtent(100, 100, 100);
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
    cudaMalloc3DArray(&d_image_aux, &channelDesc, extent);

    // Configure texture options
    tex.normalized = false;
    tex.filterMode = cudaFilterModeLinear;
    tex.addressMode[0] = cudaAddressModeBorder;
    tex.addressMode[1] = cudaAddressModeBorder;
    tex.addressMode[2] = cudaAddressModeBorder;

    cudaBindTextureToArray(tex, d_image_aux, channelDesc);

    float *d_image_end = 0;
    size_t num_bytes = 100 * 100 * 100 * sizeof(float);
    cudaMalloc((void**)&d_image_end, num_bytes);
    cudaMemset(d_image_end, 0, num_bytes);

    int divx, divy, divz; //Irrelevant for the demo, important for the main code
    divx = 32;
    divy = 32;
    divz = 1;
    dim3 grid((100 + divx - 1) / divx,
        (100 + divy - 1) / divy,
        (100 + divz - 1) / divz);
    dim3 block(divx, divy, divz);

    // Kernels
    writeKernel << <grid, block >> >(d_image_aux);
    readKernel  << <grid, block >> >(d_image_end);


    cudaUnbindTexture(tex);
    cudaFree(d_image_aux);
    cudaFree(d_image_end);

    return 0;
}

NOTE:我知道我不能写“插值”或其他任何内容。写入操作将始终采用整数索引,而读取操作则需要使用三线性插值。


我相信所有必要的部分都可以演示内核写入 3D 表面(绑定到底层 3D cudaArray),然后是来自相同数据(绑定到相同底层 3D 的 3D 纹理)的另一个内核纹理(即自动插值) cudaArray)包含在体积过滤 CUDA 示例代码 http://docs.nvidia.com/cuda/cuda-samples/index.html#volumetric-filtering-with-3d-textures-and-surface-writes.

唯一的概念差异是示例代码有 2 个不同的底层 3D cudaArray(一个用于纹理,一个用于表面),但我们可以将它们组合起来,以便随后在纹理操作期间读取写入表面的数据。

这是一个完整的示例:

$ cat texsurf.cu
#include <stdio.h>
#include <helper_cuda.h>

texture<float, cudaTextureType3D, cudaReadModeElementType>  volumeTexIn;
surface<void,  3>                                    volumeTexOut;

__global__ void
surf_write(float *data,cudaExtent volumeSize)
{
    int x = blockIdx.x*blockDim.x + threadIdx.x;
    int y = blockIdx.y*blockDim.y + threadIdx.y;
    int z = blockIdx.z*blockDim.z + threadIdx.z;

    if (x >= volumeSize.width || y >= volumeSize.height || z >= volumeSize.depth)
    {
        return;
    }
    float output = data[z*(volumeSize.width*volumeSize.height)+y*(volumeSize.width)+x];
    // surface writes need byte offsets for x!
    surf3Dwrite(output,volumeTexOut,x * sizeof(float),y,z);

}

__global__ void
tex_read(float x, float y, float z){
    printf("x: %f, y: %f, z:%f, val: %f\n", x,y,z,tex3D(volumeTexIn,x,y,z));
}

void runtest(float *data, cudaExtent vol, float x, float y, float z)
{
    // create 3D array
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc<float>();
    cudaArray_t content;
    checkCudaErrors(cudaMalloc3DArray(&content, &channelDesc, vol, cudaArraySurfaceLoadStore));

    // copy data to device
    float *d_data;
    checkCudaErrors(cudaMalloc(&d_data, vol.width*vol.height*vol.depth*sizeof(float)));
    checkCudaErrors(cudaMemcpy(d_data, data, vol.width*vol.height*vol.depth*sizeof(float), cudaMemcpyHostToDevice));

    dim3 blockSize(8,8,8);
    dim3 gridSize((vol.width+7)/8,(vol.height+7)/8,(vol.depth+7)/8);
    volumeTexIn.filterMode     = cudaFilterModeLinear;
    checkCudaErrors(cudaBindSurfaceToArray(volumeTexOut,content));
    surf_write<<<gridSize, blockSize>>>(d_data, vol);
    // bind array to 3D texture
    checkCudaErrors(cudaBindTextureToArray(volumeTexIn, content));
    tex_read<<<1,1>>>(x, y, z);
    checkCudaErrors(cudaDeviceSynchronize());
    cudaFreeArray(content);
    cudaFree(d_data);
    return;
}

int main(){
   const int dim = 8;
   float *data = (float *)malloc(dim*dim*dim*sizeof(float));
   for (int z = 0; z < dim; z++)
     for (int y = 0; y < dim; y++)
       for (int x = 0; x < dim; x++)
         data[z*dim*dim+y*dim+x] = z*100+y*10+x;
   cudaExtent vol = {dim,dim,dim};
   runtest(data, vol, 1.5, 1.5, 1.5);
   runtest(data, vol, 1.6, 1.6, 1.6);
   return 0;
}


$ nvcc -I/usr/local/cuda/samples/common/inc texsurf.cu -o texsurf
$ cuda-memcheck ./texsurf
========= CUDA-MEMCHECK
x: 1.500000, y: 1.500000, z:1.500000, val: 111.000000
x: 1.600000, y: 1.600000, z:1.600000, val: 122.234375
========= ERROR SUMMARY: 0 errors
$

我不会尝试在这里提供有关线性纹理过滤的完整教程。这里还有很多其他示例问题,涵盖了索引和过滤的细节,但这似乎不是这个问题的关键。我选择了点 (1.5, 1.5, 1.5) 和 (1.6, 1.6, 1.6) 以便于验证基础数据;结果对我来说很有意义。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

3D 数组作为纹理在 CUDA 中写入和读取 的相关文章

随机推荐

  • 与 java 一起使用的最佳数学库是什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 组合两个相等链表的转轮技术

    所以 我在这里面临着一个疑问 我正在读 破解编码面试 一书 那里写着下面的文字 假设你有一个链表a1 gt a2 gt an gt b1 gt b2 bn 并且您想将其重新排列为a1 gt b1 gt a2 gt b2 gt an gt b
  • 如何删除mongodb中的深层嵌套对象

    假设我有一个代表这样的书籍的文档 id 1234567890 title Lord Of The Rings books 1234567890 id 123456789890 title The Two Towers page count
  • 如何更改 wcf 客户端中的时间戳安全标头?

    我正在尝试修改安全标头的默认过期时间 即 5 分钟到 1 分钟 服务器的安全策略之一是时间戳 请求的日期 生存时间为一分钟 任何想法 我尝试创建自定义绑定但没有成功
  • ActiveAdmin 中的格式提示问题(不需要的对象 ID 输出)

    当我使用 formattastic DSL 进行 ActiveAdmin 编辑表单时 我得到以下输出 0x00000006bd1018 gt 图片标签 gt 为什么这从 obj inspect 的结果开始以及如何删除这部分 导致此错误的代码
  • 如何正确使用范围 https://www.googleapis.com/auth/drive.file

    我尝试使用以下代码访问我的 Google 云端硬盘中的 Google 表格文件 import gspread from oauth2client service account import ServiceAccountCredential
  • 我的 UITableViewController 中的内存泄漏在哪里?

    表视图工作正常 但是当我离开视图并第二次返回时 出现内存泄漏 可能 viewDidLoad 中的某些内容不确定 我正在运行泄漏工具并收到以下通知 Leaked Object Address Size Responsible Library
  • 在PyQt中,如何将终端嵌入到窗口中?

    我有一个小脚本 旨在将 xterm 嵌入 PyQt GUI 中 在 Linux 上 它可以工作 创建一个如下所示的 GUI 然而 在 OS X 上运行相同的脚本会产生两个如下所示的窗口 有谁知道如何解决这个问题并防止 OS X 搞砸 GUI
  • 我应该将变量保留为瞬态吗?

    我一直在尝试使用 Apache Spark 来解决一些查询 例如 top k skyline 等 我做了一个包装纸 其中包含SparkConf and JavaSparkContext named SparkContext 这个类也实现了可
  • 将标准输入和标准输出重定向到文件

    我目前是一个学校的助教C语言简介班级 该课程是使用 Visual Studio 进行教学的 但是在评分时 我只使用一个简单的 Windows 批处理脚本来处理所有提交的作业 编译它们 在测试文件上运行它们 并将输出重定向到我可以打印的一系列
  • ListView获取滚动位置?

    我正在使用 MergeAdapter 来自 Mark Murphy 的优秀项目系列 您可以将它与 ListView 一起使用 我试图在刷新时重建适配器的内容 而不是 就地 刷新并调用notifyDataSetChange 我想获取列表视图的
  • 在 R data.table 中,如何将变量参数传递给表达式?

    我遇到了一个 R 小问题data table 非常感谢您的帮助 我该怎么做呢 getResult lt function dt expr gby e lt substitute expr b lt substitute gby return
  • 使用 Excel VBA 重命名文件

    这就是我需要做的 我在 Excel 工作表中有这两列 带文件名 第一列包含当前文件名 第二列包含我想要将文件重命名为的名称 我需要使用它 因为重命名没有模式 例如 下面可能是一组文件 Current Name gt Rename To Ab
  • Scala中如何从内部类引用外部对象

    考虑这段代码 这是一种类型安全单元 abstract class UnitsZone type ConcreteUnit lt AbstractUnit abstract class AbstractUnit val qty Int SOM
  • simplexml_load_file 不起作用

    我下面有这段代码 它在我的远程托管服务器上运行良好 但由于某种原因不能在我的本地 Linux 机器上运行 我也尝试使用 file get contents 来获得宁静的服务 但它也返回 false 有谁知道为什么会发生这种情况 谢谢 xml
  • 使用“devtools::install_github”和克隆 GitHub 存储库有什么区别?

    I used devtools install github 在 R 中安装存储库 并使用以下命令安装了存储库git clone在终端 这两条路线有什么区别 到目前为止 我明白我可以使用library package 在 R 中 并将加载该
  • Angular 5中如何从父组件继承子组件中的CSS样式

    我有一个父组件 其中有一个子组件 父组件有一些 css 类 子组件扩展了它们 我尝试使用 host 查看文档 但似乎无法使其正常工作 子组件 div class table row body div class table cell bod
  • 对指针数组进行排序

    我是否正确地认为 为了对指针数组进行排序 将指针视为 int 是可以的 例如 qsort ptrs n sizeof void int cmp 我想对 ptr 进行排序以确定是否存在重复项 而不管指针指向的类型是什么 因此 qsort 是执
  • 如何调用shell脚本来启动后端Java进程?

    完成 Jenkins 任务后 我使用 Jenkins 的后置条件配置部分执行 Linux shell 脚本 这个 Linux shell 脚本想要在后端启动备用服务 并且不能导致 Jenkins 暂停 我尝试使用 nohup 等 但不起作用
  • 3D 数组作为纹理在 CUDA 中写入和读取

    由于我正在编程的算法的性质 我需要用一些特定的数学写入 填充 3D 矩阵 然后从该矩阵 在单独的内核中 读取作为 3D 线性插值纹理 由于纹理是一种读取模式 我假设我可以以某种方式在绑定到纹理的全局内存中写入 并从中单独读取 而不需要双倍内