Различные режимы адресации текстур CUDA

Я использую текстуру CUDA в режиме пограничной адресации (cudaAddressModeBorder). Я читаю координаты текстуры, используя tex2D<float>(). Когда координаты текстуры выходят за пределы текстуры, tex2D<float>() возвращает 0.

Как я могу изменить это возвращаемое значение границы с 0 на что-то другое? Я мог бы проверить координату текстуры вручную и установить значение границы самостоятельно. Мне было интересно, есть ли CUDA API, где я могу установить такое значение границы.


person Ashwin Nanjappa    schedule 26.09.2013    source источник
comment
Аппаратное обеспечение поддерживает настройку цвета, но это не отображается в CUDA. Возможно потому, что ни один из классических режимов адресации не требует дополнительных параметров. NVIDIA зарегистрировала его как запрошенную функцию. В качестве обходного пути, возможно, вы можете нарисовать границу в 1 пиксель нужного вам цвета вокруг текстуры и использовать режим адресации зажима вместе с измененными координатами.   -  person Roger Dahl    schedule 26.09.2013
comment
@RogerDahl Я догадался, что это просто проблема API CUDA. Потому что цвет границы можно установить в DirectX для того же оборудования. В любом случае, я не могу изменить текстуру в данном конкретном случае, поэтому для меня нет решения :-)   -  person Ashwin Nanjappa    schedule 27.09.2013


Ответы (2)


Как упомянул sgarizvi, CUDA поддерживает только четыре ненастраиваемых режима адресации, а именно: clamp, border, wrap и mirror< /strong>, которые описаны в Разделе 3.2.11.1. руководства по программированию CUDA.

Первые два работают как в ненормализованных, так и в нормализованных координатах, а два последних — только в нормализованных координатах.

Чтобы описать первые два, давайте рассмотрим случай ненормированных координат и рассмотрим для простоты одномерные сигналы. В этом случае входная последовательность c[k] с k=0,...,M-1.

cudaAddressModeClamp

Сигнал c[k] продолжается за пределами k=0,...,M-1, так что c[k] = c[0] для k < 0 и c[k] = c[M-1] для k >= M.

cudaAddressModeBorder

Сигнал c[k] продолжается за пределами k=0,...,M-1, так что c[k] = 0 для k < 0и для k >= M.

Теперь, чтобы описать последние два режима адресации, мы вынуждены рассматривать нормализованные координаты, так что предполагается, что отсчеты входного сигнала 1D равны c[k / M] с k=0,...,M-1.

cudaAddressModeWrap

Сигнал c[k / M] продолжается за пределами k=0,...,M-1, так что он является периодическим с периодом, равным M. Другими словами, c[(k + p * M) / M] = c[k / M] для любого (положительного, отрицательного или исчезающего) целого числа p.

cudaAddressModeMirror

Сигнал c[k / M] продолжается за пределами k=0,...,M-1, так что он является периодическим с периодом, равным 2 * M - 2. Другими словами, c[l / M] = c[k / M] для любых l и k таких, что (l + k)mod(2 * M - 2) = 0.

Следующий код иллюстрирует все четыре доступных режима адресации.

#include <stdio.h>

texture<float, 1, cudaReadModeElementType> texture_clamp;
texture<float, 1, cudaReadModeElementType> texture_border;
texture<float, 1, cudaReadModeElementType> texture_wrap;
texture<float, 1, cudaReadModeElementType> texture_mirror;

/********************/
/* CUDA ERROR CHECK */
/********************/
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
    if (code != cudaSuccess) 
    {
        fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
        if (abort) exit(code);
    }
}

/******************************/
/* CUDA ADDRESS MODE CLAMPING */
/******************************/
__global__ void Test_texture_clamping(const int M) {

    printf("Texture clamping - i = %i; value = %f\n", -threadIdx.x, tex1D(texture_clamp, -(float)threadIdx.x));
    printf("Texture clamping - i = %i; value = %f\n", M + threadIdx.x, tex1D(texture_clamp, (float)(M + threadIdx.x)));

}

/****************************/
/* CUDA ADDRESS MODE BORDER */
/****************************/
__global__ void Test_texture_border(const int M) {

    printf("Texture border - i = %i; value = %f\n", -threadIdx.x, tex1D(texture_border, -(float)threadIdx.x));
    printf("Texture border - i = %i; value = %f\n", M + threadIdx.x, tex1D(texture_border, (float)(M + threadIdx.x)));

}

/**************************/
/* CUDA ADDRESS MODE WRAP */
/**************************/
__global__ void Test_texture_wrap(const int M) {

    printf("Texture wrap - i = %i; value = %f\n", -threadIdx.x, tex1D(texture_wrap, -(float)threadIdx.x/(float)M));
    printf("Texture wrap - i = %i; value = %f\n", M + threadIdx.x, tex1D(texture_wrap, (float)(M + threadIdx.x)/(float)M));

}

/****************************/
/* CUDA ADDRESS MODE MIRROR */
/****************************/
__global__ void Test_texture_mirror(const int M) {

    printf("Texture mirror - i = %i; value = %f\n", -threadIdx.x, tex1D(texture_mirror, -(float)threadIdx.x/(float)M));
    printf("Texture mirror - i = %i; value = %f\n", M + threadIdx.x, tex1D(texture_mirror, (float)(M + threadIdx.x)/(float)M));

}

/********/
/* MAIN */
/********/
void main(){

    const int M = 4;

    // --- Host side memory allocation and initialization
    float *h_data = (float*)malloc(M * sizeof(float));

    for (int i=0; i<M; i++) h_data[i] = (float)i;

    // --- Texture clamping
    cudaArray* d_data_clamping = NULL; gpuErrchk(cudaMallocArray(&d_data_clamping, &texture_clamp.channelDesc, M, 1)); 
    gpuErrchk(cudaMemcpyToArray(d_data_clamping, 0, 0, h_data, M * sizeof(float), cudaMemcpyHostToDevice)); 
    cudaBindTextureToArray(texture_clamp, d_data_clamping); 
    texture_clamp.normalized = false; 
    texture_clamp.addressMode[0] = cudaAddressModeClamp;

    dim3 dimBlock(2 * M, 1); dim3 dimGrid(1, 1);
    Test_texture_clamping<<<dimGrid,dimBlock>>>(M);

    printf("\n\n\n");

    // --- Texture border
    cudaArray* d_data_border = NULL; gpuErrchk(cudaMallocArray(&d_data_border, &texture_border.channelDesc, M, 1)); 
    gpuErrchk(cudaMemcpyToArray(d_data_border, 0, 0, h_data, M * sizeof(float), cudaMemcpyHostToDevice)); 
    cudaBindTextureToArray(texture_border, d_data_border); 
    texture_border.normalized = false; 
    texture_border.addressMode[0] = cudaAddressModeBorder;

    Test_texture_border<<<dimGrid,dimBlock>>>(M);

    printf("\n\n\n");

    // --- Texture wrap
    cudaArray* d_data_wrap = NULL; gpuErrchk(cudaMallocArray(&d_data_wrap, &texture_wrap.channelDesc, M, 1)); 
    gpuErrchk(cudaMemcpyToArray(d_data_wrap, 0, 0, h_data, M * sizeof(float), cudaMemcpyHostToDevice)); 
    cudaBindTextureToArray(texture_wrap, d_data_wrap); 
    texture_wrap.normalized = true; 
    texture_wrap.addressMode[0] = cudaAddressModeWrap;

    Test_texture_wrap<<<dimGrid,dimBlock>>>(M);

    printf("\n\n\n");

    // --- Texture mirror
    cudaArray* d_data_mirror = NULL; gpuErrchk(cudaMallocArray(&d_data_mirror, &texture_mirror.channelDesc, M, 1)); 
    gpuErrchk(cudaMemcpyToArray(d_data_mirror, 0, 0, h_data, M * sizeof(float), cudaMemcpyHostToDevice)); 
    cudaBindTextureToArray(texture_mirror, d_data_mirror); 
    texture_mirror.normalized = true ; 
    texture_mirror.addressMode[0] = cudaAddressModeMirror;

    Test_texture_mirror<<<dimGrid,dimBlock>>>(M);

    printf("\n\n\n");
}

Это выходы

index                  -7  -6  -5  -4  -3  -2  -1  0  1  2  3  4  5  6  7  8  9  10  11
clamp                   0   0   0   0   0   0   0  0  1  2  3  3  3  3  3  3  3   3   3
border                  0   0   0   0   0   0   0  0  1  2  3  0  0  0  0  0  0   0   0
wrap                    1   2   3   0   1   2   3  0  1  2  3  0  1  2  3  0  1   2   3
mirror                  1   2   3   3   2   1   0  0  1  2  3  3  2  1  0  0  1   2   3
person Vitality    schedule 10.12.2014
comment
Я бы хотел, чтобы это была документация cuda, а не cudaTextureDesc::addressMode specifies the addressing mode!! . Спасибо Нвидиа.... - person Ander Biguri; 20.08.2015
comment
Спасибо, очень полезно. - person Michael; 13.12.2016

На данный момент (CUDA 5.5) поведение выборки текстуры CUDA не настраивается. Только 1 из 4 автоматических встроенных режимов (например, Граница, Зажим, Обтекание и Зеркало) может быть используется для выборки текстур вне диапазона.

person sgarizvi    schedule 26.09.2013