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_CONTEXT OsContext);
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 CmTask *mBatchTask;
141 std::vector<CmKernel *> mAddedKernels;
142 std::vector<CmKernel *> mKernelsToPurge;
143 std::vector<CmThreadSpace *> mThreadSpacesToPurge;
144 bool mHasBatchedTask;
145 VpCmSurfaceHolder<CmBuffer> *mConditionalBatchBuffer; // CmContext does NOT own this.
146 CM_CONDITIONAL_END_PARAM mCondParam;
147 EventListener *mEventListener; // CmContext does NOT own this.
148 };
149
150 static inline
ConvertMosFmtToGmmFmt(MOS_FORMAT format)151 GMM_RESOURCE_FORMAT ConvertMosFmtToGmmFmt(MOS_FORMAT format)
152 {
153 switch (format)
154 {
155 case Format_X8R8G8B8: return GMM_FORMAT_B8G8R8X8_UNORM_TYPE;
156 case Format_A8R8G8B8: return GMM_FORMAT_B8G8R8A8_UNORM_TYPE;
157 case Format_NV12: return GMM_FORMAT_NV12_TYPE;
158 case Format_A8: return GMM_FORMAT_A8_UNORM_TYPE;
159 case Format_YUY2: return GMM_FORMAT_R8G8_UNORM_TYPE;
160 case Format_R8G8UN: return GMM_FORMAT_R8G8_UNORM_TYPE;
161 case Format_R32F: return GMM_FORMAT_R32_FLOAT_TYPE;
162 case Format_AYUV: return GMM_FORMAT_AYUV_TYPE;
163 case Format_Buffer: return GMM_FORMAT_A8_UNORM_TYPE;
164 // Format_A16R16G16B16 and Format_A16B16G16R16 are using the same surface layout.
165 case Format_A16R16G16B16: return GMM_FORMAT_R16G16B16A16_UNORM_TYPE;
166 case Format_A16B16G16R16: return GMM_FORMAT_R16G16B16A16_UNORM_TYPE;
167 default:
168 {
169 VPHAL_RENDER_ASSERTMESSAGE("Unsupported format %d\n", format);
170 return GMM_FORMAT_INVALID;
171 }
172 }
173 }
174
175 static inline
ConvertGmmFmtToMosFmt(GMM_RESOURCE_FORMAT format)176 MOS_FORMAT ConvertGmmFmtToMosFmt(GMM_RESOURCE_FORMAT format)
177 {
178 switch (format)
179 {
180 case GMM_FORMAT_B8G8R8X8_UNORM_TYPE : return Format_X8R8G8B8;
181 case GMM_FORMAT_B8G8R8A8_UNORM_TYPE : return Format_A8R8G8B8;
182 case GMM_FORMAT_NV12_TYPE: return Format_NV12;
183 case GMM_FORMAT_A8_UNORM_TYPE : return Format_A8;
184 case GMM_FORMAT_R8G8_UNORM_TYPE : return Format_R8G8UN;
185 case GMM_FORMAT_R32_FLOAT_TYPE : return Format_R32F;
186 case GMM_FORMAT_AYUV_TYPE : return Format_AYUV;
187 // WA for GMM and MDF issue. Will revisit it after fixing the issue.
188 case GMM_FORMAT_R16G16B16A16_UNORM_TYPE: return Format_A16B16G16R16;
189 default:
190 {
191 VPHAL_RENDER_ASSERTMESSAGE("Unsupported format %d\n", format);
192 return Format_Invalid;
193 }
194 }
195 }
196
197 static inline
GetBitsPerPixel(GMM_RESOURCE_FORMAT format)198 int GetBitsPerPixel(GMM_RESOURCE_FORMAT format)
199 {
200 switch (format)
201 {
202 case GMM_FORMAT_B8G8R8X8_UNORM_TYPE: return 32;
203 case GMM_FORMAT_B8G8R8A8_UNORM_TYPE: return 32;
204 case GMM_FORMAT_NV12_TYPE: return 12;
205 case GMM_FORMAT_A8_UNORM_TYPE: return 8;
206 case GMM_FORMAT_R8G8_UNORM_TYPE: return 16;
207 case GMM_FORMAT_R32_FLOAT_TYPE: return 32;
208 case GMM_FORMAT_AYUV_TYPE: return 32;
209 case GMM_FORMAT_R16G16B16A16_UNORM_TYPE: return 64;
210 case GMM_FORMAT_R16G16B16X16_UNORM_TYPE: return 64;
211 default:
212 {
213 VPHAL_RENDER_ASSERTMESSAGE("Unsupported format %d\n", format);
214 return 0;
215 }
216 }
217 }
218
219 template <typename CmSurfType>
220 class VpCmSurfaceHolder
221 {
222 public:
223 static_assert(
224 std::is_same<CmSurfType, CmBuffer >::value ||
225 std::is_same<CmSurfType, CmSurface2D>::value ||
226 std::is_same<CmSurfType, CmSurface3D>::value,
227 "CmSurfType need to be one of CmBuffer, CmSurface2D or CmSurface3D.");
228
VpCmSurfaceHolder(PVPHAL_SURFACE vpSurf,CmContext * cmContext)229 VpCmSurfaceHolder(PVPHAL_SURFACE vpSurf, CmContext *cmContext):
230 mCmSurface(nullptr),
231 mSurfaceIndex(nullptr),
232 mSamplerSurfaceIndex(nullptr),
233 mSampler8x8SurfaceIndex(nullptr),
234 mWidth(vpSurf->dwWidth),
235 mHeight(vpSurf->dwHeight),
236 mDepth(vpSurf->dwDepth),
237 mFormat(ConvertMosFmtToGmmFmt(vpSurf->Format)),
238 m_cmContext(cmContext)
239 {
240 int result = CreateCmSurfaceSpecialized(vpSurf, mCmSurface);
241 if ((result != CM_SUCCESS) || (!mCmSurface))
242 {
243 VPHAL_RENDER_ASSERTMESSAGE("Failed to create VpCmSurfaceHolder from VP Surface!\n");
244 return;
245 }
246 mCmSurface->GetIndex(mSurfaceIndex);
247 }
248
VpCmSurfaceHolder(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmContext * cmContext)249 VpCmSurfaceHolder(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmContext *cmContext) :
250 mCmSurface(nullptr),
251 mSurfaceIndex(nullptr),
252 mSamplerSurfaceIndex(nullptr),
253 mSampler8x8SurfaceIndex(nullptr),
254 mWidth(width),
255 mHeight(height),
256 mDepth(depth),
257 mFormat(format),
258 m_cmContext(cmContext)
259 {
260 int result = CreateCmSurfaceSpecialized(width, height, depth, format, mCmSurface);
261 if ((result != CM_SUCCESS) || (!mCmSurface))
262 {
263 VPHAL_RENDER_ASSERTMESSAGE("Failed to create VpCmSurfaceHolder!\n");
264 return;
265 }
266 mCmSurface->GetIndex(mSurfaceIndex);
267 }
268
~VpCmSurfaceHolder()269 virtual ~VpCmSurfaceHolder()
270 {
271 VPHAL_RENDER_CHK_NULL_NO_STATUS_RETURN(m_cmContext);
272 CmDevice *dev = m_cmContext->GetCmDevice();
273
274 if (mSampler8x8SurfaceIndex)
275 {
276 dev->DestroySampler8x8Surface(mSampler8x8SurfaceIndex);
277 }
278
279 if (mSamplerSurfaceIndex)
280 {
281 dev->DestroySamplerSurface(mSamplerSurfaceIndex);
282 }
283
284 if (mCmSurface)
285 {
286 dev->DestroySurface(mCmSurface);
287 }
288 }
289
GetCmSurface()290 CmSurfType* GetCmSurface() const
291 {
292 return mCmSurface;
293 }
294
GetCmSurfaceIndex()295 SurfaceIndex* GetCmSurfaceIndex()
296 {
297 if (!mSurfaceIndex)
298 {
299 mCmSurface->GetIndex(mSurfaceIndex);
300 }
301 return mSurfaceIndex;
302 }
303
GetCmSamplerSurfaceIndex()304 SurfaceIndex* GetCmSamplerSurfaceIndex()
305 {
306 if (!mSamplerSurfaceIndex)
307 {
308 if (!m_cmContext)
309 {
310 return mSamplerSurfaceIndex;
311 }
312 int result = m_cmContext->GetCmDevice()->CreateSamplerSurface2D(mCmSurface, mSamplerSurfaceIndex);
313 if (result != CM_SUCCESS)
314 {
315 VPHAL_RENDER_ASSERTMESSAGE("Failed in CreateSamplerSurface2D!\n");
316 }
317
318 }
319 return mSamplerSurfaceIndex;
320 }
321
GetCmSampler8x8SurfaceIndex()322 SurfaceIndex* GetCmSampler8x8SurfaceIndex()
323 {
324 if (!mSampler8x8SurfaceIndex)
325 {
326 if (!m_cmContext)
327 {
328 return mSampler8x8SurfaceIndex;
329 }
330 int result = m_cmContext->GetCmDevice()->CreateSampler8x8Surface(mCmSurface, mSampler8x8SurfaceIndex, CM_AVS_SURFACE, CM_SURFACE_CLAMP);
331 if (result != CM_SUCCESS)
332 {
333 VPHAL_RENDER_ASSERTMESSAGE("Failed in CreateSampler8x8Surface!\n");
334 }
335 }
336 return mSampler8x8SurfaceIndex;
337 }
338
GetSurfaceDimentions(int & width,int & height,int & depth)339 void GetSurfaceDimentions(int &width, int &height, int &depth)
340 {
341 width = mWidth;
342 height = mHeight;
343 depth = mDepth;
344 }
345
GetSurfaceSize()346 int GetSurfaceSize() const
347 {
348 return (mWidth * mHeight * mDepth * GetBitsPerPixel(mFormat)) >> 3;
349 }
350
GetFormat()351 GMM_RESOURCE_FORMAT GetFormat() const
352 {
353 return mFormat;
354 }
355
InitSurfaceFromFile(const std::string & fileName)356 void InitSurfaceFromFile(const std::string &fileName)
357 {
358 std::ifstream blob(fileName, std::ifstream::ate | std::ifstream::binary);
359 if (!blob.is_open())
360 {
361 VPHAL_RENDER_ASSERTMESSAGE("Error in opening raw data file: %s.\n", fileName.c_str());
362 return;
363 }
364 const int fileSize = static_cast<int>(blob.tellg());
365 if (fileSize == 0)
366 {
367 VPHAL_RENDER_ASSERTMESSAGE("file size is 0.\n");
368 return;
369 }
370 blob.seekg(0, blob.beg);
371 std::vector<char> temp(GetSurfaceSize());
372 blob.read(temp.data(), MOS_MIN(fileSize, GetSurfaceSize()));
373 mCmSurface->WriteSurface((unsigned char *)temp.data(), nullptr);
374 }
375
DumpSurfaceToFile(const std::string & fileName)376 void DumpSurfaceToFile(const std::string &fileName)
377 {
378 std::ofstream blob(fileName, std::ofstream::out | std::ifstream::binary);
379
380 if (!blob.is_open())
381 {
382 VPHAL_RENDER_ASSERTMESSAGE("Error in opening raw data file: %s.\n", fileName.c_str());
383 return;
384 }
385
386 const int size = GetSurfaceSize();
387 std::vector<char> temp(size);
388 mCmSurface->ReadSurface((unsigned char*)temp.data(), nullptr, size);
389 blob.write(temp.data(), size);
390 }
391
392 private:
393 VpCmSurfaceHolder(const VpCmSurfaceHolder &) = delete;
394 VpCmSurfaceHolder& operator=(const VpCmSurfaceHolder &) = delete;
395
CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf,CmSurfType * & surf)396 inline int CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf, CmSurfType* &surf)
397 {
398 return 0;
399 }
400
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmSurfType * & surf)401 inline int CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmSurfType* &surf)
402 {
403 return 0;
404 }
405
406 PVPHAL_SURFACE mVphalSurface = nullptr;
407 CmSurfType *mCmSurface = nullptr;
408 SurfaceIndex *mSurfaceIndex = nullptr;
409 SurfaceIndex *mSamplerSurfaceIndex = nullptr;
410 SurfaceIndex *mSampler8x8SurfaceIndex = nullptr;
411
412 const int mWidth = 0;
413 const int mHeight = 0;
414 const int mDepth = 0;
415 const GMM_RESOURCE_FORMAT mFormat;
416 CmContext *m_cmContext = nullptr;
417 };
418
419 template <>
CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf,CmBuffer * & surf)420 inline int VpCmSurfaceHolder<CmBuffer>::CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf, CmBuffer* &surf)
421 {
422 if (!m_cmContext)
423 {
424 return CM_NULL_POINTER;
425 }
426 return m_cmContext->GetCmDevice()->CreateBuffer(&vpSurf->OsResource, surf);
427 }
428
429 template <>
CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf,CmSurface2D * & surf)430 inline int VpCmSurfaceHolder<CmSurface2D>::CreateCmSurfaceSpecialized(PVPHAL_SURFACE vpSurf, CmSurface2D* &surf)
431 {
432 if (!m_cmContext)
433 {
434 return CM_NULL_POINTER;
435 }
436 return m_cmContext->GetCmDevice()->CreateSurface2D(&vpSurf->OsResource, surf);
437 }
438
439 template <>
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmBuffer * & surf)440 inline int VpCmSurfaceHolder<CmBuffer>::CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmBuffer* &surf)
441 {
442 if (!m_cmContext)
443 {
444 return CM_NULL_POINTER;
445 }
446 return m_cmContext->GetCmDevice()->CreateBuffer(width, surf);
447 }
448
449 template <>
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmSurface2D * & surf)450 inline int VpCmSurfaceHolder<CmSurface2D>::CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmSurface2D* &surf)
451 {
452 if (!m_cmContext)
453 {
454 return CM_NULL_POINTER;
455 }
456 return m_cmContext->GetCmDevice()->CreateSurface2D(width, height, ConvertGmmFmtToMosFmt(format), surf);
457 }
458
459 template <>
CreateCmSurfaceSpecialized(int width,int height,int depth,GMM_RESOURCE_FORMAT format,CmSurface3D * & surf)460 inline int VpCmSurfaceHolder<CmSurface3D>::CreateCmSurfaceSpecialized(int width, int height, int depth, GMM_RESOURCE_FORMAT format, CmSurface3D* &surf)
461 {
462 if (!m_cmContext)
463 {
464 return CM_NULL_POINTER;
465 }
466 return m_cmContext->GetCmDevice()->CreateSurface3D(width, height, depth, ConvertGmmFmtToMosFmt(format), surf);
467 }
468
469 class VPRender
470 {
471 public:
~VPRender()472 virtual ~VPRender()
473 {
474 }
475
476 virtual void Render(void *payload) = 0;
477 };
478
479 // A simple CM kernel render wrapper.
480 // All methods derived classes need to implement are private.
481 // This means the calling order of such methods is fixed, and they will
482 // get hooked to the Render() entry method in this base class.
483 class VPCmRenderer: public VPRender
484 {
485 public:
486 VPCmRenderer(const std::string &name, CmContext *cmContext);
487 virtual ~VPCmRenderer();
488
489 void Render(void *payload) override;
490
SetmBlockingMode(bool enable)491 void SetmBlockingMode(bool enable)
492 {
493 mBlockingMode = enable;
494 }
495
EnableDump(bool enable)496 void EnableDump(bool enable)
497 {
498 mEnableDump = enable;
499 }
500
EnableBatchDispatch(bool enable)501 void EnableBatchDispatch(bool enable)
502 {
503 mBatchDispatch = enable;
504 }
505
506 protected:
507 CmProgram* LoadProgram(const void *binary, int size);
508 CmProgram* LoadProgram(const std::string& binaryFileName);
509
510 const std::string mName;
511 CmContext *m_cmContext = nullptr;
512
513 private:
514 virtual void AttachPayload(void *) = 0;
515 virtual CmKernel* GetKernelToRun(std::string &name) = 0;
516 virtual void GetThreadSpaceDimension(int &tsWidth, int &tsHeight, int &tsColor) = 0;
517 virtual void PrepareKernel(CmKernel *kernel) = 0;
518
519 // Derived class can override this method if special setup needs be performed on thread space,
520 // like walking pattern, dependency pattern(scoreboard), etc.
SetupThreadSpace(CmThreadSpace * threadSpace,int,int,int)521 virtual void SetupThreadSpace(CmThreadSpace *threadSpace, int /*tsWidth*/, int /*tsHeight*/, int /*tsColor*/)
522 {
523 threadSpace->SelectMediaWalkingPattern(CM_WALK_VERTICAL);
524 }
525
526 // This method will take effect only if this renderer works in batch dispatching mode(multi-kernels in one task).
527 // Be careful if derived class want to override it. Return true is always safe and workable.
528 // Return false if its kernel has no dependency against previous ones,
529 // thus will enable kernel parallel execution, which can improve performance in some cases.
NeedAddSync()530 virtual bool NeedAddSync()
531 {
532 return true;
533 }
534
CannotAssociateThreadSpace()535 virtual bool CannotAssociateThreadSpace()
536 {
537 return true;
538 }
539
Dump()540 virtual void Dump()
541 {
542 }
543
544 bool mBatchDispatch;
545 bool mBlockingMode;
546 bool mEnableDump;
547 };
548
549 #endif // __VPHAL_MDF_WRAPPER_H__
550