• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,const cl::ExecutionStatus initialStatus,const QueueSerial eventSerial)16 CLEventVk::CLEventVk(const cl::Event &event,
17                      const cl::ExecutionStatus initialStatus,
18                      const QueueSerial eventSerial)
19     : CLEventImpl(event),
20       mStatus(cl::ToCLenum(initialStatus)),
21       mProfilingTimestamps(ProfilingTimestamps{}),
22       mQueueSerial(eventSerial)
23 {
24     ANGLE_CL_IMPL_TRY(setTimestamp(*mStatus));
25 }
26 
~CLEventVk()27 CLEventVk::~CLEventVk() {}
28 
onEventCreate()29 angle::Result CLEventVk::onEventCreate()
30 {
31     ASSERT(!isUserEvent());
32     ASSERT(mQueueSerial.valid());
33 
34     if (cl::FromCLenum<cl::ExecutionStatus>(*mStatus) == cl::ExecutionStatus::Complete)
35     {
36         // Submission finished at this point, just set event to complete
37         ANGLE_TRY(setStatusAndExecuteCallback(CL_COMPLETE));
38     }
39     else
40     {
41         getFrontendObject().getCommandQueue()->getImpl<CLCommandQueueVk>().addEventReference(*this);
42         if (getFrontendObject().getCommandQueue()->getProperties().intersects(
43                 CL_QUEUE_PROFILING_ENABLE))
44         {
45             // Block for profiling so that we get timestamps per-command
46             ANGLE_TRY(getFrontendObject().getCommandQueue()->getImpl<CLCommandQueueVk>().finish());
47         }
48     }
49     return angle::Result::Continue;
50 }
51 
getCommandExecutionStatus(cl_int & executionStatus)52 angle::Result CLEventVk::getCommandExecutionStatus(cl_int &executionStatus)
53 {
54     executionStatus = *mStatus;
55     return angle::Result::Continue;
56 }
57 
setUserEventStatus(cl_int executionStatus)58 angle::Result CLEventVk::setUserEventStatus(cl_int executionStatus)
59 {
60     ASSERT(isUserEvent());
61 
62     // Not much to do here other than storing the user supplied state.
63     // Error checking and single call enforcement is responsibility of the front end.
64     ANGLE_TRY(setStatusAndExecuteCallback(executionStatus));
65 
66     // User event set and callback(s) finished - notify those waiting
67     mUserEventCondition.notify_all();
68 
69     return angle::Result::Continue;
70 }
71 
setCallback(cl::Event & event,cl_int commandExecCallbackType)72 angle::Result CLEventVk::setCallback(cl::Event &event, cl_int commandExecCallbackType)
73 {
74     ASSERT(commandExecCallbackType >= CL_COMPLETE);
75     ASSERT(commandExecCallbackType < CL_QUEUED);
76 
77     // Not much to do, acknowledge the presence of callback and returns
78     mHaveCallbacks->at(commandExecCallbackType) = true;
79 
80     return angle::Result::Continue;
81 }
82 
getProfilingInfo(cl::ProfilingInfo name,size_t valueSize,void * value,size_t * valueSizeRet)83 angle::Result CLEventVk::getProfilingInfo(cl::ProfilingInfo name,
84                                           size_t valueSize,
85                                           void *value,
86                                           size_t *valueSizeRet)
87 {
88     cl_ulong valueUlong   = 0;
89     size_t copySize       = 0;
90     const void *copyValue = nullptr;
91 
92     auto profilingTimestamps = mProfilingTimestamps.synchronize();
93 
94     switch (name)
95     {
96         case cl::ProfilingInfo::CommandQueued:
97             valueUlong = profilingTimestamps->commandQueuedTS;
98             break;
99         case cl::ProfilingInfo::CommandSubmit:
100             valueUlong = profilingTimestamps->commandSubmitTS;
101             break;
102         case cl::ProfilingInfo::CommandStart:
103             valueUlong = profilingTimestamps->commandStartTS;
104             break;
105         case cl::ProfilingInfo::CommandEnd:
106             valueUlong = profilingTimestamps->commandEndTS;
107             break;
108         case cl::ProfilingInfo::CommandComplete:
109             valueUlong = profilingTimestamps->commandCompleteTS;
110             break;
111         default:
112             UNREACHABLE();
113     }
114     copyValue = &valueUlong;
115     copySize  = sizeof(valueUlong);
116 
117     if ((value != nullptr) && (copyValue != nullptr))
118     {
119         memcpy(value, copyValue, std::min(valueSize, copySize));
120     }
121 
122     if (valueSizeRet != nullptr)
123     {
124         *valueSizeRet = copySize;
125     }
126 
127     return angle::Result::Continue;
128 }
129 
waitForUserEventStatus()130 angle::Result CLEventVk::waitForUserEventStatus()
131 {
132     ASSERT(isUserEvent());
133 
134     cl_int status = CL_QUEUED;
135     std::unique_lock<std::mutex> ul(mUserEventMutex);
136     ANGLE_TRY(getCommandExecutionStatus(status));
137     if (status > CL_COMPLETE)
138     {
139         // User is responsible for setting the user-event object, we need to wait for that event
140         // (We dont care what the outcome is, just need to wait until that event triggers)
141         INFO() << "Waiting for user-event (" << &mEvent
142                << ") to be set! (aka clSetUserEventStatus)";
143         mUserEventCondition.wait(ul);
144     }
145 
146     return angle::Result::Continue;
147 }
148 
setStatusAndExecuteCallback(cl_int status)149 angle::Result CLEventVk::setStatusAndExecuteCallback(cl_int status)
150 {
151     auto statusHandle        = mStatus.synchronize();
152     auto haveCallbacksHandle = mHaveCallbacks.synchronize();
153 
154     // we might skip states in some cases i.e. move from QUEUED to COMPLETE, so
155     // make sure we are setting time stamps for all transitions
156     ASSERT(*statusHandle >= status);
157     while (*statusHandle > status)
158     {
159         (*statusHandle)--;
160         ANGLE_TRY(setTimestamp(*statusHandle));
161         if (*statusHandle >= CL_COMPLETE && *statusHandle < CL_QUEUED &&
162             haveCallbacksHandle->at(*statusHandle))
163         {
164             getFrontendObject().callback(*statusHandle);
165             haveCallbacksHandle->at(*statusHandle) = false;
166         }
167     }
168 
169     return angle::Result::Continue;
170 }
171 
setTimestamp(cl_int status)172 angle::Result CLEventVk::setTimestamp(cl_int status)
173 {
174     if (!isUserEvent() &&
175         mEvent.getCommandQueue()->getProperties().intersects(CL_QUEUE_PROFILING_ENABLE))
176     {
177         // TODO(aannestrand) Just get current CPU timestamp for now, look into Vulkan GPU device
178         // timestamp query instead and later make CPU timestamp a fallback if GPU timestamp cannot
179         // be queried http://anglebug.com/357902514
180         cl_ulong cpuTS =
181             std::chrono::time_point_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now())
182                 .time_since_epoch()
183                 .count();
184 
185         auto profilingTimestamps = mProfilingTimestamps.synchronize();
186 
187         switch (status)
188         {
189             case CL_QUEUED:
190                 profilingTimestamps->commandQueuedTS = cpuTS;
191                 break;
192             case CL_SUBMITTED:
193                 profilingTimestamps->commandSubmitTS = cpuTS;
194                 break;
195             case CL_RUNNING:
196                 profilingTimestamps->commandStartTS = cpuTS;
197                 break;
198             case CL_COMPLETE:
199                 profilingTimestamps->commandEndTS = cpuTS;
200 
201                 // Returns a value equivalent to passing CL_PROFILING_COMMAND_END if the device
202                 // associated with event does not support device-side enqueue.
203                 // https://registry.khronos.org/OpenCL/specs/3.0-unified/html/OpenCL_API.html#_device_side_enqueue
204                 profilingTimestamps->commandCompleteTS = cpuTS;
205                 break;
206             default:
207                 UNREACHABLE();
208         }
209     }
210 
211     return angle::Result::Continue;
212 }
213 
214 }  // namespace rx
215