Source browser

examples/runner.hpp

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

File fingerprint
1#ifndef SHDR_EXAMPLES_RUNNER_HPP // Open this include guard or optional feature branch.
2#define SHDR_EXAMPLES_RUNNER_HPP // Define SHDR_EXAMPLES_RUNNER_HPP for the declarations that follow.
3
4#include "shdr.h" // Include shdr.h declarations.
5#include <cmath> // Include cmath declarations.
6#include <iostream> // Include iostream declarations.
7#include <memory> // Include memory declarations.
8#include <random> // Include random declarations.
9#include <stdexcept> // Include stdexcept declarations.
10#include <string> // Include string declarations.
11#ifdef SHDR_HAVE_EGL // Enable this branch when its feature macro is defined.
12#include "egl_context.hpp" // Include egl_context.hpp declarations.
13#endif // Finish this conditional compilation branch.
14
15namespace shdr_examples { // Group these helpers within their namespace.
16
17/// Select CPU execution by default, or an explicitly requested GL profile.
18class runner { // Own an optional GPU device and select the pipeline execution backend.
19    std::unique_ptr<shdr::device> device_; // Keep the optional headless context alive until the example finishes.
20
21  public: // Set public access for the following class members.
22    runner(int argc, char** argv) { // Read the common optional GPU profile from this example's command line.
23        if (argc == 1) // Select CPU execution for the default command line.
24            return; // Finish initializing the CPU runner.
25        if (argc != 3 || std::string(argv[1]) != "--gpu") // Accept exactly the documented --gpu PROFILE option.
26            throw std::invalid_argument("usage: executable [--gpu es31|es32|gl43|gl45|gl46]"); // Report usage: executable [--gpu es31|es32|gl43|gl45|gl46].
27        const std::string name(argv[2]); // Construct name with these initial values.
28        shdr::profile profile; // Declare profile for the following calculation.
29        if (name == "es31") // Check this condition before entering the following branch.
30            profile = shdr::profile::es31; // Set profile from this expression.
31        else if (name == "es32") // Select the GLES 3.2 device profile.
32            profile = shdr::profile::es32; // Set profile from this expression.
33        else if (name == "gl43") // Select the desktop GL 4.3 device profile.
34            profile = shdr::profile::gl43; // Set profile from this expression.
35        else if (name == "gl45") // Select the desktop GL 4.5 device profile.
36            profile = shdr::profile::gl45; // Set profile from this expression.
37        else if (name == "gl46") // Select the desktop GL 4.6 device profile.
38            profile = shdr::profile::gl46; // Set profile from this expression.
39        else // Reject profile names outside the supported list.
40            throw std::invalid_argument("unknown GL profile: " + name); // Report unknown GL profile: .
41#ifdef SHDR_HAVE_EGL // Enable this branch when its feature macro is defined.
42        device_.reset(new shdr::headless_device(profile)); // Create the requested headless context through the public library backend.
43#else // Select the alternative implementation for this build.
44        (void)profile; // Consume the parsed profile value in the CPU build configuration.
45        throw std::runtime_error( // Report this failed operation.
46            "GPU examples were not enabled. Configure with EGL development files"); // Provide this text argument for the operation above.
47#endif // Finish this conditional compilation branch.
48    } // End this block.
49
50    void run(const shdr::pipeline& pipeline) { // Execute any prepared pipeline using this example's selected backend.
51        if (device_) // Use the GPU device only when the command line requested one.
52            pipeline.run(*device_); // Run default stages on GPU while preserving explicitly selected CPU stages.
53        else // Execute the default stages on the CPU backend.
54            pipeline.run(); // Run the pipeline through the standard C++ implementation.
55    } // End this block.
56
57    bool gpu() const { // Expose the selected backend for result labels and optional GPU checks.
58        return bool(device_); // Report whether this runner owns a headless GPU device.
59    } // End this block.
60    shdr::device* device() const { // Expose the optional device for interop, synchronization and timing.
61        return device_.get(); // Return the retained device or null for ordinary CPU execution.
62    } // End this block.
63}; // Finish this declaration.
64
65/// Fail examples and tests with a useful diagnostic when CPU/GPU results diverge.
66inline void // Declare void for the following calculation.
67require_close(float actual, float expected, const std::string& label, float tolerance = 0.0001f) { // Compare a computed scalar with its independently calculated reference.
68    if (!std::isfinite(actual) || std::fabs(actual - expected) > tolerance) { // Reject nonfinite results and differences above the chosen absolute tolerance.
69        throw std::runtime_error(label + ": expected " + std::to_string(expected) + ", received " + // Identify the failed case and show both expected and received values.
70                                 std::to_string(actual)); // Include the computed value in the comparison diagnostic.
71    } // End this block.
72} // End this block.
73
74/// Use repeatable random inputs so each backend receives identical test data.
75inline void randomize(shdr::buffer<float>& values, unsigned seed, float lower, float upper) { // Fill a host buffer with reproducible uniformly distributed test values.
76    std::mt19937 generator(seed); // Initialize the deterministic random sequence from the caller's seed.
77    std::uniform_real_distribution<float> distribution(lower, upper); // Select the caller's inclusive lower and upper distribution bounds.
78    float* data = values.data(); // Mark the host resource modified before filling its elements.
79    for (std::size_t i = 0; i < values.size(); ++i) // Initialize every element of the buffer exactly once.
80        data[i] = distribution(generator); // Store the next random sample from the selected interval.
81} // End this block.
82
83} // namespace shdr_examples
84#endif // Finish this conditional compilation branch.