Overview of the texture view design in C++ AMP


In order to enhance C++ AMP texture support with more features such as sampling and mipmap levels, we redesigned the C++ AMP texture view APIs in Visual Studio 2013. In this blog post, I will give you an overview of the changes we made in the design of texture views compared to Visual Studio 2012 and the rationale behind our design. Hopefully it will help to enable you to pick the appropriate texture types for your needs.

Texture APIs in Visual Studio 2012

Due to the current hardware limitation, reading and writing the same texture resource in the same kernel is only supported for very limited cases: 1-component texture type with 32-bit non-norm formats. For all other cases, either read access or write access, but not both, can be performed on the same texture within the same kernel.

In C++ AMP of Visual Studio 2012, the main texture usages we focused on, were to take advantage of texture’s hardware caches optimized for spatial locality and to support sub-word packing. We wanted to enable C++ AMP users to use the texture type just like the array type, which has the ability to be read from and written to within the same kernel. Therefore, we decided to let the texture<T,N> type serve the 1 component read/write scenario, and other read-only usages and introduced a new type writeonly_texture_view<T,N> to handle write-only usages.

The following table summarizes the texture API design of C++ AMP in Visual Studio 2012:

type

#Components

Lambda capture

Read

Write

texture<T, N>

1

ref

Yes

Yes

 

1

const ref

Yes

No

 

2, 4

ref, const ref

Yes

No

writeonly_texture_view<T, N>

1, 2, 4

value

No

Yes

 

Texture APIs in Visual Studio 2013

In Visual Studio 2013, we wanted to expose more hardware accelerated operations available for textures, such as sampling and mipmap level support. However, we encountered some design issues when trying to enhance the existing texture APIs with these new functionalities:

  • Texture sampling and reading a range of mipmap levels are only supported on texture sources that are guaranteed to be read-only. However, with the existing texture APIs, we cannot determine at the compile time if a one component texture object is read-only or not. Note that a const reference to a texture object cannot guarantee that it’s a read-only texture resource since it’s possible to capture a non-const reference to a texture object and then convert it to a const reference which is very common in C++ due to const reference function parameters.
  • The underlying platform supports binding a sub-range of mipmap levels of a texture for read, which is more efficient than binding the whole texture object. Neither the texture type nor the writeonly_texture_view type could represent such a read-only sub-range concept.
  • In order to write into a texture with multiple mipmap levels, a writable texture resource must be bound to the specific mipmap level that is being written to. The texture type represents the whole texture object including all mipmap levels, thus, is not suitable to represent a specific mipmap level. The writeonly_texture_view type, on the other hand, cannot represent the case that a writable texture resource is bound to a specific mipmap level of a texture whose value type supports both read and write in the same kernel.

To address these issues, in Visual Studio 2013, we introduced two new texture view types: texture_view<const T, N> and texture_view<T, N> to represent read-only texture views and read/write texture views respectively, which are consistent to the array_view’s design. In order to be backward compatible, we kept texture and writeonly_texture_view APIs as they are in Visual Studio 2012, but we are deprecating writeonly_texture_view since its functionality is now a subset of texture_view<T, N>.

The following table summarizes the new C++ AMP texture API design in Visual Studio 2013:

type

#Comp

Lambda
capture

Read

Write

sampling

MipLevel
access

texture<T, N>

1

ref

Yes

Yes

No (1)

level 0

 

1

const ref

Yes

No (3)

No (1)

level 0

 

2, 4

ref,

const ref

Yes

No (2)

No (1)

level 0

writeonly_texture_view<T, N>

(deprecated)

1, 2, 4

value

No (1)

Yes

No (1)

level 0

texture_view<const T, N>

1,2,4

value

Yes

No (1)

Yes

The range is defined upon construction; each level is dynamically indexable

texture_view<T, N>

 

1

value

Yes

Yes

No (1)

a specific level defined upon construction

2, 4

value

No (2)

Yes

No (1)

a specific level defined upon construction

The number in the parenthesis after “No” indicates how the specific operation is disallowed:

1 — No member function is defined for the operation;

2 — Static assertion is triggered for cases that are statically known unsupported for the operation;

3 — The member function for the operation is non-const, and thus not accessible by the const reference assuming the constness is not casted away; the results would be undefined if constness is casted away;

Note that currently texture_view does not have the automatic data management and movement functionality as array_view provides. A texture_view can only be accessed on the accelerator_view where the underlying texture resides. But this functionality may be added in the future release.

This concludes the overview of the C++ AMP texture view design in Visual Studio 2013. We will have separate blog posts diving into details of texture sampling and mipmap support. So stay tuned. As usual, we’d love to hear your feedbacks, comments and questions below or on our MSDN Forum.


Comments (9)

  1. David Cuccia says:

    Thanks – great to see evolution of C++/AMP to align and evolve with DX capabilities. I'm not very familiar with the API, but, what is the limitation restricting ref lambda capture multi-component texture writes?

  2. Read and write in the same kernel is not supported for multi-component textures. If we allow writes on a texture ref with multi-component, we would need some way to disallow reads on such texture ref at compile time. Making the [] operator const won't help because texture<T,N>& to const texture<T,N>& conversion is allowed and encouraged for parameter passing. Putting static assertion in texture's [] operator doesn't work either because it could be a read-only texture, in which case, reads should be allowed for multi-component textures. Therefore, we use a separate type (writeonly_texture_view in VS2012 and texture_view in VS2013) to indicate that the texture is not readonly, then we could use static assertion in the index operator to ensure that only single component texture_view objects are allowed for read. If not for the sake of backward compatibility, I probably would prefer to remove the texture type, or at least make it readonly. Do this make sense?

  3. David Cuccia says:

    Hi,

    I'd posted a reply here, but it seems to have been lost – did you see it?

    David

  4. I saw it in a notification email, but then I couldn't find it here. So I thought it was deleted somehow. Do you want to repost it?

  5. David Cuccia says:

    Strange. I essentially said that what you laid out makes sense. One thing that piqued my interest was your last comment regarding removing the texture type. Would you advocate the same for the array type? I know textures are "GPU" only but I'd see that distinction blurring as time moves on. I understood that array has a different behavior upon construction and method invocation than array_view that may be useful – is the same for texture/texture_view?

  6. The difference between array and array_view is bigger than the difference between texture and texture_view. array_view has automatic memory management and section support, which means there are at least two situations you might need to use array instead of array_view:

    (1) when you want to explicitly control when/how to copy the data between host and accelerators; (2) when you are not using sections, and super care about the slight overhead introduced by array_view when doing the extra index calculation in order to support section. So no, I wouldn't say we should get rid of array, although it's debatable whether we should make its semantics as direct data container like vector and capture it as reference, or make it another kind of view, but without automatic memory management and section support.

  7. Hi.

    This is somewhat unrelated to your article but I am looking for the HLSL intrinsic functions such as length for vectors. What are the corresponding methods in AMP?

  8. Hello marten_range,

    AMP does note provide any intrinsic function for anything wider than a scalar. Also on modern GPU architectures, such intrinsic is not expected to do any better than manually rolled out length function.

  9. LobsterNinja says:

    I would love to see a complete pure C++ AMP code sample that simply loads "lena.bmp" and samples from it (with interpolation). There seems to be a huge number of examples that fail to describe how to do this, and even more web pages that describe theory without code.