Prefer Your Language

Search This Blog

CUDA Array in CUDA | How to use CUDA Array in CUDA | CUDA ARRAY


CUDA Array in CUDA | How to use CUDA Array in CUDA

In the previous articles [this, this] we have discussed texturememory and cudaChannelFormatDesc () in CUDA. In this article we learn how to use CUDA Array in CUDA programming, which will be very useful when you start using Texture memory and Surface memory (will be discusses in future article).

Before start discussion please learn how to use cudaChannelFormatDesc ()  in CUDA, which also introduce CUDA Array.
If you walked from use cudaChannelFormatDesc ()   in CUDA than read future otherwise go through given link.

Let’s start our discussion over CUDA Array

CUDA arrays are similar like an array in CUDA but specially they are memory areas dedicate to textures. They are read-only for the GPU (and are only accessible through texture fetches), and can be written to by the CPU using cudaMemcpyToArray ().

In essence, CUDA arrays are opaque memory layouts optimized for texture fetching. They are one-dimensional, two-dimensional, or three-dimensional and composed of elements, each of which has 1, 2 or 4 components that may be signed or unsigned 8-, 16- or 32-bit integers, 16-bit floats, or 32-bit floats. CUDA arrays are only readable by kernels through texture fetching and may only be bound to texture references with the same number of packed components.

Allocating a CUDA array requires the specification of a channel format description matching the one used by the texture that needs to be mapped on it.

Note:

Devices with capability 2.0 or higher can write to CUDA arrays using surfaces, a read-write feature similar to textures. Table F-2   listed about the CUDA Array in terms of device compute capability.

Please be familiar with the following functions;



Allocation of CUDA Array in CUDA

For allocation of CUDA Array use cudaMallocArray ( )

texture<> someTex;

cudaArray *dArray;

cudaMallocArray( &dArray, &someTex.channelDesc, width, height);


Using CUDA Array in CUDA

To use CUDA Array in CUDA we use cudaMemcpyToArray () and cudaBindTextureToArray


cudaMemcpyToArray ( dArray, wOffset, hOffset, source, size, cudaMemcpyHostToDevice);

cudaBindTextureToArray ( someTex, dArray );

Copies size bytes from the memory area pointed by Source to the CUDA Array dArray starting at upper left corner (wOffset, hOffset)


Releasing CUDA Array memory in CUDA
For releasing the memory pointer by CUDA Array we use cudaFreeArray ()

cudaFreeArray ( dArray );



Complete Example of CUDA Array and cudaChannelFormatDesc () 


#include "HEADER.h"
#include "ERROR.h"

// 2D float texture
texture<float, cudaTextureType2D, cudaReadModeElementType> texRef;


// Simple transformation kernel
__global__ void transformKernel(float* output, int width, int height, float theta)
{
      // Calculate normalized texture coordinates
      unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
     
      unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
     
      float u = x / (float)width;
     
      float v = y / (float)height;
     
      // Transform coordinates
      u -= 0.5f;
     
      v -= 0.5f; 
     
      float tu = u * cosf(theta) - v * sinf(theta) + 0.5f ;
     
      float tv = v * cosf(theta) + u * sinf(theta) + 0.5f ;
     
      // Read from texture and write to global memory
      output[y * width + x] = tex2D(texRef, tu, tv);
}

// Host code
int main()
{
      int width = 3 , height = 3 ;

      float h_data[3][3] ;
      for ( int i =0 ; i<3 ; i++ )
                  for ( int j = 0 ; j<3; j++ )
                              h_data [i][j] = i*j ;

      int size = width*height*sizeof(float) ;
     
      // Allocate CUDA array in device memory
      cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0,
                                             cudaChannelFormatKindFloat );
     
      cudaArray* cuArray;
     
      cudaMallocArray(&cuArray, &channelDesc, width, height);
     
      // Copy to device memory some data located at address h_data
      // in host memory
      cudaMemcpyToArray(cuArray, 0, 0, h_data, size, cudaMemcpyHostToDevice);
     
      // Set texture parameters
      texRef.addressMode[0] = cudaAddressModeWrap;
      texRef.addressMode[1] = cudaAddressModeWrap;
      texRef.filterMode = cudaFilterModeLinear;
      texRef.normalized = true;
     
      // Bind the array to the texture reference
      cudaBindTextureToArray(texRef, cuArray, channelDesc);
     
      // Allocate result of transformation in device memory
      float* output;
     
      cudaMalloc(&output, size );
     
      // Invoke kernel
      dim3 dimBlock(16, 16);
      dim3 dimGrid( (width + dimBlock.x - 1) / dimBlock.x,
                       (height + dimBlock.y - 1) / dimBlock.y );
     
      transformKernel<<<dimGrid, dimBlock>>>(output, width, height, 90 );
     
      printf ("\n Original array \n");
      for ( int i =0 ; i<3 ; i++ )
      {
            for ( int j = 0 ; j<3; j++ )
                              printf ("%f ", h_data [i][j] );
           
            printf ("\n");
      }

      CUDA_CALL ( cudaMemcpy (h_data , output, size, cudaMemcpyDeviceToHost ) );

      printf ("\n After operation \n ");
      for ( int i =0 ; i<3 ; i++ )
      {
            for ( int j = 0 ; j<3; j++ )
                              printf ("%f ", h_data [i][j] );
           
            printf ("\n");
      }

      system ("pause");
      // Free device memory
      cudaFreeArray(cuArray);
      cudaFree(output);
      return 0;
}


Sample output
Fig.


I hope you must like this article and have learned CUDA Array and how to use CUDA Array in CUDA.

Got Questions?
Feel free to ask me any question because I'd be happy to walk you through step by step! 
Want to Contact us? Click here



cudaChannelFormatDesc () in CUDA | How to use cudaChannelFormatDesc in CUDA | CUDA Channels


cudaChannelFormatDesc () in CUDA | How to use cudaChannelFormatDesc in CUDA

In this article we learn how to use cudaChannelFormatDesc () in-build function in CUDA. Background of this function is very interesting [ (I can’t open that secret here ;) ].
So, if you are planning to use CUDA Array’s, then you have to be understand what is 
cudaChannelFormatDesc() function in CUDA.

So, Today I going to teach you, how to use
cudaChannelFormatDesc() function in CUDA, related to CUDA Array’s. For sake of advice, I advise you please go through this article for sake of understanding.
Let’s start our discussion;

cudaChannelFormatDesc ( )

channelDesc describes the format of the value that is returned when fetching the texture;
The cudaChannelFormatDesc describes the format of a texture element.


struct cudaChannelFormatDesc {
                                                                   int x, y, z, w;
                                                                   enum cudaChannelFormatKind  f;
                                                         }


Where,
 x, y, z, w :                      are set to the number of bits for each component, and
 f:                                       is one of the
cudaChannelFormatKindSigned (if these components are of signed integer type)
cudaChannelFormatKindUnsigned (if they are of unsigned integer type)
cudaChannelFormatKindFloat (if they are of floating point type )
Example
For float texels we could create a channel with;
              cudaCreateChannelDesc( 32, 0, 0, 0, cudaChannelFormatKindFloat );
While for short4 texels this would be
             cudaCreateChannelDesc( 16, 16, 16, 16, cudaChannelFormatKindSigned );





Before a kernel can use a texture reference to read from texture memory, the texture reference must be bound to a texture using cudaBindTexture() or cudaBindTexture2D() for linear memory, or cudaBindTextureToArray() for CUDA arrays. cudaUnbindTexture() is used to unbind a texture reference. It is recommended to allocate two-dimensional textures in linear memory using cudaMallocPitch() and use the pitch returned by cudaMallocPitch() as input parameter to cudaBindTexture2D().

The following code samples bind a texture reference to aCUDA Array’s cuArray:

Using the low-level API:

texture <float, cudaTextureType2D, cudaReadModeElementType> texRef;

textureReference* texRefPtr;

cudaGetTextureReference(&texRefPtr, "texRef");

cudaChannelFormatDesc channelDesc;

cudaGetChannelDesc(&channelDesc, cuArray);

cudaBindTextureToArray(texRef, cuArray, &channelDesc);

Using the high-level API:


texture<float, cudaTextureType2D, cudaReadModeElementType> texRef;

cudaBindTextureToArray(texRef, cuArray);

The format specified when binding a texture to a texture reference must match the parameters specified when declaring the texture reference; otherwise, the results of texture fetches are undefined.

Complete Example of CUDA Array and cudaChannelFormatDesc () 


#include "HEADER.h"
#include "ERROR.h"

// 2D float texture
texture<float, cudaTextureType2D, cudaReadModeElementType> texRef;


// Simple transformation kernel
__global__ void transformKernel(float* output, int width, int height, float theta)
{
      // Calculate normalized texture coordinates
      unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
     
      unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
     
      float u = x / (float)width;
     
      float v = y / (float)height;
     
      // Transform coordinates
      u -= 0.5f;
     
      v -= 0.5f; 
     
      float tu = u * cosf(theta) - v * sinf(theta) + 0.5f ;
     
      float tv = v * cosf(theta) + u * sinf(theta) + 0.5f ;
     
      // Read from texture and write to global memory
      output[y * width + x] = tex2D(texRef, tu, tv);
}

// Host code
int main()
{
      int width = 3 , height = 3 ;

      float h_data[3][3] ;
      for ( int i =0 ; i<3 ; i++ )
                  for ( int j = 0 ; j<3; j++ )
                              h_data [i][j] = i*j ;

      int size = width*height*sizeof(float) ;
     
      // Allocate CUDA array in device memory
      cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 0, 0, 0,
                                             cudaChannelFormatKindFloat );
     
      cudaArray* cuArray;
     
      cudaMallocArray(&cuArray, &channelDesc, width, height);
     
      // Copy to device memory some data located at address h_data
      // in host memory
      cudaMemcpyToArray(cuArray, 0, 0, h_data, size, cudaMemcpyHostToDevice);
     
      // Set texture parameters
      texRef.addressMode[0] = cudaAddressModeWrap;
      texRef.addressMode[1] = cudaAddressModeWrap;
      texRef.filterMode = cudaFilterModeLinear;
      texRef.normalized = true;
     
      // Bind the array to the texture reference
      cudaBindTextureToArray(texRef, cuArray, channelDesc);
     
      // Allocate result of transformation in device memory
      float* output;
     
      cudaMalloc(&output, size );
     
      // Invoke kernel
      dim3 dimBlock(16, 16);
      dim3 dimGrid( (width + dimBlock.x - 1) / dimBlock.x,
                       (height + dimBlock.y - 1) / dimBlock.y );
     
      transformKernel<<<dimGrid, dimBlock>>>(output, width, height, 90 );
     
      printf ("\n Original array \n");
      for ( int i =0 ; i<3 ; i++ )
      {
            for ( int j = 0 ; j<3; j++ )
                              printf ("%f ", h_data [i][j] );
           
            printf ("\n");
      }

      CUDA_CALL ( cudaMemcpy (h_data , output, size, cudaMemcpyDeviceToHost ) );

      printf ("\n After operation \n ");
      for ( int i =0 ; i<3 ; i++ )
      {
            for ( int j = 0 ; j<3; j++ )
                              printf ("%f ", h_data [i][j] );
           
            printf ("\n");
      }

      system ("pause");
      // Free device memory
      cudaFreeArray(cuArray);
      cudaFree(output);
      return 0;
}


Sample output

Fig.


I hope you must like this article and have learned cudaChannelFormatDesc ( ) and how to use cudaChannelFormatDesc ( ) in CUDA.

If you want to know about Texture memory; click here

Got Questions?
Feel free to ask me any question because I'd be happy to walk you through step by step! 
Want to Contact us? Click here


Become a contributor to this blog. Click on contact us tab
Blogger Template by Clairvo