1//
2// Copyright 2021 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// CLEvent.cpp: Implements the cl::Event class.
7
8#include "libANGLE/CLEvent.h"
9
10#include "libANGLE/CLCommandQueue.h"
11#include "libANGLE/CLContext.h"
12
13#include <cstring>
14
15namespace cl
16{
17
18cl_int Event::setUserEventStatus(cl_int executionStatus)
19{
20    const cl_int errorCode = mImpl->setUserEventStatus(executionStatus);
21    if (errorCode == CL_SUCCESS)
22    {
23        mStatusWasChanged = true;
24    }
25    return errorCode;
26}
27
28cl_int Event::getInfo(EventInfo name, size_t valueSize, void *value, size_t *valueSizeRet) const
29{
30    cl_int execStatus     = 0;
31    cl_uint valUInt       = 0u;
32    void *valPointer      = nullptr;
33    const void *copyValue = nullptr;
34    size_t copySize       = 0u;
35
36    switch (name)
37    {
38        case EventInfo::CommandQueue:
39            valPointer = CommandQueue::CastNative(mCommandQueue.get());
40            copyValue  = &valPointer;
41            copySize   = sizeof(valPointer);
42            break;
43        case EventInfo::CommandType:
44            copyValue = &mCommandType;
45            copySize  = sizeof(mCommandType);
46            break;
47        case EventInfo::ReferenceCount:
48            valUInt   = getRefCount();
49            copyValue = &valUInt;
50            copySize  = sizeof(valUInt);
51            break;
52        case EventInfo::CommandExecutionStatus:
53        {
54            const cl_int errorCode = mImpl->getCommandExecutionStatus(execStatus);
55            if (errorCode != CL_SUCCESS)
56            {
57                return errorCode;
58            }
59            copyValue = &execStatus;
60            copySize  = sizeof(execStatus);
61            break;
62        }
63        case EventInfo::Context:
64            valPointer = mContext->getNative();
65            copyValue  = &valPointer;
66            copySize   = sizeof(valPointer);
67            break;
68        default:
69            return CL_INVALID_VALUE;
70    }
71
72    if (value != nullptr)
73    {
74        // CL_INVALID_VALUE if size in bytes specified by param_value_size is < size of return type
75        // as described in the Event Queries table and param_value is not NULL.
76        if (valueSize < copySize)
77        {
78            return CL_INVALID_VALUE;
79        }
80        if (copyValue != nullptr)
81        {
82            std::memcpy(value, copyValue, copySize);
83        }
84    }
85    if (valueSizeRet != nullptr)
86    {
87        *valueSizeRet = copySize;
88    }
89    return CL_SUCCESS;
90}
91
92cl_int Event::setCallback(cl_int commandExecCallbackType, EventCB pfnNotify, void *userData)
93{
94    auto callbacks = mCallbacks.synchronize();
95    // Only when required register a single callback with the back end for each callback type.
96    if ((*callbacks)[commandExecCallbackType].empty())
97    {
98        ANGLE_CL_TRY(mImpl->setCallback(*this, commandExecCallbackType));
99        // This event has to be retained until the callback is called.
100        retain();
101    }
102    (*callbacks)[commandExecCallbackType].emplace_back(pfnNotify, userData);
103    return CL_SUCCESS;
104}
105
106cl_int Event::getProfilingInfo(ProfilingInfo name,
107                               size_t valueSize,
108                               void *value,
109                               size_t *valueSizeRet)
110{
111    return mImpl->getProfilingInfo(name, valueSize, value, valueSizeRet);
112}
113
114Event::~Event() = default;
115
116void Event::callback(cl_int commandStatus)
117{
118    ASSERT(commandStatus >= 0 && commandStatus < 3);
119    const Callbacks callbacks = std::move(mCallbacks->at(commandStatus));
120    for (const CallbackData &data : callbacks)
121    {
122        data.first(this, commandStatus, data.second);
123    }
124    // This event can be released after the callback was called.
125    if (release())
126    {
127        delete this;
128    }
129}
130
131EventPtrs Event::Cast(cl_uint numEvents, const cl_event *eventList)
132{
133    EventPtrs events;
134    events.reserve(numEvents);
135    while (numEvents-- != 0u)
136    {
137        events.emplace_back(&(*eventList++)->cast<Event>());
138    }
139    return events;
140}
141
142Event::Event(Context &context, cl_int &errorCode)
143    : mContext(&context),
144      mCommandType(CL_COMMAND_USER),
145      mImpl(context.getImpl().createUserEvent(*this, errorCode))
146{}
147
148Event::Event(CommandQueue &queue,
149             cl_command_type commandType,
150             const rx::CLEventImpl::CreateFunc &createFunc,
151             cl_int &errorCode)
152    : mContext(&queue.getContext()),
153      mCommandQueue(&queue),
154      mCommandType(commandType),
155      mImpl(createFunc(*this))
156{}
157
158}  // namespace cl
159