xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/CLEventVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // CLEventVk.cpp: Implements the class methods for CLEventVk.
7 
8 #include "libANGLE/renderer/vulkan/CLEventVk.h"
9 #include "libANGLE/renderer/vulkan/CLCommandQueueVk.h"
10 
11 #include "libANGLE/cl_utils.h"
12 
13 namespace rx
14 {
15 
CLEventVk(const cl::Event & event)16 CLEventVk::CLEventVk(const cl::Event &event)
17     : CLEventImpl(event),
18       mStatus(isUserEvent() ? CL_SUBMITTED : CL_QUEUED),
19       mProfilingTimestamps(ProfilingTimestamps{})
20 {
21     ANGLE_CL_IMPL_TRY(setTimestamp(*mStatus));
22 }
23 
~CLEventVk()24 CLEventVk::~CLEventVk() {}
25 
getCommandExecutionStatus(cl_int & executionStatus)26 angle::Result CLEventVk::getCommandExecutionStatus(cl_int &executionStatus)
27 {
28     executionStatus = *mStatus;
29     return angle::Result::Continue;
30 }
31 
setUserEventStatus(cl_int executionStatus)32 angle::Result CLEventVk::setUserEventStatus(cl_int executionStatus)
33 {
34     ASSERT(isUserEvent());
35 
36     // Not much to do here other than storing the user supplied state.
37     // Error checking and single call enforcement is responsibility of the front end.
38     ANGLE_TRY(setStatusAndExecuteCallback(executionStatus));
39 
40     // User event set and callback(s) finished - notify those waiting
41     mUserEventCondition.notify_all();
42 
43     return angle::Result::Continue;
44 }
45 
setCallback(cl::Event & event,cl_int commandExecCallbackType)46 angle::Result CLEventVk::setCallback(cl::Event &event, cl_int commandExecCallbackType)
47 {
48     ASSERT(commandExecCallbackType >= CL_COMPLETE);
49     ASSERT(commandExecCallbackType < CL_QUEUED);
50 
51     // Not much to do, acknowledge the presence of callback and returns
52     mHaveCallbacks->at(commandExecCallbackType) = true;
53 
54     return angle::Result::Continue;
55 }
56 
getProfilingInfo(cl::ProfilingInfo name,size_t valueSize,void * value,size_t * valueSizeRet)57 angle::Result CLEventVk::getProfilingInfo(cl::ProfilingInfo name,
58                                           size_t valueSize,
59                                           void *value,
60                                           size_t *valueSizeRet)
61 {
62     cl_ulong valueUlong   = 0;
63     size_t copySize       = 0;
64     const void *copyValue = nullptr;
65 
66     auto profilingTimestamps = mProfilingTimestamps.synchronize();
67 
68     switch (name)
69     {
70         case cl::ProfilingInfo::CommandQueued:
71             valueUlong = profilingTimestamps->commandQueuedTS;
72             break;
73         case cl::ProfilingInfo::CommandSubmit:
74             valueUlong = profilingTimestamps->commandSubmitTS;
75             break;
76         case cl::ProfilingInfo::CommandStart:
77             valueUlong = profilingTimestamps->commandStartTS;
78             break;
79         case cl::ProfilingInfo::CommandEnd:
80             valueUlong = profilingTimestamps->commandEndTS;
81             break;
82         case cl::ProfilingInfo::CommandComplete:
83             valueUlong = profilingTimestamps->commandCompleteTS;
84             break;
85         default:
86             UNREACHABLE();
87     }
88     copyValue = &valueUlong;
89     copySize  = sizeof(valueUlong);
90 
91     if ((value != nullptr) && (copyValue != nullptr))
92     {
93         memcpy(value, copyValue, std::min(valueSize, copySize));
94     }
95 
96     if (valueSizeRet != nullptr)
97     {
98         *valueSizeRet = copySize;
99     }
100 
101     return angle::Result::Continue;
102 }
103 
waitForUserEventStatus()104 angle::Result CLEventVk::waitForUserEventStatus()
105 {
106     ASSERT(isUserEvent());
107 
108     cl_int status = CL_QUEUED;
109     std::unique_lock<std::mutex> ul(mUserEventMutex);
110     ANGLE_TRY(getCommandExecutionStatus(status));
111     if (status > CL_COMPLETE)
112     {
113         // User is responsible for setting the user-event object, we need to wait for that event
114         // (We dont care what the outcome is, just need to wait until that event triggers)
115         INFO() << "Waiting for user-event (" << &mEvent
116                << ") to be set! (aka clSetUserEventStatus)";
117         mUserEventCondition.wait(ul);
118     }
119 
120     return angle::Result::Continue;
121 }
122 
setStatusAndExecuteCallback(cl_int status)123 angle::Result CLEventVk::setStatusAndExecuteCallback(cl_int status)
124 {
125     *mStatus = status;
126 
127     ANGLE_TRY(setTimestamp(status));
128     if (status >= CL_COMPLETE && status < CL_QUEUED && mHaveCallbacks->at(status))
129     {
130         auto haveCallbacks = mHaveCallbacks.synchronize();
131 
132         // Sanity check, callback(s) only from this exec status should be outstanding
133         ASSERT(std::count(haveCallbacks->begin() + status, haveCallbacks->end(), true) == 1);
134 
135         getFrontendObject().callback(status);
136         haveCallbacks->at(status) = false;
137     }
138 
139     return angle::Result::Continue;
140 }
141 
setTimestamp(cl_int status)142 angle::Result CLEventVk::setTimestamp(cl_int status)
143 {
144     if (!isUserEvent() &&
145         mEvent.getCommandQueue()->getProperties().intersects(CL_QUEUE_PROFILING_ENABLE))
146     {
147         // TODO(aannestrand) Just get current CPU timestamp for now, look into Vulkan GPU device
148         // timestamp query instead and later make CPU timestamp a fallback if GPU timestamp cannot
149         // be queried http://anglebug.com/357902514
150         cl_ulong cpuTS =
151             std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now())
152                 .time_since_epoch()
153                 .count();
154 
155         auto profilingTimestamps = mProfilingTimestamps.synchronize();
156 
157         switch (status)
158         {
159             case CL_QUEUED:
160                 profilingTimestamps->commandQueuedTS = cpuTS;
161                 break;
162             case CL_SUBMITTED:
163                 profilingTimestamps->commandSubmitTS = cpuTS;
164                 break;
165             case CL_RUNNING:
166                 profilingTimestamps->commandStartTS = cpuTS;
167                 break;
168             case CL_COMPLETE:
169                 profilingTimestamps->commandEndTS = cpuTS;
170 
171                 // Returns a value equivalent to passing CL_PROFILING_COMMAND_END if the device
172                 // associated with event does not support device-side enqueue.
173                 // https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#_device_side_enqueue
174                 profilingTimestamps->commandCompleteTS = cpuTS;
175                 break;
176             default:
177                 UNREACHABLE();
178         }
179     }
180 
181     return angle::Result::Continue;
182 }
183 
184 }  // namespace rx
185