Source browser

examples/images.cpp

Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.

File fingerprint
1#include "runner.hpp" // Include runner.hpp declarations.
2
3/// Link SSBO and image stages, checking a full two-dimensional CPU/GPU result.
4int main(int argc, char** argv) { // Run this example and validate its results.
5    try { // Run the operation while retaining the error handling below.
6        shdr_examples::runner run(argc, argv); // Select CPU execution or the requested headless GPU profile.
7        const unsigned width = 19, height = 13; // Choose dimensions that exercise partial final workgroups on both image axes.
8        shdr::buffer<float> input(width * height), output(width * height); // Allocate distinct resources for the input, intermediate stages and final result.
9        shdr::image2d<float, 1> original(width, height), filtered(width, height); // Allocate separate input and output images for neighborhood sampling.
10        shdr_examples::randomize(input, 1102u, 0.0f, 23.0f); // Fill the input with reproducible random values.
11
12        auto upload_owner = shdr::make_kernel("buffer_to_image_kernel"); // Create the linked buffer to image kernel instance.
13        shdr::kernel& upload = *upload_owner; // Retain the owned shader instance for every stage that references it.
14        upload.bind("input_values", input); // Copy the host buffer into the image shared with the blur stage.
15        upload.bind("output_image", original); // Copy the host buffer into the image shared with the blur stage.
16
17        auto blur_owner = shdr::make_kernel("blur_kernel"); // Create the linked blur kernel instance.
18        shdr::kernel& blur = *blur_owner; // Retain the owned shader instance for every stage that references it.
19        blur.bind("input_image", original); // Connect the immutable input image and the separate filtered image.
20        blur.bind("output_image", filtered); // Connect the immutable input image and the separate filtered image.
21
22        auto download_owner = shdr::make_kernel("image_to_buffer_kernel"); // Create the linked image to buffer kernel instance.
23        shdr::kernel& download = *download_owner; // Retain the owned shader instance for every stage that references it.
24        download.bind("input_image", filtered); // Copy the filtered image into the buffer used by the host result check.
25        download.bind("output_values", output); // Copy the filtered image into the buffer used by the host result check.
26
27        const shdr::extent groups((width + 7) / 8, (height + 7) / 8); // Round up both image axes to the shader's eight-by-eight local size.
28        shdr::pipeline pipeline; // Declare pipeline for the following calculation.
29        pipeline += shdr::dispatch(upload, groups); // Begin by transferring values between two shader resource types.
30        pipeline += shdr::dispatch(blur, groups); // Consume the image produced by the preceding stage and filter its neighborhood.
31        pipeline += shdr::dispatch(download, groups); // Return the filtered scalar pixels to a buffer resource.
32        run.run(pipeline); // Execute the configured pipeline on the requested backend.
33
34        const shdr::buffer<float>& read_input = input; // Use a constant buffer view so GPU writes synchronize before host reads.
35        const shdr::buffer<float>& read_output = output; // Use a constant buffer view so GPU writes synchronize before host reads.
36        for (unsigned y = 0; y < height; ++y) { // Iterate over y for this calculation.
37            for (unsigned x = 0; x < width; ++x) { // Iterate over x for this calculation.
38                float expected = 0.0f; // Start the independent scalar reference at zero.
39                for (int dy = -1; dy <= 1; ++dy) { // Iterate over dy for this calculation.
40                    for (int dx = -1; dx <= 1; ++dx) { // Iterate over dx for this calculation.
41                        const unsigned sx = // Choose the reference sample column before applying the border rule.
42                            unsigned(std::max(0, std::min(int(width) - 1, int(x) + dx))); // Clamp this reference coordinate to the nearest valid image edge.
43                        const unsigned sy = // Choose the reference sample row before applying the border rule.
44                            unsigned(std::max(0, std::min(int(height) - 1, int(y) + dy))); // Clamp this reference coordinate to the nearest valid image edge.
45                        expected += read_input.data()[sy * width + sx]; // Accumulate the independently clamped three-by-three input neighborhood.
46                    } // End this block.
47                } // End this block.
48                shdr_examples::require_close(read_output.data()[y * width + x], // Check the computed value against the independent reference.
49                                             expected / 9.0f, // Average exactly nine clamped neighbor samples.
50                                             "image pixel " + std::to_string(y * width + x)); // Identify the flattened pixel if this reference comparison fails.
51            } // End this block.
52        } // End this block.
53        std::cout << (run.gpu() ? "GPU" : "CPU") << " buffer/image pipeline: " << width << " x " // Write this part of the example result or diagnostic.
54                  << height << " pixels verified\n"; // Write this part of the example result or diagnostic.
55        return 0; // Report successful completion.
56#ifdef SHDR_HAVE_EGL // Enable this branch when its feature macro is defined.
57    } catch (const shdr_examples::context_unavailable& error) { // Report the exception from the preceding operation.
58        std::cerr << "SKIP: " << error.what() << "\n"; // Write this part of the example result or diagnostic.
59        return 77; // Report an unavailable optional GPU backend.
60#endif // Finish this conditional compilation branch.
61    } catch (const std::exception& error) { // Report the exception from the preceding operation.
62        std::cerr << error.what() << "\n"; // Write this part of the example result or diagnostic.
63        return 1; // Report a failed check or operation.
64    } // End this block.
65} // End this block.