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.h
24 //! \brief Abstraction for MDF related operations.
25 //! \details It is a thin wrapper layer based on MDF APIs.
26 //!
27 #ifndef __VPHAL_MDF_WRAPPER_H__
28 #define __VPHAL_MDF_WRAPPER_H__
29
30 #include <fstream>
31 #include <vector>
32 #include <type_traits>
33 #include <string>
34 #include <unordered_map>
35 #include "cm_rt_umd.h"
36 #include "vphal.h"
37
38 template <typename CmSurfType>
39 class VpCmSurfaceHolder;
40 class CmContext;
41
42 class EventListener
43 {
44 public:
45 virtual void OnEventAvailable(CmEvent *event, const std::string &name) = 0;
46 };
47
48 class EventManager : public EventListener
49 {
50 public:
EventManager(const std::string & owner,CmContext * cmContext)51 EventManager(const std::string &owner, CmContext *cmContext) :
52 mOwner(owner),
53 m_cmContext(cmContext)
54 {
55 }
~EventManager()56 virtual ~EventManager()
57 {
58 Clear();
59 }
60
61 void OnEventAvailable(CmEvent *event, const std::string &name) override;
62 CmEvent* GetLastEvent() const;
63
64 private:
65 void AddEvent(const std::string &name, CmEvent *event);
66 void Clear();
67 void Profiling() const;
68
69 std::unordered_map<std::string, std::vector<CmEvent *> > mEventMap;
70 const std::string mOwner;
71 int mEventCount = 0;
72 CmEvent *mLastEvent = nullptr;
73 bool mReport = false;
74 CmContext *m_cmContext = nullptr;
75 };
76
77 // This is not multi-threads safe. Is it a good idea to use singleton here?
78 class CmContext
79 {
80 public:
81 // noncopyable
82 CmContext(const CmContext&) = delete;
83 CmContext& operator=(const CmContext&) = delete;
84 CmContext(PMOS_INTERFACE osInterface);
85 virtual ~CmContext();
86
87 void Destroy();
88
GetCmDevice()89 CmDevice* GetCmDevice() const
90 {
91 return mCmDevice;
92 }
93
GetCmQueue()94 CmQueue* GetCmQueue() const
95 {
96 return mCmQueue;
97 }
98
GetCmVebox()99 CmVebox* GetCmVebox() const
100 {
101 return mCmVebox;
102 }
103
ConnectEventListener(EventListener * listener)104 void ConnectEventListener(EventListener *listener)
105 {
106 mEventListener = listener;
107 }
108
109 CmKernel* CloneKernel(CmKernel *kernel);
110 void BatchKernel(CmKernel *kernel, CmThreadSpace *threadSpace, bool bFence);
111 void FlushBatchTask(bool waitForFinish);
112 void RunSingleKernel(
113 CmKernel *kernel,
114 CmThreadSpace *threadSpace,
115 const std::string &name,
116 bool waitForFinish);
117
BeginConditionalExecute(VpCmSurfaceHolder<CmBuffer> * conditionalBatchBuffer)118 void BeginConditionalExecute(VpCmSurfaceHolder<CmBuffer> *conditionalBatchBuffer)
119 {
120 FlushBatchTask(false);
121 mConditionalBatchBuffer = conditionalBatchBuffer;
122 }
123
EndConditionalExecute()124 void EndConditionalExecute()
125 {
126 FlushBatchTask(false);
127 mConditionalBatchBuffer = nullptr;
128 }
129
130 private:
131
132 void EnqueueTask(CmTask *task, CmThreadSpace *threadSpace, const std::string &name, bool waitForFinish);
133
134 int mRefCount;
135
136 CmDevice *mCmDevice;
137 CmQueue *mCmQueue;
138 CmVebox *mCmVebox;
139
140 PMOS_INTERFACE m_osInterface = nullptr;
141 CmTask *mBatchTask;
142 std::vector<CmKernel *> mAddedKernels;
143 std::vector<CmKernel *> mKernelsToPurge;
144 std::vector<CmThreadSpace *> mThreadSpacesToPurge;
145 bool mHasBatchedTask;
146 VpCmSurfaceHolder<CmBuffer> *mConditionalBatchBuffer; // CmContext does NOT own this.
147 CM_CONDITIONAL_END_PARAM mCondParam;
148 EventListener *mEventListener; // CmContext does NOT own this.
149 };
150
151 static inline
ConvertMosFmtToGmmFmt(MOS_FORMAT format)152 GMM_RESOURCE_FORMAT ConvertMosFmtToGmmFmt(MOS_FORMAT format)
153 {
154 switch (format)
155 {
156 case Format_X8R8G8B8: return GMM_FORMAT_B8G8R8X8_UNORM_TYPE;
157 case Format_A8R8G8B8: return GMM_FORMAT_B8G8R8A8_UNORM_TYPE;
158 case Format_NV12: return GMM_FORMAT_NV12_TYPE;
159 case Format_A8: return GMM_FORMAT_A8_UNORM_TYPE;
160 case Format_YUY2: return GMM_FORMAT_R8G8_UNORM_TYPE;
161 case Format_R8G8UN: return GMM_FORMAT_R8G8_UNORM_TYPE;
162 case Format_R32F: return GMM_FORMAT_R32_FLOAT_TYPE;
163 case Format_AYUV: return GMM_FORMAT_AYUV_TYPE;
164 case Format_Buffer: return GMM_FORMAT_A8_UNORM_TYPE;
165 // Format_A16R16G16B16 and Format_A16B16G16R16 are using the same surface layout.
166 case Format_A16R16G16B16: return GMM_FORMAT_R16G16B16A16_UNORM_TYPE;
167 case Format_A16B16G16R16: return GMM_FORMAT_R16G16B16A16_UNORM_TYPE;
168 default:
169 {
170 VPHAL_RENDER_ASSERTMESSAGE("Unsupported format %d\n", format);
171 return GMM_FORMAT_INVALID;
172 }
173 }
174 }
175
176 static inline
ConvertGmmFmtToMosFmt(GMM_RESOURCE_FORMAT format)177 MOS_FORMAT ConvertGmmFmtToMosFmt(GMM_RESOURCE_FORMAT format)
178 {
179 switch (format)
180 {
181 case GMM_FORMAT_B8G8R8X8_UNORM_TYPE : return Format_X8R8G8B8;
182 case GMM_FORMAT_B8G8R8A8_UNORM_TYPE : return Format_A8R8G8B8;
183 case GMM_FORMAT_NV12_TYPE: return Format_NV12;
184 case GMM_FORMAT_A8_UNORM_TYPE : return Format_A8;
185 case GMM_FORMAT_R8G8_UNORM_TYPE : return Format_R8G8UN;
186 case GMM_FORMAT_R32_FLOAT_TYPE : return Format_R32F;
187 case GMM_FORMAT_AYUV_TYPE : return Format_AYUV;
188 // WA for GMM and MDF issue. Will revisit it after fixing the issue.
189 case GMM_FORMAT_R16G16B16A16_UNORM_TYPE: return Format_A16B16G16R16;
190 default:
191 {
192 VPHAL_RENDER_ASSERTMESSAGE("Unsupported format %d\n", format);
193 return Format_Invalid;
194 }
195 }
196 }
197
198 static inline
GetBitsPerPixel(GMM_RESOURCE_FORMAT format)199 int GetBitsPerPixel(GMM_RESOURCE_FORMAT format)
200 {
201 switch (format)
202 {
203 case GMM_FORMAT_B8G8R8X8_UNORM_TYPE: return 32;
204 case GMM_FORMAT_B8G8R8A8_UNORM_TYPE: return 32;
205 case GMM_FORMAT_NV12_TYPE: return 12;
206 case GMM_FORMAT_A8_UNORM_TYPE: return 8;
207 case GMM_FORMAT_R8G8_UNORM_TYPE: return 16;
208 case GMM_FORMAT_R32_FLOAT_TYPE: return 32;
209 case GMM_FORMAT_AYUV_TYPE: return 32;
210 case GMM_FORMAT_R16G16B16A16_UNORM_TYPE: return 64;
211 case GMM_FORMAT_R16G16B16X16_UNORM_TYPE: return 64;
212 default:
213 {
214 VPHAL_RENDER_ASSERTMESSAGE("Unsupported format %d\n", format);
215 return 0;
216 }
217 }
218 }
219
220 template <typename CmSurfType>
221 class VpCmSurfaceHolder
222 {
223 public:
224 static_assert(
225 std::is_same<CmSurfType, CmBuffer >::value ||
226 std::is_same<CmSurfType, CmSurface2D>::value ||
227 std::is_same<CmSurfType, CmSurface3D>::value,
228 "CmSurfType need to be one of CmBuffer, CmSurface2D or CmSurface3D.");
229
VpCmSurfaceHolder(PVPHAL_SURFACE vpSurf,CmContext * cmContext)230 VpCmSurfaceHolder(PVPHAL_SURFACE vpSurf, CmContext *cmContext):
231 mCmSurface(nullptr),
232 mSurfaceIndex(nullptr),
233 mSamplerSurfaceIndex(nullptr),
234 mSampler8x8SurfaceIndex(nullptr),
235 mWidth(vpSurf->dwWidth),
236 mHeight(vpSurf->dwHeight),
237 mDepth(vpSurf->dwDepth),
238 mFormat(ConvertMosFmtToGmmFmt(vpSurf->Format)),
239 m_cmContext(cmContext)
240 {
241 int result = CreateCmSurfaceSpecialized(vpSurf, mCmSurface);
242 if ((result != CM_SUCCESS) || (!mCmSurface))
243 {
244 VPHAL_RENDER_ASSERTMESSAGE("Failed to create VpCmSurfaceHolder from VP Surface!\n");
245 return;
246 }
247 result = mCmSurface->GetIndex(mSurfaceIndex);
248 if (result != CM_SUCCESS)
249 {
250 VPHAL_RENDER_ASSERTMESSAGE("Failed to Get Surface Index");
251 }
252 }
253
VpCmSurfaceHolder(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmContext * cmContext)254 VpCmSurfaceHolder(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmContext *cmContext) :
255 mCmSurface(nullptr),
256 mSurfaceIndex(nullptr),
257 mSamplerSurfaceIndex(nullptr),
258 mSampler8x8SurfaceIndex(nullptr),
259 mWidth(width),
260 mHeight(height),
261 mDepth(depth),
262 mFormat(format),
263 m_cmContext(cmContext)
264 {
265 int result = CreateCmSurfaceSpecialized(width, height, depth, format, mCmSurface);
266 if ((result != CM_SUCCESS) || (!mCmSurface))
267 {
268 VPHAL_RENDER_ASSERTMESSAGE("Failed to create VpCmSurfaceHolder!\n");
269 return;
270 }
271 mCmSurface->GetIndex(mSurfaceIndex);
272 }
273
~VpCmSurfaceHolder()274 virtual ~VpCmSurfaceHolder()
275 {
276 VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(m_cmContext);
277 CmDevice *dev = m_cmContext->GetCmDevice();
278 int result = CM_SUCCESS;
279
280 if (mSampler8x8SurfaceIndex)
281 {
282 result = dev->DestroySampler8x8Surface(mSampler8x8SurfaceIndex);
283 if (result != CM_SUCCESS)
284 {
285 VPHAL_RENDER_ASSERTMESSAGE("Failed to destroy mSampler8x8SurfaceIndex!");
286 }
287 }
288
289 if (mSamplerSurfaceIndex)
290 {
291 result = dev->DestroySamplerSurface(mSamplerSurfaceIndex);
292 if (result != CM_SUCCESS)
293 {
294 VPHAL_RENDER_ASSERTMESSAGE("Failed to destroy mSamplerSurfaceIndex!");
295 }
296 }
297
298 if (mCmSurface)
299 {
300 result = dev->DestroySurface(mCmSurface);
301 if (result != CM_SUCCESS)
302 {
303 VPHAL_RENDER_ASSERTMESSAGE("Failed to destroy mCmSurface!");
304 }
305 }
306 }
307
GetCmSurface()308 CmSurfType* GetCmSurface() const
309 {
310 return mCmSurface;
311 }
312
GetCmSurfaceIndex()313 SurfaceIndex* GetCmSurfaceIndex()
314 {
315 if (!mSurfaceIndex)
316 {
317 int result = mCmSurface->GetIndex(mSurfaceIndex);
318 if (result != CM_SUCCESS)
319 {
320 VPHAL_RENDER_ASSERTMESSAGE("Failed to GetCmSurfaceIndex!");
321 }
322 }
323 return mSurfaceIndex;
324 }
325
GetCmSamplerSurfaceIndex()326 SurfaceIndex* GetCmSamplerSurfaceIndex()
327 {
328 if (!mSamplerSurfaceIndex)
329 {
330 if (!m_cmContext)
331 {
332 return mSamplerSurfaceIndex;
333 }
334 int result = m_cmContext->GetCmDevice()->CreateSamplerSurface2D(mCmSurface, mSamplerSurfaceIndex);
335 if (result != CM_SUCCESS)
336 {
337 VPHAL_RENDER_ASSERTMESSAGE("Failed in CreateSamplerSurface2D!\n");
338 }
339
340 }
341 return mSamplerSurfaceIndex;
342 }
343
GetCmSampler8x8SurfaceIndex()344 SurfaceIndex* GetCmSampler8x8SurfaceIndex()
345 {
346 if (!mSampler8x8SurfaceIndex)
347 {
348 if (!m_cmContext)
349 {
350 return mSampler8x8SurfaceIndex;
351 }
352 int result = m_cmContext->GetCmDevice()->CreateSampler8x8Surface(mCmSurface, mSampler8x8SurfaceIndex, CM_AVS_SURFACE, CM_SURFACE_CLAMP);
353 if (result != CM_SUCCESS)
354 {
355 VPHAL_RENDER_ASSERTMESSAGE("Failed in CreateSampler8x8Surface!\n");
356 }
357 }
358 return mSampler8x8SurfaceIndex;
359 }
360
GetSurfaceDimentions(int & width,int & height,int & depth)361 void GetSurfaceDimentions(int &width, int &height, int &depth)
362 {
363 width = mWidth;
364 height = mHeight;
365 depth = mDepth;
366 }
367
GetSurfaceSize()368 int GetSurfaceSize() const
369 {
370 return (mWidth * mHeight * mDepth * GetBitsPerPixel(mFormat)) >> 3;
371 }
372
GetFormat()373 GMM_RESOURCE_FORMAT GetFormat() const
374 {
375 return mFormat;
376 }
377
InitSurfaceFromFile(const std::string & fileName)378 void InitSurfaceFromFile(const std::string &fileName)
379 {
380 std::ifstream blob(fileName, std::ifstream::ate | std::ifstream::binary);
381 if (!blob.is_open())
382 {
383 VPHAL_RENDER_ASSERTMESSAGE("Error in opening raw data file: %s.\n", fileName.c_str());
384 return;
385 }
386 const int fileSize = static_cast<int>(blob.tellg());
387 if (fileSize == 0)
388 {
389 VPHAL_RENDER_ASSERTMESSAGE("file size is 0.\n");
390 return;
391 }
392 blob.seekg(0, blob.beg);
393 std::vector<char> temp(GetSurfaceSize());
394 blob.read(temp.data(), MOS_MIN(fileSize, GetSurfaceSize()));
395 mCmSurface->WriteSurface((unsigned char *)temp.data(), nullptr);
396 }
397
DumpSurfaceToFile(const std::string & fileName)398 void DumpSurfaceToFile(const std::string &fileName)
399 {
400 std::ofstream blob(fileName, std::ofstream::out | std::ifstream::binary);
401
402 if (!blob.is_open())
403 {
404 VPHAL_RENDER_ASSERTMESSAGE("Error in opening raw data file: %s.\n", fileName.c_str());
405 return;
406 }
407
408 const int size = GetSurfaceSize();
409 std::vector<char> temp(size);
410 mCmSurface->ReadSurface((unsigned char*)temp.data(), nullptr, size);
411 blob.write(temp.data(), size);
412 }
413
414 private:
415 VpCmSurfaceHolder(const VpCmSurfaceHolder &) = delete;
416 VpCmSurfaceHolder& operator=(const VpCmSurfaceHolder &) = delete;
417
CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf,CmSurfType * & surf)418 inline int CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf, CmSurfType* &surf)
419 {
420 return 0;
421 }
422
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmSurfType * & surf)423 inline int CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmSurfType* &surf)
424 {
425 return 0;
426 }
427
428 PVPHAL_SURFACE mVphalSurface = nullptr;
429 CmSurfType *mCmSurface = nullptr;
430 SurfaceIndex *mSurfaceIndex = nullptr;
431 SurfaceIndex *mSamplerSurfaceIndex = nullptr;
432 SurfaceIndex *mSampler8x8SurfaceIndex = nullptr;
433
434 const int mWidth = 0;
435 const int mHeight = 0;
436 const int mDepth = 0;
437 const GMM_RESOURCE_FORMAT mFormat;
438 CmContext *m_cmContext = nullptr;
439 };
440
441 template <>
CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf,CmBuffer * & surf)442 inline int VpCmSurfaceHolder<CmBuffer>::CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf, CmBuffer* &surf)
443 {
444 if (!m_cmContext)
445 {
446 return CM_NULL_POINTER;
447 }
448 return m_cmContext->GetCmDevice()->CreateBuffer(&vpSurf->OsResource, surf);
449 }
450
451 template <>
CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf,CmSurface2D * & surf)452 inline int VpCmSurfaceHolder<CmSurface2D>::CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf, CmSurface2D* &surf)
453 {
454 if (!m_cmContext)
455 {
456 return CM_NULL_POINTER;
457 }
458 return m_cmContext->GetCmDevice()->CreateSurface2D(&vpSurf->OsResource, surf);
459 }
460
461 template <>
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmBuffer * & surf)462 inline int VpCmSurfaceHolder<CmBuffer>::CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmBuffer* &surf)
463 {
464 if (!m_cmContext)
465 {
466 return CM_NULL_POINTER;
467 }
468 return m_cmContext->GetCmDevice()->CreateBuffer(width, surf);
469 }
470
471 template <>
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmSurface2D * & surf)472 inline int VpCmSurfaceHolder<CmSurface2D>::CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmSurface2D* &surf)
473 {
474 if (!m_cmContext)
475 {
476 return CM_NULL_POINTER;
477 }
478 return m_cmContext->GetCmDevice()->CreateSurface2D(width, height, ConvertGmmFmtToMosFmt(format), surf);
479 }
480
481 template <>
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmSurface3D * & surf)482 inline int VpCmSurfaceHolder<CmSurface3D>::CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmSurface3D* &surf)
483 {
484 if (!m_cmContext)
485 {
486 return CM_NULL_POINTER;
487 }
488 return m_cmContext->GetCmDevice()->CreateSurface3D(width, height, depth, ConvertGmmFmtToMosFmt(format), surf);
489 }
490
491 class VPRender
492 {
493 public:
~VPRender()494 virtual ~VPRender()
495 {
496 }
497
498 virtual void Render(void *payload) = 0;
499 };
500
501 // A simple CM kernel render wrapper.
502 // All methods derived classes need to implement are private.
503 // This means the calling order of such methods is fixed, and they will
504 // get hooked to the Render() entry method in this base class.
505 class VPCmRenderer: public VPRender
506 {
507 public:
508 VPCmRenderer(const std::string &name, CmContext *cmContext);
509 virtual ~VPCmRenderer();
510
511 void Render(void *payload) override;
512
SetmBlockingMode(bool enable)513 void SetmBlockingMode(bool enable)
514 {
515 mBlockingMode = enable;
516 }
517
EnableDump(bool enable)518 void EnableDump(bool enable)
519 {
520 mEnableDump = enable;
521 }
522
EnableBatchDispatch(bool enable)523 void EnableBatchDispatch(bool enable)
524 {
525 mBatchDispatch = enable;
526 }
527
528 protected:
529 CmProgram* LoadProgram(const void *binary, int size);
530 CmProgram* LoadProgram(const std::string& binaryFileName);
531
532 const std::string mName;
533 CmContext *m_cmContext = nullptr;
534
535 private:
536 virtual void AttachPayload(void *) = 0;
537 virtual CmKernel* GetKernelToRun(std::string &name) = 0;
538 virtual void GetThreadSpaceDimension(int &tsWidth, int &tsHeight, int &tsColor) = 0;
539 virtual void PrepareKernel(CmKernel *kernel) = 0;
540
541 // Derived class can override this method if special setup needs be performed on thread space,
542 // like walking pattern, dependency pattern(scoreboard), etc.
SetupThreadSpace(CmThreadSpace * threadSpace,int,int,int)543 virtual void SetupThreadSpace(CmThreadSpace *threadSpace, int /*tsWidth*/, int /*tsHeight*/, int /*tsColor*/)
544 {
545 int32_t iStatus = threadSpace->SelectMediaWalkingPattern(CM_WALK_VERTICAL);
546 if (iStatus != CM_SUCCESS)
547 {
548 VPHAL_RENDER_ASSERTMESSAGE("SelectMediaWalkingPattern Returns %d", iStatus);
549 }
550 }
551
552 // This method will take effect only if this renderer works in batch dispatching mode(multi-kernels in one task).
553 // Be careful if derived class want to override it. Return true is always safe and workable.
554 // Return false if its kernel has no dependency against previous ones,
555 // thus will enable kernel parallel execution, which can improve performance in some cases.
NeedAddSync()556 virtual bool NeedAddSync()
557 {
558 return true;
559 }
560
CannotAssociateThreadSpace()561 virtual bool CannotAssociateThreadSpace()
562 {
563 return true;
564 }
565
Dump()566 virtual void Dump()
567 {
568 }
569
570 bool mBatchDispatch;
571 bool mBlockingMode;
572 bool mEnableDump;
573 };
574
575 #endif // __VPHAL_MDF_WRAPPER_H__
576