blob: 5acd9a1a8a28668e8172826ecf66aa2ece890a13 [file] [log] [blame]
//
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// CLContextVk.cpp: Implements the class methods for CLContextVk.
#include "libANGLE/renderer/vulkan/CLContextVk.h"
#include "libANGLE/renderer/vulkan/CLCommandQueueVk.h"
#include "libANGLE/renderer/vulkan/CLEventVk.h"
#include "libANGLE/renderer/vulkan/CLMemoryVk.h"
#include "libANGLE/renderer/vulkan/CLProgramVk.h"
#include "libANGLE/renderer/vulkan/vk_renderer.h"
#include "libANGLE/renderer/vulkan/vk_utils.h"
#include "libANGLE/CLBuffer.h"
#include "libANGLE/CLContext.h"
#include "libANGLE/CLEvent.h"
#include "libANGLE/CLProgram.h"
#include "libANGLE/cl_utils.h"
namespace rx
{
CLContextVk::CLContextVk(const cl::Context &context, const cl::DevicePtrs devicePtrs)
: CLContextImpl(context),
vk::Context(getPlatform()->getRenderer()),
mAssociatedDevices(devicePtrs)
{}
CLContextVk::~CLContextVk() = default;
void CLContextVk::handleError(VkResult errorCode,
const char *file,
const char *function,
unsigned int line)
{
ASSERT(errorCode != VK_SUCCESS);
CLenum clErrorCode = CL_SUCCESS;
switch (errorCode)
{
case VK_ERROR_TOO_MANY_OBJECTS:
case VK_ERROR_OUT_OF_HOST_MEMORY:
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
clErrorCode = CL_OUT_OF_HOST_MEMORY;
break;
default:
clErrorCode = CL_INVALID_OPERATION;
}
ERR() << "Internal Vulkan error (" << errorCode << "): " << VulkanResultString(errorCode);
ERR() << " CL error (" << clErrorCode << ")";
if (errorCode == VK_ERROR_DEVICE_LOST)
{
handleDeviceLost();
}
ANGLE_CL_SET_ERROR(clErrorCode);
}
void CLContextVk::handleDeviceLost() const
{
// For now just notify the renderer
getRenderer()->notifyDeviceLost();
}
angle::Result CLContextVk::getDevices(cl::DevicePtrs *devicePtrsOut) const
{
ASSERT(!mAssociatedDevices.empty());
*devicePtrsOut = mAssociatedDevices;
return angle::Result::Continue;
}
angle::Result CLContextVk::createCommandQueue(const cl::CommandQueue &commandQueue,
CLCommandQueueImpl::Ptr *commandQueueOut)
{
CLCommandQueueVk *queueImpl = new CLCommandQueueVk(commandQueue);
if (queueImpl == nullptr)
{
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
ANGLE_TRY(queueImpl->init());
*commandQueueOut = CLCommandQueueVk::Ptr(std::move(queueImpl));
return angle::Result::Continue;
}
angle::Result CLContextVk::createBuffer(const cl::Buffer &buffer,
void *hostPtr,
CLMemoryImpl::Ptr *bufferOut)
{
CLBufferVk *memory = new (std::nothrow) CLBufferVk(buffer);
if (memory == nullptr)
{
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
ANGLE_TRY(memory->create(hostPtr));
*bufferOut = CLMemoryImpl::Ptr(memory);
mAssociatedObjects->mMemories.emplace(buffer.getNative());
return angle::Result::Continue;
}
angle::Result CLContextVk::createImage(const cl::Image &image,
cl::MemFlags flags,
const cl_image_format &format,
const cl::ImageDescriptor &desc,
void *hostPtr,
CLMemoryImpl::Ptr *imageOut)
{
UNIMPLEMENTED();
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
}
angle::Result CLContextVk::getSupportedImageFormats(cl::MemFlags flags,
cl::MemObjectType imageType,
cl_uint numEntries,
cl_image_format *imageFormats,
cl_uint *numImageFormats)
{
UNIMPLEMENTED();
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
}
angle::Result CLContextVk::createSampler(const cl::Sampler &sampler, CLSamplerImpl::Ptr *samplerOut)
{
UNIMPLEMENTED();
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
}
angle::Result CLContextVk::createProgramWithSource(const cl::Program &program,
const std::string &source,
CLProgramImpl::Ptr *programOut)
{
CLProgramVk *programVk = new (std::nothrow) CLProgramVk(program);
if (programVk == nullptr)
{
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
ANGLE_TRY(programVk->init());
*programOut = CLProgramImpl::Ptr(std::move(programVk));
return angle::Result::Continue;
}
angle::Result CLContextVk::createProgramWithIL(const cl::Program &program,
const void *il,
size_t length,
CLProgramImpl::Ptr *programOut)
{
UNIMPLEMENTED();
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
}
angle::Result CLContextVk::createProgramWithBinary(const cl::Program &program,
const size_t *lengths,
const unsigned char **binaries,
cl_int *binaryStatus,
CLProgramImpl::Ptr *programOut)
{
CLProgramVk *programVk = new (std::nothrow) CLProgramVk(program);
if (programVk == nullptr)
{
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
ANGLE_TRY(programVk->init(lengths, binaries, binaryStatus));
*programOut = CLProgramImpl::Ptr(std::move(programVk));
return angle::Result::Continue;
}
angle::Result CLContextVk::createProgramWithBuiltInKernels(const cl::Program &program,
const char *kernel_names,
CLProgramImpl::Ptr *programOut)
{
UNIMPLEMENTED();
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_RESOURCES);
}
angle::Result CLContextVk::linkProgram(const cl::Program &program,
const cl::DevicePtrs &devices,
const char *options,
const cl::ProgramPtrs &inputPrograms,
cl::Program *notify,
CLProgramImpl::Ptr *programOut)
{
const cl::DevicePtrs &devicePtrs = !devices.empty() ? devices : mContext.getDevices();
CLProgramVk::Ptr programImpl = CLProgramVk::Ptr(new (std::nothrow) CLProgramVk(program));
if (programImpl == nullptr)
{
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
cl::DevicePtrs linkDeviceList;
CLProgramVk::LinkProgramsList linkProgramsList;
cl::BitField libraryOrObject(CL_PROGRAM_BINARY_TYPE_LIBRARY |
CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT);
for (const cl::DevicePtr &devicePtr : devicePtrs)
{
CLProgramVk::LinkPrograms linkPrograms;
for (const cl::ProgramPtr &inputProgram : inputPrograms)
{
const CLProgramVk::DeviceProgramData *deviceProgramData =
inputProgram->getImpl<CLProgramVk>().getDeviceProgramData(devicePtr->getNative());
// Should be valid at this point
ASSERT(deviceProgramData != nullptr);
if (libraryOrObject.isSet(deviceProgramData->binaryType))
{
linkPrograms.push_back(deviceProgramData);
}
}
if (!linkPrograms.empty())
{
linkDeviceList.push_back(devicePtr);
linkProgramsList.push_back(linkPrograms);
}
}
// Perform link
if (notify)
{
std::shared_ptr<angle::WaitableEvent> asyncEvent =
mContext.getPlatform().getMultiThreadPool()->postWorkerTask(
std::make_shared<CLAsyncBuildTask>(
programImpl.get(), linkDeviceList, std::string(options ? options : ""), "",
CLProgramVk::BuildType::LINK, linkProgramsList, notify));
ASSERT(asyncEvent != nullptr);
}
else
{
if (!programImpl->buildInternal(linkDeviceList, std::string(options ? options : ""), "",
CLProgramVk::BuildType::LINK, linkProgramsList))
{
ANGLE_CL_RETURN_ERROR(CL_LINK_PROGRAM_FAILURE);
}
}
*programOut = std::move(programImpl);
return angle::Result::Continue;
}
angle::Result CLContextVk::createUserEvent(const cl::Event &event, CLEventImpl::Ptr *eventOut)
{
*eventOut = CLEventImpl::Ptr(new (std::nothrow) CLEventVk(event));
if (*eventOut == nullptr)
{
ANGLE_CL_RETURN_ERROR(CL_OUT_OF_HOST_MEMORY);
}
return angle::Result::Continue;
}
angle::Result CLContextVk::waitForEvents(const cl::EventPtrs &events)
{
for (auto &event : events)
{
CLEventVk *eventVk = &event.get()->getImpl<CLEventVk>();
if (eventVk->isUserEvent())
{
ANGLE_TRY(eventVk->waitForUserEventStatus());
}
else
{
// TODO rework this to instead (flush w/ ResourceUse serial wait) once we move away from
// spawning a submit-thread/Task for flush routine
// https://anglebug.com/8669
ANGLE_TRY(event->getCommandQueue()->finish());
}
}
return angle::Result::Continue;
}
} // namespace rx