• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft 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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_context.h"
25 #include "d3d12_screen.h"
26 #include "d3d12_video_proc.h"
27 #include "d3d12_residency.h"
28 #include "d3d12_util.h"
29 #include "d3d12_resource.h"
30 #include "d3d12_video_buffer.h"
31 
32 void
d3d12_video_processor_begin_frame(struct pipe_video_codec * codec,struct pipe_video_buffer * target,struct pipe_picture_desc * picture)33 d3d12_video_processor_begin_frame(struct pipe_video_codec * codec,
34                                 struct pipe_video_buffer *target,
35                                 struct pipe_picture_desc *picture)
36 {
37     struct d3d12_video_processor * pD3D12Proc = (struct d3d12_video_processor *) codec;
38     debug_printf("[d3d12_video_processor] d3d12_video_processor_begin_frame - "
39                 "fenceValue: %d\n",
40                 pD3D12Proc->m_fenceValue);
41 
42     // Setup process frame arguments for output/target texture.
43     struct d3d12_video_buffer *pOutputVideoBuffer = (struct d3d12_video_buffer *) target;
44 
45     // Make the resources permanently resident for video use
46     d3d12_promote_to_permanent_residency(pD3D12Proc->m_pD3D12Screen, pOutputVideoBuffer->texture);
47 
48     ID3D12Resource *pDstD3D12Res = d3d12_resource_resource(pOutputVideoBuffer->texture);
49     auto dstDesc = GetDesc(pDstD3D12Res);
50     pD3D12Proc->m_OutputArguments = {
51         {
52             {
53                     pDstD3D12Res, // ID3D12Resource *pTexture2D;
54                     0, // UINT Subresource;
55             },
56             {
57                     NULL, // ID3D12Resource *pTexture2D;
58                     0 // UINT Subresource;
59             }
60         },
61         { 0, 0, (int) dstDesc.Width, (int) dstDesc.Height }
62     };
63 
64     debug_printf("d3d12_video_processor_begin_frame: Beginning new scene with Output ID3D12Resource: %p (%d %d)\n", pDstD3D12Res, (int) dstDesc.Width, (int) dstDesc.Height);
65 }
66 
67 void
d3d12_video_processor_end_frame(struct pipe_video_codec * codec,struct pipe_video_buffer * target,struct pipe_picture_desc * picture)68 d3d12_video_processor_end_frame(struct pipe_video_codec * codec,
69                               struct pipe_video_buffer *target,
70                               struct pipe_picture_desc *picture)
71 {
72     struct d3d12_video_processor * pD3D12Proc = (struct d3d12_video_processor *) codec;
73     debug_printf("[d3d12_video_processor] d3d12_video_processor_end_frame - "
74                 "fenceValue: %d\n",
75                 pD3D12Proc->m_fenceValue);
76 
77     auto curOutputDesc = GetOutputStreamDesc(pD3D12Proc->m_spVideoProcessor.Get());
78     auto curOutputTexFmt = GetDesc(pD3D12Proc->m_OutputArguments.OutputStream[0].pTexture2D).Format;
79 
80     bool inputFmtsMatch = pD3D12Proc->m_inputStreamDescs.size() == pD3D12Proc->m_ProcessInputs.size();
81     unsigned curInputIdx = 0;
82     while( (curInputIdx < pD3D12Proc->m_inputStreamDescs.size()) && inputFmtsMatch)
83     {
84         inputFmtsMatch = inputFmtsMatch && (pD3D12Proc->m_inputStreamDescs[curInputIdx].Format == GetDesc(pD3D12Proc->m_ProcessInputs[curInputIdx].InputStream[0].pTexture2D).Format);
85         curInputIdx++;
86     }
87 
88     bool inputCountMatches = (pD3D12Proc->m_ProcessInputs.size() == pD3D12Proc->m_spVideoProcessor->GetNumInputStreamDescs());
89     bool outputFmtMatches = (curOutputDesc.Format == curOutputTexFmt);
90     bool needsVPRecreation = (
91         !inputCountMatches // Requested batch has different number of Inputs to be blit'd
92         || !outputFmtMatches // output texture format different than vid proc object expects
93         || !inputFmtsMatch // inputs texture formats different than vid proc object expects
94     );
95 
96     if(needsVPRecreation) {
97         debug_printf("[d3d12_video_processor] d3d12_video_processor_end_frame - Attempting to re-create ID3D12VideoProcessor "
98                       "input count matches %d inputFmtsMatch: %d outputFmtsMatch %d \n", inputCountMatches, inputFmtsMatch, outputFmtMatches);
99 
100         DXGI_COLOR_SPACE_TYPE InputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
101         DXGI_FORMAT OutputFormat = curOutputTexFmt;
102         DXGI_COLOR_SPACE_TYPE OutputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
103 
104         std::vector<DXGI_FORMAT> InputFormats;
105         for(D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS1 curInput : pD3D12Proc->m_ProcessInputs)
106         {
107             InputFormats.push_back(GetDesc(curInput.InputStream[0].pTexture2D).Format);
108         }
109 
110         if(!d3d12_video_processor_check_caps_and_create_processor(pD3D12Proc, InputFormats, InputColorSpace, OutputFormat, OutputColorSpace))
111         {
112             debug_printf("[d3d12_video_processor] d3d12_video_processor_end_frame - Failure when "
113                       " trying to re-create the ID3D12VideoProcessor for current batch streams configuration\n");
114             assert(false);
115         }
116     }
117 
118     // Schedule barrier transitions
119     std::vector<D3D12_RESOURCE_BARRIER> barrier_transitions;
120     barrier_transitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
121                                 pD3D12Proc->m_OutputArguments.OutputStream[0].pTexture2D,
122                                 D3D12_RESOURCE_STATE_COMMON,
123                                 D3D12_RESOURCE_STATE_VIDEO_PROCESS_WRITE));
124 
125     for(D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS1 curInput : pD3D12Proc->m_ProcessInputs)
126         barrier_transitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
127                                     curInput.InputStream[0].pTexture2D,
128                                     D3D12_RESOURCE_STATE_COMMON,
129                                     D3D12_RESOURCE_STATE_VIDEO_PROCESS_READ));
130 
131     pD3D12Proc->m_spCommandList->ResourceBarrier(static_cast<uint32_t>(barrier_transitions.size()), barrier_transitions.data());
132 
133     // Schedule process operation
134 
135     pD3D12Proc->m_spCommandList->ProcessFrames1(pD3D12Proc->m_spVideoProcessor.Get(), &pD3D12Proc->m_OutputArguments, pD3D12Proc->m_ProcessInputs.size(), pD3D12Proc->m_ProcessInputs.data());
136 
137     // Schedule reverse (back to common) transitions before command list closes for current frame
138 
139     for (auto &BarrierDesc : barrier_transitions)
140         std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
141 
142     pD3D12Proc->m_spCommandList->ResourceBarrier(static_cast<uint32_t>(barrier_transitions.size()), barrier_transitions.data());
143 }
144 
145 void
d3d12_video_processor_process_frame(struct pipe_video_codec * codec,struct pipe_video_buffer * input_texture,const struct pipe_vpp_desc * process_properties)146 d3d12_video_processor_process_frame(struct pipe_video_codec *codec,
147                         struct pipe_video_buffer *input_texture,
148                         const struct pipe_vpp_desc *process_properties)
149 {
150     struct d3d12_video_processor * pD3D12Proc = (struct d3d12_video_processor *) codec;
151 
152     // Get the underlying resources from the pipe_video_buffers
153     struct d3d12_video_buffer *pInputVideoBuffer = (struct d3d12_video_buffer *) input_texture;
154 
155     // Make the resources permanently resident for video use
156     d3d12_promote_to_permanent_residency(pD3D12Proc->m_pD3D12Screen, pInputVideoBuffer->texture);
157 
158     ID3D12Resource *pSrcD3D12Res = d3d12_resource_resource(pInputVideoBuffer->texture);
159 
160     // y0 = top
161     // x0 = left
162     // x1 = right
163     // y1 = bottom
164 
165     debug_printf("d3d12_video_processor_process_frame: Adding Input ID3D12Resource: %p to scene (Output target %p)\n", pSrcD3D12Res, pD3D12Proc->m_OutputArguments.OutputStream[0].pTexture2D);
166     debug_printf("d3d12_video_processor_process_frame: Input box: top: %d left: %d right: %d bottom: %d\n", process_properties->src_region.y0, process_properties->src_region.x0, process_properties->src_region.x1, process_properties->src_region.y1);
167     debug_printf("d3d12_video_processor_process_frame: Output box: top: %d left: %d right: %d bottom: %d\n", process_properties->dst_region.y0, process_properties->dst_region.x0, process_properties->dst_region.x1, process_properties->dst_region.y1);
168     debug_printf("d3d12_video_processor_process_frame: Requested alpha blend mode %d global alpha: %f \n", process_properties->blend.mode, process_properties->blend.global_alpha);
169 
170     // Setup process frame arguments for current input texture.
171 
172     unsigned curInputStreamIndex = pD3D12Proc->m_ProcessInputs.size();
173     D3D12_VIDEO_PROCESS_INPUT_STREAM_ARGUMENTS1 InputArguments = {
174         {
175         { // D3D12_VIDEO_PROCESS_INPUT_STREAM InputStream[0];
176                 pSrcD3D12Res, // ID3D12Resource *pTexture2D;
177                 0, // UINT Subresource
178                 {//D3D12_VIDEO_PROCESS_REFERENCE_SET ReferenceSet;
179                     0, //UINT NumPastFrames;
180                     NULL, //ID3D12Resource **ppPastFrames;
181                     NULL, // UINT *pPastSubresources;
182                     0, //UINT NumFutureFrames;
183                     NULL, //ID3D12Resource **ppFutureFrames;
184                     NULL //UINT *pFutureSubresources;
185                 }
186         },
187         { // D3D12_VIDEO_PROCESS_INPUT_STREAM InputStream[1];
188                 NULL, //ID3D12Resource *pTexture2D;
189                 0, //UINT Subresource;
190                 {//D3D12_VIDEO_PROCESS_REFERENCE_SET ReferenceSet;
191                     0, //UINT NumPastFrames;
192                     NULL, //ID3D12Resource **ppPastFrames;
193                     NULL, // UINT *pPastSubresources;
194                     0, //UINT NumFutureFrames;
195                     NULL, //ID3D12Resource **ppFutureFrames;
196                     NULL //UINT *pFutureSubresources;
197                 }
198         }
199         },
200         { // D3D12_VIDEO_PROCESS_TRANSFORM Transform;
201             // y0 = top
202             // x0 = left
203             // x1 = right
204             // y1 = bottom
205             // typedef struct _RECT
206             // {
207             //     int left;
208             //     int top;
209             //     int right;
210             //     int bottom;
211             // } RECT;
212             { process_properties->src_region.x0/*left*/, process_properties->src_region.y0/*top*/, process_properties->src_region.x1/*right*/, process_properties->src_region.y1/*bottom*/ },
213             { process_properties->dst_region.x0/*left*/, process_properties->dst_region.y0/*top*/, process_properties->dst_region.x1/*right*/, process_properties->dst_region.y1/*bottom*/ }, // D3D12_RECT DestinationRectangle;
214             pD3D12Proc->m_inputStreamDescs[curInputStreamIndex].EnableOrientation ? d3d12_video_processor_convert_pipe_rotation(process_properties->orientation) : D3D12_VIDEO_PROCESS_ORIENTATION_DEFAULT, // D3D12_VIDEO_PROCESS_ORIENTATION Orientation;
215         },
216         D3D12_VIDEO_PROCESS_INPUT_STREAM_FLAG_NONE,
217         { // D3D12_VIDEO_PROCESS_INPUT_STREAM_RATE RateInfo;
218             0,
219             0,
220         },
221         // INT                                    FilterLevels[32];
222         {
223             0, // Trailing zeroes on the rest
224         },
225         //D3D12_VIDEO_PROCESS_ALPHA_BLENDING;
226         {
227             (process_properties->blend.mode == PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA),
228             process_properties->blend.global_alpha
229         },
230         // D3D12_VIDEO_FIELD_TYPE FieldType
231         D3D12_VIDEO_FIELD_TYPE_NONE,
232     };
233 
234     debug_printf("ProcessFrame InArgs Orientation %d \n\tSrc top: %d left: %d right: %d bottom: %d\n\tDst top: %d left: %d right: %d bottom: %d\n", InputArguments.Transform.Orientation,
235         InputArguments.Transform.SourceRectangle.top, InputArguments.Transform.SourceRectangle.left, InputArguments.Transform.SourceRectangle.right, InputArguments.Transform.SourceRectangle.bottom,
236         InputArguments.Transform.DestinationRectangle.top, InputArguments.Transform.DestinationRectangle.left, InputArguments.Transform.DestinationRectangle.right, InputArguments.Transform.DestinationRectangle.bottom);
237 
238     pD3D12Proc->m_ProcessInputs.push_back(InputArguments);
239 
240     ///
241     /// Flush work to the GPU and blocking wait until GPU finishes
242     ///
243     pD3D12Proc->m_needsGPUFlush = true;
244 }
245 
246 void
d3d12_video_processor_destroy(struct pipe_video_codec * codec)247 d3d12_video_processor_destroy(struct pipe_video_codec * codec)
248 {
249     if (codec == nullptr) {
250         return;
251     }
252     d3d12_video_processor_flush(codec);   // Flush pending work before destroying.
253 
254     // Call dtor to make ComPtr work
255     struct d3d12_video_processor * pD3D12Proc = (struct d3d12_video_processor *) codec;
256     delete pD3D12Proc;
257 }
258 
259 void
d3d12_video_processor_flush(struct pipe_video_codec * codec)260 d3d12_video_processor_flush(struct pipe_video_codec * codec)
261 {
262     struct d3d12_video_processor * pD3D12Proc = (struct d3d12_video_processor *) codec;
263     assert(pD3D12Proc);
264     assert(pD3D12Proc->m_spD3D12VideoDevice);
265     assert(pD3D12Proc->m_spCommandQueue);
266 
267     // Flush buffer_subdata batch and Wait the m_spCommandQueue for GPU upload completion
268     // before executing the current batch below. Input objects coming from the pipe_context (ie. input texture) must be fully finished working with before processor can read them.
269     struct pipe_fence_handle *completion_fence = NULL;
270     debug_printf("[d3d12_video_processor] d3d12_video_processor_flush - Flushing pD3D12Proc->m_pD3D12Context->base. and GPU sync between Video/Context queues before flushing Video Process Queue.\n");
271     pD3D12Proc->m_pD3D12Context->base.flush(&pD3D12Proc->m_pD3D12Context->base, &completion_fence, PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
272     assert(completion_fence);
273     struct d3d12_fence *casted_completion_fence = d3d12_fence(completion_fence);
274     pD3D12Proc->m_spCommandQueue->Wait(casted_completion_fence->cmdqueue_fence, casted_completion_fence->value);
275 
276     debug_printf("[d3d12_video_processor] d3d12_video_processor_flush started. Will flush video queue work and CPU wait on "
277                     "fenceValue: %d\n",
278                     pD3D12Proc->m_fenceValue);
279 
280     if (!pD3D12Proc->m_needsGPUFlush) {
281         debug_printf("[d3d12_video_processor] d3d12_video_processor_flush started. Nothing to flush, all up to date.\n");
282     } else {
283         HRESULT hr = pD3D12Proc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
284         if (hr != S_OK) {
285             debug_printf("[d3d12_video_processor] d3d12_video_processor_flush"
286                             " - D3D12Device was removed BEFORE commandlist "
287                             "execution with HR %x.\n",
288                             hr);
289             goto flush_fail;
290         }
291 
292         // Close and execute command list and wait for idle on CPU blocking
293         // this method before resetting list and allocator for next submission.
294 
295         if (pD3D12Proc->m_transitionsBeforeCloseCmdList.size() > 0) {
296             pD3D12Proc->m_spCommandList->ResourceBarrier(pD3D12Proc->m_transitionsBeforeCloseCmdList.size(),
297                                                             pD3D12Proc->m_transitionsBeforeCloseCmdList.data());
298             pD3D12Proc->m_transitionsBeforeCloseCmdList.clear();
299         }
300 
301         hr = pD3D12Proc->m_spCommandList->Close();
302         if (FAILED(hr)) {
303             debug_printf("[d3d12_video_processor] d3d12_video_processor_flush - Can't close command list with HR %x\n", hr);
304             goto flush_fail;
305         }
306 
307         ID3D12CommandList *ppCommandLists[1] = { pD3D12Proc->m_spCommandList.Get() };
308         pD3D12Proc->m_spCommandQueue->ExecuteCommandLists(1, ppCommandLists);
309         pD3D12Proc->m_spCommandQueue->Signal(pD3D12Proc->m_spFence.Get(), pD3D12Proc->m_fenceValue);
310         pD3D12Proc->m_spFence->SetEventOnCompletion(pD3D12Proc->m_fenceValue, nullptr);
311         debug_printf("[d3d12_video_processor] d3d12_video_processor_flush - ExecuteCommandLists finished on signal with "
312                         "fenceValue: %d\n",
313                         pD3D12Proc->m_fenceValue);
314 
315         hr = pD3D12Proc->m_spCommandAllocator->Reset();
316         if (FAILED(hr)) {
317             debug_printf(
318                 "[d3d12_video_processor] d3d12_video_processor_flush - resetting ID3D12CommandAllocator failed with HR %x\n",
319                 hr);
320             goto flush_fail;
321         }
322 
323         hr = pD3D12Proc->m_spCommandList->Reset(pD3D12Proc->m_spCommandAllocator.Get());
324         if (FAILED(hr)) {
325             debug_printf(
326                 "[d3d12_video_processor] d3d12_video_processor_flush - resetting ID3D12GraphicsCommandList failed with HR %x\n",
327                 hr);
328             goto flush_fail;
329         }
330 
331         // Validate device was not removed
332         hr = pD3D12Proc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
333         if (hr != S_OK) {
334             debug_printf("[d3d12_video_processor] d3d12_video_processor_flush"
335                             " - D3D12Device was removed AFTER commandlist "
336                             "execution with HR %x, but wasn't before.\n",
337                             hr);
338             goto flush_fail;
339         }
340 
341         debug_printf(
342             "[d3d12_video_processor] d3d12_video_processor_flush - GPU signaled execution finalized for fenceValue: %d\n",
343             pD3D12Proc->m_fenceValue);
344 
345         pD3D12Proc->m_fenceValue++;
346         pD3D12Proc->m_needsGPUFlush = false;
347     }
348     pD3D12Proc->m_ProcessInputs.clear();
349     // Free the fence after completion finished
350     if(completion_fence)
351         pD3D12Proc->m_pD3D12Screen->base.fence_reference(&pD3D12Proc->m_pD3D12Screen->base, &completion_fence, NULL);
352 
353     return;
354 
355 flush_fail:
356     debug_printf("[d3d12_video_processor] d3d12_video_processor_flush failed for fenceValue: %d\n", pD3D12Proc->m_fenceValue);
357     assert(false);
358 }
359 
360 struct pipe_video_codec *
d3d12_video_processor_create(struct pipe_context * context,const struct pipe_video_codec * codec)361 d3d12_video_processor_create(struct pipe_context *context, const struct pipe_video_codec *codec)
362 {
363    ///
364    /// Initialize d3d12_video_processor
365    ///
366 
367    // Not using new doesn't call ctor and the initializations in the class declaration are lost
368    struct d3d12_video_processor *pD3D12Proc = new d3d12_video_processor;
369 
370    pD3D12Proc->base = *codec;
371 
372    pD3D12Proc->base.context = context;
373    pD3D12Proc->base.width = codec->width;
374    pD3D12Proc->base.height = codec->height;
375    pD3D12Proc->base.destroy = d3d12_video_processor_destroy;
376    pD3D12Proc->base.begin_frame = d3d12_video_processor_begin_frame;
377    pD3D12Proc->base.process_frame = d3d12_video_processor_process_frame;
378    pD3D12Proc->base.end_frame = d3d12_video_processor_end_frame;
379    pD3D12Proc->base.flush = d3d12_video_processor_flush;
380 
381    ///
382 
383    ///
384    /// Try initializing D3D12 Video device and check for device caps
385    ///
386 
387    struct d3d12_context *pD3D12Ctx = (struct d3d12_context *) context;
388    pD3D12Proc->m_pD3D12Context = pD3D12Ctx;
389    pD3D12Proc->m_pD3D12Screen = d3d12_screen(pD3D12Ctx->base.screen);
390 
391     // Assume defaults for now, can re-create if necessary when d3d12_video_processor_end_frame kicks off the processing
392     DXGI_COLOR_SPACE_TYPE InputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
393     std::vector<DXGI_FORMAT> InputFormats = { DXGI_FORMAT_NV12 };
394     DXGI_FORMAT OutputFormat = DXGI_FORMAT_NV12;
395     DXGI_COLOR_SPACE_TYPE OutputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
396 
397    ///
398    /// Create processor objects
399    ///
400    if (FAILED(pD3D12Proc->m_pD3D12Screen->dev->QueryInterface(
401           IID_PPV_ARGS(pD3D12Proc->m_spD3D12VideoDevice.GetAddressOf())))) {
402       debug_printf("[d3d12_video_processor] d3d12_video_create_processor - D3D12 Device has no Video support\n");
403       goto failed;
404    }
405 
406    if (!d3d12_video_processor_check_caps_and_create_processor(pD3D12Proc, InputFormats, InputColorSpace, OutputFormat, OutputColorSpace)) {
407       debug_printf("[d3d12_video_processor] d3d12_video_create_processor - Failure on "
408                       "d3d12_video_processor_check_caps_and_create_processor\n");
409       goto failed;
410    }
411 
412    if (!d3d12_video_processor_create_command_objects(pD3D12Proc)) {
413       debug_printf(
414          "[d3d12_video_processor] d3d12_video_create_processor - Failure on d3d12_video_processor_create_command_objects\n");
415       goto failed;
416    }
417 
418     debug_printf("[d3d12_video_processor] d3d12_video_create_processor - Created successfully!\n");
419 
420    return &pD3D12Proc->base;
421 
422 failed:
423    if (pD3D12Proc != nullptr) {
424       d3d12_video_processor_destroy(&pD3D12Proc->base);
425    }
426 
427    return nullptr;
428 }
429 
430 bool
d3d12_video_processor_check_caps_and_create_processor(struct d3d12_video_processor * pD3D12Proc,std::vector<DXGI_FORMAT> InputFormats,DXGI_COLOR_SPACE_TYPE InputColorSpace,DXGI_FORMAT OutputFormat,DXGI_COLOR_SPACE_TYPE OutputColorSpace)431 d3d12_video_processor_check_caps_and_create_processor(struct d3d12_video_processor *pD3D12Proc,
432                                                         std::vector<DXGI_FORMAT> InputFormats,
433                                                         DXGI_COLOR_SPACE_TYPE InputColorSpace,
434                                                         DXGI_FORMAT OutputFormat,
435                                                         DXGI_COLOR_SPACE_TYPE OutputColorSpace)
436 {
437     HRESULT hr = S_OK;
438 
439     D3D12_VIDEO_FIELD_TYPE FieldType = D3D12_VIDEO_FIELD_TYPE_NONE;
440     D3D12_VIDEO_FRAME_STEREO_FORMAT StereoFormat = D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE;
441     DXGI_RATIONAL FrameRate = { 30, 1 };
442     DXGI_RATIONAL AspectRatio = { 1, 1 };
443 
444     struct ResolStruct {
445         uint Width;
446         uint Height;
447     };
448 
449     ResolStruct resolutionsList[] = {
450         { 8192, 8192 },   // 8k
451         { 8192, 4320 },   // 8k - alternative
452         { 7680, 4800 },   // 8k - alternative
453         { 7680, 4320 },   // 8k - alternative
454         { 4096, 2304 },   // 2160p (4K)
455         { 4096, 2160 },   // 2160p (4K) - alternative
456         { 2560, 1440 },   // 1440p
457         { 1920, 1200 },   // 1200p
458         { 1920, 1080 },   // 1080p
459         { 1280, 720 },    // 720p
460         { 800, 600 },
461     };
462 
463     pD3D12Proc->m_SupportCaps =
464     {
465         0, // NodeIndex
466         { resolutionsList[0].Width, resolutionsList[0].Height, { InputFormats[0], InputColorSpace } },
467         FieldType,
468         StereoFormat,
469         FrameRate,
470         { OutputFormat, OutputColorSpace },
471         StereoFormat,
472         FrameRate,
473     };
474 
475     uint32_t idxResol = 0;
476     bool bSupportsAny = false;
477     while ((idxResol < ARRAY_SIZE(resolutionsList)) && !bSupportsAny) {
478         pD3D12Proc->m_SupportCaps.InputSample.Width = resolutionsList[idxResol].Width;
479         pD3D12Proc->m_SupportCaps.InputSample.Height = resolutionsList[idxResol].Height;
480         if (SUCCEEDED(pD3D12Proc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_PROCESS_SUPPORT, &pD3D12Proc->m_SupportCaps, sizeof(pD3D12Proc->m_SupportCaps)))) {
481             bSupportsAny = ((pD3D12Proc->m_SupportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != 0);
482         }
483         idxResol++;
484     }
485 
486     if ((pD3D12Proc->m_SupportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED)
487     {
488         if((pD3D12Proc->m_SupportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) {
489         debug_printf("[d3d12_video_processor] d3d12_video_processor_check_caps_and_create_processor - D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED not returned by driver. "
490                             "failed with SupportFlags %x\n",
491                             pD3D12Proc->m_SupportCaps.SupportFlags);
492         }
493     }
494 
495     D3D12_VIDEO_PROCESS_FILTER_FLAGS enabledFilterFlags = D3D12_VIDEO_PROCESS_FILTER_FLAG_NONE;
496 
497     bool enableOrientation = (
498         ((pD3D12Proc->m_SupportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ROTATION) != 0)
499         || ((pD3D12Proc->m_SupportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_FLIP) != 0)
500     );
501 
502     D3D12_VIDEO_PROCESS_INPUT_STREAM_DESC inputStreamDesc = {
503         InputFormats[0],
504         InputColorSpace,
505         AspectRatio,                            // SourceAspectRatio;
506         AspectRatio,                            // DestinationAspectRatio;
507         FrameRate,                              // FrameRate
508         pD3D12Proc->m_SupportCaps.ScaleSupport.OutputSizeRange, // SourceSizeRange
509         pD3D12Proc->m_SupportCaps.ScaleSupport.OutputSizeRange, // DestinationSizeRange
510         enableOrientation,
511         enabledFilterFlags,
512         StereoFormat,
513         FieldType,
514         D3D12_VIDEO_PROCESS_DEINTERLACE_FLAG_NONE,
515         ((pD3D12Proc->m_SupportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_BLENDING) != 0)
516         && ((pD3D12Proc->m_SupportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_FILL) != 0), // EnableAlphaBlending
517         {},                                     // LumaKey
518         0,                                      // NumPastFrames
519         0,                                      // NumFutureFrames
520         FALSE                                   // EnableAutoProcessing
521     };
522 
523     D3D12_VIDEO_PROCESS_OUTPUT_STREAM_DESC outputStreamDesc =
524     {
525         pD3D12Proc->m_SupportCaps.OutputFormat.Format,
526         OutputColorSpace,
527         D3D12_VIDEO_PROCESS_ALPHA_FILL_MODE_OPAQUE, // AlphaFillMode
528         0u,                                         // AlphaFillModeSourceStreamIndex
529         {0, 0, 0, 0},                               // BackgroundColor
530         FrameRate,                                  // FrameRate
531         FALSE                                       // EnableStereo
532     };
533 
534     // gets the required past/future frames for VP creation
535     {
536         D3D12_FEATURE_DATA_VIDEO_PROCESS_REFERENCE_INFO referenceInfo = {};
537         referenceInfo.NodeIndex = 0;
538         D3D12_VIDEO_PROCESS_FEATURE_FLAGS featureFlags = D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE;
539         featureFlags |= outputStreamDesc.AlphaFillMode ? D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_FILL : D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE;
540         featureFlags |= inputStreamDesc.LumaKey.Enable ? D3D12_VIDEO_PROCESS_FEATURE_FLAG_LUMA_KEY : D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE;
541         featureFlags |= (inputStreamDesc.StereoFormat != D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE || outputStreamDesc.EnableStereo) ? D3D12_VIDEO_PROCESS_FEATURE_FLAG_STEREO : D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE;
542         featureFlags |= inputStreamDesc.EnableOrientation ? D3D12_VIDEO_PROCESS_FEATURE_FLAG_ROTATION | D3D12_VIDEO_PROCESS_FEATURE_FLAG_FLIP : D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE;
543         featureFlags |= inputStreamDesc.EnableAlphaBlending ? D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_BLENDING : D3D12_VIDEO_PROCESS_FEATURE_FLAG_NONE;
544 
545         referenceInfo.DeinterlaceMode = inputStreamDesc.DeinterlaceMode;
546         referenceInfo.Filters = inputStreamDesc.FilterFlags;
547         referenceInfo.FeatureSupport = featureFlags;
548         referenceInfo.InputFrameRate = inputStreamDesc.FrameRate;
549         referenceInfo.OutputFrameRate = outputStreamDesc.FrameRate;
550         referenceInfo.EnableAutoProcessing = inputStreamDesc.EnableAutoProcessing;
551 
552         hr = pD3D12Proc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_PROCESS_REFERENCE_INFO, &referenceInfo, sizeof(referenceInfo));
553         if (FAILED(hr)) {
554         debug_printf("[d3d12_video_processor] d3d12_video_processor_check_caps_and_create_processor - CheckFeatureSupport "
555                         "failed with HR %x\n",
556                         hr);
557         return false;
558         }
559 
560         inputStreamDesc.NumPastFrames = referenceInfo.PastFrames;
561         inputStreamDesc.NumFutureFrames = referenceInfo.FutureFrames;
562     }
563 
564     pD3D12Proc->m_outputStreamDesc = outputStreamDesc;
565 
566     debug_printf("[d3d12_video_processor]\t Creating Video Processor\n");
567     debug_printf("[d3d12_video_processor]\t NumInputs: %d\n", (int) InputFormats.size());
568 
569     pD3D12Proc->m_inputStreamDescs.clear();
570     for (unsigned i = 0; i < InputFormats.size(); i++)
571     {
572         inputStreamDesc.Format = InputFormats[i];
573         pD3D12Proc->m_inputStreamDescs.push_back(inputStreamDesc);
574         debug_printf("[d3d12_video_processor]\t Input Stream #%d Format: %d\n", i, inputStreamDesc.Format);
575     }
576     debug_printf("[d3d12_video_processor]\t Output Stream Format: %d\n", pD3D12Proc->m_outputStreamDesc.Format);
577 
578     hr = pD3D12Proc->m_spD3D12VideoDevice->CreateVideoProcessor(pD3D12Proc->m_NodeMask,
579                                                             &pD3D12Proc->m_outputStreamDesc,
580                                                             pD3D12Proc->m_inputStreamDescs.size(),
581                                                             pD3D12Proc->m_inputStreamDescs.data(),
582                                                             IID_PPV_ARGS(pD3D12Proc->m_spVideoProcessor.GetAddressOf()));
583     if (FAILED(hr)) {
584         debug_printf("[d3d12_video_processor] d3d12_video_processor_check_caps_and_create_processor - CreateVideoProcessor "
585                     "failed with HR %x\n",
586                     hr);
587         return false;
588     }
589 
590    return true;
591 }
592 
593 bool
d3d12_video_processor_create_command_objects(struct d3d12_video_processor * pD3D12Proc)594 d3d12_video_processor_create_command_objects(struct d3d12_video_processor *pD3D12Proc)
595 {
596     assert(pD3D12Proc->m_spD3D12VideoDevice);
597 
598     D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS };
599     HRESULT hr = pD3D12Proc->m_pD3D12Screen->dev->CreateCommandQueue(
600                 &commandQueueDesc,
601                 IID_PPV_ARGS(pD3D12Proc->m_spCommandQueue.GetAddressOf()));
602 
603     if (FAILED(hr)) {
604         debug_printf("[d3d12_video_processor] d3d12_video_processor_create_command_objects - Call to CreateCommandQueue "
605                         "failed with HR %x\n",
606                         hr);
607         return false;
608     }
609 
610     hr = pD3D12Proc->m_pD3D12Screen->dev->CreateFence(0,
611          D3D12_FENCE_FLAG_NONE,
612          IID_PPV_ARGS(&pD3D12Proc->m_spFence));
613 
614     if (FAILED(hr)) {
615         debug_printf(
616             "[d3d12_video_processor] d3d12_video_processor_create_command_objects - Call to CreateFence failed with HR %x\n",
617             hr);
618         return false;
619     }
620 
621     hr = pD3D12Proc->m_pD3D12Screen->dev->CreateCommandAllocator(
622         D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
623         IID_PPV_ARGS(pD3D12Proc->m_spCommandAllocator.GetAddressOf()));
624 
625     if (FAILED(hr)) {
626         debug_printf("[d3d12_video_processor] d3d12_video_processor_create_command_objects - Call to "
627                         "CreateCommandAllocator failed with HR %x\n",
628                         hr);
629         return false;
630     }
631 
632     hr = pD3D12Proc->m_pD3D12Screen->dev->CreateCommandList(0,
633         D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS,
634         pD3D12Proc->m_spCommandAllocator.Get(),
635         nullptr,
636         IID_PPV_ARGS(pD3D12Proc->m_spCommandList.GetAddressOf()));
637 
638     if (FAILED(hr)) {
639         debug_printf("[d3d12_video_processor] d3d12_video_processor_create_command_objects - Call to CreateCommandList "
640                         "failed with HR %x\n",
641                         hr);
642         return false;
643     }
644 
645     return true;
646 }
647 
648 D3D12_VIDEO_PROCESS_ORIENTATION
d3d12_video_processor_convert_pipe_rotation(enum pipe_video_vpp_orientation orientation_flags)649 d3d12_video_processor_convert_pipe_rotation(enum pipe_video_vpp_orientation orientation_flags)
650 {
651     D3D12_VIDEO_PROCESS_ORIENTATION result = D3D12_VIDEO_PROCESS_ORIENTATION_DEFAULT;
652 
653     if(orientation_flags & PIPE_VIDEO_VPP_ROTATION_90)
654     {
655         result = (orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL) ? D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_90_FLIP_HORIZONTAL : D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_90;
656         debug_printf("d3d12_video_processor_process_frame: Orientation Mode: %s\n", (orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL) ? "D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_90_FLIP_HORIZONTAL" : "D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_90");
657     }
658     else if(orientation_flags & PIPE_VIDEO_VPP_ROTATION_180)
659     {
660         result = D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_180;
661         debug_printf("d3d12_video_processor_process_frame: Orientation Mode: D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_180\n");
662     }
663     else if(orientation_flags & PIPE_VIDEO_VPP_ROTATION_270)
664     {
665         result = (orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL) ? D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_270_FLIP_HORIZONTAL : D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_270;
666         debug_printf("d3d12_video_processor_process_frame: Orientation Mode: %s\n", (orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL) ? "D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_270_FLIP_HORIZONTAL" : "D3D12_VIDEO_PROCESS_ORIENTATION_CLOCKWISE_270");
667     }
668     else if(orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL)
669     {
670         result = D3D12_VIDEO_PROCESS_ORIENTATION_FLIP_HORIZONTAL;
671         debug_printf("d3d12_video_processor_process_frame: Orientation Mode: D3D12_VIDEO_PROCESS_ORIENTATION_FLIP_HORIZONTAL\n");
672     }
673     else if(orientation_flags & PIPE_VIDEO_VPP_FLIP_VERTICAL)
674     {
675         result = D3D12_VIDEO_PROCESS_ORIENTATION_FLIP_VERTICAL;
676         debug_printf("d3d12_video_processor_process_frame: Orientation Mode: D3D12_VIDEO_PROCESS_ORIENTATION_FLIP_VERTICAL\n");
677     }
678 
679     return result;
680 }
681