Share via


view_as function in C++ AMP

With C++ AMP, you can use array or array_view to work with data in a multi-dimensional way, which often reflects your algorithm more naturally. Sometimes, however, you might need to reshape the data to adapt data to an existing interface or to use data generated by a factory library in your algorithms. For example, you might want to take advantage of a library that only provides APIs for linear containers although your data sits in N-dimensional arrays or array_views. In this blog post, I will introduce you to the view_as function available on array and array_view, which is useful for these scenarios.

About the API

Following is the view_as signature.

 template <typename T, int N>
class array
{
    template <int K>
    array_view<T,K> view_as(extent<K> viewExtent) restrict(cpu,amp)
    template <int K>
    array_view<const T,K> view_as(extent<K> viewExtent) const restrict(cpu,amp) 
};

template <typename T>
class array_view<T,1>
{
template <int K>
    array_view<T,K> view_as(extent<K> viewExtent) const restrict(cpu,amp);
};

template <typename T>
class array_view<const T,1>
{
    template <int K> 
    array_view<const T,K> view_as(extent<K> viewExtent) const restrict(cpu,amp);
};

Note the following facts for the view_as function:

  • It is available for arrays of any rank, but only available for array_views of rank 1. This is because contiguous memory is necessary for well-defined and efficient data reshaping and in C++ AMP we only guarantee memory contiguity for arrays and the least-significant-dimension of array_views.
  • The array_view object returned preserves the constness of the original array or array_view objects, as you’d expect.
  • Its return type is array_view, not array. This is because arrays are direct data containers, i.e., different arrays always associate with different memory, but what we want with view_as is a different view over the original data instead of a new data copy. Since no data-copy is involved, the view_as operation is cheap.
  • The total element number of viewExtent should not be greater than the total element number of the original array or array_view object. Otherwise, a runtime_exception will be thrown with message “Invalid view creation”.

Example of view_as

Now let’s see a simple example that illustrates the usage of view_as to adapt data to an existing interface. For example, we have a library that provides the following API that fills the given array_view of rank 1 with random numbers:

 void random_fill(array_view<float,1> in);

Now, if you have a 2-dimentional array with float elements, you could still use this API to do initialization via view_as like:

 void fill(array<float,2> a) 
{
    random_fill(a.view_as<1>(extent<1>(a.extent.size())));
}

Another real world example would be to adapt 2D image data to a histogram calculator, which is usually a 1D algorithm.

This concludes my introduction to view_as. My next post will describe a somewhat related API: reinterpret_as. As always, you are welcome to ask questions and provide feedback below or on our MSDN forum.

Comments

  • Anonymous
    October 11, 2012
    Lingli, What is the best way to access the data after a library call? It appears that the only way I could do it was by reading an element from a temporary view which was passed to the API. I imagine, expectation for this kind of architecture would be that the original data will be discarded, hence your mentioning of histogram example. Thank you, Alan void AmpExamples::RandomFill(array_view<float, 1> & view) { parallel_for_each(view.extent, [=](index<1> idx) restrict(amp) { view[idx] = 1.f; }); } void AmpExamples::ViewAs() { cout << "nview_as example.n"; const unsigned int width = 1920; const unsigned int height = 1080; concurrency::extent<2> ext(width, height); array<float, 2> image(ext); time_point<system_clock> start = system_clock::now(); // Fill array_view<float, 1> tmpView = image.view_as<1>(concurrency::extent<1>(image.extent.size())); RandomFill(tmpView); //tmpView.synchronize(); float x = tmpView[0]; time_point<system_clock> stop = system_clock::now(); long long us = duration_cast<microseconds>(stop - start).count(); cout << "   Executed in: " << us << "us" << endl; //cout << "   tmpView(0,0) = " << tmpView(0) << endl; array_view<float, 2> view(image); index<2> idx(10, 15); cout << "   image(10,15)   = " << view[idx] << endl; }

  • Anonymous
    October 12, 2012
    The comment has been removed