As we all know, Global memory does not have a cache, access is very slow, Shared memory access is very fast, but the capacity is very small, for larger arrays, it is often a good choice to bind to texture memory. Texture memory can be cache, and the capacity is very large.
In the current CUDA version, 3D of linear memory cannot be directly bound to texture memory, one-dimensional can, therefore, it is necessary to first put the data into a 3D cuda array, and then bind the Cuda array to the texture memory, When accessing an array element, an element with coordinates (x, y, z) can be returned by taking the texture's function tex3d (tex,x,y,z).
1. Create a Cuda 3D array
In the previous Cuda version, Extent.width and height,depth, the count unit is bytes, so in the old version must use Array_width*sizeof (float), the latest 3.1 unexpectedly quietly modified. Cuda documents have always been wrong, the document is documented in Width,height,depth are in bytes, the actual value of the use of the number of elements can be assigned. If you do not assign a value directly, you can also call the function make_cudaextent (extent,width,height,depth), similar in principle.
1 cudaarray *d_u; 2 cudachannelformatdesc channeldesc = Cudacreatechanneldesc<float > (); 3 cudaextent extent; 4 extent.width=array_width; 5 extent.height=array_height; 6 extent.depth=array_depth; 7 Cudamalloc3darray (&d_u,&channeldesc,extent);
< Span class= "Apple-converted-space" >2. Copying data to 3D array
First explain the pitched pointer tool principle, if access to the array element U[x][y][z], through pitched pointer access is u_p[x+y*pitch+ z*pitch*height]. Obviously, this is pitch=width, so when creating pitched pointer we need to pass the width and height as arguments to the function make_cudapitchedptr (). In particular, it is important to note that the array that pitched pointer points to is stored differently than the traditional C-language array, and the C-language access element U[x][y][z] is through u[x*height*depth+y*depth+z]. So in order to read the required elements correctly, I recommend that you set up pitched pointer:
copyparams.srcptr = Make_ Cudapitchedptr (void*) u, array_depth*sizeof (float), array_depth, array_height);
at this time equivalent to the array u[x][y][z] is transpose, the corresponding element in the CUDA3D array is U[z][y][x],cuda document and the guide does not mention this difference, this problem was also troubled me for a long time, struggled to figure out, I hope the future SDK Sample can cover this point of attention.
1 cudamemcpy3dparms copyparams = {0 }; 2 copyparams.srcptr = Make_cudapitchedptr (( void *) u, array_width*sizeof (float 3 copyparams.dstarray = D_u; 4 copyparams.extent = extent; 5 copyparams.kind = Cudamemcpyhosttodevice; 6 Cudamemcpy3d (©params);
< Span class= "Apple-converted-space" >3. Bind 3D array to texture memory
normalized sets whether the texture coordinates are normalized. If the normalized is a non-0 value, it is addressed using a normalized to [0,1] coordinate, otherwise the coordinates of the dimension width, height, depth are used [0,width-1], [0,height-1], [0,depth-1] Addressing. For example, a texture with a size of 64x32 can be addressed by the X dimension range for coordinates of the [0,63],y dimension range [0,31]. If the 64x32 texture is addressed in a normalized manner, the coordinates on the x and y dimensions are [0.0,1.0]. This ensures that the coordinates of the texture are independent of the size of the texture. The
FilterMode is used to set the filtering mode of the texture, that is, how the returned texture values are computed from coordinates. The filtering mode can be Cudafiltermodepoint or cudafiltermodelinear. When the filter mode is Cudafiltermodepoint, the return value is the value of the cell closest to the coordinate. The Cudafiltermodelinear mode can only be used for textures with a return value of floating point, when this mode is picked up, the cells around the texture coordinates will pick up and then interpolated based on the distance between the coordinates and those cells. Linear filtering can be used for one-dimensional textures, and bilinear filtering can be used for two-dimensional textures. The return value will be the value of two cells closest to the texture coordinates (for one-dimensional textures), four cells (for two-dimensional textures), or eight cells (three-dimensional textures).
1texture<float,3,cudareadmodeelementtype>Tex_u;2Tex_u.filtermode =Cudafiltermodepoint;3tex_u.normalized =false;4Tex_u.channeldesc =Channeldesc;5 if(Cudabindtexturetoarray (Tex_u, D_u, channeldesc)! = (unsignedint) {cuda_success) {6printf"[ERROR] Could not bind texture u\n");7 return;8}
When Normolized is true, Addressmode specifies the addressing mode, that is, how to handle out-of-bounds texture coordinates; Addressmode is an array of size 3 whose first, second, and third elements each specify the addressing mode for the first, second, and third texture coordinates; The addressing mode can be equal to Cudaaddressmodeclamp, at which point the cross-border texture coordinates will be clamped to the valid range, or equal to Cudaaddressmodewrap, at which point the cross-border texture coordinates will be rounded to the valid range; Cudaaddressmodewrap only supports normalized texture coordinates.
1//Set Texture Parameters2tex.normalized =true;//access with normalized texture coordinates3Tex.filtermode = Cudafiltermodelinear;//linear interpolation4tex.addressmode[0] = Cudaaddressmodeclamp;//Clamp Texture Coordinates5tex.addressmode[1] =Cudaaddressmodeclamp;6 //bind array to 3D texture7Cutilsafecall (Cudabindtexturetoarray (Tex, D_volumearray, Channeldesc));
Binding and application of three-dimensional texture