1 // Copyright (c) 2019 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20
21 #include "common_directx.h"
22
23 #include<map>
24
25 #define D3DFMT_NV12 (D3DFORMAT)MAKEFOURCC('N','V','1','2')
26 #define D3DFMT_YV12 (D3DFORMAT)MAKEFOURCC('Y','V','1','2')
27
28 IDirect3DDeviceManager9* pDeviceManager9 = NULL;
29 IDirect3DDevice9Ex* pD3DD9 = NULL;
30 IDirect3D9Ex* pD3D9 = NULL;
31 HANDLE pDeviceHandle = NULL;
32 IDirectXVideoAccelerationService* pDXVAServiceDec = NULL;
33 IDirectXVideoAccelerationService* pDXVAServiceVPP = NULL;
34
35 bool g_bCreateSharedHandles = false;
36
37 std::map<mfxMemId*, mfxHDL> allocResponses;
38 std::map<mfxHDL, mfxFrameAllocResponse> allocDecodeResponses;
39 std::map<mfxHDL, int> allocDecodeRefCount;
40
41 const struct {
42 mfxIMPL impl; // actual implementation
43 mfxU32 adapterID; // device adapter number
44 } implTypes[] = {
45 {MFX_IMPL_HARDWARE, 0},
46 {MFX_IMPL_HARDWARE2, 1},
47 {MFX_IMPL_HARDWARE3, 2},
48 {MFX_IMPL_HARDWARE4, 3}
49 };
50
51 // =================================================================
52 // DirectX functionality required to manage D3D surfaces
53 //
54
GetIntelDeviceAdapterNum(mfxSession session)55 mfxU32 GetIntelDeviceAdapterNum(mfxSession session)
56 {
57 mfxU32 adapterNum = 0;
58 mfxIMPL impl;
59
60 MFXQueryIMPL(session, &impl);
61
62 mfxIMPL baseImpl = MFX_IMPL_BASETYPE(impl); // Extract Media SDK base implementation type
63
64 // get corresponding adapter number
65 for (mfxU8 i = 0; i < sizeof(implTypes)/sizeof(implTypes[0]); i++) {
66 if (implTypes[i].impl == baseImpl) {
67 adapterNum = implTypes[i].adapterID;
68 break;
69 }
70 }
71
72 return adapterNum;
73 }
74
75 // Create HW device context
CreateHWDevice(mfxSession session,mfxHDL * deviceHandle,HWND window,bool bCreateSharedHandles)76 mfxStatus CreateHWDevice(mfxSession session, mfxHDL* deviceHandle, HWND window, bool bCreateSharedHandles)
77 {
78 // If window handle is not supplied, get window handle from coordinate 0,0
79 if (window == NULL) {
80 POINT point = {0, 0};
81 window = WindowFromPoint(point);
82 }
83
84 g_bCreateSharedHandles = bCreateSharedHandles;
85
86 HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D9);
87 if (!pD3D9 || FAILED(hr)) return MFX_ERR_DEVICE_FAILED;
88
89 RECT rc;
90 GetClientRect(window, &rc);
91
92 D3DPRESENT_PARAMETERS D3DPP;
93 memset(&D3DPP, 0, sizeof(D3DPP));
94 D3DPP.Windowed = true;
95 D3DPP.hDeviceWindow = window;
96 D3DPP.Flags = D3DPRESENTFLAG_VIDEO;
97 D3DPP.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
98 D3DPP.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
99 D3DPP.BackBufferCount = 1;
100 D3DPP.BackBufferFormat = D3DFMT_A8R8G8B8;
101 D3DPP.BackBufferWidth = rc.right - rc.left;
102 D3DPP.BackBufferHeight = rc.bottom - rc.top;
103 D3DPP.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
104 D3DPP.SwapEffect = D3DSWAPEFFECT_DISCARD;
105
106 hr = pD3D9->CreateDeviceEx( GetIntelDeviceAdapterNum(session),
107 D3DDEVTYPE_HAL,
108 window,
109 D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
110 &D3DPP,
111 NULL,
112 &pD3DD9);
113 if (FAILED(hr)) return MFX_ERR_NULL_PTR;
114
115 hr = pD3DD9->ResetEx(&D3DPP, NULL);
116 if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
117
118 hr = pD3DD9->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
119 if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
120
121 UINT resetToken = 0;
122
123 hr = DXVA2CreateDirect3DDeviceManager9(&resetToken, &pDeviceManager9);
124 if (FAILED(hr)) return MFX_ERR_NULL_PTR;
125
126 hr = pDeviceManager9->ResetDevice(pD3DD9, resetToken);
127 if (FAILED(hr)) return MFX_ERR_UNDEFINED_BEHAVIOR;
128
129 *deviceHandle = (mfxHDL)pDeviceManager9;
130
131 return MFX_ERR_NONE;
132 }
133
GetDevice()134 IDirect3DDevice9Ex* GetDevice()
135 {
136 return pD3DD9;
137 }
138
139
140 // Free HW device context
CleanupHWDevice()141 void CleanupHWDevice()
142 {
143 if (pDeviceManager9)
144 pDeviceManager9->CloseDeviceHandle(pDeviceHandle);
145 MSDK_SAFE_RELEASE(pDXVAServiceDec);
146 MSDK_SAFE_RELEASE(pDXVAServiceVPP);
147 MSDK_SAFE_RELEASE(pDeviceManager9);
148 MSDK_SAFE_RELEASE(pD3DD9);
149 MSDK_SAFE_RELEASE(pD3D9);
150 }
151
ClearYUVSurfaceD3D(mfxMemId memId)152 void ClearYUVSurfaceD3D(mfxMemId memId)
153 {
154 IDirect3DSurface9* pSurface;
155 D3DSURFACE_DESC desc;
156 D3DLOCKED_RECT locked;
157 pSurface = (IDirect3DSurface9*)memId;
158 pSurface->GetDesc(&desc);
159 pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
160 memset((mfxU8*)locked.pBits, 100, desc.Height*locked.Pitch); // Y plane
161 memset((mfxU8*)locked.pBits + desc.Height * locked.Pitch, 50, (desc.Height*locked.Pitch)/2); // UV plane
162 pSurface->UnlockRect();
163 }
164
ClearRGBSurfaceD3D(mfxMemId memId)165 void ClearRGBSurfaceD3D(mfxMemId memId)
166 {
167 IDirect3DSurface9* pSurface;
168 D3DSURFACE_DESC desc;
169 D3DLOCKED_RECT locked;
170 pSurface = (IDirect3DSurface9*)memId;
171 pSurface->GetDesc(&desc);
172 pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
173 memset((mfxU8*)locked.pBits, 100, desc.Height*locked.Pitch); // RGBA
174 pSurface->UnlockRect();
175 }
176
177 //
178 // Media SDK memory allocator entrypoints....
179 //
_simple_alloc(mfxFrameAllocRequest * request,mfxFrameAllocResponse * response)180 mfxStatus _simple_alloc(mfxFrameAllocRequest* request, mfxFrameAllocResponse* response)
181 {
182 DWORD DxvaType;
183 HRESULT hr = S_OK;
184
185 // Determine surface format (current simple implementation only supports NV12 and RGB4(32))
186 D3DFORMAT format;
187 if (MFX_FOURCC_NV12 == request->Info.FourCC)
188 format = D3DFMT_NV12;
189 else if (MFX_FOURCC_RGB4 == request->Info.FourCC)
190 format = D3DFMT_A8R8G8B8;
191 else if (MFX_FOURCC_YUY2 == request->Info.FourCC)
192 format = D3DFMT_YUY2;
193 else if (MFX_FOURCC_YV12 == request->Info.FourCC)
194 format = D3DFMT_YV12;
195 else
196 format = (D3DFORMAT)request->Info.FourCC;
197
198
199 // Determine render target
200 if (MFX_MEMTYPE_DXVA2_PROCESSOR_TARGET & request->Type)
201 DxvaType = DXVA2_VideoProcessorRenderTarget;
202 else
203 DxvaType = DXVA2_VideoDecoderRenderTarget;
204
205 // Force use of video processor if color conversion is required (with this simple set of samples we only illustrate RGB4 color converison via VPP)
206 if (D3DFMT_A8R8G8B8 == format) // must use processor service
207 DxvaType = DXVA2_VideoProcessorRenderTarget;
208
209 mfxMemId* mids = NULL;
210 if (!g_bCreateSharedHandles) {
211 mids = new mfxMemId[request->NumFrameSuggested];
212 if (!mids) return MFX_ERR_MEMORY_ALLOC;
213 } else {
214 mids = new mfxMemId[request->NumFrameSuggested*2];
215 if (!mids) return MFX_ERR_MEMORY_ALLOC;
216
217 memset(mids, 0, sizeof(mfxMemId)*request->NumFrameSuggested*2);
218 }
219
220 if (!pDeviceHandle) {
221 hr = pDeviceManager9->OpenDeviceHandle(&pDeviceHandle);
222 if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
223 }
224
225 IDirectXVideoAccelerationService* pDXVAServiceTmp = NULL;
226
227 if (DXVA2_VideoDecoderRenderTarget == DxvaType) { // for both decode and encode
228 if (pDXVAServiceDec == NULL)
229 hr = pDeviceManager9->GetVideoService(pDeviceHandle, IID_IDirectXVideoDecoderService, (void**)&pDXVAServiceDec);
230
231 pDXVAServiceTmp = pDXVAServiceDec;
232 } else { // DXVA2_VideoProcessorRenderTarget ; for VPP
233 if (pDXVAServiceVPP == NULL)
234 hr = pDeviceManager9->GetVideoService(pDeviceHandle, IID_IDirectXVideoProcessorService, (void**)&pDXVAServiceVPP);
235
236 pDXVAServiceTmp = pDXVAServiceVPP;
237 }
238 if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
239
240 if (g_bCreateSharedHandles && !(MFX_MEMTYPE_INTERNAL_FRAME & request->Type)) {
241 // Allocate surfaces with shared handles. Commonly used for OpenCL interoperability
242 for (int i=0; i<request->NumFrameSuggested; ++i) {
243 mfxMemId* tmpptr = mids + i + request->NumFrameSuggested;
244
245 hr = pDXVAServiceTmp->CreateSurface(request->Info.Width,
246 request->Info.Height,
247 0,
248 format,
249 D3DPOOL_DEFAULT,
250 0,
251 DxvaType,
252 (IDirect3DSurface9**)mids+i,
253 (HANDLE*)(tmpptr));
254 }
255 } else {
256 // Allocate surfaces
257 hr = pDXVAServiceTmp->CreateSurface(request->Info.Width,
258 request->Info.Height,
259 request->NumFrameSuggested - 1,
260 format,
261 D3DPOOL_DEFAULT,
262 0,
263 DxvaType,
264 (IDirect3DSurface9**)mids,
265 NULL);
266 }
267 if (FAILED(hr)) return MFX_ERR_MEMORY_ALLOC;
268
269 response->mids = mids;
270 response->NumFrameActual = request->NumFrameSuggested;
271
272 return MFX_ERR_NONE;
273 }
274
simple_alloc(mfxHDL pthis,mfxFrameAllocRequest * request,mfxFrameAllocResponse * response)275 mfxStatus simple_alloc(mfxHDL pthis, mfxFrameAllocRequest* request, mfxFrameAllocResponse* response)
276 {
277 mfxStatus sts = MFX_ERR_NONE;
278
279 if (request->Type & MFX_MEMTYPE_SYSTEM_MEMORY)
280 return MFX_ERR_UNSUPPORTED;
281
282 if (allocDecodeResponses.find(pthis) != allocDecodeResponses.end() &&
283 MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
284 MFX_MEMTYPE_FROM_DECODE & request->Type) {
285 // Memory for this request was already allocated during manual allocation stage. Return saved response
286 // When decode acceleration device (DXVA) is created it requires a list of D3D surfaces to be passed.
287 // Therefore Media SDK will ask for the surface info/mids again at Init() stage, thus requiring us to return the saved response
288 // (No such restriction applies to Encode or VPP)
289 *response = allocDecodeResponses[pthis];
290 allocDecodeRefCount[pthis]++;
291 } else {
292 sts = _simple_alloc(request, response);
293
294 if (MFX_ERR_NONE == sts) {
295 if ( MFX_MEMTYPE_EXTERNAL_FRAME & request->Type &&
296 MFX_MEMTYPE_FROM_DECODE & request->Type) {
297 // Decode alloc response handling
298 allocDecodeResponses[pthis] = *response;
299 allocDecodeRefCount[pthis]++;
300 } else {
301 // Encode and VPP alloc response handling
302 allocResponses[response->mids] = pthis;
303 }
304 }
305 }
306
307 return sts;
308 }
309
simple_lock(mfxHDL pthis,mfxMemId mid,mfxFrameData * ptr)310 mfxStatus simple_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr)
311 {
312 pthis; // To suppress warning for this unused parameter
313
314 IDirect3DSurface9* pSurface = (IDirect3DSurface9*)mid;
315
316 if (pSurface == 0) return MFX_ERR_INVALID_HANDLE;
317 if (ptr == 0) return MFX_ERR_LOCK_MEMORY;
318
319 D3DSURFACE_DESC desc;
320 HRESULT hr = pSurface->GetDesc(&desc);
321 if (FAILED(hr)) return MFX_ERR_LOCK_MEMORY;
322
323 D3DLOCKED_RECT locked;
324 hr = pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
325 if (FAILED(hr)) return MFX_ERR_LOCK_MEMORY;
326
327 // In these simple set of samples we only illustrate usage of NV12 and RGB4(32)
328 if (D3DFMT_NV12 == desc.Format) {
329 ptr->Pitch = (mfxU16)locked.Pitch;
330 ptr->Y = (mfxU8*)locked.pBits;
331 ptr->U = (mfxU8*)locked.pBits + desc.Height * locked.Pitch;
332 ptr->V = ptr->U + 1;
333 } else if (D3DFMT_A8R8G8B8 == desc.Format) {
334 ptr->Pitch = (mfxU16)locked.Pitch;
335 ptr->B = (mfxU8*)locked.pBits;
336 ptr->G = ptr->B + 1;
337 ptr->R = ptr->B + 2;
338 ptr->A = ptr->B + 3;
339 } else if (D3DFMT_YUY2 == desc.Format) {
340 ptr->Pitch = (mfxU16)locked.Pitch;
341 ptr->Y = (mfxU8*)locked.pBits;
342 ptr->U = ptr->Y + 1;
343 ptr->V = ptr->Y + 3;
344 } else if (D3DFMT_YV12 == desc.Format) {
345 ptr->Pitch = (mfxU16)locked.Pitch;
346 ptr->Y = (mfxU8*)locked.pBits;
347 ptr->V = ptr->Y + desc.Height * locked.Pitch;
348 ptr->U = ptr->V + (desc.Height * locked.Pitch) / 4;
349 } else if (D3DFMT_P8 == desc.Format) {
350 ptr->Pitch = (mfxU16)locked.Pitch;
351 ptr->Y = (mfxU8*)locked.pBits;
352 ptr->U = 0;
353 ptr->V = 0;
354 }
355
356 return MFX_ERR_NONE;
357 }
358
simple_unlock(mfxHDL pthis,mfxMemId mid,mfxFrameData * ptr)359 mfxStatus simple_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData* ptr)
360 {
361 pthis; // To suppress warning for this unused parameter
362
363 IDirect3DSurface9* pSurface = (IDirect3DSurface9*)mid;
364
365 if (pSurface == 0) return MFX_ERR_INVALID_HANDLE;
366
367 pSurface->UnlockRect();
368
369 if (NULL != ptr) {
370 ptr->Pitch = 0;
371 ptr->R = 0;
372 ptr->G = 0;
373 ptr->B = 0;
374 ptr->A = 0;
375 }
376
377 return MFX_ERR_NONE;
378 }
379
simple_gethdl(mfxHDL pthis,mfxMemId mid,mfxHDL * handle)380 mfxStatus simple_gethdl(mfxHDL pthis, mfxMemId mid, mfxHDL* handle)
381 {
382 pthis; // To suppress warning for this unused parameter
383
384 if (handle == 0) return MFX_ERR_INVALID_HANDLE;
385
386 *handle = mid;
387 return MFX_ERR_NONE;
388 }
389
390
_simple_free(mfxFrameAllocResponse * response)391 mfxStatus _simple_free(mfxFrameAllocResponse* response)
392 {
393 if (response->mids) {
394 for (mfxU32 i = 0; i < response->NumFrameActual; i++) {
395 if (response->mids[i]) {
396 IDirect3DSurface9* handle = (IDirect3DSurface9*)response->mids[i];
397 handle->Release();
398 }
399 }
400 }
401
402 delete [] response->mids;
403 response->mids = 0;
404
405 return MFX_ERR_NONE;
406 }
407
simple_free(mfxHDL pthis,mfxFrameAllocResponse * response)408 mfxStatus simple_free(mfxHDL pthis, mfxFrameAllocResponse* response)
409 {
410 if (!response) return MFX_ERR_NULL_PTR;
411
412 if (allocResponses.find(response->mids) == allocResponses.end()) {
413 // Decode free response handling
414 if (--allocDecodeRefCount[pthis] == 0) {
415 _simple_free(response);
416 allocDecodeResponses.erase(pthis);
417 allocDecodeRefCount.erase(pthis);
418 }
419 } else {
420 // Encode and VPP free response handling
421 allocResponses.erase(response->mids);
422 _simple_free(response);
423 }
424
425 return MFX_ERR_NONE;
426 }
427