CUDA立方体地图纹理

时间:2014-03-27 07:36:28

标签: opengl cuda gpu

如何在CUDA中处理OpenGL立方体贴图纹理?

当想要在CUDA内核中使用OpenGL纹理时,要做的一件事就是从已注册的图像和映射资源中检索CUDA数组,在本例中是一个纹理。在驱动程序API中,它由cuGraphicsSubResourceGetMappedArray调用完成,在2D纹理的情况下,这不是问题。但在谈到上述立方体贴图时,此函数的第三个参数需要面部枚举(如CU_CUBEMAP_FACE_POSITIVE_X)。因此出现了一些问题 - 当一个人通过这样的枚举时,返回的纹理数组将仅包含该特定面的数据,对吧?然后如何使用立方体纹理作为一个整体,执行立方体映射,同样:

color = texCube(cubeMap, x, y, z);

或者在CUDA内核中不可能这样做,需要在用户代码中使用2D纹理和适当的计算和采样吗?

1 个答案:

答案 0 :(得分:2)

好的 - 我自己设法解决了这个问题,虽然解决方案并不像使用其他CUDA功能那么简单。

要将CUDA纹理参考与任何纹理绑定,无论是从OpenGL还是D3D获取,都必须提供映射到资源的CUDA数组,使用cuGraphicsSubResourceGetMappedArray来检索它。正如我在问题中提到的,在一维或二维纹理的情况下很简单。但是对于其他可用类型,它更复杂。

我们需要一个引用绑定的CUDA数组。立方体贴图纹理也是如此。但在这种情况下,阵列必须是3D阵列。问题是CUDA驱动程序API仅提供上述功能以从这样的纹理资源中检索单个图层,并将其映射到单个二维数组。为了得到我们想要的东西,我们必须使自己成为包含所有图层的3D数组(或者在立方体贴图的情况下使用面)。

首先,我们必须使用上面的函数为每个图层/面部获取数组。下一步是通过调用cuArray3DCreate创建3D数组,并提供适当的参数集(大小/层数,细节级别,数据格式,每个纹素的通道数和一些标志)。然后我们必须复制图层'通过对cuMemcpy3D的一系列调用,将数组传递给3D,每个图层/面阵列都有一个。

最后,我们使用cuTexRefSetArray设置目标CUDA纹理参考,并使用我们创建并复制到的3D数组。在设备代码内部,我们使用适当的纹理类型和模式(float4和立方体贴图)创建一个引用,并使用texCubemap对其进行采样。

下面我放了一个函数的片段,它完成了所有这些,在CIRT Repository(cirt_server.c文件,函数cirtTexImage3D)中全长可用。

//...
if (result)
{
    // Create a 3D array...
    CUDA_ARRAY3D_DESCRIPTOR layeredTextureDescr;
    layeredTextureDescr.Width = w;
    layeredTextureDescr.Height = h;
    layeredTextureDescr.Depth = d;
    layeredTextureDescr.Format = map_type_to_format(type);
    layeredTextureDescr.NumChannels = format == CIRT_RGB ? CIRT_RGBA : format;
    layeredTextureDescr.Flags = map_target_to_flags(target);

    if (result) result = LogCUDADriverCall(cuArray3DCreate(&hTexRefArray, &layeredTextureDescr),
        FUN_NAME(": cuArray3DCreate_tex3D"), __FILE_LINE__);

    // Copy the acquired layer/face arrays into the collective 3D one...
    CUDA_MEMCPY3D layerCopyDescr;
    layerCopyDescr.srcMemoryType = CU_MEMORYTYPE_ARRAY;
    layerCopyDescr.srcXInBytes = 0;
    layerCopyDescr.srcZ = 0;
    layerCopyDescr.srcY = 0;
    layerCopyDescr.srcLOD = 0;

    layerCopyDescr.dstMemoryType = CU_MEMORYTYPE_ARRAY;
    layerCopyDescr.dstLOD = 0;

    layerCopyDescr.WidthInBytes = layeredTextureDescr.NumChannels * w;
    layerCopyDescr.Height = h;
    layerCopyDescr.Depth = target == CIRT_TEXTURE_CUBE_MAP ? 1 : d;
    layerCopyDescr.dstArray = hTexRefArray;

    for (i = 0; i < num_layers; ++i)
    {
        layer = ((num_layers == 6) ? CU_CUBEMAP_FACE_POSITIVE_X + i : i);
        layerCopyDescr.dstXInBytes = 0;
        layerCopyDescr.dstY = 0;
        layerCopyDescr.dstZ = i;
        layerCopyDescr.srcArray = hLayres[i];

        if (result) result = LogCUDADriverCall(cuMemcpy3D(&layerCopyDescr), 
            FUN_NAME(": cuMemcpy3D_tex3D"), __FILE_LINE__);
    }

    // Finally bind the 3D array with texture reference...
    if (result) LogCUDADriverCall(cuTexRefSetArray(hTexRef, hTexRefArray, CU_TRSA_OVERRIDE_FORMAT),
        FUN_NAME(": cuTexRefSetArray_tex3D"), __FILE_LINE__);

    if (hLayres)
        free(hLayres);

    if (result)
        current->m_oTextureManager.m_cuTextureRes[current->m_oTextureManager.m_nTexCount++] = hTexResource;
}
//...

我现在只使用立方体贴图检查它,但它也应该可以正常使用3D纹理。