【问题标题】:CUDA texture interpolation incorrect for normalized co-ordinatesCUDA 纹理插值对于归一化坐标不正确
【发布时间】:2014-07-17 06:35:30
【问题描述】:

我正在尝试在浮点查找表上使用 CUDA 纹理插值。当使用归一化坐标时,结果不正确;当使用非归一化坐标时,它们是正确的。这是为什么呢?

可编译示例:

#include <thrust/device_vector.h>
#include <thrust/host_vector.h>

texture<float, cudaTextureType1D, cudaReadModeElementType> table_tex;

const int N_table = 6;

// y = 2*x for x in [0, 1)
float table[N_table] = {0, 0.4, 0.8, 1.2, 1.6, 2.0};

__global__ void hw_linear_interpolation(const float* inputs,
                                        float* interpolated,
                                        const unsigned int n_inputs)
{
    int tid = threadIdx.x;

    if (tid < n_inputs)
    {
        float val = inputs[tid];

#ifdef NORMALIZED
        float interp = tex1D(table_tex, val);
#else
        float interp = tex1D(table_tex, (N_table-1)*val+0.5f);
#endif
        interpolated[tid] = interp;
    }
}

int main(void)
{
    int N_inputs = 11;

    thrust::host_vector<float> h_inputs(N_inputs);
    thrust::device_vector<float> d_outputs(N_inputs);
    thrust::host_vector<float> h_outputs(N_inputs);

    // Allocate CUDA array in device memory to bind table_tex to.
    cudaChannelFormatDesc channelDesc =
                             cudaCreateChannelDesc<float>();
    cudaArray* cuArray_table;
    cudaMallocArray(&cuArray_table, &channelDesc, N_table, 0);

    // Copy to device memory some data located at address h_data
    // in host memory
    cudaMemcpyToArray(cuArray_table, 0, 0, table, N_table*sizeof(float),
                      cudaMemcpyHostToDevice);

    // Initialize input values to interpolate from the table for.
    for (int i=0; i<N_inputs; i++) {
        h_inputs[i] = i*0.1f;
    }

    thrust::device_vector<float> d_inputs = h_inputs;

    // Set up texture for linear interpolation with normalized inputs.
    table_tex.addressMode[0] = cudaAddressModeClamp;
    table_tex.filterMode = cudaFilterModeLinear;
#ifdef NORMALIZED
    table_tex.normalized = true;
#else
    table_tex.normalized = false;
#endif

    cudaBindTextureToArray(table_tex, cuArray_table);
    hw_linear_interpolation<<<1, 128>>>(
        thrust::raw_pointer_cast(d_inputs.data()),
        thrust::raw_pointer_cast(d_outputs.data()),
        N_inputs);
    cudaUnbindTexture(table_tex);
    h_outputs = d_outputs;

    std::cout << "     x     |   interp. y   |   actual y  ";
    std::cout << std::endl;
    std::cout << "-----------------------------------------";
    std::cout << std::endl;

    std::cout.setf(std::ios::fixed, std::ios::floatfield);
    for (int i=0; i<N_inputs; i++)
    {
        std::cout << "    ";
        std::cout.precision(1);
        std::cout.width(3);
        std::cout << h_inputs[i];
        std::cout << "    |";

        std::cout << "    ";
        std::cout.precision(5);
        std::cout.width(7);
        std::cout << h_outputs[i];
        std::cout << "    |";

        std::cout << "   ";
        std::cout.width(7);
        std::cout << 2*(i*0.1f);
        std::cout << std::endl;
    }

    return 0;
}

编译为nvcc -arch=sm_20 interpolation_so.cu 给出

$ ./a.out 
     x     |   interp. y   |   actual y  
-----------------------------------------
    0.0    |    0.00000    |   0.00000
    0.1    |    0.20000    |   0.20000
    0.2    |    0.40000    |   0.40000
    0.3    |    0.60000    |   0.60000
    0.4    |    0.80000    |   0.80000
    0.5    |    1.00000    |   1.00000
    0.6    |    1.20000    |   1.20000
    0.7    |    1.40000    |   1.40000
    0.8    |    1.60000    |   1.60000
    0.9    |    1.80000    |   1.80000
    1.0    |    2.00000    |   2.00000

但编译为nvcc -arch=sm_20 interpolation_so.cu -DNORMALIZED 给出

$ ./a.out
     x     |   interp. y   |   actual y  
-----------------------------------------
    0.0    |    0.00000    |   0.00000
    0.1    |    0.04063    |   0.20000
    0.2    |    0.27969    |   0.40000
    0.3    |    0.52031    |   0.60000
    0.4    |    0.75938    |   0.80000
    0.5    |    1.00000    |   1.00000
    0.6    |    1.24063    |   1.20000
    0.7    |    1.47969    |   1.40000
    0.8    |    1.72031    |   1.60000
    0.9    |    1.95938    |   1.80000
    1.0    |    2.00000    |   2.00000

编辑:基于Dithermaster's answer的部分修复

【问题讨论】:

    标签: cuda textures interpolation


    【解决方案1】:

    因为你在这里加了 0.5:tex1D(table_tex, val+0.5f); 归一化坐标从 0.0 到 1.0,因此将 0.5 偏移量添加到整个范围的一半。

    【讨论】:

    • 是的,这是发布的代码中的一个问题,但不止于此。在代码中进行这种更改并不能完全“修复”它。
    • 但它应该让你更接近。可能下一个问题是这些值“略微”关闭,因为从 0.0 到第一个像素中心的半像素间隔是恒定的,而另一端也是如此(最后一个像素的中心到 1.0)。这就是为什么在非标准化情况下添加 0.5 的原因。见eecg.toronto.edu/~moshovos/CUDA08/slides/008%20-%20Textures.ppt
    • ...尤其是第 13 张幻灯片,还有通往它的幻灯片,以便您了解它所展示的内容。
    • 谢谢。问题已更新。我确实对此感到疑惑,但将docs.nvidia.com/cuda/cuda-c-programming-guide/… 中的描述误解为也适用于标准化坐标(这显然没有意义)。但是我无法确定在标准化情况下需要添加什么,如果实际上可以实现我想要的......?
    • 试试这个:float interp = tex1D(table_tex, (((n_table-1)/(float)n_table))*(val+0.1f));
    猜你喜欢
    • 1970-01-01
    • 2012-05-04
    • 2020-07-12
    • 1970-01-01
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多