193 lines
4.8 KiB
C++
193 lines
4.8 KiB
C++
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <algorithm>
|
|
#include <computeManager/computeManager.h>
|
|
#include <user/compute.h>
|
|
|
|
namespace smo {
|
|
namespace compute {
|
|
|
|
void ComputeManager::initialize()
|
|
{
|
|
if (initialized) { return; }
|
|
|
|
cl_int err;
|
|
|
|
// Get number of platforms
|
|
cl_uint numPlatforms = 0;
|
|
err = clGetPlatformIDs(0, nullptr, &numPlatforms);
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": failed to get OpenCL platforms: " +
|
|
std::to_string(err));
|
|
}
|
|
if (numPlatforms == 0)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": no OpenCL platforms found");
|
|
}
|
|
|
|
// Get all platforms
|
|
std::vector<cl_platform_id> platforms(numPlatforms);
|
|
err = clGetPlatformIDs(numPlatforms, platforms.data(), nullptr);
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": failed to enumerate OpenCL platforms: " +
|
|
std::to_string(err));
|
|
}
|
|
|
|
// Enumerate devices for each platform
|
|
for (cl_uint p = 0; p < numPlatforms; ++p)
|
|
{
|
|
cl_platform_id platform = platforms[p];
|
|
|
|
// Check platform version
|
|
char platformVersion[128];
|
|
err = clGetPlatformInfo(
|
|
platform, CL_PLATFORM_VERSION,
|
|
sizeof(platformVersion), platformVersion, nullptr);
|
|
|
|
if (err == CL_SUCCESS)
|
|
{
|
|
if (!validateOpenClVersion(platformVersion, "platform", 1, 2))
|
|
{
|
|
std::cout << __func__ << ": skipping platform " << p
|
|
<< " with incompatible OpenCL version "
|
|
<< std::string(platformVersion) << std::endl;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Get number of devices
|
|
cl_uint numDevices = 0;
|
|
err = clGetDeviceIDs(
|
|
platform, CL_DEVICE_TYPE_ALL, 0, nullptr, &numDevices);
|
|
|
|
if (err != CL_SUCCESS || numDevices == 0)
|
|
{
|
|
std::cout << __func__ << ": skipping platform " << p
|
|
<< " with no devices" << std::endl;
|
|
continue;
|
|
}
|
|
|
|
// Get all devices
|
|
std::vector<cl_device_id> platformDevices(numDevices);
|
|
err = clGetDeviceIDs(
|
|
platform, CL_DEVICE_TYPE_ALL, numDevices,
|
|
platformDevices.data(), nullptr);
|
|
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": failed to enumerate devices for "
|
|
"platform " + std::to_string(p) + ": " + std::to_string(err));
|
|
}
|
|
|
|
// Create ComputeDevice for each device
|
|
for (cl_uint d = 0; d < numDevices; ++d)
|
|
{
|
|
cl_device_id device = platformDevices[d];
|
|
|
|
// Check device version
|
|
char deviceVersion[128];
|
|
err = clGetDeviceInfo(
|
|
device, CL_DEVICE_VERSION,
|
|
sizeof(deviceVersion), deviceVersion, nullptr);
|
|
|
|
if (err == CL_SUCCESS)
|
|
{
|
|
if (!validateOpenClVersion(deviceVersion, "device", 1, 2))
|
|
{
|
|
std::cout << __func__ << ": skipping device " << d
|
|
<< " with incompatible OpenCL version "
|
|
<< std::string(deviceVersion) << std::endl;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Create ComputeDevice (constructor creates context and queue)
|
|
try
|
|
{
|
|
auto deviceObj = std::make_shared<ComputeDevice>(
|
|
platform, device);
|
|
devices.push_back(deviceObj);
|
|
}
|
|
catch (const std::runtime_error& e)
|
|
{
|
|
// Re-throw with more context about which device/platform
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": failed to create ComputeDevice "
|
|
"for device " + std::to_string(d) + " on platform " +
|
|
std::to_string(p) + ": " + e.what());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (devices.empty())
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": no compatible OpenCL devices found");
|
|
}
|
|
|
|
initialized = true;
|
|
std::cout << __func__ << ": Initialized with " << devices.size()
|
|
<< " compute device(s)" << std::endl;
|
|
}
|
|
|
|
void ComputeManager::finalize()
|
|
{
|
|
if (!initialized) { return; }
|
|
|
|
// Release all devices (their shared_ptrs will clean up contexts/queues)
|
|
devices.clear();
|
|
initialized = false;
|
|
std::cout << __func__ << ": Finalized" << std::endl;
|
|
}
|
|
|
|
std::shared_ptr<ClBuffer>
|
|
ComputeManager::createUseHostPtrBuffer(
|
|
void* hostPtr, size_t size, cl_mem_flags flags)
|
|
{
|
|
if (!initialized)
|
|
{
|
|
std::cerr << __func__ << ": ComputeManager not initialized"
|
|
<< std::endl;
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": ComputeManager not initialized");
|
|
}
|
|
|
|
return std::make_shared<ClBuffer>(hostPtr, size, flags, devices);
|
|
}
|
|
|
|
void ComputeManager::releaseUseHostPtrBuffer(std::shared_ptr<ClBuffer> buffer)
|
|
{
|
|
// No-op: ClBuffer's destructor handles cleanup automatically
|
|
// This function exists for API compatibility
|
|
(void)buffer;
|
|
}
|
|
|
|
std::shared_ptr<ComputeDevice> ComputeManager::getDevice()
|
|
{
|
|
if (!initialized || devices.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Return first available device
|
|
// In the future, this will filter based on ComputeDeviceConstraints
|
|
return devices[0];
|
|
}
|
|
|
|
void ComputeManager::releaseDevice(std::shared_ptr<ComputeDevice> device)
|
|
{
|
|
// Placeholder for future refcounting implementation
|
|
// Devices are only removed in finalize()
|
|
(void)device;
|
|
}
|
|
|
|
} // namespace compute
|
|
} // namespace smo
|