Commit 44a5c913 by John Plate Committed by Angle LUCI CQ

CL: Make CL front end and back end thread-safe

Add locking to all mutable variables of the CL objects in the front end and pass-through back end to make them thread-safe. This fixes a crash in a multi-threaded CTS test. Bug: angleproject:6015 Change-Id: I1d6471c851217639411c434c82acd32d14035291 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2967468 Commit-Queue: John Plate <jplate@google.com> Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 7753c837
//
// 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.
//
// Spinlock.h:
// Spinlock is a lock that loops actively until it gets the resource.
// Only use it when the lock will be granted in reasonably short time.
#ifndef COMMON_SPINLOCK_H_
#define COMMON_SPINLOCK_H_
#include <atomic>
// TODO(jplate) Add pause for ARM, http://anglebug.com:6067
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
extern "C" void _mm_pause();
# pragma intrinsic(_mm_pause)
# define ANGLE_SMT_PAUSE() _mm_pause()
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
# define ANGLE_SMT_PAUSE() __asm__ __volatile__("pause;")
#else
# define ANGLE_SMT_PAUSE() static_cast<void>(0)
#endif
namespace angle
{
class Spinlock
{
public:
Spinlock() noexcept;
bool try_lock() noexcept;
void lock() noexcept;
void unlock() noexcept;
private:
std::atomic_bool mLock;
};
inline Spinlock::Spinlock() noexcept : mLock(false) {}
inline bool Spinlock::try_lock() noexcept
{
// Relaxed check first to prevent unnecessary cache misses.
return !mLock.load(std::memory_order_relaxed) &&
!mLock.exchange(true, std::memory_order_acquire);
}
inline void Spinlock::lock() noexcept
{
while (mLock.exchange(true, std::memory_order_acquire))
{
// Relaxed wait to prevent unnecessary cache misses.
while (mLock.load(std::memory_order_relaxed))
{
// Optimization for simultaneous multithreading.
ANGLE_SMT_PAUSE();
}
}
}
inline void Spinlock::unlock() noexcept
{
mLock.store(false, std::memory_order_release);
}
} // namespace angle
#endif // COMMON_SPINLOCK_H_
...@@ -43,10 +43,11 @@ cl_int CommandQueue::getInfo(CommandQueueInfo name, ...@@ -43,10 +43,11 @@ cl_int CommandQueue::getInfo(CommandQueueInfo name,
void *value, void *value,
size_t *valueSizeRet) const size_t *valueSizeRet) const
{ {
cl_uint valUInt = 0u; cl_command_queue_properties properties = 0u;
void *valPointer = nullptr; cl_uint valUInt = 0u;
const void *copyValue = nullptr; void *valPointer = nullptr;
size_t copySize = 0u; const void *copyValue = nullptr;
size_t copySize = 0u;
switch (name) switch (name)
{ {
...@@ -66,8 +67,9 @@ cl_int CommandQueue::getInfo(CommandQueueInfo name, ...@@ -66,8 +67,9 @@ cl_int CommandQueue::getInfo(CommandQueueInfo name,
copySize = sizeof(valUInt); copySize = sizeof(valUInt);
break; break;
case CommandQueueInfo::Properties: case CommandQueueInfo::Properties:
copyValue = &mProperties; properties = mProperties->get();
copySize = sizeof(mProperties); copyValue = &properties;
copySize = sizeof(properties);
break; break;
case CommandQueueInfo::PropertiesArray: case CommandQueueInfo::PropertiesArray:
copyValue = mPropArray.data(); copyValue = mPropArray.data();
...@@ -78,7 +80,7 @@ cl_int CommandQueue::getInfo(CommandQueueInfo name, ...@@ -78,7 +80,7 @@ cl_int CommandQueue::getInfo(CommandQueueInfo name,
copySize = sizeof(mSize); copySize = sizeof(mSize);
break; break;
case CommandQueueInfo::DeviceDefault: case CommandQueueInfo::DeviceDefault:
valPointer = CommandQueue::CastNative(mDevice->mDefaultCommandQueue); valPointer = CommandQueue::CastNative(*mDevice->mDefaultCommandQueue);
copyValue = &valPointer; copyValue = &valPointer;
copySize = sizeof(valPointer); copySize = sizeof(valPointer);
break; break;
...@@ -110,23 +112,23 @@ cl_int CommandQueue::setProperty(CommandQueueProperties properties, ...@@ -110,23 +112,23 @@ cl_int CommandQueue::setProperty(CommandQueueProperties properties,
cl_bool enable, cl_bool enable,
cl_command_queue_properties *oldProperties) cl_command_queue_properties *oldProperties)
{ {
auto props = mProperties.synchronize();
if (oldProperties != nullptr) if (oldProperties != nullptr)
{ {
*oldProperties = mProperties.get(); *oldProperties = props->get();
} }
const cl_int result = mImpl->setProperty(properties, enable);
if (result == CL_SUCCESS) ANGLE_CL_TRY(mImpl->setProperty(properties, enable));
if (enable == CL_FALSE)
{ {
if (enable == CL_FALSE) props->clear(properties);
{ }
mProperties.clear(properties); else
} {
else props->set(properties);
{
mProperties.set(properties);
}
} }
return result; return CL_SUCCESS;
} }
cl_int CommandQueue::enqueueReadBuffer(cl_mem buffer, cl_int CommandQueue::enqueueReadBuffer(cl_mem buffer,
...@@ -695,9 +697,10 @@ cl_int CommandQueue::finish() ...@@ -695,9 +697,10 @@ cl_int CommandQueue::finish()
CommandQueue::~CommandQueue() CommandQueue::~CommandQueue()
{ {
if (mDevice->mDefaultCommandQueue == this) auto queue = mDevice->mDefaultCommandQueue.synchronize();
if (*queue == this)
{ {
mDevice->mDefaultCommandQueue = nullptr; *queue = nullptr;
} }
} }
...@@ -720,9 +723,9 @@ CommandQueue::CommandQueue(Context &context, ...@@ -720,9 +723,9 @@ CommandQueue::CommandQueue(Context &context,
mSize(size), mSize(size),
mImpl(context.getImpl().createCommandQueue(*this, errorCode)) mImpl(context.getImpl().createCommandQueue(*this, errorCode))
{ {
if (mProperties.isSet(CL_QUEUE_ON_DEVICE_DEFAULT)) if (mProperties->isSet(CL_QUEUE_ON_DEVICE_DEFAULT))
{ {
mDevice->mDefaultCommandQueue = this; *mDevice->mDefaultCommandQueue = this;
} }
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "libANGLE/CLObject.h" #include "libANGLE/CLObject.h"
#include "libANGLE/renderer/CLCommandQueueImpl.h" #include "libANGLE/renderer/CLCommandQueueImpl.h"
#include "common/SynchronizedValue.h"
#include <limits> #include <limits>
namespace cl namespace cl
...@@ -281,7 +283,7 @@ class CommandQueue final : public _cl_command_queue, public Object ...@@ -281,7 +283,7 @@ class CommandQueue final : public _cl_command_queue, public Object
const ContextPtr mContext; const ContextPtr mContext;
const DevicePtr mDevice; const DevicePtr mDevice;
const PropArray mPropArray; const PropArray mPropArray;
CommandQueueProperties mProperties; angle::SynchronizedValue<CommandQueueProperties> mProperties;
const cl_uint mSize = kNoSize; const cl_uint mSize = kNoSize;
const rx::CLCommandQueueImpl::Ptr mImpl; const rx::CLCommandQueueImpl::Ptr mImpl;
...@@ -305,17 +307,17 @@ inline const Device &CommandQueue::getDevice() const ...@@ -305,17 +307,17 @@ inline const Device &CommandQueue::getDevice() const
inline CommandQueueProperties CommandQueue::getProperties() const inline CommandQueueProperties CommandQueue::getProperties() const
{ {
return mProperties; return *mProperties;
} }
inline bool CommandQueue::isOnHost() const inline bool CommandQueue::isOnHost() const
{ {
return mProperties.isNotSet(CL_QUEUE_ON_DEVICE); return mProperties->isNotSet(CL_QUEUE_ON_DEVICE);
} }
inline bool CommandQueue::isOnDevice() const inline bool CommandQueue::isOnDevice() const
{ {
return mProperties.isSet(CL_QUEUE_ON_DEVICE); return mProperties->isSet(CL_QUEUE_ON_DEVICE);
} }
inline bool CommandQueue::hasSize() const inline bool CommandQueue::hasSize() const
......
...@@ -347,6 +347,8 @@ cl_int Device::createSubDevices(const cl_device_partition_property *properties, ...@@ -347,6 +347,8 @@ cl_int Device::createSubDevices(const cl_device_partition_property *properties,
while (!subDeviceCreateFuncs.empty()) while (!subDeviceCreateFuncs.empty())
{ {
devices.emplace_back(new Device(mPlatform, this, type, subDeviceCreateFuncs.front())); devices.emplace_back(new Device(mPlatform, this, type, subDeviceCreateFuncs.front()));
// Release initialization reference, lifetime controlled by RefPointer.
devices.back()->release();
if (!devices.back()->mInfo.isValid()) if (!devices.back()->mInfo.isValid())
{ {
return CL_INVALID_VALUE; return CL_INVALID_VALUE;
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include "libANGLE/CLObject.h" #include "libANGLE/CLObject.h"
#include "libANGLE/renderer/CLDeviceImpl.h" #include "libANGLE/renderer/CLDeviceImpl.h"
#include "common/Spinlock.h"
#include "common/SynchronizedValue.h"
#include <functional> #include <functional>
namespace cl namespace cl
...@@ -59,7 +62,7 @@ class Device final : public _cl_device_id, public Object ...@@ -59,7 +62,7 @@ class Device final : public _cl_device_id, public Object
const rx::CLDeviceImpl::Ptr mImpl; const rx::CLDeviceImpl::Ptr mImpl;
const rx::CLDeviceImpl::Info mInfo; const rx::CLDeviceImpl::Info mInfo;
CommandQueue *mDefaultCommandQueue = nullptr; angle::SynchronizedValue<CommandQueue *, angle::Spinlock> mDefaultCommandQueue = nullptr;
friend class CommandQueue; friend class CommandQueue;
friend class Platform; friend class Platform;
......
...@@ -91,18 +91,15 @@ cl_int Event::getInfo(EventInfo name, size_t valueSize, void *value, size_t *val ...@@ -91,18 +91,15 @@ cl_int Event::getInfo(EventInfo name, size_t valueSize, void *value, size_t *val
cl_int Event::setCallback(cl_int commandExecCallbackType, EventCB pfnNotify, void *userData) cl_int Event::setCallback(cl_int commandExecCallbackType, EventCB pfnNotify, void *userData)
{ {
auto callbacks = mCallbacks.synchronize();
// Only when required register a single callback with the back end for each callback type. // Only when required register a single callback with the back end for each callback type.
if (mCallbacks[commandExecCallbackType].empty()) if ((*callbacks)[commandExecCallbackType].empty())
{ {
const cl_int errorCode = mImpl->setCallback(*this, commandExecCallbackType); ANGLE_CL_TRY(mImpl->setCallback(*this, commandExecCallbackType));
if (errorCode != CL_SUCCESS)
{
return errorCode;
}
// This event has to be retained until the callback is called. // This event has to be retained until the callback is called.
retain(); retain();
} }
mCallbacks[commandExecCallbackType].emplace_back(pfnNotify, userData); (*callbacks)[commandExecCallbackType].emplace_back(pfnNotify, userData);
return CL_SUCCESS; return CL_SUCCESS;
} }
...@@ -119,7 +116,8 @@ Event::~Event() = default; ...@@ -119,7 +116,8 @@ Event::~Event() = default;
void Event::callback(cl_int commandStatus) void Event::callback(cl_int commandStatus)
{ {
ASSERT(commandStatus >= 0 && commandStatus < 3); ASSERT(commandStatus >= 0 && commandStatus < 3);
for (const CallbackData &data : mCallbacks[commandStatus]) const Callbacks callbacks = std::move(mCallbacks->at(commandStatus));
for (const CallbackData &data : callbacks)
{ {
data.first(this, commandStatus, data.second); data.first(this, commandStatus, data.second);
} }
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "libANGLE/CLObject.h" #include "libANGLE/CLObject.h"
#include "libANGLE/renderer/CLEventImpl.h" #include "libANGLE/renderer/CLEventImpl.h"
#include "common/SynchronizedValue.h"
#include <array> #include <array>
namespace cl namespace cl
...@@ -51,6 +53,7 @@ class Event final : public _cl_event, public Object ...@@ -51,6 +53,7 @@ class Event final : public _cl_event, public Object
private: private:
using CallbackData = std::pair<EventCB, void *>; using CallbackData = std::pair<EventCB, void *>;
using Callbacks = std::vector<CallbackData>;
Event(Context &context, cl_int &errorCode); Event(Context &context, cl_int &errorCode);
...@@ -69,7 +72,7 @@ class Event final : public _cl_event, public Object ...@@ -69,7 +72,7 @@ class Event final : public _cl_event, public Object
// Create separate storage for each possible callback type. // Create separate storage for each possible callback type.
static_assert(CL_COMPLETE == 0 && CL_RUNNING == 1 && CL_SUBMITTED == 2, static_assert(CL_COMPLETE == 0 && CL_RUNNING == 1 && CL_SUBMITTED == 2,
"OpenCL command execution status values are not as assumed"); "OpenCL command execution status values are not as assumed");
std::array<std::vector<CallbackData>, 3u> mCallbacks; angle::SynchronizedValue<std::array<Callbacks, 3u>> mCallbacks;
friend class Object; friend class Object;
}; };
......
...@@ -45,7 +45,7 @@ MemFlags InheritMemFlags(MemFlags flags, Memory *parent) ...@@ -45,7 +45,7 @@ MemFlags InheritMemFlags(MemFlags flags, Memory *parent)
cl_int Memory::setDestructorCallback(MemoryCB pfnNotify, void *userData) cl_int Memory::setDestructorCallback(MemoryCB pfnNotify, void *userData)
{ {
mDestructorCallbacks.emplace(pfnNotify, userData); mDestructorCallbacks->emplace(pfnNotify, userData);
return CL_SUCCESS; return CL_SUCCESS;
} }
...@@ -80,8 +80,9 @@ cl_int Memory::getInfo(MemInfo name, size_t valueSize, void *value, size_t *valu ...@@ -80,8 +80,9 @@ cl_int Memory::getInfo(MemInfo name, size_t valueSize, void *value, size_t *valu
copySize = sizeof(mHostPtr); copySize = sizeof(mHostPtr);
break; break;
case MemInfo::MapCount: case MemInfo::MapCount:
copyValue = &mMapCount; valUInt = mMapCount;
copySize = sizeof(mMapCount); copyValue = &valUInt;
copySize = sizeof(valUInt);
break; break;
case MemInfo::ReferenceCount: case MemInfo::ReferenceCount:
valUInt = getRefCount(); valUInt = getRefCount();
...@@ -137,11 +138,13 @@ cl_int Memory::getInfo(MemInfo name, size_t valueSize, void *value, size_t *valu ...@@ -137,11 +138,13 @@ cl_int Memory::getInfo(MemInfo name, size_t valueSize, void *value, size_t *valu
Memory::~Memory() Memory::~Memory()
{ {
while (!mDestructorCallbacks.empty()) std::stack<CallbackData> callbacks;
mDestructorCallbacks->swap(callbacks);
while (!callbacks.empty())
{ {
const MemoryCB callback = mDestructorCallbacks.top().first; const MemoryCB callback = callbacks.top().first;
void *const userData = mDestructorCallbacks.top().second; void *const userData = callbacks.top().second;
mDestructorCallbacks.pop(); callbacks.pop();
callback(this, userData); callback(this, userData);
} }
} }
...@@ -158,7 +161,8 @@ Memory::Memory(const Buffer &buffer, ...@@ -158,7 +161,8 @@ Memory::Memory(const Buffer &buffer,
mFlags(flags), mFlags(flags),
mHostPtr(flags.isSet(CL_MEM_USE_HOST_PTR) ? hostPtr : nullptr), mHostPtr(flags.isSet(CL_MEM_USE_HOST_PTR) ? hostPtr : nullptr),
mImpl(context.getImpl().createBuffer(buffer, size, hostPtr, errorCode)), mImpl(context.getImpl().createBuffer(buffer, size, hostPtr, errorCode)),
mSize(size) mSize(size),
mMapCount(0u)
{} {}
Memory::Memory(const Buffer &buffer, Memory::Memory(const Buffer &buffer,
...@@ -174,7 +178,8 @@ Memory::Memory(const Buffer &buffer, ...@@ -174,7 +178,8 @@ Memory::Memory(const Buffer &buffer,
mParent(&parent), mParent(&parent),
mOffset(offset), mOffset(offset),
mImpl(parent.mImpl->createSubBuffer(buffer, flags, size, errorCode)), mImpl(parent.mImpl->createSubBuffer(buffer, flags, size, errorCode)),
mSize(size) mSize(size),
mMapCount(0u)
{} {}
Memory::Memory(const Image &image, Memory::Memory(const Image &image,
...@@ -192,7 +197,8 @@ Memory::Memory(const Image &image, ...@@ -192,7 +197,8 @@ Memory::Memory(const Image &image,
mHostPtr(flags.isSet(CL_MEM_USE_HOST_PTR) ? hostPtr : nullptr), mHostPtr(flags.isSet(CL_MEM_USE_HOST_PTR) ? hostPtr : nullptr),
mParent(parent), mParent(parent),
mImpl(context.getImpl().createImage(image, flags, format, desc, hostPtr, errorCode)), mImpl(context.getImpl().createImage(image, flags, format, desc, hostPtr, errorCode)),
mSize(mImpl ? mImpl->getSize(errorCode) : 0u) mSize(mImpl ? mImpl->getSize(errorCode) : 0u),
mMapCount(0u)
{} {}
} // namespace cl } // namespace cl
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
#include "libANGLE/CLObject.h" #include "libANGLE/CLObject.h"
#include "libANGLE/renderer/CLMemoryImpl.h" #include "libANGLE/renderer/CLMemoryImpl.h"
#include "common/Spinlock.h"
#include "common/SynchronizedValue.h"
#include <atomic>
#include <stack> #include <stack>
namespace cl namespace cl
...@@ -83,8 +87,8 @@ class Memory : public _cl_mem, public Object ...@@ -83,8 +87,8 @@ class Memory : public _cl_mem, public Object
const rx::CLMemoryImpl::Ptr mImpl; const rx::CLMemoryImpl::Ptr mImpl;
const size_t mSize; const size_t mSize;
std::stack<CallbackData> mDestructorCallbacks; angle::SynchronizedValue<std::stack<CallbackData>, angle::Spinlock> mDestructorCallbacks;
cl_uint mMapCount = 0u; std::atomic<cl_uint> mMapCount;
friend class Buffer; friend class Buffer;
friend class Context; friend class Context;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
namespace cl namespace cl
{ {
Object::Object() : mRefCount(0u) {} Object::Object() : mRefCount(1u) {}
Object::~Object() Object::~Object()
{ {
......
...@@ -39,8 +39,13 @@ class Object ...@@ -39,8 +39,13 @@ class Object
template <typename T, typename... Args> template <typename T, typename... Args>
static T *Create(cl_int &errorCode, Args &&... args) static T *Create(cl_int &errorCode, Args &&... args)
{ {
RefPointer<T> object(new T(std::forward<Args>(args)..., errorCode)); T *object = new T(std::forward<Args>(args)..., errorCode);
return errorCode == CL_SUCCESS ? object.release() : nullptr; if (errorCode != CL_SUCCESS)
{
delete object;
object = nullptr;
}
return object;
} }
private: private:
......
...@@ -76,6 +76,8 @@ void Platform::Initialize(const cl_icd_dispatch &dispatch, ...@@ -76,6 +76,8 @@ void Platform::Initialize(const cl_icd_dispatch &dispatch,
while (!createFuncs.empty()) while (!createFuncs.empty())
{ {
platforms.emplace_back(new Platform(createFuncs.front())); platforms.emplace_back(new Platform(createFuncs.front()));
// Release initialization reference, lifetime controlled by RefPointer.
platforms.back()->release();
if (!platforms.back()->mInfo.isValid() || platforms.back()->mDevices.empty()) if (!platforms.back()->mInfo.isValid() || platforms.back()->mDevices.empty())
{ {
platforms.pop_back(); platforms.pop_back();
...@@ -264,6 +266,8 @@ DevicePtrs Platform::createDevices(rx::CLDeviceImpl::CreateDatas &&createDatas) ...@@ -264,6 +266,8 @@ DevicePtrs Platform::createDevices(rx::CLDeviceImpl::CreateDatas &&createDatas)
{ {
devices.emplace_back( devices.emplace_back(
new Device(*this, nullptr, createDatas.front().first, createDatas.front().second)); new Device(*this, nullptr, createDatas.front().first, createDatas.front().second));
// Release initialization reference, lifetime controlled by RefPointer.
devices.back()->release();
if (!devices.back()->mInfo.isValid()) if (!devices.back()->mInfo.isValid())
{ {
devices.pop_back(); devices.pop_back();
......
...@@ -32,9 +32,8 @@ cl_int Program::build(cl_uint numDevices, ...@@ -32,9 +32,8 @@ cl_int Program::build(cl_uint numDevices,
{ {
// This program has to be retained until the notify callback is called. // This program has to be retained until the notify callback is called.
retain(); retain();
mCallback = pfnNotify; *mCallback = CallbackData(pfnNotify, userData);
mUserData = userData; notify = this;
notify = this;
} }
return mImpl->build(devices, options, notify); return mImpl->build(devices, options, notify);
} }
...@@ -65,9 +64,8 @@ cl_int Program::compile(cl_uint numDevices, ...@@ -65,9 +64,8 @@ cl_int Program::compile(cl_uint numDevices,
{ {
// This program has to be retained until the notify callback is called. // This program has to be retained until the notify callback is called.
retain(); retain();
mCallback = pfnNotify; *mCallback = CallbackData(pfnNotify, userData);
mUserData = userData; notify = this;
notify = this;
} }
return mImpl->compile(devices, options, programs, headerIncludeNames, notify); return mImpl->compile(devices, options, programs, headerIncludeNames, notify);
} }
...@@ -192,11 +190,11 @@ Program::~Program() = default; ...@@ -192,11 +190,11 @@ Program::~Program() = default;
void Program::callback() void Program::callback()
{ {
ASSERT(mCallback != nullptr); CallbackData callbackData;
const ProgramCB callback = mCallback; mCallback->swap(callbackData);
void *const userData = mUserData; const ProgramCB callback = callbackData.first;
mCallback = nullptr; void *const userData = callbackData.second;
mUserData = nullptr; ASSERT(callback != nullptr);
callback(this, userData); callback(this, userData);
// This program can be released after the callback was called. // This program can be released after the callback was called.
if (release()) if (release())
...@@ -208,18 +206,18 @@ void Program::callback() ...@@ -208,18 +206,18 @@ void Program::callback()
Program::Program(Context &context, std::string &&source, cl_int &errorCode) Program::Program(Context &context, std::string &&source, cl_int &errorCode)
: mContext(&context), : mContext(&context),
mDevices(context.getDevices()), mDevices(context.getDevices()),
mNumAttachedKernels(0u),
mImpl(context.getImpl().createProgramWithSource(*this, source, errorCode)), mImpl(context.getImpl().createProgramWithSource(*this, source, errorCode)),
mSource(std::move(source)), mSource(std::move(source))
mNumAttachedKernels(0u)
{} {}
Program::Program(Context &context, const void *il, size_t length, cl_int &errorCode) Program::Program(Context &context, const void *il, size_t length, cl_int &errorCode)
: mContext(&context), : mContext(&context),
mDevices(context.getDevices()), mDevices(context.getDevices()),
mIL(static_cast<const char *>(il), length), mIL(static_cast<const char *>(il), length),
mNumAttachedKernels(0u),
mImpl(context.getImpl().createProgramWithIL(*this, il, length, errorCode)), mImpl(context.getImpl().createProgramWithIL(*this, il, length, errorCode)),
mSource(mImpl ? mImpl->getSource(errorCode) : std::string{}), mSource(mImpl ? mImpl->getSource(errorCode) : std::string{})
mNumAttachedKernels(0u)
{} {}
Program::Program(Context &context, Program::Program(Context &context,
...@@ -230,18 +228,18 @@ Program::Program(Context &context, ...@@ -230,18 +228,18 @@ Program::Program(Context &context,
cl_int &errorCode) cl_int &errorCode)
: mContext(&context), : mContext(&context),
mDevices(std::move(devices)), mDevices(std::move(devices)),
mNumAttachedKernels(0u),
mImpl(context.getImpl() mImpl(context.getImpl()
.createProgramWithBinary(*this, lengths, binaries, binaryStatus, errorCode)), .createProgramWithBinary(*this, lengths, binaries, binaryStatus, errorCode)),
mSource(mImpl ? mImpl->getSource(errorCode) : std::string{}), mSource(mImpl ? mImpl->getSource(errorCode) : std::string{})
mNumAttachedKernels(0u)
{} {}
Program::Program(Context &context, DevicePtrs &&devices, const char *kernelNames, cl_int &errorCode) Program::Program(Context &context, DevicePtrs &&devices, const char *kernelNames, cl_int &errorCode)
: mContext(&context), : mContext(&context),
mDevices(std::move(devices)), mDevices(std::move(devices)),
mNumAttachedKernels(0u),
mImpl(context.getImpl().createProgramWithBuiltInKernels(*this, kernelNames, errorCode)), mImpl(context.getImpl().createProgramWithBuiltInKernels(*this, kernelNames, errorCode)),
mSource(mImpl ? mImpl->getSource(errorCode) : std::string{}), mSource(mImpl ? mImpl->getSource(errorCode) : std::string{})
mNumAttachedKernels(0u)
{} {}
Program::Program(Context &context, Program::Program(Context &context,
...@@ -253,22 +251,17 @@ Program::Program(Context &context, ...@@ -253,22 +251,17 @@ Program::Program(Context &context,
cl_int &errorCode) cl_int &errorCode)
: mContext(&context), : mContext(&context),
mDevices(!devices.empty() ? devices : context.getDevices()), mDevices(!devices.empty() ? devices : context.getDevices()),
// This program has to be retained until the notify callback is called.
mCallback(pfnNotify != nullptr ? (retain(), CallbackData(pfnNotify, userData))
: CallbackData()),
mNumAttachedKernels(0u),
mImpl(context.getImpl().linkProgram(*this, mImpl(context.getImpl().linkProgram(*this,
devices, devices,
options, options,
inputPrograms, inputPrograms,
pfnNotify != nullptr ? this : nullptr, pfnNotify != nullptr ? this : nullptr,
errorCode)), errorCode)),
mSource(mImpl ? mImpl->getSource(errorCode) : std::string{}), mSource(mImpl ? mImpl->getSource(errorCode) : std::string{})
mCallback(pfnNotify), {}
mUserData(userData),
mNumAttachedKernels(0u)
{
if (mCallback != nullptr)
{
// This program has to be retained until the notify callback is called.
retain();
}
}
} // namespace cl } // namespace cl
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include "libANGLE/CLKernel.h" #include "libANGLE/CLKernel.h"
#include "libANGLE/renderer/CLProgramImpl.h" #include "libANGLE/renderer/CLProgramImpl.h"
#include "common/Spinlock.h"
#include "common/SynchronizedValue.h"
#include <atomic> #include <atomic>
namespace cl namespace cl
...@@ -86,17 +89,20 @@ class Program final : public _cl_program, public Object ...@@ -86,17 +89,20 @@ class Program final : public _cl_program, public Object
void *userData, void *userData,
cl_int &errorCode); cl_int &errorCode);
using CallbackData = std::pair<ProgramCB, void *>;
const ContextPtr mContext; const ContextPtr mContext;
const DevicePtrs mDevices; const DevicePtrs mDevices;
const std::string mIL; const std::string mIL;
const rx::CLProgramImpl::Ptr mImpl;
const std::string mSource;
ProgramCB mCallback = nullptr;
void *mUserData = nullptr;
// mCallback might be accessed from implementation initialization
// and needs to be initialized first.
angle::SynchronizedValue<CallbackData, angle::Spinlock> mCallback;
std::atomic<cl_uint> mNumAttachedKernels; std::atomic<cl_uint> mNumAttachedKernels;
const rx::CLProgramImpl::Ptr mImpl;
const std::string mSource;
friend class Kernel; friend class Kernel;
friend class Object; friend class Object;
}; };
...@@ -123,7 +129,7 @@ inline bool Program::hasDevice(const _cl_device_id *device) const ...@@ -123,7 +129,7 @@ inline bool Program::hasDevice(const _cl_device_id *device) const
inline bool Program::isBuilding() const inline bool Program::isBuilding() const
{ {
return mCallback != nullptr; return mCallback->first != nullptr;
} }
inline bool Program::hasAttachedKernels() const inline bool Program::hasAttachedKernels() const
......
...@@ -42,7 +42,7 @@ CLCommandQueueCL::CLCommandQueueCL(const cl::CommandQueue &commandQueue, cl_comm ...@@ -42,7 +42,7 @@ CLCommandQueueCL::CLCommandQueueCL(const cl::CommandQueue &commandQueue, cl_comm
{ {
if (commandQueue.getProperties().isSet(CL_QUEUE_ON_DEVICE)) if (commandQueue.getProperties().isSet(CL_QUEUE_ON_DEVICE))
{ {
commandQueue.getContext().getImpl<CLContextCL>().mDeviceQueues.emplace( commandQueue.getContext().getImpl<CLContextCL>().mData->mDeviceQueues.emplace(
commandQueue.getNative()); commandQueue.getNative());
} }
} }
...@@ -52,7 +52,7 @@ CLCommandQueueCL::~CLCommandQueueCL() ...@@ -52,7 +52,7 @@ CLCommandQueueCL::~CLCommandQueueCL()
if (mCommandQueue.getProperties().isSet(CL_QUEUE_ON_DEVICE)) if (mCommandQueue.getProperties().isSet(CL_QUEUE_ON_DEVICE))
{ {
const size_t numRemoved = const size_t numRemoved =
mCommandQueue.getContext().getImpl<CLContextCL>().mDeviceQueues.erase( mCommandQueue.getContext().getImpl<CLContextCL>().mData->mDeviceQueues.erase(
mCommandQueue.getNative()); mCommandQueue.getNative());
ASSERT(numRemoved == 1u); ASSERT(numRemoved == 1u);
} }
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include "libANGLE/renderer/CLContextImpl.h" #include "libANGLE/renderer/CLContextImpl.h"
#include "common/Spinlock.h"
#include "common/SynchronizedValue.h"
#include <unordered_set> #include <unordered_set>
namespace rx namespace rx
...@@ -83,11 +86,16 @@ class CLContextCL : public CLContextImpl ...@@ -83,11 +86,16 @@ class CLContextCL : public CLContextImpl
cl_int waitForEvents(const cl::EventPtrs &events) override; cl_int waitForEvents(const cl::EventPtrs &events) override;
private: private:
const cl_context mNative; struct Mutable
{
std::unordered_set<const _cl_mem *> mMemories;
std::unordered_set<const _cl_sampler *> mSamplers;
std::unordered_set<const _cl_command_queue *> mDeviceQueues;
};
using MutableData = angle::SynchronizedValue<Mutable, angle::Spinlock>;
std::unordered_set<const _cl_mem *> mMemories; const cl_context mNative;
std::unordered_set<const _cl_sampler *> mSamplers; MutableData mData;
std::unordered_set<const _cl_command_queue *> mDeviceQueues;
friend class CLCommandQueueCL; friend class CLCommandQueueCL;
friend class CLMemoryCL; friend class CLMemoryCL;
...@@ -96,17 +104,20 @@ class CLContextCL : public CLContextImpl ...@@ -96,17 +104,20 @@ class CLContextCL : public CLContextImpl
inline bool CLContextCL::hasMemory(cl_mem memory) const inline bool CLContextCL::hasMemory(cl_mem memory) const
{ {
return mMemories.find(memory) != mMemories.cend(); const auto data = mData.synchronize();
return data->mMemories.find(memory) != data->mMemories.cend();
} }
inline bool CLContextCL::hasSampler(cl_sampler sampler) const inline bool CLContextCL::hasSampler(cl_sampler sampler) const
{ {
return mSamplers.find(sampler) != mSamplers.cend(); const auto data = mData.synchronize();
return data->mSamplers.find(sampler) != data->mSamplers.cend();
} }
inline bool CLContextCL::hasDeviceQueue(cl_command_queue queue) const inline bool CLContextCL::hasDeviceQueue(cl_command_queue queue) const
{ {
return mDeviceQueues.find(queue) != mDeviceQueues.cend(); const auto data = mData.synchronize();
return data->mDeviceQueues.find(queue) != data->mDeviceQueues.cend();
} }
} // namespace rx } // namespace rx
......
...@@ -18,13 +18,13 @@ namespace rx ...@@ -18,13 +18,13 @@ namespace rx
CLMemoryCL::CLMemoryCL(const cl::Memory &memory, cl_mem native) CLMemoryCL::CLMemoryCL(const cl::Memory &memory, cl_mem native)
: CLMemoryImpl(memory), mNative(native) : CLMemoryImpl(memory), mNative(native)
{ {
memory.getContext().getImpl<CLContextCL>().mMemories.emplace(memory.getNative()); memory.getContext().getImpl<CLContextCL>().mData->mMemories.emplace(memory.getNative());
} }
CLMemoryCL::~CLMemoryCL() CLMemoryCL::~CLMemoryCL()
{ {
const size_t numRemoved = const size_t numRemoved =
mMemory.getContext().getImpl<CLContextCL>().mMemories.erase(mMemory.getNative()); mMemory.getContext().getImpl<CLContextCL>().mData->mMemories.erase(mMemory.getNative());
ASSERT(numRemoved == 1u); ASSERT(numRemoved == 1u);
if (mNative->getDispatch().clReleaseMemObject(mNative) != CL_SUCCESS) if (mNative->getDispatch().clReleaseMemObject(mNative) != CL_SUCCESS)
......
...@@ -18,13 +18,13 @@ namespace rx ...@@ -18,13 +18,13 @@ namespace rx
CLSamplerCL::CLSamplerCL(const cl::Sampler &sampler, cl_sampler native) CLSamplerCL::CLSamplerCL(const cl::Sampler &sampler, cl_sampler native)
: CLSamplerImpl(sampler), mNative(native) : CLSamplerImpl(sampler), mNative(native)
{ {
sampler.getContext().getImpl<CLContextCL>().mSamplers.emplace(sampler.getNative()); sampler.getContext().getImpl<CLContextCL>().mData->mSamplers.emplace(sampler.getNative());
} }
CLSamplerCL::~CLSamplerCL() CLSamplerCL::~CLSamplerCL()
{ {
const size_t numRemoved = const size_t numRemoved =
mSampler.getContext().getImpl<CLContextCL>().mSamplers.erase(mSampler.getNative()); mSampler.getContext().getImpl<CLContextCL>().mData->mSamplers.erase(mSampler.getNative());
ASSERT(numRemoved == 1u); ASSERT(numRemoved == 1u);
if (mNative->getDispatch().clReleaseSampler(mNative) != CL_SUCCESS) if (mNative->getDispatch().clReleaseSampler(mNative) != CL_SUCCESS)
......
...@@ -19,6 +19,8 @@ libangle_common_sources = [ ...@@ -19,6 +19,8 @@ libangle_common_sources = [
"src/common/PackedGLEnums_autogen.h", "src/common/PackedGLEnums_autogen.h",
"src/common/PoolAlloc.cpp", "src/common/PoolAlloc.cpp",
"src/common/PoolAlloc.h", "src/common/PoolAlloc.h",
"src/common/Spinlock.h",
"src/common/SynchronizedValue.h",
"src/common/aligned_memory.cpp", "src/common/aligned_memory.cpp",
"src/common/aligned_memory.h", "src/common/aligned_memory.h",
"src/common/android_util.cpp", "src/common/android_util.cpp",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment