Views and Subviews

Buffers are objects returned by memory allocation methods. They own the data stored in memory and track the lifetime of that memory. They follow the buffer concept. On the other hand, Views only point to memory but do not own it and can be used within a kernel in addition to on the host. Unlike an MdSpan, the Views contains information about which API was used to allocate the memory. This information is required for certain functions, such as copying memory.

View are typically used when:

  • You already have a host container such as std::vector and want to use it with alpaka.

  • You want to work only on parts of a buffer, for example a slice, halo region, or tile.

  • You want to use the data of an buffer within a kernel without copying it.

Creating a View

You can create a non-owning view from alpaka buffers and then derive a subview from it.

auto hostBuffer = onHost::allocHost<int>(size_t{8});
auto middleViewToBuffer = hostBuffer.getSubView(size_t{2}, size_t{4});

Creating a view from a STL vector is supported too. The subview creating is the same as for buffers.

auto hostView = makeView(hostData);
auto middleView = hostView.getSubView(size_t{2}, size_t{4});

This is useful when the data already exists and you want to keep using the original storage. For example, a stencil update often wants the interior cells only, while a boundary kernel wants a narrow halo view around the edge.

Copying Through a View

Views work with the usual memory operations. That means you can, for example, allocate device memory based on a view and copy only the relevant slice back.

auto deviceBuffer = onHost::allocLike(device, hostView);
onHost::memcpy(queue, deviceBuffer, hostView);

auto hostSlice = onHost::allocHost<int>(4u);
onHost::memcpy(queue, hostSlice, deviceBuffer.getSubView(Vec{size_t{2}}, Vec{size_t{4}}));
onHost::wait(queue);

Typical use cases include:

  • Copying a subrange of a 1D vector.

  • Only the inner area of the grid containing the actual data, without the halo, should be copied into a stencil code.

Complete Source File

070_views.cpp
 1/* Copyright 2026 René Widera
 2 * SPDX-License-Identifier: ISC
 3 */
 4
 5#include "docsTest.hpp"
 6
 7#include <alpaka/alpaka.hpp>
 8
 9#include <catch2/catch_template_test_macros.hpp>
10#include <catch2/catch_test_macros.hpp>
11
12#include <vector>
13
14using namespace alpaka;
15
16TEMPLATE_LIST_TEST_CASE("tutorial views and subviews", "[docs]", docs::test::TestBackends)
17{
18    auto selector = onHost::makeDeviceSelector(TestType::makeDict());
19    if(!selector.isAvailable())
20        return;
21    onHost::concepts::Device auto device = selector.makeDevice(0);
22    onHost::Queue queue = device.makeQueue();
23
24    std::vector<int> hostData{0, 1, 2, 3, 4, 5, 6, 7};
25
26    auto hostView = makeView(hostData);
27    auto middleView = hostView.getSubView(size_t{2}, size_t{4});
28
29    CHECK(hostView.getExtents().x() == 8u);
30    CHECK(middleView.getExtents().x() == 4u);
31    CHECK(middleView[Vec{size_t{0}}] == 2);
32    CHECK(middleView[Vec{size_t{3}}] == 5);
33
34    auto hostBuffer = onHost::allocHost<int>(size_t{8});
35    auto middleViewToBuffer = hostBuffer.getSubView(size_t{2}, size_t{4});
36
37    onHost::memcpy(queue, middleViewToBuffer, middleView);
38    onHost::wait(queue);
39    CHECK(middleViewToBuffer.getExtents().x() == 4u);
40    CHECK(middleViewToBuffer[Vec{size_t{0}}] == 2);
41    CHECK(middleViewToBuffer[Vec{size_t{3}}] == 5);
42
43    auto deviceBuffer = onHost::allocLike(device, hostView);
44    onHost::memcpy(queue, deviceBuffer, hostView);
45
46    auto hostSlice = onHost::allocHost<int>(4u);
47    onHost::memcpy(queue, hostSlice, deviceBuffer.getSubView(Vec{size_t{2}}, Vec{size_t{4}}));
48    onHost::wait(queue);
49
50    CHECK(hostSlice[Vec{0u}] == 2);
51    CHECK(hostSlice[Vec{1u}] == 3);
52    CHECK(hostSlice[Vec{2u}] == 4);
53    CHECK(hostSlice[Vec{3u}] == 5);
54}