Files
ANSLibs/ANS-HWiNFO/external/OpenCL/lib/SDK.md

10 KiB

OpenCL SDK Library

The OpenCL SDK Library hosts both C and C++ utilities which are generally useful for writing OpenCL applications but are either dependency-heavy or contentious. Because these utilities aren't the subject of universal interest, these utilities are not exported, meaning SDK installations won't install their headers nor their libraries. Doing so the OpenCL Utility Library can be kept dependency-free.

The utilities are broken into to libraries, OpenCLSDK and OpenCLSDKCpp. Samples include <CL/Utils/Utils.h>/<CL/Utils/Utils.hpp> and link to their libraries respectively.

List of utilities

Command-line interface utilities

C

struct cl_sdk_options_DeviceTriplet
{
    int plat_index;
    int dev_index;
    cl_device_type dev_type;
};

struct cl_sdk_options_Diagnostic
{
    bool verbose;
    bool quiet;
};

struct cl_sdk_options_SingleDevice
{
    struct cl_sdk_options_DeviceTriplet triplet;
};

struct cl_sdk_options_MultiDevice
{
    struct cl_sdk_options_DeviceTriplet * triplets;
    size_t number;
};

C++

struct cl::sdk::DeviceTriplet
{
    int plat_index;
    int dev_index;
    cl_device_type dev_type;
};
struct cl::sdk::Diagnostic
{
    bool verbose,
         quiet;
};
struct cl::sdk::SingleDevice
{
    DeviceTriplet triplet;
};
struct cl::sdk::MultiDevice
{
    cl::vector<DeviceTriplet> triplets;
};
struct cl::sdk::Window
{
    int width;
    int height;
    bool fullscreen;
};

The SDK Library deduplicates the storage the result of common CLI argument parsing. These types are used throughout the SDK samples.

C++

template <typename Option>
auto cl::sdk::parse();

template <typename Option, typename... Parsers>
Option cl::sdk::comprehend(Parsers... parsers);

template <typename... Options>
std::tuple<Options...> cl::sdk::parse_cli(int argc, char* argv[], std::string banner = "OpenCL SDK sample template")

These functions reduce the boilerplate needed for each sample to introduce their own set of command-line arguments and helps deduplicate the set of common options which most samples inherit.

The first two are the customizable parts where each sample (and the the pre-defined options) specify how CLI arguments should be processed. cl::sdk::parse() specifies what the option names are and should return an instance of tuple-like type (std::get<int>(const type&) be valid) containing smart-pointer-like types (ptr.get() be valid) holding TCLAP arguments and switches. cl::sdk::comprehend() takes this tuple already expanded as arguments with names and "makes sense" of the strings of args already validated during parsing and returns a singular struct of the options at hand.

The types returned by cl::sdk::parse() must exactly match the Parsers... of cl::sdk::comprehend().

cl::sdk::parse_cli() is a simple metaprogram that invokes the parse and comprehend functions of all the Options types it is given in the correct order. First it registers all the command-line arguments and switches, then invokes the parse method of the underlying CLI parser and then invokes the comprehend method of the

Simplest example is the C++ SAXPY sample adding a single option to control the length of the vector operands. The sample uses a single OpenCL device and respects diagnostic level options as well.

C++

// Sample-specific option
struct SaxpyOptions { size_t length; };

// Add option to CLI parsing SDK utility
template <> auto cl::sdk::parse<SaxpyOptions>(){
    return std::make_tuple(
        std::make_shared<TCLAP::ValueArg<size_t>>("l", "length", "Length of input", false, 1'048'576, "positive integral")
    );
}
template <> SaxpyOptions cl::sdk::comprehend<SaxpyOptions>(
    std::shared_ptr<TCLAP::ValueArg<size_t>> length_arg){
    return SaxpyOptions{
        length_arg->getValue()
    };
}

int main(int argc, char* argv[])
{
    try
    {
        // Parse command-line options
        auto opts = cl::sdk::parse_cli<
                        cl::sdk::options::Diagnostic,
                        cl::sdk::options::SingleDevice,
                        SaxpyOptions>(argc, argv);
        const auto& diag_opts  = std::get<0>(opts);
        const auto& dev_opts   = std::get<1>(opts);
        const auto& saxpy_opts = std::get<2>(opts);
    ...
    }
    // catch clauses
}

(Note: C++17 structured-bindings allows cleaner binding of names to the members of the tuple returned by cl::sdk::parse_cli.)

Pseudo Random Number Generation utilities

C

void cl_sdk_fill_with_random_floats(pcg32_random_t * rng, cl_float * arr, const size_t len);

Fills an array with random floats in the range [0, 1).

  • rng must point to a valid PRNG instance.
  • arr must be allocated storage long enough to store the results.
  • len is the count of elements that will be written to arr.
void cl_sdk_fill_with_random_floats_range(pcg32_random_t * rng,
    cl_float * arr, const size_t len, const cl_float low, const cl_float hi);

Fills an array with random floats in the range [low, hi).

  • rng must point to a valid PRNG instance.
  • arr must be allocated storage long enough to store the results.
  • len is the count of elements that will be written to arr.
  • low is the low-end of the range.
  • hi is the high-end of the range.
void cl_sdk_fill_with_random_ints_range(pcg32_random_t * rng,
    cl_int * arr, const size_t len, const cl_int low, const cl_int hi);

Fills an array with uniformly distributed numbers in the range [low, hi]. Uses rejection sampling from uniform bit distribution.

  • rng must point to a valid PRNG instance.
  • arr must be allocated storage long enough to store the results.
  • len is the count of elements that will be written to arr.
  • low is the low-end of the range.
  • hi is the high-end of the range.

C++

template <typename PRNG, typename... Containers>
void fill_with_random(PRNG&& prng, Containers&&... containers);

Fills containers with random numbers using a user-provided PRNG.

  • prng must be a PRNG, a callable type with T(void) signature where T is implicitly convertible to the value_type of containers.
  • containers must be a container providing a LegacyOutputIterator.

Image utilities

C

typedef struct cl_sdk_image
{
    int width, height, pixel_size;
    unsigned char* pixels;
}
cl_sdk_image;

C++

struct cl::sdk::Image
{
    int width, height, pixel_size;
    cl::vector<unsigned char> pixels;
};

Used to store pixel information of images read/written to/from storage.

  • width and height store the number of pixels the image has in x-y directions respectively.
  • pixel_size stores the number of bytes used to store a single pixel.
  • pixels stores the actual pixel data.

C

cl_sdk_image cl_sdk_read_image(const char* file_name, cl_int* err);

C++

Image cl::sdk::read_image(const char* file_name, cl_int* err);

Reads a BMP/JPEG/PNG image from disk.

  • file_name specifies the absolute or relative path (to the current working-directory) to the image.
  • err is an optional pointer used to capture error conditions.

Returns an cl_sdk_image/cl::sdk::Image instance. If an error occurs, the returned image is in an invalid state.

C

void cl_sdk_write_image(const char * file_name, const cl_sdk_image * im, cl_int * err);

C++

void cl::sdk::write_image(const char* file_name, const Image& image, cl_int* err);

Writes a BMP/JPEG/PNG image from disk.

  • file_name specifies the absolute or relative path (to the current working-directory) to the image.
  • image is the source of pixel information.
  • err is an optional pointer used to capture error conditions.

OpenCL-OpenGL interop utilities

C++

cl::vector<cl_context_properties> cl::sdk::get_interop_context_properties(const cl::Device& plat, cl_int* error = nullptr);

This function returns a null-terminated list of context properties required to setup an OpenCL-OpenGL interop context with the currently active OpenGL context.

If error is non-null or if CL_HPP_ENABLE_EXCEPTIONS is used, ordinary OpenCL error codes may be returned and the following library-specific error codes:

  • CL_UTIL_OS_GL_QUERY_ERROR if platform-specific errors occur when trying to query for the currently active OpenGL context.

C++

cl::Context cl::sdk::get_interop_context(int plat_id, int dev_id, cl_device_type type, cl_int* error = nullptr);

This function creates an interop context on the platform with id plat_id with a single device of type type and id dev_id which is able to share resources with the currently active OpenGL context.

If error is non-null or if CL_HPP_ENABLE_EXCEPTIONS is used, ordinary OpenCL error codes may be returned and the following library-specific error codes:

  • CL_UTIL_INDEX_OUT_OF_RANGE if the requested platform or device id is outside the range of available platforms or devices of the selected type on the platform.
  • CL_UTIL_OS_GL_QUERY_ERROR if platform-specific errors occur when trying to query for the currently active OpenGL context.

C++

class cl::sdk::InteropWindow : public sf::Window
{
public:
    explicit InteropWindow(
        sf::VideoMode mode,
        const sf::String& title,
        sf::Uint32 style = sf::Style::Default,
        const sf::ContextSettings& settings = sf::ContextSettings{},
        int platform_id = 0,
        int device_id = 0,
        cl_bitfield device_type = CL_DEVICE_TYPE_DEFAULT
    );

    void run();

protected:
    // Core functionality to be overriden
    virtual void initializeGL() = 0;            // Function that initializes all OpenGL assets needed to draw a scene
    virtual void initializeCL() = 0;            // Function that initializes all OpenCL assets needed to draw a scene
    virtual void updateScene() = 0;             // Function that holds scene update guaranteed not to conflict with drawing
    virtual void render() = 0;                  // Function that does the native rendering
    virtual void event(const sf::Event& e) = 0; // Function that handles render area resize

    cl::Context opencl_context;
    bool cl_khr_gl_event_supported;
};

This class encapsulates an interactive window with the content being one OpenGL canvas. It provides a set of functions for the user to override in derived classes.