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