xref: /aosp_15_r20/external/intel-media-driver/media_driver/agnostic/common/vp/hal/vphal_mdf_wrapper.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
1 /*
2 * Copyright (c) 2009-2018, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file     vphal_mdf_wrapper.cpp
24 //! \brief    Abstraction for MDF related operations.
25 //! \details  It is a thin wrapper layer based on MDF APIs.
26 //!
27 #include "vphal_mdf_wrapper.h"
28 #include <algorithm>
29 #include <cstdio>
30 
31 
OnEventAvailable(CmEvent * event,const std::string & name)32 void EventManager::OnEventAvailable(CmEvent *event, const std::string &name)
33 {
34     AddEvent(name, event);
35 }
36 
AddEvent(const std::string & name,CmEvent * event)37 void EventManager::AddEvent(const std::string &name, CmEvent *event)
38 {
39     if (mEventCount >= (128 * 1024) / sizeof(CmEvent))
40     {
41         if (mReport)
42         {
43             Profiling();
44         }
45 
46         Clear();
47     }
48 
49     mEventMap[name].push_back(event);
50     mLastEvent = event;
51     mEventCount++;
52 }
53 
Clear()54 void EventManager::Clear()
55 {
56     VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(m_cmContext);
57     CmQueue *queue = m_cmContext->GetCmQueue();
58     VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(queue);
59     for (auto it : mEventMap)
60     {
61         for (CmEvent *event : it.second)
62         {
63             queue->DestroyEvent(event);
64         }
65     }
66 
67     mEventMap.clear();
68     mEventCount = 0;
69     mLastEvent = nullptr;
70 }
71 
Profiling() const72 void EventManager::Profiling() const
73 {
74     VPHAL_RENDER_NORMALMESSAGE("------------------------%s Profiling Report------------------------\n", mOwner.c_str());
75     for (auto it : mEventMap)
76     {
77         int count = 0;
78         double totalTimeInMS = 0.0;
79         for (CmEvent *event : it.second)
80         {
81             uint64_t executionTimeInNS = 0;
82             int result = event->GetExecutionTime(executionTimeInNS);
83             if (result != CM_SUCCESS)
84             {
85                 VPHAL_RENDER_ASSERTMESSAGE("[%s]: CM GetExecutionTime error: %d\n", it.first.c_str(), result);
86                 continue;
87             }
88             totalTimeInMS += executionTimeInNS / 1000000.0;
89             count++;
90         }
91         VPHAL_RENDER_NORMALMESSAGE("[%s]: execution count %llu, average time %f ms.\n", it.first.c_str(), it.second.size(), totalTimeInMS / count);
92     }
93     VPHAL_RENDER_NORMALMESSAGE("------------------------%s Profiling Report End------------------------\n", mOwner.c_str());
94 }
95 
GetLastEvent() const96 CmEvent* EventManager::GetLastEvent() const
97 {
98     return mLastEvent;
99 }
100 
CmContext(PMOS_INTERFACE osInterface)101 CmContext::CmContext(PMOS_INTERFACE osInterface) :
102     mRefCount(0),
103     mCmDevice(nullptr),
104     mCmQueue(nullptr),
105     mCmVebox(nullptr),
106     m_osInterface(osInterface),
107     mBatchTask(nullptr),
108     mHasBatchedTask(false),
109     mConditionalBatchBuffer(nullptr),
110     mCondParam({ 0 }),
111     mEventListener(nullptr)
112 {
113     VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(osInterface);
114 
115     const unsigned int MDF_DEVICE_CREATE_OPTION =
116         ((CM_DEVICE_CREATE_OPTION_SCRATCH_SPACE_DISABLE)                                |
117          (CM_DEVICE_CONFIG_DSH_DISABLE_MASK)                                            |
118          (CM_DEVICE_CONFIG_TASK_NUM_16 << CM_DEVICE_CONFIG_TASK_NUM_OFFSET)             |
119          (CM_DEVICE_CONFIG_MEDIA_RESET_ENABLE)                                          |
120          (CM_DEVICE_CONFIG_EXTRA_TASK_NUM_4 << CM_DEVICE_CONFIG_EXTRA_TASK_NUM_OFFSET)  |
121          (CM_DEVICE_CONFIG_GPUCONTEXT_ENABLE)                                           |
122          (32 << CM_DEVICE_CONFIG_KERNELBINARYGSH_OFFSET));
123 
124     int result = osInterface->pfnCreateCmDevice(osInterface->pOsContext, mCmDevice, MDF_DEVICE_CREATE_OPTION, CM_DEVICE_CREATE_PRIORITY_DEFAULT);
125     if (result != CM_SUCCESS)
126     {
127         VPHAL_RENDER_ASSERTMESSAGE("CmDevice creation error %d\n", result);
128         return;
129     }
130 
131     result = mCmDevice->CreateQueue(mCmQueue);
132     if (result != CM_SUCCESS)
133     {
134         VPHAL_RENDER_ASSERTMESSAGE("CmQueue creation error %d\n", result);
135         return;
136     }
137 
138     result = mCmDevice->CreateVebox(mCmVebox);
139     if (result != CM_SUCCESS)
140     {
141         VPHAL_RENDER_ASSERTMESSAGE("CmVebox creation error %d\n", result);
142         return;
143     }
144 
145 #if (_DEBUG || _RELEASE_INTERNAL)
146     result = mCmDevice->InitPrintBuffer(32768);
147     if (result != CM_SUCCESS)
148     {
149         VPHAL_RENDER_ASSERTMESSAGE("Init printf error: %d\n", result);
150         return;
151     }
152 #endif
153 
154     result = mCmDevice->CreateTask(mBatchTask);
155     if (result != CM_SUCCESS)
156     {
157         VPHAL_RENDER_ASSERTMESSAGE("Create batch task error: %d\n", result);
158         return;
159     }
160 
161 }
162 
CloneKernel(CmKernel * kernel)163 CmKernel* CmContext::CloneKernel(CmKernel *kernel)
164 {
165     auto it = std::find(mAddedKernels.begin(), mAddedKernels.end(), kernel);
166     if (it != mAddedKernels.end())
167     {
168         CmKernel *newKernel = nullptr;
169         int result = mCmDevice->CloneKernel(newKernel, kernel);
170         if (result != CM_SUCCESS)
171         {
172             // Clone kernel failed, try to use the old one.
173             VPHAL_RENDER_ASSERTMESSAGE("Clone kernel failed: %d\n", result);
174             return kernel;
175         }
176         mKernelsToPurge.push_back(newKernel);
177         return newKernel;
178     }
179     else
180     {
181         return kernel;
182     }
183 }
184 
BatchKernel(CmKernel * kernel,CmThreadSpace * threadSpace,bool bFence)185 void CmContext::BatchKernel(CmKernel *kernel, CmThreadSpace *threadSpace, bool bFence)
186 {
187     int result;
188 
189     if (mConditionalBatchBuffer && mAddedKernels.empty())
190     {
191         result = mBatchTask->AddConditionalEnd(mConditionalBatchBuffer->GetCmSurfaceIndex(), 0, &mCondParam);
192         if (result != CM_SUCCESS)
193         {
194             VPHAL_RENDER_ASSERTMESSAGE("Batch task AddConditionalEnd error: %d\n", result);
195             return;
196         }
197     }
198 
199     if (bFence)
200     {
201         result = mBatchTask->AddSync();
202         if (result != CM_SUCCESS)
203         {
204             VPHAL_RENDER_ASSERTMESSAGE("Batch task add sync error: %d\n", result);
205             return;
206         }
207     }
208 
209     result = mBatchTask->AddKernel(kernel);
210     if (result == CM_EXCEED_MAX_KERNEL_PER_ENQUEUE)
211     {
212         // Reach max kernels per task, flush and try again.
213         bool needAddBack = false;
214         if (mKernelsToPurge.back() == kernel)
215         {
216             mKernelsToPurge.pop_back();
217             needAddBack = true;
218         }
219 
220         FlushBatchTask(false);
221         BatchKernel(kernel, threadSpace, false);
222 
223         if (needAddBack)
224         {
225             mKernelsToPurge.push_back(kernel);
226         }
227 
228         return;
229     }
230     else if (result != CM_SUCCESS)
231     {
232         VPHAL_RENDER_ASSERTMESSAGE("Batch task add sync error: %d\n", result);
233         return;
234     }
235 
236     mAddedKernels.push_back(kernel);
237     mThreadSpacesToPurge.push_back(threadSpace);
238     mHasBatchedTask = true;
239 }
240 
FlushBatchTask(bool waitForFinish)241 void CmContext::FlushBatchTask(bool waitForFinish)
242 {
243     int result = CM_SUCCESS;
244 
245     if (mAddedKernels.empty())
246     {
247         return;
248     }
249 
250     EnqueueTask(mBatchTask, nullptr, "BatchTask", waitForFinish);
251 
252     for(auto it : mThreadSpacesToPurge)
253     {
254         result = mCmDevice->DestroyThreadSpace(it);
255         if (result != CM_SUCCESS)
256         {
257             VPHAL_RENDER_ASSERTMESSAGE("CM DestroyThreadSpace Fail %d", result);
258         }
259     }
260 
261     for(auto it : mKernelsToPurge)
262     {
263         result = mCmDevice->DestroyKernel(it);
264         if (result != CM_SUCCESS)
265         {
266             VPHAL_RENDER_ASSERTMESSAGE("CM DestroyKernel Fail %d", result);
267         }
268     }
269 
270     mThreadSpacesToPurge.clear();
271     mKernelsToPurge.clear();
272     mAddedKernels.clear();
273     result = mBatchTask->Reset();
274     if (result != CM_SUCCESS)
275     {
276         VPHAL_RENDER_ASSERTMESSAGE("CM Batch Task Reset Fail %d", result);
277     }
278 }
279 
RunSingleKernel(CmKernel * kernel,CmThreadSpace * threadSpace,const std::string & name,bool waitForFinish)280 void CmContext::RunSingleKernel(
281     CmKernel *kernel,
282     CmThreadSpace *threadSpace,
283     const std::string &name,
284     bool waitForFinish)
285 {
286     FlushBatchTask(false);
287 
288     CmTask *task = nullptr;
289     int result = mCmDevice->CreateTask(task);
290     if (result != CM_SUCCESS)
291     {
292         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CmDevice CreateTask error: %d\n", name.c_str(), result);
293         return;
294     }
295 
296     if (mConditionalBatchBuffer)
297     {
298         result = task->AddConditionalEnd(mConditionalBatchBuffer->GetCmSurfaceIndex(), 0, &mCondParam);
299         if (result != CM_SUCCESS)
300         {
301             VPHAL_RENDER_ASSERTMESSAGE("[%s]: AddConditionalEnd error: %d\n", name.c_str(), result);
302             mCmDevice->DestroyTask(task);
303             return;
304         }
305     }
306 
307     result = task->AddKernel(kernel);
308     if (result != CM_SUCCESS)
309     {
310         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CmDevice AddKernel error: %d\n", name.c_str(), result);
311         mCmDevice->DestroyTask(task);
312         return;
313     }
314 
315     EnqueueTask(task, threadSpace, name, waitForFinish);
316 }
317 
EnqueueTask(CmTask * task,CmThreadSpace * threadSpace,const std::string & name,bool waitForFinish)318 void CmContext::EnqueueTask(CmTask *task, CmThreadSpace *threadSpace, const std::string &name, bool waitForFinish)
319 {
320     CmEvent *event = nullptr;
321     int result = mCmQueue->Enqueue(task, event, threadSpace);
322     if (result != CM_SUCCESS)
323     {
324         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CmDevice enqueue error: %d\n", name.c_str(), result);
325         return;
326     }
327 
328     if (waitForFinish)
329     {
330         result = event->WaitForTaskFinished(-1);
331         if (result != CM_SUCCESS)
332         {
333             VPHAL_RENDER_ASSERTMESSAGE("WaitForTaskFinished Failed %d", result);
334         }
335 
336 #if (_DEBUG || _RELEASE_INTERNAL)
337         result = mCmDevice->FlushPrintBuffer();
338         if (result != CM_SUCCESS)
339         {
340             VPHAL_RENDER_ASSERTMESSAGE("[%s]: Flush printf buffer error: %d", name.c_str(), result);
341         }
342         std::fflush(stdout);
343 #endif
344     }
345 
346     if (mEventListener)
347     {
348         mEventListener->OnEventAvailable(event, name);
349     }
350     else
351     {
352         if (event != nullptr)
353         {
354             result = mCmQueue->DestroyEvent(event);
355             if (result != CM_SUCCESS)
356             {
357                 VPHAL_RENDER_ASSERTMESSAGE("DestroyEvent Failed %d", result);
358             }
359         }
360     }
361 }
362 
Destroy()363 void CmContext::Destroy()
364 {
365     int result = CM_SUCCESS;
366     FlushBatchTask(false);
367 
368     if (mBatchTask)
369     {
370         result = mCmDevice->DestroyTask(mBatchTask);
371         if (result != CM_SUCCESS)
372         {
373             VPHAL_RENDER_ASSERTMESSAGE("CM DestroyTask Fail %d", result);
374         }
375     }
376 
377     if (mCmVebox)
378     {
379         result = mCmDevice->DestroyVebox(mCmVebox);
380         if (result != CM_SUCCESS)
381         {
382             VPHAL_RENDER_ASSERTMESSAGE("CM DestroyVebox Fail %d", result);
383         }
384     }
385 
386     if (mCmDevice && m_osInterface)
387     {
388         m_osInterface->pfnDestroyCmDevice(mCmDevice);
389     }
390 
391     mBatchTask = nullptr;
392     mCmVebox   = nullptr;
393     mCmDevice  = nullptr;
394 }
395 
~CmContext()396 CmContext::~CmContext()
397 {
398     Destroy();
399 }
400 
VPCmRenderer(const std::string & name,CmContext * cmContext)401 VPCmRenderer::VPCmRenderer(const std::string &name, CmContext *cmContext) :
402     mName(name),
403     m_cmContext(cmContext),
404     mBatchDispatch(true),
405     mBlockingMode(false),
406     mEnableDump(false)
407 {
408 }
409 
~VPCmRenderer()410 VPCmRenderer::~VPCmRenderer()
411 {
412 }
413 
LoadProgram(const std::string & binaryFileName)414 CmProgram* VPCmRenderer::LoadProgram(const std::string& binaryFileName)
415 {
416     std::ifstream isa(binaryFileName, std::ifstream::ate | std::ifstream::binary);
417 
418     if (!isa.is_open())
419     {
420         VPHAL_RENDER_ASSERTMESSAGE("Error in opening ISA file: %s.\n", binaryFileName.c_str());
421         return nullptr;
422     }
423 
424     int size = static_cast<int>(isa.tellg());
425     if (size == 0)
426     {
427         VPHAL_RENDER_ASSERTMESSAGE("Code size is 0.\n");
428         return nullptr;
429     }
430 
431     isa.seekg(0, isa.beg);
432     std::vector<char> code(size);
433     isa.read(code.data(), size);
434 
435     CmProgram *program = nullptr;
436     if (!m_cmContext)
437     {
438         return nullptr;
439     }
440     CmDevice *dev    = m_cmContext->GetCmDevice();
441     if (!dev)
442     {
443         return nullptr;
444     }
445     int       result = dev->LoadProgram(code.data(), size, program, "-nojitter");
446     if (result != CM_SUCCESS)
447     {
448         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CM LoadProgram error %d\n", mName.c_str(), result);
449         return nullptr;
450     }
451 
452     return program;
453 }
454 
LoadProgram(const void * binary,int size)455 CmProgram* VPCmRenderer::LoadProgram(const void *binary, int size)
456 {
457     if (!binary || size == 0)
458     {
459         VPHAL_RENDER_ASSERTMESSAGE("Invalid program to load.\n");
460         return nullptr;
461     }
462 
463     CmProgram *program = nullptr;
464     if (!m_cmContext)
465     {
466         return nullptr;
467     }
468     CmDevice *dev    = m_cmContext->GetCmDevice();
469     if (!dev)
470     {
471         return nullptr;
472     }
473     int       result = dev->LoadProgram(const_cast<void *>(binary), size, program, "-nojitter");
474     if (result != CM_SUCCESS)
475     {
476         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CM LoadProgram error %d\n", mName.c_str(), result);
477         return nullptr;
478     }
479 
480     return program;
481 }
482 
Render(void * payload)483 void VPCmRenderer::Render(void *payload)
484 {
485     AttachPayload(payload);
486 
487     std::string kernelName;
488     CmKernel *kernel = GetKernelToRun(kernelName);
489     if (!kernel)
490     {
491         VPHAL_RENDER_ASSERTMESSAGE("[%s]: Did not find proper kernel to run\n", mName.c_str());
492         return;
493     }
494 
495     int tsWidth, tsHeight, tsColor;
496     GetThreadSpaceDimension(tsWidth, tsHeight, tsColor);
497     if (!tsWidth || !tsHeight || !tsColor)
498     {
499         VPHAL_RENDER_ASSERTMESSAGE("[%s]: Degenerate thread space, return immediately.\n", mName.c_str());
500         return;
501     }
502 
503     VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(m_cmContext);
504     CmThreadSpace *threadSpace = nullptr;
505     CmDevice *dev = m_cmContext->GetCmDevice();
506     VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(dev);
507     int result = dev->CreateThreadSpace(tsWidth, tsHeight, threadSpace);
508     if (result != CM_SUCCESS)
509     {
510         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CM Create ThreadSpace error: %d\n", mName.c_str(), result);
511         return;
512     }
513 
514     SetupThreadSpace(threadSpace, tsWidth, tsHeight, tsColor);
515 
516     // We need to use CloneKernel API to add the same kernel multiple times into one task.
517     bool bBatch = mBatchDispatch && !mBlockingMode && !mEnableDump && !CannotAssociateThreadSpace();
518     if (bBatch)
519     {
520         kernel = m_cmContext->CloneKernel(kernel);
521     }
522 
523     result = kernel->SetThreadCount(tsWidth * tsHeight * tsColor);
524     if (result != CM_SUCCESS)
525     {
526         VPHAL_RENDER_ASSERTMESSAGE("[%s]: CM Set ThreadCount error: %d\n", mName.c_str(), result);
527     }
528 
529     if (!CannotAssociateThreadSpace())
530     {
531         kernel->AssociateThreadSpace(threadSpace);
532     }
533 
534     PrepareKernel(kernel);
535 
536     if (bBatch)
537     {
538         m_cmContext->BatchKernel(kernel, threadSpace, NeedAddSync());
539     }
540     else
541     {
542         m_cmContext->RunSingleKernel(kernel, CannotAssociateThreadSpace() ? threadSpace : nullptr, kernelName, mBlockingMode);
543         dev->DestroyThreadSpace(threadSpace);
544     }
545 
546     if (mEnableDump)
547     {
548         Dump();
549     }
550 
551     AttachPayload(nullptr);
552 }