1 /*
2 * Copyright (c) 2018-2019, 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      cm_ish_base.cpp
24 //! \brief     Contains Class CmISHBase  definitions
25 //!
26 
27 #include "cm_ish.h"
28 #include "cm_kernel_ex.h"
29 
30 using namespace CMRT_UMD;
31 
CmISHBase()32 CmISHBase::CmISHBase():
33     m_osInterface(nullptr),
34     m_resource(nullptr),
35     m_lockedData(nullptr),
36     m_size(0),
37     m_offset(0),
38     m_trackerProducer(nullptr),
39     m_lastTrackerToken(nullptr),
40     m_addedKernelCount(0),
41     m_isSipKernelLoaded(false),
42     m_sipKernel(nullptr),
43     m_sipKernelSize(0),
44     m_sipKernelOffset(0)
45 {
46 
47 }
48 
~CmISHBase()49 CmISHBase::~CmISHBase()
50 {
51     MOS_GFXRES_FREE_FLAGS resFreeFlags = {0};
52 
53     resFreeFlags.AssumeNotInUse = 1;
54 
55     while (m_destroyedTrackers.size())
56     {
57         MOS_RESOURCE *res = m_destroyedResources.back();
58         m_osInterface->pfnFreeResourceWithFlag(m_osInterface, res, resFreeFlags.Value);
59 
60         FrameTrackerToken *trackerToken = m_destroyedTrackers.back();
61 
62         MOS_FreeMemory(res);
63         MOS_Delete(trackerToken);
64         m_destroyedResources.pop_back();
65         m_destroyedTrackers.pop_back();
66     }
67     // delete current resource
68     if (m_resource)
69     {
70         m_osInterface->pfnUnlockResource(m_osInterface, m_resource);
71         m_osInterface->pfnFreeResourceWithFlag(m_osInterface, m_resource, resFreeFlags.Value);
72         MOS_FreeMemory(m_resource);
73     }
74 
75     if (m_lastTrackerToken)
76     {
77         MOS_Delete(m_lastTrackerToken);
78     }
79 
80     if (m_sipKernel)
81     {
82         MOS_FreeMemory(m_sipKernel);
83     }
84 }
85 
Initialize(CM_HAL_STATE * cmhal,FrameTrackerProducer * trackerProducer)86 MOS_STATUS CmISHBase::Initialize(CM_HAL_STATE *cmhal, FrameTrackerProducer *trackerProducer)
87 {
88     m_osInterface = cmhal->osInterface;
89     m_trackerProducer = trackerProducer;
90     ExpandHeapSize(m_initSize);
91 
92     if (!cmhal->midThreadPreemptionDisabled)
93     {
94         CM_CHK_MOSSTATUS_RETURN(CreateSipKernel(cmhal)); // generate sip kernel in m_sipKernel
95     }
96 
97     return MOS_STATUS_SUCCESS;
98 }
99 
LoadKernels(CmKernelEx ** kernels,int count)100 MOS_STATUS CmISHBase::LoadKernels(CmKernelEx **kernels, int count)
101 {
102     uint32_t blockSizes[CM_MAX_KERNELS_PER_TASK];
103     uint32_t blockIdx = 0;
104     uint32_t totalSize = 0;
105     for (int i = 0; i < count; i++)
106     {
107         CmKernelEx *kernel = kernels[i];
108         // check if the kernel is in ish
109         CmISHBase *rIsh = nullptr;
110         int rIdx = -1;
111         kernel->GetRecordedInfo(&rIsh, &rIdx);
112         if (rIsh == this && rIdx >= 0 && rIdx < (int)m_addedKernelCount && m_addedKernels[rIdx] == kernel)
113         {
114             //printf("HFDebug: reUse kernel %p in ish, name %s\n", kernel, kernel->GetName());
115             continue;
116         }
117         auto ite = m_addedHashValues.find(kernel->GetHashValue());
118         if (ite != m_addedHashValues.end())
119         {
120             continue;
121         }
122         //printf("HFDebug: add a new kernel %p in ish, name %s\n", kernel, kernel->GetName());
123         uint8_t *nkernel = nullptr;
124         uint32_t size = 0;
125         kernel->GetNativeKernel(&nkernel, &size);
126         uint32_t temp = MOS_ALIGN_CEIL(size + m_kernelPadding, m_kernelAlign);
127         blockSizes[blockIdx ++] = temp;
128         totalSize += temp;
129     }
130 
131     uint32_t neededSize = totalSize;
132     if (!m_isSipKernelLoaded && m_sipKernelSize)
133     {
134         neededSize += MOS_ALIGN_CEIL(m_sipKernelSize + m_kernelPadding, m_kernelAlign);
135     }
136     if (m_offset + neededSize > m_size)
137     {
138         ExpandHeapSize(neededSize);
139     }
140 
141     if (!m_isSipKernelLoaded && m_sipKernelSize)
142     {
143         uint32_t temp = MOS_ALIGN_CEIL(m_sipKernelSize + m_kernelPadding, m_kernelAlign);
144 
145         // Copy Cm Kernel Binary
146         MOS_SecureMemcpy(m_lockedData + m_offset, m_size - m_offset, m_sipKernel, m_sipKernelSize);
147 
148         // Padding bytes dummy instructions after kernel binary to resolve page fault issue
149         MOS_ZeroMemory(m_lockedData + m_offset + m_sipKernelSize, temp - m_sipKernelSize);
150         m_sipKernelOffset = m_offset;
151         m_offset += temp;
152 
153         m_isSipKernelLoaded = true;
154     }
155 
156     for (int i = 0; i < count; i++)
157     {
158         CmKernelEx *kernel = kernels[i];
159         // check if the kernel is in ish
160         CmISHBase *rIsh = nullptr;
161         int rIdx = -1;
162         kernel->GetRecordedInfo(&rIsh, &rIdx);
163         if (rIsh == this && rIdx >= 0 && rIdx < (int)m_addedKernelCount && m_addedKernels[rIdx] == kernel)
164         {
165             continue;
166         }
167         auto ite = m_addedHashValues.find(kernel->GetHashValue());
168         if (ite != m_addedHashValues.end())
169         {
170             uint32_t offset = ite->second;
171             kernel->Recorded(this, -1, offset);
172             continue;
173         }
174         // copy kernel binary
175         uint8_t *nkernel = nullptr;
176         uint32_t size = 0;
177         kernel->GetNativeKernel(&nkernel, &size);
178         uint32_t temp = MOS_ALIGN_CEIL(size + m_kernelPadding, m_kernelAlign);
179 
180         // Copy Cm Kernel Binary
181         MOS_SecureMemcpy(m_lockedData + m_offset, m_size - m_offset, nkernel, size);
182 
183         // Padding bytes dummy instructions after kernel binary to resolve page fault issue
184         MOS_ZeroMemory(m_lockedData + m_offset + size, temp - size);
185 
186         // record
187         m_addedKernels.push_back(kernel);
188         kernel->Recorded(this, (int)m_addedKernelCount, m_offset);
189         m_addedHashValues[kernel->GetHashValue()] = m_offset;
190         m_addedKernelCount ++;
191         m_offset += temp;
192     }
193     return MOS_STATUS_SUCCESS;
194 }
195 
ExpandHeapSize(uint32_t extraSize)196 MOS_STATUS CmISHBase::ExpandHeapSize(uint32_t extraSize)
197 {
198     uint32_t addSize = MOS_ALIGN_CEIL(extraSize, m_expandStep);
199     // destroy the old resource
200     if (m_resource)
201     {
202         m_destroyedResources.push_front(m_resource);
203         m_destroyedTrackers.push_front(m_lastTrackerToken);
204     }
205 
206     // allocate new resource
207     m_resource = (PMOS_RESOURCE)MOS_AllocAndZeroMemory(sizeof(MOS_RESOURCE));
208     CM_CHK_NULL_RETURN_MOSERROR(m_resource);
209     MOS_ALLOC_GFXRES_PARAMS allocParams;
210     MOS_ZeroMemory(&allocParams, sizeof(allocParams));
211     allocParams.Type = MOS_GFXRES_BUFFER;
212     allocParams.TileType = MOS_TILE_LINEAR;
213     allocParams.Format = Format_Buffer;
214     allocParams.dwBytes = m_size + addSize;
215     allocParams.pBufName = "ISHeap";
216 
217     CM_CHK_MOSSTATUS_RETURN(m_osInterface->pfnAllocateResource(m_osInterface, &allocParams,
218                                                                m_resource));
219     CM_CHK_MOSSTATUS_RETURN(m_osInterface->pfnRegisterResource(m_osInterface, m_resource,
220                                                                true, true));
221     CM_CHK_MOSSTATUS_RETURN(m_osInterface->pfnSkipResourceSync(m_resource));
222 
223     m_size += addSize;
224     m_offset = 0;
225 
226     MOS_LOCK_PARAMS lockParams;
227     MOS_ZeroMemory(&lockParams, sizeof(lockParams));
228     lockParams.WriteOnly = 1;
229     lockParams.NoOverWrite = 1;
230     lockParams.Uncached = 1;
231     m_lockedData = (uint8_t*)m_osInterface->pfnLockResource(m_osInterface, m_resource, &lockParams);
232 
233     // one new tracker token with one new resource
234     m_lastTrackerToken = MOS_New(FrameTrackerToken);
235     m_lastTrackerToken->SetProducer(m_trackerProducer);
236 
237     // no kernel is in the new heap
238     m_addedKernels.clear();
239     m_addedKernelCount = 0;
240     m_addedHashValues.clear();
241     Refresh();
242     m_isSipKernelLoaded = false;
243 
244     return MOS_STATUS_SUCCESS;
245 }
246 
Refresh()247 MOS_STATUS CmISHBase::Refresh()
248 {
249     MOS_GFXRES_FREE_FLAGS resFreeFlags = {0};
250 
251     resFreeFlags.AssumeNotInUse = 1;
252 
253     // goes from back to front to handle tracker overflow
254     while (m_destroyedTrackers.size())
255     {
256         FrameTrackerToken *trackerToken = m_destroyedTrackers.back();
257         if (!trackerToken->IsExpired())
258         {
259             break;
260         }
261         MOS_RESOURCE *res = m_destroyedResources.back();
262         m_osInterface->pfnUnlockResource(m_osInterface, res);
263         m_osInterface->pfnFreeResourceWithFlag(m_osInterface, res, resFreeFlags.Value);
264 
265         m_destroyedResources.pop_back();
266         m_destroyedTrackers.pop_back();
267 
268         MOS_FreeMemory(res);
269         MOS_Delete(trackerToken);
270     }
271 
272     return MOS_STATUS_SUCCESS;
273 }
274 
Clean()275 void CmISHBase::Clean()
276 {
277     m_offset = 0;
278     m_addedKernels.clear();
279     m_addedKernelCount = 0;
280     Refresh();
281     m_isSipKernelLoaded = false;
282 }
283 
284