1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "d3d12_context.h" 25bf215546Sopenharmony_ci#include "d3d12_format.h" 26bf215546Sopenharmony_ci#include "d3d12_resource.h" 27bf215546Sopenharmony_ci#include "d3d12_screen.h" 28bf215546Sopenharmony_ci#include "d3d12_surface.h" 29bf215546Sopenharmony_ci#include "d3d12_video_dec.h" 30bf215546Sopenharmony_ci#include "d3d12_video_dec_h264.h" 31bf215546Sopenharmony_ci#include "d3d12_video_buffer.h" 32bf215546Sopenharmony_ci#include "d3d12_residency.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "vl/vl_video_buffer.h" 35bf215546Sopenharmony_ci#include "util/format/u_format.h" 36bf215546Sopenharmony_ci#include "util/u_inlines.h" 37bf215546Sopenharmony_ci#include "util/u_memory.h" 38bf215546Sopenharmony_ci#include "util/u_video.h" 39bf215546Sopenharmony_ci#include "util/vl_vlc.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistruct pipe_video_codec * 42bf215546Sopenharmony_cid3d12_video_create_decoder(struct pipe_context *context, const struct pipe_video_codec *codec) 43bf215546Sopenharmony_ci{ 44bf215546Sopenharmony_ci /// 45bf215546Sopenharmony_ci /// Initialize d3d12_video_decoder 46bf215546Sopenharmony_ci /// 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci // Not using new doesn't call ctor and the initializations in the class declaration are lost 50bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = new d3d12_video_decoder; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci pD3D12Dec->base = *codec; 53bf215546Sopenharmony_ci pD3D12Dec->m_screen = context->screen; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci pD3D12Dec->base.context = context; 56bf215546Sopenharmony_ci pD3D12Dec->base.width = codec->width; 57bf215546Sopenharmony_ci pD3D12Dec->base.height = codec->height; 58bf215546Sopenharmony_ci // Only fill methods that are supported by the d3d12 decoder, leaving null the rest (ie. encode_* / decode_macroblock 59bf215546Sopenharmony_ci // / get_feedback for encode) 60bf215546Sopenharmony_ci pD3D12Dec->base.destroy = d3d12_video_decoder_destroy; 61bf215546Sopenharmony_ci pD3D12Dec->base.begin_frame = d3d12_video_decoder_begin_frame; 62bf215546Sopenharmony_ci pD3D12Dec->base.decode_bitstream = d3d12_video_decoder_decode_bitstream; 63bf215546Sopenharmony_ci pD3D12Dec->base.end_frame = d3d12_video_decoder_end_frame; 64bf215546Sopenharmony_ci pD3D12Dec->base.flush = d3d12_video_decoder_flush; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci pD3D12Dec->m_decodeFormat = d3d12_convert_pipe_video_profile_to_dxgi_format(codec->profile); 67bf215546Sopenharmony_ci pD3D12Dec->m_d3d12DecProfileType = d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(codec->profile); 68bf215546Sopenharmony_ci pD3D12Dec->m_d3d12DecProfile = d3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(codec->profile); 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci /// 71bf215546Sopenharmony_ci /// Try initializing D3D12 Video device and check for device caps 72bf215546Sopenharmony_ci /// 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci struct d3d12_context *pD3D12Ctx = (struct d3d12_context *) context; 75bf215546Sopenharmony_ci pD3D12Dec->m_pD3D12Screen = d3d12_screen(pD3D12Ctx->base.screen); 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci /// 78bf215546Sopenharmony_ci /// Create decode objects 79bf215546Sopenharmony_ci /// 80bf215546Sopenharmony_ci HRESULT hr = S_OK; 81bf215546Sopenharmony_ci if (FAILED(pD3D12Dec->m_pD3D12Screen->dev->QueryInterface( 82bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spD3D12VideoDevice.GetAddressOf())))) { 83bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_create_decoder - D3D12 Device has no Video support\n"); 84bf215546Sopenharmony_ci goto failed; 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci if (!d3d12_video_decoder_check_caps_and_create_decoder(pD3D12Dec->m_pD3D12Screen, pD3D12Dec)) { 88bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_create_decoder - Failure on " 89bf215546Sopenharmony_ci "d3d12_video_decoder_check_caps_and_create_decoder\n"); 90bf215546Sopenharmony_ci goto failed; 91bf215546Sopenharmony_ci } 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci if (!d3d12_video_decoder_create_command_objects(pD3D12Dec->m_pD3D12Screen, pD3D12Dec)) { 94bf215546Sopenharmony_ci debug_printf( 95bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_create_decoder - Failure on d3d12_video_decoder_create_command_objects\n"); 96bf215546Sopenharmony_ci goto failed; 97bf215546Sopenharmony_ci } 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci if (!d3d12_video_decoder_create_video_state_buffers(pD3D12Dec->m_pD3D12Screen, pD3D12Dec)) { 100bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_create_decoder - Failure on " 101bf215546Sopenharmony_ci "d3d12_video_decoder_create_video_state_buffers\n"); 102bf215546Sopenharmony_ci goto failed; 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci pD3D12Dec->m_decodeFormatInfo = { pD3D12Dec->m_decodeFormat }; 106bf215546Sopenharmony_ci hr = pD3D12Dec->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO, 107bf215546Sopenharmony_ci &pD3D12Dec->m_decodeFormatInfo, 108bf215546Sopenharmony_ci sizeof(pD3D12Dec->m_decodeFormatInfo)); 109bf215546Sopenharmony_ci if(FAILED(hr)) { 110bf215546Sopenharmony_ci debug_printf("CheckFeatureSupport failed with HR %x\n", hr); 111bf215546Sopenharmony_ci goto failed; 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci return &pD3D12Dec->base; 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_cifailed: 117bf215546Sopenharmony_ci if (pD3D12Dec != nullptr) { 118bf215546Sopenharmony_ci d3d12_video_decoder_destroy((struct pipe_video_codec *) pD3D12Dec); 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci return nullptr; 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci/** 125bf215546Sopenharmony_ci * Destroys a d3d12_video_decoder 126bf215546Sopenharmony_ci * Call destroy_XX for applicable XX nested member types before deallocating 127bf215546Sopenharmony_ci * Destroy methods should check != nullptr on their input target argument as this method can be called as part of 128bf215546Sopenharmony_ci * cleanup from failure on the creation method 129bf215546Sopenharmony_ci */ 130bf215546Sopenharmony_civoid 131bf215546Sopenharmony_cid3d12_video_decoder_destroy(struct pipe_video_codec *codec) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci if (codec == nullptr) { 134bf215546Sopenharmony_ci return; 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci d3d12_video_decoder_flush(codec); // Flush pending work before destroying. 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci // 142bf215546Sopenharmony_ci // Destroys a decoder 143bf215546Sopenharmony_ci // Call destroy_XX for applicable XX nested member types before deallocating 144bf215546Sopenharmony_ci // Destroy methods should check != nullptr on their input target argument as this method can be called as part of 145bf215546Sopenharmony_ci // cleanup from failure on the creation method 146bf215546Sopenharmony_ci // 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci // No need for d3d12_destroy_video_objects 149bf215546Sopenharmony_ci // All the objects created here are smart pointer members of d3d12_video_decoder 150bf215546Sopenharmony_ci // No need for d3d12_destroy_video_decoder_and_heap 151bf215546Sopenharmony_ci // All the objects created here are smart pointer members of d3d12_video_decoder 152bf215546Sopenharmony_ci // No need for d3d12_destroy_video_dpbmanagers 153bf215546Sopenharmony_ci // All the objects created here are smart pointer members of d3d12_video_decoder 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci // No need for m_pD3D12Screen as it is not managed by d3d12_video_decoder 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci // Call dtor to make ComPtr work 158bf215546Sopenharmony_ci delete pD3D12Dec; 159bf215546Sopenharmony_ci} 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci/** 162bf215546Sopenharmony_ci * start decoding of a new frame 163bf215546Sopenharmony_ci */ 164bf215546Sopenharmony_civoid 165bf215546Sopenharmony_cid3d12_video_decoder_begin_frame(struct pipe_video_codec *codec, 166bf215546Sopenharmony_ci struct pipe_video_buffer *target, 167bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 168bf215546Sopenharmony_ci{ 169bf215546Sopenharmony_ci // Do nothing here. Initialize happens on decoder creation, re-config (if any) happens in 170bf215546Sopenharmony_ci // d3d12_video_decoder_decode_bitstream 171bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec; 172bf215546Sopenharmony_ci assert(pD3D12Dec); 173bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_begin_frame finalized for fenceValue: %d\n", 174bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 175bf215546Sopenharmony_ci} 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci/** 178bf215546Sopenharmony_ci * decode a bitstream 179bf215546Sopenharmony_ci */ 180bf215546Sopenharmony_civoid 181bf215546Sopenharmony_cid3d12_video_decoder_decode_bitstream(struct pipe_video_codec *codec, 182bf215546Sopenharmony_ci struct pipe_video_buffer *target, 183bf215546Sopenharmony_ci struct pipe_picture_desc *picture, 184bf215546Sopenharmony_ci unsigned num_buffers, 185bf215546Sopenharmony_ci const void *const *buffers, 186bf215546Sopenharmony_ci const unsigned *sizes) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec; 189bf215546Sopenharmony_ci assert(pD3D12Dec); 190bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_decode_bitstream started for fenceValue: %d\n", 191bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 192bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 193bf215546Sopenharmony_ci assert(pD3D12Dec->m_spDecodeCommandQueue); 194bf215546Sopenharmony_ci assert(pD3D12Dec->m_pD3D12Screen); 195bf215546Sopenharmony_ci struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) target; 196bf215546Sopenharmony_ci assert(pD3D12VideoBuffer); 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci /// 199bf215546Sopenharmony_ci /// Compressed bitstream buffers 200bf215546Sopenharmony_ci /// 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci /// Mesa VA frontend Video buffer passing semantics for H264, HEVC, MPEG4, VC1 and PIPE_VIDEO_PROFILE_VC1_ADVANCED 203bf215546Sopenharmony_ci /// are: If num_buffers == 1 -> buf[0] has the compressed bitstream WITH the starting code If num_buffers == 2 -> 204bf215546Sopenharmony_ci /// buf[0] has the NALU starting code and buf[1] has the compressed bitstream WITHOUT any starting code. If 205bf215546Sopenharmony_ci /// num_buffers = 3 -> It's JPEG, not supported in D3D12. num_buffers is at most 3. 206bf215546Sopenharmony_ci /// Mesa VDPAU frontend passes the buffers as they get passed in VdpDecoderRender without fixing any start codes 207bf215546Sopenharmony_ci /// except for PIPE_VIDEO_PROFILE_VC1_ADVANCED 208bf215546Sopenharmony_ci // In https://http.download.nvidia.com/XFree86/vdpau/doxygen/html/index.html#video_mixer_usage it's mentioned that: 209bf215546Sopenharmony_ci // It is recommended that applications pass solely the slice data to VDPAU; specifically that any header data 210bf215546Sopenharmony_ci // structures be excluded from the portion of the bitstream passed to VDPAU. VDPAU implementations must operate 211bf215546Sopenharmony_ci // correctly if non-slice data is included, at least for formats employing start codes to delimit slice data. For all 212bf215546Sopenharmony_ci // codecs/profiles it's highly recommended (when the codec/profile has such codes...) that the start codes are passed 213bf215546Sopenharmony_ci // to VDPAU, even when not included in the bitstream the VDPAU client is parsing. Let's assume we get all the start 214bf215546Sopenharmony_ci // codes for VDPAU. The doc also says "VDPAU implementations must operate correctly if non-slice data is included, at 215bf215546Sopenharmony_ci // least for formats employing start codes to delimit slice data" if we ever get an issue with VDPAU start codes we 216bf215546Sopenharmony_ci // should consider adding the code that handles this in the VDPAU layer above the gallium driver like mesa VA does. 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci // To handle the multi-slice case end_frame already takes care of this by parsing the start codes from the 219bf215546Sopenharmony_ci // combined bitstream of all decode_bitstream calls. 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci // VAAPI seems to send one decode_bitstream command per slice, but we should also support the VDPAU case where the 222bf215546Sopenharmony_ci // buffers have multiple buffer array entry per slice {startCode (optional), slice1, slice2, ..., startCode 223bf215546Sopenharmony_ci // (optional) , sliceN} 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci if (num_buffers > 2) // Assume this means multiple slices at once in a decode_bitstream call 226bf215546Sopenharmony_ci { 227bf215546Sopenharmony_ci // Based on VA frontend codebase, this never happens for video (no JPEG) 228bf215546Sopenharmony_ci // Based on VDPAU frontends codebase, this only happens when sending more than one slice at once in decode bitstream 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci // To handle the case where VDPAU send all the slices at once in a single decode_bitstream call, let's pretend it 231bf215546Sopenharmony_ci // was a series of different calls 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci // group by start codes and buffers and perform calls for the number of slices 234bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_decode_bitstream multiple slices on same call detected " 235bf215546Sopenharmony_ci "for fenceValue: %d, breaking down the calls into one per slice\n", 236bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci size_t curBufferIdx = 0; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci // Vars to be used for the delegation calls to decode_bitstream 241bf215546Sopenharmony_ci unsigned call_num_buffers = 0; 242bf215546Sopenharmony_ci const void *const *call_buffers = nullptr; 243bf215546Sopenharmony_ci const unsigned *call_sizes = nullptr; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci while (curBufferIdx < num_buffers) { 246bf215546Sopenharmony_ci // Store the current buffer as the base array pointer for the delegated call, later decide if it'll be a 247bf215546Sopenharmony_ci // startcode+slicedata or just slicedata call 248bf215546Sopenharmony_ci call_buffers = &buffers[curBufferIdx]; 249bf215546Sopenharmony_ci call_sizes = &sizes[curBufferIdx]; 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci // Usually start codes are less or equal than 4 bytes 252bf215546Sopenharmony_ci // If the current buffer is a start code buffer, send it along with the next buffer. Otherwise, just send the 253bf215546Sopenharmony_ci // current buffer. 254bf215546Sopenharmony_ci call_num_buffers = (sizes[curBufferIdx] <= 4) ? 2 : 1; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci // Delegate call with one or two buffers only 257bf215546Sopenharmony_ci d3d12_video_decoder_decode_bitstream(codec, target, picture, call_num_buffers, call_buffers, call_sizes); 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci curBufferIdx += call_num_buffers; // Consume from the loop the buffers sent in the last call 260bf215546Sopenharmony_ci } 261bf215546Sopenharmony_ci } else { 262bf215546Sopenharmony_ci /// 263bf215546Sopenharmony_ci /// Handle single slice buffer path, maybe with an extra start code buffer at buffers[0]. 264bf215546Sopenharmony_ci /// 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci // Both the start codes being present at buffers[0] and the rest in buffers [1] or full buffer at [0] cases can be 267bf215546Sopenharmony_ci // handled by flattening all the buffers into a single one and passing that to HW. 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci size_t totalReceivedBuffersSize = 0u; // Combined size of all sizes[] 270bf215546Sopenharmony_ci for (size_t bufferIdx = 0; bufferIdx < num_buffers; bufferIdx++) { 271bf215546Sopenharmony_ci totalReceivedBuffersSize += sizes[bufferIdx]; 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci // Bytes of data pre-staged before this decode_frame call 275bf215546Sopenharmony_ci size_t preStagedDataSize = pD3D12Dec->m_stagingDecodeBitstream.size(); 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci // Extend the staging buffer size, as decode_frame can be called several times before end_frame 278bf215546Sopenharmony_ci pD3D12Dec->m_stagingDecodeBitstream.resize(preStagedDataSize + totalReceivedBuffersSize); 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci // Point newSliceDataPositionDstBase to the end of the pre-staged data in m_stagingDecodeBitstream, where the new 281bf215546Sopenharmony_ci // buffers will be appended 282bf215546Sopenharmony_ci uint8_t *newSliceDataPositionDstBase = pD3D12Dec->m_stagingDecodeBitstream.data() + preStagedDataSize; 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci // Append new data at the end. 285bf215546Sopenharmony_ci size_t dstOffset = 0u; 286bf215546Sopenharmony_ci for (size_t bufferIdx = 0; bufferIdx < num_buffers; bufferIdx++) { 287bf215546Sopenharmony_ci memcpy(newSliceDataPositionDstBase + dstOffset, buffers[bufferIdx], sizes[bufferIdx]); 288bf215546Sopenharmony_ci dstOffset += sizes[bufferIdx]; 289bf215546Sopenharmony_ci } 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_decode_bitstream finalized for fenceValue: %d\n", 292bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci} 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_civoid 297bf215546Sopenharmony_cid3d12_video_decoder_store_upper_layer_references(struct d3d12_video_decoder *pD3D12Dec, 298bf215546Sopenharmony_ci struct pipe_video_buffer *target, 299bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 300bf215546Sopenharmony_ci{ 301bf215546Sopenharmony_ci switch (pD3D12Dec->m_d3d12DecProfileType) { 302bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 303bf215546Sopenharmony_ci { 304bf215546Sopenharmony_ci pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture; 305bf215546Sopenharmony_ci pD3D12Dec->m_pCurrentDecodeTarget = target; 306bf215546Sopenharmony_ci pD3D12Dec->m_pCurrentReferenceTargets = pPicControlH264->ref; 307bf215546Sopenharmony_ci } break; 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci default: 310bf215546Sopenharmony_ci { 311bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 312bf215546Sopenharmony_ci } break; 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci} 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci/** 317bf215546Sopenharmony_ci * end decoding of the current frame 318bf215546Sopenharmony_ci */ 319bf215546Sopenharmony_civoid 320bf215546Sopenharmony_cid3d12_video_decoder_end_frame(struct pipe_video_codec *codec, 321bf215546Sopenharmony_ci struct pipe_video_buffer *target, 322bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 323bf215546Sopenharmony_ci{ 324bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec; 325bf215546Sopenharmony_ci assert(pD3D12Dec); 326bf215546Sopenharmony_ci struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pD3D12Dec->m_pD3D12Screen; 327bf215546Sopenharmony_ci assert(pD3D12Screen); 328bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame started for fenceValue: %d\n", 329bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 330bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 331bf215546Sopenharmony_ci assert(pD3D12Dec->m_spDecodeCommandQueue); 332bf215546Sopenharmony_ci struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) target; 333bf215546Sopenharmony_ci assert(pD3D12VideoBuffer); 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci /// 336bf215546Sopenharmony_ci /// Store current decode output target texture and reference textures from upper layer 337bf215546Sopenharmony_ci /// 338bf215546Sopenharmony_ci d3d12_video_decoder_store_upper_layer_references(pD3D12Dec, target, picture); 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci /// 341bf215546Sopenharmony_ci /// Codec header picture parameters buffers 342bf215546Sopenharmony_ci /// 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci d3d12_video_decoder_store_converted_dxva_picparams_from_pipe_input(pD3D12Dec, picture, pD3D12VideoBuffer); 345bf215546Sopenharmony_ci assert(pD3D12Dec->m_picParamsBuffer.size() > 0); 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci /// 348bf215546Sopenharmony_ci /// Prepare Slice control buffers before clearing staging buffer 349bf215546Sopenharmony_ci /// 350bf215546Sopenharmony_ci assert(pD3D12Dec->m_stagingDecodeBitstream.size() > 0); // Make sure the staging wasn't cleared yet in end_frame 351bf215546Sopenharmony_ci d3d12_video_decoder_prepare_dxva_slices_control(pD3D12Dec, picture); 352bf215546Sopenharmony_ci assert(pD3D12Dec->m_SliceControlBuffer.size() > 0); 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci /// 355bf215546Sopenharmony_ci /// Upload m_stagingDecodeBitstream to GPU memory now that end_frame is called and clear staging buffer 356bf215546Sopenharmony_ci /// 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci uint64_t sliceDataStagingBufferSize = pD3D12Dec->m_stagingDecodeBitstream.size(); 359bf215546Sopenharmony_ci uint8_t *sliceDataStagingBufferPtr = pD3D12Dec->m_stagingDecodeBitstream.data(); 360bf215546Sopenharmony_ci 361bf215546Sopenharmony_ci // Reallocate if necessary to accomodate the current frame bitstream buffer in GPU memory 362bf215546Sopenharmony_ci if (pD3D12Dec->m_curFrameCompressedBitstreamBufferAllocatedSize < sliceDataStagingBufferSize) { 363bf215546Sopenharmony_ci if (!d3d12_video_decoder_create_staging_bitstream_buffer(pD3D12Screen, pD3D12Dec, sliceDataStagingBufferSize)) { 364bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Failure on " 365bf215546Sopenharmony_ci "d3d12_video_decoder_create_staging_bitstream_buffer\n"); 366bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_decoder_end_frame failed for fenceValue: %d\n", 367bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 368bf215546Sopenharmony_ci assert(false); 369bf215546Sopenharmony_ci return; 370bf215546Sopenharmony_ci } 371bf215546Sopenharmony_ci } 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci // Upload frame bitstream CPU data to ID3D12Resource buffer 374bf215546Sopenharmony_ci pD3D12Dec->m_curFrameCompressedBitstreamBufferPayloadSize = 375bf215546Sopenharmony_ci sliceDataStagingBufferSize; // This can be less than m_curFrameCompressedBitstreamBufferAllocatedSize. 376bf215546Sopenharmony_ci assert(pD3D12Dec->m_curFrameCompressedBitstreamBufferPayloadSize <= 377bf215546Sopenharmony_ci pD3D12Dec->m_curFrameCompressedBitstreamBufferAllocatedSize); 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci /* One-shot transfer operation with data supplied in a user 380bf215546Sopenharmony_ci * pointer. 381bf215546Sopenharmony_ci */ 382bf215546Sopenharmony_ci pipe_resource *pPipeCompressedBufferObj = 383bf215546Sopenharmony_ci d3d12_resource_from_resource(&pD3D12Screen->base, pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Get()); 384bf215546Sopenharmony_ci assert(pPipeCompressedBufferObj); 385bf215546Sopenharmony_ci pD3D12Dec->base.context->buffer_subdata(pD3D12Dec->base.context, // context 386bf215546Sopenharmony_ci pPipeCompressedBufferObj, // dst buffer 387bf215546Sopenharmony_ci PIPE_MAP_WRITE, // usage PIPE_MAP_x 388bf215546Sopenharmony_ci 0, // offset 389bf215546Sopenharmony_ci sizeof(*sliceDataStagingBufferPtr) * sliceDataStagingBufferSize, // size 390bf215546Sopenharmony_ci sliceDataStagingBufferPtr // data 391bf215546Sopenharmony_ci ); 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci // Flush buffer_subdata batch and wait on this CPU thread for GPU work completion 394bf215546Sopenharmony_ci // before deleting the source CPU buffer below 395bf215546Sopenharmony_ci struct pipe_fence_handle *pUploadGPUCompletionFence = NULL; 396bf215546Sopenharmony_ci pD3D12Dec->base.context->flush(pD3D12Dec->base.context, 397bf215546Sopenharmony_ci &pUploadGPUCompletionFence, 398bf215546Sopenharmony_ci PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH); 399bf215546Sopenharmony_ci assert(pUploadGPUCompletionFence); 400bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Waiting on GPU completion fence for " 401bf215546Sopenharmony_ci "buffer_subdata to upload compressed bitstream.\n"); 402bf215546Sopenharmony_ci pD3D12Screen->base.fence_finish(&pD3D12Screen->base, NULL, pUploadGPUCompletionFence, PIPE_TIMEOUT_INFINITE); 403bf215546Sopenharmony_ci pD3D12Screen->base.fence_reference(&pD3D12Screen->base, &pUploadGPUCompletionFence, NULL); 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci // [After buffer_subdata GPU work is finished] Clear CPU staging buffer now that end_frame is called and was uploaded 406bf215546Sopenharmony_ci // to GPU for DecodeFrame call. 407bf215546Sopenharmony_ci pD3D12Dec->m_stagingDecodeBitstream.resize(0); 408bf215546Sopenharmony_ci 409bf215546Sopenharmony_ci /// 410bf215546Sopenharmony_ci /// Proceed to record the GPU Decode commands 411bf215546Sopenharmony_ci /// 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci // Requested conversions by caller upper layer (none for now) 414bf215546Sopenharmony_ci d3d12_video_decode_output_conversion_arguments requestedConversionArguments = {}; 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci /// 417bf215546Sopenharmony_ci /// Record DecodeFrame operation and resource state transitions. 418bf215546Sopenharmony_ci /// 419bf215546Sopenharmony_ci 420bf215546Sopenharmony_ci // Translate input D3D12 structure 421bf215546Sopenharmony_ci D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS d3d12InputArguments = {}; 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci d3d12InputArguments.CompressedBitstream.pBuffer = pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Get(); 424bf215546Sopenharmony_ci d3d12InputArguments.CompressedBitstream.Offset = 0u; 425bf215546Sopenharmony_ci constexpr uint64_t d3d12BitstreamOffsetAlignment = 426bf215546Sopenharmony_ci 128u; // specified in 427bf215546Sopenharmony_ci // https://docs.microsoft.com/en-us/windows/win32/api/d3d12video/ne-d3d12video-d3d12_video_decode_tier 428bf215546Sopenharmony_ci assert((d3d12InputArguments.CompressedBitstream.Offset == 0) || 429bf215546Sopenharmony_ci ((d3d12InputArguments.CompressedBitstream.Offset % d3d12BitstreamOffsetAlignment) == 0)); 430bf215546Sopenharmony_ci d3d12InputArguments.CompressedBitstream.Size = pD3D12Dec->m_curFrameCompressedBitstreamBufferPayloadSize; 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER resourceBarrierCommonToDecode[1] = { 433bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(d3d12InputArguments.CompressedBitstream.pBuffer, 434bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 435bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_DECODE_READ), 436bf215546Sopenharmony_ci }; 437bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(1u, resourceBarrierCommonToDecode); 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci // Schedule reverse (back to common) transitions before command list closes for current frame 440bf215546Sopenharmony_ci pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back( 441bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(d3d12InputArguments.CompressedBitstream.pBuffer, 442bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_DECODE_READ, 443bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON)); 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci /// 446bf215546Sopenharmony_ci /// Clear texture (no reference only flags in resource allocation) to use as decode output to send downstream for 447bf215546Sopenharmony_ci /// display/consumption 448bf215546Sopenharmony_ci /// 449bf215546Sopenharmony_ci ID3D12Resource *pOutputD3D12Texture; 450bf215546Sopenharmony_ci uint outputD3D12Subresource = 0; 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci /// 453bf215546Sopenharmony_ci /// Ref Only texture (with reference only flags in resource allocation) to use as reconstructed picture decode output 454bf215546Sopenharmony_ci /// and to store as future reference in DPB 455bf215546Sopenharmony_ci /// 456bf215546Sopenharmony_ci ID3D12Resource *pRefOnlyOutputD3D12Texture; 457bf215546Sopenharmony_ci uint refOnlyOutputD3D12Subresource = 0; 458bf215546Sopenharmony_ci 459bf215546Sopenharmony_ci if(!d3d12_video_decoder_prepare_for_decode_frame(pD3D12Dec, 460bf215546Sopenharmony_ci target, 461bf215546Sopenharmony_ci pD3D12VideoBuffer, 462bf215546Sopenharmony_ci &pOutputD3D12Texture, // output 463bf215546Sopenharmony_ci &outputD3D12Subresource, // output 464bf215546Sopenharmony_ci &pRefOnlyOutputD3D12Texture, // output 465bf215546Sopenharmony_ci &refOnlyOutputD3D12Subresource, // output 466bf215546Sopenharmony_ci requestedConversionArguments)) { 467bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Failure on " 468bf215546Sopenharmony_ci "d3d12_video_decoder_prepare_for_decode_frame\n"); 469bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_decoder_end_frame failed for fenceValue: %d\n", 470bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 471bf215546Sopenharmony_ci assert(false); 472bf215546Sopenharmony_ci return; 473bf215546Sopenharmony_ci } 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci /// 476bf215546Sopenharmony_ci /// Set codec picture parameters CPU buffer 477bf215546Sopenharmony_ci /// 478bf215546Sopenharmony_ci 479bf215546Sopenharmony_ci d3d12InputArguments.NumFrameArguments = 480bf215546Sopenharmony_ci 1u; // Only the codec data received from the above layer with picture params 481bf215546Sopenharmony_ci d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = { 482bf215546Sopenharmony_ci D3D12_VIDEO_DECODE_ARGUMENT_TYPE_PICTURE_PARAMETERS, 483bf215546Sopenharmony_ci static_cast<uint32_t>(pD3D12Dec->m_picParamsBuffer.size()), 484bf215546Sopenharmony_ci pD3D12Dec->m_picParamsBuffer.data(), 485bf215546Sopenharmony_ci }; 486bf215546Sopenharmony_ci 487bf215546Sopenharmony_ci if (pD3D12Dec->m_SliceControlBuffer.size() > 0) { 488bf215546Sopenharmony_ci d3d12InputArguments.NumFrameArguments++; 489bf215546Sopenharmony_ci d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = { 490bf215546Sopenharmony_ci D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL, 491bf215546Sopenharmony_ci static_cast<uint32_t>(pD3D12Dec->m_SliceControlBuffer.size()), 492bf215546Sopenharmony_ci pD3D12Dec->m_SliceControlBuffer.data(), 493bf215546Sopenharmony_ci }; 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci if (pD3D12Dec->m_InverseQuantMatrixBuffer.size() > 0) { 497bf215546Sopenharmony_ci d3d12InputArguments.NumFrameArguments++; 498bf215546Sopenharmony_ci d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = { 499bf215546Sopenharmony_ci D3D12_VIDEO_DECODE_ARGUMENT_TYPE_INVERSE_QUANTIZATION_MATRIX, 500bf215546Sopenharmony_ci static_cast<uint32_t>(pD3D12Dec->m_InverseQuantMatrixBuffer.size()), 501bf215546Sopenharmony_ci pD3D12Dec->m_InverseQuantMatrixBuffer.data(), 502bf215546Sopenharmony_ci }; 503bf215546Sopenharmony_ci } 504bf215546Sopenharmony_ci 505bf215546Sopenharmony_ci d3d12InputArguments.ReferenceFrames = pD3D12Dec->m_spDPBManager->get_current_reference_frames(); 506bf215546Sopenharmony_ci if (D3D12_DEBUG_VERBOSE & d3d12_debug) { 507bf215546Sopenharmony_ci pD3D12Dec->m_spDPBManager->print_dpb(); 508bf215546Sopenharmony_ci } 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci d3d12InputArguments.pHeap = pD3D12Dec->m_spVideoDecoderHeap.Get(); 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci // translate output D3D12 structure 513bf215546Sopenharmony_ci D3D12_VIDEO_DECODE_OUTPUT_STREAM_ARGUMENTS1 d3d12OutputArguments = {}; 514bf215546Sopenharmony_ci d3d12OutputArguments.pOutputTexture2D = pOutputD3D12Texture; 515bf215546Sopenharmony_ci d3d12OutputArguments.OutputSubresource = outputD3D12Subresource; 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_ci bool fReferenceOnly = (pD3D12Dec->m_ConfigDecoderSpecificFlags & 518bf215546Sopenharmony_ci d3d12_video_decode_config_specific_flag_reference_only_textures_required) != 0; 519bf215546Sopenharmony_ci if (fReferenceOnly) { 520bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.Enable = TRUE; 521bf215546Sopenharmony_ci 522bf215546Sopenharmony_ci assert(pRefOnlyOutputD3D12Texture); 523bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.pReferenceTexture2D = pRefOnlyOutputD3D12Texture; 524bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.ReferenceSubresource = refOnlyOutputD3D12Subresource; 525bf215546Sopenharmony_ci 526bf215546Sopenharmony_ci const D3D12_RESOURCE_DESC &descReference = GetDesc(d3d12OutputArguments.ConversionArguments.pReferenceTexture2D); 527bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.DecodeColorSpace = d3d12_convert_from_legacy_color_space( 528bf215546Sopenharmony_ci !util_format_is_yuv(d3d12_get_pipe_format(descReference.Format)), 529bf215546Sopenharmony_ci util_format_get_blocksize(d3d12_get_pipe_format(descReference.Format)) * 8 /*bytes to bits conversion*/, 530bf215546Sopenharmony_ci /* StudioRGB= */ false, 531bf215546Sopenharmony_ci /* P709= */ true, 532bf215546Sopenharmony_ci /* StudioYUV= */ true); 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci const D3D12_RESOURCE_DESC &descOutput = GetDesc(d3d12OutputArguments.pOutputTexture2D); 535bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.OutputColorSpace = d3d12_convert_from_legacy_color_space( 536bf215546Sopenharmony_ci !util_format_is_yuv(d3d12_get_pipe_format(descOutput.Format)), 537bf215546Sopenharmony_ci util_format_get_blocksize(d3d12_get_pipe_format(descOutput.Format)) * 8 /*bytes to bits conversion*/, 538bf215546Sopenharmony_ci /* StudioRGB= */ false, 539bf215546Sopenharmony_ci /* P709= */ true, 540bf215546Sopenharmony_ci /* StudioYUV= */ true); 541bf215546Sopenharmony_ci 542bf215546Sopenharmony_ci const D3D12_VIDEO_DECODER_HEAP_DESC &HeapDesc = GetDesc(pD3D12Dec->m_spVideoDecoderHeap.Get()); 543bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.OutputWidth = HeapDesc.DecodeWidth; 544bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.OutputHeight = HeapDesc.DecodeHeight; 545bf215546Sopenharmony_ci } else { 546bf215546Sopenharmony_ci d3d12OutputArguments.ConversionArguments.Enable = FALSE; 547bf215546Sopenharmony_ci } 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci CD3DX12_RESOURCE_DESC outputDesc(GetDesc(d3d12OutputArguments.pOutputTexture2D)); 550bf215546Sopenharmony_ci uint32_t MipLevel, PlaneSlice, ArraySlice; 551bf215546Sopenharmony_ci D3D12DecomposeSubresource(d3d12OutputArguments.OutputSubresource, 552bf215546Sopenharmony_ci outputDesc.MipLevels, 553bf215546Sopenharmony_ci outputDesc.ArraySize(), 554bf215546Sopenharmony_ci MipLevel, 555bf215546Sopenharmony_ci ArraySlice, 556bf215546Sopenharmony_ci PlaneSlice); 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) { 559bf215546Sopenharmony_ci uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); 560bf215546Sopenharmony_ci 561bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER resourceBarrierCommonToDecode[1] = { 562bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(d3d12OutputArguments.pOutputTexture2D, 563bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 564bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, 565bf215546Sopenharmony_ci planeOutputSubresource), 566bf215546Sopenharmony_ci }; 567bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(1u, resourceBarrierCommonToDecode); 568bf215546Sopenharmony_ci } 569bf215546Sopenharmony_ci 570bf215546Sopenharmony_ci // Schedule reverse (back to common) transitions before command list closes for current frame 571bf215546Sopenharmony_ci for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) { 572bf215546Sopenharmony_ci uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); 573bf215546Sopenharmony_ci pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back( 574bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(d3d12OutputArguments.pOutputTexture2D, 575bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, 576bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 577bf215546Sopenharmony_ci planeOutputSubresource)); 578bf215546Sopenharmony_ci } 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci // Record DecodeFrame 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandList->DecodeFrame1(pD3D12Dec->m_spVideoDecoder.Get(), 583bf215546Sopenharmony_ci &d3d12OutputArguments, 584bf215546Sopenharmony_ci &d3d12InputArguments); 585bf215546Sopenharmony_ci 586bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame finalized for fenceValue: %d\n", 587bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 588bf215546Sopenharmony_ci 589bf215546Sopenharmony_ci /// 590bf215546Sopenharmony_ci /// Flush work to the GPU and blocking wait until decode finishes 591bf215546Sopenharmony_ci /// 592bf215546Sopenharmony_ci pD3D12Dec->m_needsGPUFlush = true; 593bf215546Sopenharmony_ci d3d12_video_decoder_flush(codec); 594bf215546Sopenharmony_ci 595bf215546Sopenharmony_ci if (!pD3D12Dec->m_spDPBManager->is_pipe_buffer_underlying_output_decode_allocation()) { 596bf215546Sopenharmony_ci /// 597bf215546Sopenharmony_ci /// If !pD3D12Dec->m_spDPBManager->is_pipe_buffer_underlying_output_decode_allocation() 598bf215546Sopenharmony_ci /// We cannot use the standalone video buffer allocation directly and we must use instead 599bf215546Sopenharmony_ci /// either a ID3D12Resource with DECODE_REFERENCE only flag or a texture array within the same 600bf215546Sopenharmony_ci /// allocation 601bf215546Sopenharmony_ci /// Do GPU->GPU texture copy from decode output to pipe target decode texture sampler view planes 602bf215546Sopenharmony_ci /// 603bf215546Sopenharmony_ci 604bf215546Sopenharmony_ci // Get destination resource 605bf215546Sopenharmony_ci struct pipe_sampler_view **pPipeDstViews = target->get_sampler_view_planes(target); 606bf215546Sopenharmony_ci 607bf215546Sopenharmony_ci // Get source pipe_resource 608bf215546Sopenharmony_ci pipe_resource *pPipeSrc = 609bf215546Sopenharmony_ci d3d12_resource_from_resource(&pD3D12Screen->base, d3d12OutputArguments.pOutputTexture2D); 610bf215546Sopenharmony_ci assert(pPipeSrc); 611bf215546Sopenharmony_ci 612bf215546Sopenharmony_ci // Copy all format subresources/texture planes 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) { 615bf215546Sopenharmony_ci assert(d3d12OutputArguments.OutputSubresource < INT16_MAX); 616bf215546Sopenharmony_ci struct pipe_box box = { 0, 617bf215546Sopenharmony_ci 0, 618bf215546Sopenharmony_ci // src array slice, taken as Z for TEXTURE_2D_ARRAY 619bf215546Sopenharmony_ci static_cast<int16_t>(d3d12OutputArguments.OutputSubresource), 620bf215546Sopenharmony_ci static_cast<int>(pPipeDstViews[PlaneSlice]->texture->width0), 621bf215546Sopenharmony_ci static_cast<int16_t>(pPipeDstViews[PlaneSlice]->texture->height0), 622bf215546Sopenharmony_ci 1 }; 623bf215546Sopenharmony_ci 624bf215546Sopenharmony_ci pD3D12Dec->base.context->resource_copy_region(pD3D12Dec->base.context, 625bf215546Sopenharmony_ci pPipeDstViews[PlaneSlice]->texture, // dst 626bf215546Sopenharmony_ci 0, // dst level 627bf215546Sopenharmony_ci 0, // dstX 628bf215546Sopenharmony_ci 0, // dstY 629bf215546Sopenharmony_ci 0, // dstZ 630bf215546Sopenharmony_ci (PlaneSlice == 0) ? pPipeSrc : pPipeSrc->next, // src 631bf215546Sopenharmony_ci 0, // src level 632bf215546Sopenharmony_ci &box); 633bf215546Sopenharmony_ci } 634bf215546Sopenharmony_ci // Flush resource_copy_region batch and wait on this CPU thread for GPU work completion 635bf215546Sopenharmony_ci struct pipe_fence_handle *completion_fence = NULL; 636bf215546Sopenharmony_ci pD3D12Dec->base.context->flush(pD3D12Dec->base.context, 637bf215546Sopenharmony_ci &completion_fence, 638bf215546Sopenharmony_ci PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH); 639bf215546Sopenharmony_ci assert(completion_fence); 640bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Waiting on GPU completion fence for " 641bf215546Sopenharmony_ci "resource_copy_region on decoded frame.\n"); 642bf215546Sopenharmony_ci pD3D12Screen->base.fence_finish(&pD3D12Screen->base, NULL, completion_fence, PIPE_TIMEOUT_INFINITE); 643bf215546Sopenharmony_ci pD3D12Screen->base.fence_reference(&pD3D12Screen->base, &completion_fence, NULL); 644bf215546Sopenharmony_ci } 645bf215546Sopenharmony_ci} 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci/** 648bf215546Sopenharmony_ci * flush any outstanding command buffers to the hardware 649bf215546Sopenharmony_ci * should be called before a video_buffer is acessed by the gallium frontend again 650bf215546Sopenharmony_ci */ 651bf215546Sopenharmony_civoid 652bf215546Sopenharmony_cid3d12_video_decoder_flush(struct pipe_video_codec *codec) 653bf215546Sopenharmony_ci{ 654bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec; 655bf215546Sopenharmony_ci assert(pD3D12Dec); 656bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 657bf215546Sopenharmony_ci assert(pD3D12Dec->m_spDecodeCommandQueue); 658bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush started. Will flush video queue work and CPU wait on " 659bf215546Sopenharmony_ci "fenceValue: %d\n", 660bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 661bf215546Sopenharmony_ci 662bf215546Sopenharmony_ci if (!pD3D12Dec->m_needsGPUFlush) { 663bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush started. Nothing to flush, all up to date.\n"); 664bf215546Sopenharmony_ci } else { 665bf215546Sopenharmony_ci HRESULT hr = pD3D12Dec->m_pD3D12Screen->dev->GetDeviceRemovedReason(); 666bf215546Sopenharmony_ci if (hr != S_OK) { 667bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush" 668bf215546Sopenharmony_ci " - D3D12Device was removed BEFORE commandlist " 669bf215546Sopenharmony_ci "execution with HR %x.\n", 670bf215546Sopenharmony_ci hr); 671bf215546Sopenharmony_ci goto flush_fail; 672bf215546Sopenharmony_ci } 673bf215546Sopenharmony_ci 674bf215546Sopenharmony_ci // Close and execute command list and wait for idle on CPU blocking 675bf215546Sopenharmony_ci // this method before resetting list and allocator for next submission. 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci if (pD3D12Dec->m_transitionsBeforeCloseCmdList.size() > 0) { 678bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(pD3D12Dec->m_transitionsBeforeCloseCmdList.size(), 679bf215546Sopenharmony_ci pD3D12Dec->m_transitionsBeforeCloseCmdList.data()); 680bf215546Sopenharmony_ci pD3D12Dec->m_transitionsBeforeCloseCmdList.clear(); 681bf215546Sopenharmony_ci } 682bf215546Sopenharmony_ci 683bf215546Sopenharmony_ci hr = pD3D12Dec->m_spDecodeCommandList->Close(); 684bf215546Sopenharmony_ci if (FAILED(hr)) { 685bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush - Can't close command list with HR %x\n", hr); 686bf215546Sopenharmony_ci goto flush_fail; 687bf215546Sopenharmony_ci } 688bf215546Sopenharmony_ci 689bf215546Sopenharmony_ci ID3D12CommandList *ppCommandLists[1] = { pD3D12Dec->m_spDecodeCommandList.Get() }; 690bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandQueue->ExecuteCommandLists(1, ppCommandLists); 691bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandQueue->Signal(pD3D12Dec->m_spFence.Get(), pD3D12Dec->m_fenceValue); 692bf215546Sopenharmony_ci pD3D12Dec->m_spFence->SetEventOnCompletion(pD3D12Dec->m_fenceValue, nullptr); 693bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush - ExecuteCommandLists finished on signal with " 694bf215546Sopenharmony_ci "fenceValue: %d\n", 695bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 696bf215546Sopenharmony_ci 697bf215546Sopenharmony_ci hr = pD3D12Dec->m_spCommandAllocator->Reset(); 698bf215546Sopenharmony_ci if (FAILED(hr)) { 699bf215546Sopenharmony_ci debug_printf( 700bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_decoder_flush - resetting ID3D12CommandAllocator failed with HR %x\n", 701bf215546Sopenharmony_ci hr); 702bf215546Sopenharmony_ci goto flush_fail; 703bf215546Sopenharmony_ci } 704bf215546Sopenharmony_ci 705bf215546Sopenharmony_ci hr = pD3D12Dec->m_spDecodeCommandList->Reset(pD3D12Dec->m_spCommandAllocator.Get()); 706bf215546Sopenharmony_ci if (FAILED(hr)) { 707bf215546Sopenharmony_ci debug_printf( 708bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_decoder_flush - resetting ID3D12GraphicsCommandList failed with HR %x\n", 709bf215546Sopenharmony_ci hr); 710bf215546Sopenharmony_ci goto flush_fail; 711bf215546Sopenharmony_ci } 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_ci // Validate device was not removed 714bf215546Sopenharmony_ci hr = pD3D12Dec->m_pD3D12Screen->dev->GetDeviceRemovedReason(); 715bf215546Sopenharmony_ci if (hr != S_OK) { 716bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush" 717bf215546Sopenharmony_ci " - D3D12Device was removed AFTER commandlist " 718bf215546Sopenharmony_ci "execution with HR %x, but wasn't before.\n", 719bf215546Sopenharmony_ci hr); 720bf215546Sopenharmony_ci goto flush_fail; 721bf215546Sopenharmony_ci } 722bf215546Sopenharmony_ci 723bf215546Sopenharmony_ci debug_printf( 724bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_decoder_flush - GPU signaled execution finalized for fenceValue: %d\n", 725bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue); 726bf215546Sopenharmony_ci 727bf215546Sopenharmony_ci pD3D12Dec->m_fenceValue++; 728bf215546Sopenharmony_ci pD3D12Dec->m_needsGPUFlush = false; 729bf215546Sopenharmony_ci } 730bf215546Sopenharmony_ci return; 731bf215546Sopenharmony_ci 732bf215546Sopenharmony_ciflush_fail: 733bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush failed for fenceValue: %d\n", pD3D12Dec->m_fenceValue); 734bf215546Sopenharmony_ci assert(false); 735bf215546Sopenharmony_ci} 736bf215546Sopenharmony_ci 737bf215546Sopenharmony_cibool 738bf215546Sopenharmony_cid3d12_video_decoder_create_command_objects(const struct d3d12_screen *pD3D12Screen, 739bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec) 740bf215546Sopenharmony_ci{ 741bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 742bf215546Sopenharmony_ci 743bf215546Sopenharmony_ci D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE }; 744bf215546Sopenharmony_ci HRESULT hr = pD3D12Screen->dev->CreateCommandQueue(&commandQueueDesc, 745bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spDecodeCommandQueue.GetAddressOf())); 746bf215546Sopenharmony_ci if (FAILED(hr)) { 747bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to CreateCommandQueue " 748bf215546Sopenharmony_ci "failed with HR %x\n", 749bf215546Sopenharmony_ci hr); 750bf215546Sopenharmony_ci return false; 751bf215546Sopenharmony_ci } 752bf215546Sopenharmony_ci 753bf215546Sopenharmony_ci hr = pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pD3D12Dec->m_spFence)); 754bf215546Sopenharmony_ci if (FAILED(hr)) { 755bf215546Sopenharmony_ci debug_printf( 756bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to CreateFence failed with HR %x\n", 757bf215546Sopenharmony_ci hr); 758bf215546Sopenharmony_ci return false; 759bf215546Sopenharmony_ci } 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci hr = pD3D12Screen->dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE, 762bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spCommandAllocator.GetAddressOf())); 763bf215546Sopenharmony_ci if (FAILED(hr)) { 764bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to " 765bf215546Sopenharmony_ci "CreateCommandAllocator failed with HR %x\n", 766bf215546Sopenharmony_ci hr); 767bf215546Sopenharmony_ci return false; 768bf215546Sopenharmony_ci } 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci hr = pD3D12Screen->dev->CreateCommandList(0, 771bf215546Sopenharmony_ci D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE, 772bf215546Sopenharmony_ci pD3D12Dec->m_spCommandAllocator.Get(), 773bf215546Sopenharmony_ci nullptr, 774bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spDecodeCommandList.GetAddressOf())); 775bf215546Sopenharmony_ci 776bf215546Sopenharmony_ci if (FAILED(hr)) { 777bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to CreateCommandList " 778bf215546Sopenharmony_ci "failed with HR %x\n", 779bf215546Sopenharmony_ci hr); 780bf215546Sopenharmony_ci return false; 781bf215546Sopenharmony_ci } 782bf215546Sopenharmony_ci 783bf215546Sopenharmony_ci return true; 784bf215546Sopenharmony_ci} 785bf215546Sopenharmony_ci 786bf215546Sopenharmony_cibool 787bf215546Sopenharmony_cid3d12_video_decoder_check_caps_and_create_decoder(const struct d3d12_screen *pD3D12Screen, 788bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec) 789bf215546Sopenharmony_ci{ 790bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 791bf215546Sopenharmony_ci 792bf215546Sopenharmony_ci pD3D12Dec->m_decoderDesc = {}; 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci D3D12_VIDEO_DECODE_CONFIGURATION decodeConfiguration = { pD3D12Dec->m_d3d12DecProfile, 795bf215546Sopenharmony_ci D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE, 796bf215546Sopenharmony_ci D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE }; 797bf215546Sopenharmony_ci 798bf215546Sopenharmony_ci D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT decodeSupport = {}; 799bf215546Sopenharmony_ci decodeSupport.NodeIndex = pD3D12Dec->m_NodeIndex; 800bf215546Sopenharmony_ci decodeSupport.Configuration = decodeConfiguration; 801bf215546Sopenharmony_ci decodeSupport.Width = pD3D12Dec->base.width; 802bf215546Sopenharmony_ci decodeSupport.Height = pD3D12Dec->base.height; 803bf215546Sopenharmony_ci decodeSupport.DecodeFormat = pD3D12Dec->m_decodeFormat; 804bf215546Sopenharmony_ci // no info from above layer on framerate/bitrate 805bf215546Sopenharmony_ci decodeSupport.FrameRate.Numerator = 0; 806bf215546Sopenharmony_ci decodeSupport.FrameRate.Denominator = 0; 807bf215546Sopenharmony_ci decodeSupport.BitRate = 0; 808bf215546Sopenharmony_ci 809bf215546Sopenharmony_ci HRESULT hr = pD3D12Dec->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_DECODE_SUPPORT, 810bf215546Sopenharmony_ci &decodeSupport, 811bf215546Sopenharmony_ci sizeof(decodeSupport)); 812bf215546Sopenharmony_ci if (FAILED(hr)) { 813bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_check_caps_and_create_decoder - CheckFeatureSupport " 814bf215546Sopenharmony_ci "failed with HR %x\n", 815bf215546Sopenharmony_ci hr); 816bf215546Sopenharmony_ci return false; 817bf215546Sopenharmony_ci } 818bf215546Sopenharmony_ci 819bf215546Sopenharmony_ci if (!(decodeSupport.SupportFlags & D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED)) { 820bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_check_caps_and_create_decoder - " 821bf215546Sopenharmony_ci "D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED was false when checking caps \n"); 822bf215546Sopenharmony_ci return false; 823bf215546Sopenharmony_ci } 824bf215546Sopenharmony_ci 825bf215546Sopenharmony_ci pD3D12Dec->m_configurationFlags = decodeSupport.ConfigurationFlags; 826bf215546Sopenharmony_ci pD3D12Dec->m_tier = decodeSupport.DecodeTier; 827bf215546Sopenharmony_ci 828bf215546Sopenharmony_ci if (d3d12_video_decoder_supports_aot_dpb(decodeSupport, pD3D12Dec->m_d3d12DecProfileType)) { 829bf215546Sopenharmony_ci pD3D12Dec->m_ConfigDecoderSpecificFlags |= d3d12_video_decode_config_specific_flag_array_of_textures; 830bf215546Sopenharmony_ci } 831bf215546Sopenharmony_ci 832bf215546Sopenharmony_ci if (decodeSupport.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_HEIGHT_ALIGNMENT_MULTIPLE_32_REQUIRED) { 833bf215546Sopenharmony_ci pD3D12Dec->m_ConfigDecoderSpecificFlags |= d3d12_video_decode_config_specific_flag_alignment_height; 834bf215546Sopenharmony_ci } 835bf215546Sopenharmony_ci 836bf215546Sopenharmony_ci if (decodeSupport.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_REFERENCE_ONLY_ALLOCATIONS_REQUIRED) { 837bf215546Sopenharmony_ci pD3D12Dec->m_ConfigDecoderSpecificFlags |= 838bf215546Sopenharmony_ci d3d12_video_decode_config_specific_flag_reference_only_textures_required; 839bf215546Sopenharmony_ci } 840bf215546Sopenharmony_ci 841bf215546Sopenharmony_ci pD3D12Dec->m_decoderDesc.NodeMask = pD3D12Dec->m_NodeMask; 842bf215546Sopenharmony_ci pD3D12Dec->m_decoderDesc.Configuration = decodeConfiguration; 843bf215546Sopenharmony_ci 844bf215546Sopenharmony_ci hr = pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoder(&pD3D12Dec->m_decoderDesc, 845bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spVideoDecoder.GetAddressOf())); 846bf215546Sopenharmony_ci if (FAILED(hr)) { 847bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_check_caps_and_create_decoder - CreateVideoDecoder " 848bf215546Sopenharmony_ci "failed with HR %x\n", 849bf215546Sopenharmony_ci hr); 850bf215546Sopenharmony_ci return false; 851bf215546Sopenharmony_ci } 852bf215546Sopenharmony_ci 853bf215546Sopenharmony_ci return true; 854bf215546Sopenharmony_ci} 855bf215546Sopenharmony_ci 856bf215546Sopenharmony_cibool 857bf215546Sopenharmony_cid3d12_video_decoder_create_video_state_buffers(const struct d3d12_screen *pD3D12Screen, 858bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec) 859bf215546Sopenharmony_ci{ 860bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 861bf215546Sopenharmony_ci if (!d3d12_video_decoder_create_staging_bitstream_buffer(pD3D12Screen, 862bf215546Sopenharmony_ci pD3D12Dec, 863bf215546Sopenharmony_ci pD3D12Dec->m_InitialCompBitstreamGPUBufferSize)) { 864bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_video_state_buffers - Failure on " 865bf215546Sopenharmony_ci "d3d12_video_decoder_create_staging_bitstream_buffer\n"); 866bf215546Sopenharmony_ci return false; 867bf215546Sopenharmony_ci } 868bf215546Sopenharmony_ci 869bf215546Sopenharmony_ci return true; 870bf215546Sopenharmony_ci} 871bf215546Sopenharmony_ci 872bf215546Sopenharmony_cibool 873bf215546Sopenharmony_cid3d12_video_decoder_create_staging_bitstream_buffer(const struct d3d12_screen *pD3D12Screen, 874bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec, 875bf215546Sopenharmony_ci uint64_t bufSize) 876bf215546Sopenharmony_ci{ 877bf215546Sopenharmony_ci assert(pD3D12Dec->m_spD3D12VideoDevice); 878bf215546Sopenharmony_ci 879bf215546Sopenharmony_ci if (pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Get() != nullptr) { 880bf215546Sopenharmony_ci pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Reset(); 881bf215546Sopenharmony_ci } 882bf215546Sopenharmony_ci 883bf215546Sopenharmony_ci auto descHeap = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT, pD3D12Dec->m_NodeMask, pD3D12Dec->m_NodeMask); 884bf215546Sopenharmony_ci auto descResource = CD3DX12_RESOURCE_DESC::Buffer(bufSize); 885bf215546Sopenharmony_ci HRESULT hr = pD3D12Screen->dev->CreateCommittedResource( 886bf215546Sopenharmony_ci &descHeap, 887bf215546Sopenharmony_ci D3D12_HEAP_FLAG_NONE, 888bf215546Sopenharmony_ci &descResource, 889bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 890bf215546Sopenharmony_ci nullptr, 891bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_curFrameCompressedBitstreamBuffer.GetAddressOf())); 892bf215546Sopenharmony_ci if (FAILED(hr)) { 893bf215546Sopenharmony_ci debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_staging_bitstream_buffer - " 894bf215546Sopenharmony_ci "CreateCommittedResource failed with HR %x\n", 895bf215546Sopenharmony_ci hr); 896bf215546Sopenharmony_ci return false; 897bf215546Sopenharmony_ci } 898bf215546Sopenharmony_ci 899bf215546Sopenharmony_ci pD3D12Dec->m_curFrameCompressedBitstreamBufferAllocatedSize = bufSize; 900bf215546Sopenharmony_ci return true; 901bf215546Sopenharmony_ci} 902bf215546Sopenharmony_ci 903bf215546Sopenharmony_cibool 904bf215546Sopenharmony_cid3d12_video_decoder_prepare_for_decode_frame(struct d3d12_video_decoder *pD3D12Dec, 905bf215546Sopenharmony_ci struct pipe_video_buffer *pCurrentDecodeTarget, 906bf215546Sopenharmony_ci struct d3d12_video_buffer *pD3D12VideoBuffer, 907bf215546Sopenharmony_ci ID3D12Resource **ppOutTexture2D, 908bf215546Sopenharmony_ci uint32_t *pOutSubresourceIndex, 909bf215546Sopenharmony_ci ID3D12Resource **ppRefOnlyOutTexture2D, 910bf215546Sopenharmony_ci uint32_t *pRefOnlyOutSubresourceIndex, 911bf215546Sopenharmony_ci const d3d12_video_decode_output_conversion_arguments &conversionArgs) 912bf215546Sopenharmony_ci{ 913bf215546Sopenharmony_ci if(!d3d12_video_decoder_reconfigure_dpb(pD3D12Dec, pD3D12VideoBuffer, conversionArgs)) { 914bf215546Sopenharmony_ci debug_printf("d3d12_video_decoder_reconfigure_dpb failed!\n"); 915bf215546Sopenharmony_ci return false; 916bf215546Sopenharmony_ci } 917bf215546Sopenharmony_ci 918bf215546Sopenharmony_ci // Refresh DPB active references for current frame, release memory for unused references. 919bf215546Sopenharmony_ci d3d12_video_decoder_refresh_dpb_active_references(pD3D12Dec); 920bf215546Sopenharmony_ci 921bf215546Sopenharmony_ci // Get the output texture for the current frame to be decoded 922bf215546Sopenharmony_ci pD3D12Dec->m_spDPBManager->get_current_frame_decode_output_texture(pCurrentDecodeTarget, 923bf215546Sopenharmony_ci ppOutTexture2D, 924bf215546Sopenharmony_ci pOutSubresourceIndex); 925bf215546Sopenharmony_ci 926bf215546Sopenharmony_ci auto vidBuffer = (struct d3d12_video_buffer *)(pCurrentDecodeTarget); 927bf215546Sopenharmony_ci // If is_pipe_buffer_underlying_output_decode_allocation is enabled, 928bf215546Sopenharmony_ci // we can just use the underlying allocation in pCurrentDecodeTarget 929bf215546Sopenharmony_ci // and avoid an extra copy after decoding the frame. 930bf215546Sopenharmony_ci // If this is the case, we need to handle the residency of this resource 931bf215546Sopenharmony_ci // (if not we're actually creating the resources with CreateCommitedResource with 932bf215546Sopenharmony_ci // residency by default) 933bf215546Sopenharmony_ci if(pD3D12Dec->m_spDPBManager->is_pipe_buffer_underlying_output_decode_allocation()) { 934bf215546Sopenharmony_ci assert(d3d12_resource_resource(vidBuffer->texture) == *ppOutTexture2D); 935bf215546Sopenharmony_ci // Make it permanently resident for video use 936bf215546Sopenharmony_ci d3d12_promote_to_permanent_residency(pD3D12Dec->m_pD3D12Screen, vidBuffer->texture); 937bf215546Sopenharmony_ci } 938bf215546Sopenharmony_ci 939bf215546Sopenharmony_ci // Get the reference only texture for the current frame to be decoded (if applicable) 940bf215546Sopenharmony_ci bool fReferenceOnly = (pD3D12Dec->m_ConfigDecoderSpecificFlags & 941bf215546Sopenharmony_ci d3d12_video_decode_config_specific_flag_reference_only_textures_required) != 0; 942bf215546Sopenharmony_ci if (fReferenceOnly) { 943bf215546Sopenharmony_ci bool needsTransitionToDecodeWrite = false; 944bf215546Sopenharmony_ci pD3D12Dec->m_spDPBManager->get_reference_only_output(pCurrentDecodeTarget, 945bf215546Sopenharmony_ci ppRefOnlyOutTexture2D, 946bf215546Sopenharmony_ci pRefOnlyOutSubresourceIndex, 947bf215546Sopenharmony_ci needsTransitionToDecodeWrite); 948bf215546Sopenharmony_ci assert(needsTransitionToDecodeWrite); 949bf215546Sopenharmony_ci 950bf215546Sopenharmony_ci CD3DX12_RESOURCE_DESC outputDesc(GetDesc(*ppRefOnlyOutTexture2D)); 951bf215546Sopenharmony_ci uint32_t MipLevel, PlaneSlice, ArraySlice; 952bf215546Sopenharmony_ci D3D12DecomposeSubresource(*pRefOnlyOutSubresourceIndex, 953bf215546Sopenharmony_ci outputDesc.MipLevels, 954bf215546Sopenharmony_ci outputDesc.ArraySize(), 955bf215546Sopenharmony_ci MipLevel, 956bf215546Sopenharmony_ci ArraySlice, 957bf215546Sopenharmony_ci PlaneSlice); 958bf215546Sopenharmony_ci 959bf215546Sopenharmony_ci for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) { 960bf215546Sopenharmony_ci uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); 961bf215546Sopenharmony_ci 962bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER resourceBarrierCommonToDecode[1] = { 963bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(*ppRefOnlyOutTexture2D, 964bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 965bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, 966bf215546Sopenharmony_ci planeOutputSubresource), 967bf215546Sopenharmony_ci }; 968bf215546Sopenharmony_ci pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(1u, resourceBarrierCommonToDecode); 969bf215546Sopenharmony_ci } 970bf215546Sopenharmony_ci 971bf215546Sopenharmony_ci // Schedule reverse (back to common) transitions before command list closes for current frame 972bf215546Sopenharmony_ci for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) { 973bf215546Sopenharmony_ci uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); 974bf215546Sopenharmony_ci pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back( 975bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(*ppRefOnlyOutTexture2D, 976bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE, 977bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 978bf215546Sopenharmony_ci planeOutputSubresource)); 979bf215546Sopenharmony_ci } 980bf215546Sopenharmony_ci } 981bf215546Sopenharmony_ci 982bf215546Sopenharmony_ci // If decoded needs reference_only entries in the dpb, use the reference_only allocation for current frame 983bf215546Sopenharmony_ci // otherwise, use the standard output resource 984bf215546Sopenharmony_ci ID3D12Resource *pCurrentFrameDPBEntry = fReferenceOnly ? *ppRefOnlyOutTexture2D : *ppOutTexture2D; 985bf215546Sopenharmony_ci uint32_t currentFrameDPBEntrySubresource = fReferenceOnly ? *pRefOnlyOutSubresourceIndex : *pOutSubresourceIndex; 986bf215546Sopenharmony_ci 987bf215546Sopenharmony_ci switch (pD3D12Dec->m_d3d12DecProfileType) { 988bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 989bf215546Sopenharmony_ci { 990bf215546Sopenharmony_ci d3d12_video_decoder_prepare_current_frame_references_h264(pD3D12Dec, 991bf215546Sopenharmony_ci pCurrentFrameDPBEntry, 992bf215546Sopenharmony_ci currentFrameDPBEntrySubresource); 993bf215546Sopenharmony_ci } break; 994bf215546Sopenharmony_ci 995bf215546Sopenharmony_ci default: 996bf215546Sopenharmony_ci { 997bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 998bf215546Sopenharmony_ci } break; 999bf215546Sopenharmony_ci } 1000bf215546Sopenharmony_ci 1001bf215546Sopenharmony_ci return true; 1002bf215546Sopenharmony_ci} 1003bf215546Sopenharmony_ci 1004bf215546Sopenharmony_cibool 1005bf215546Sopenharmony_cid3d12_video_decoder_reconfigure_dpb(struct d3d12_video_decoder *pD3D12Dec, 1006bf215546Sopenharmony_ci struct d3d12_video_buffer *pD3D12VideoBuffer, 1007bf215546Sopenharmony_ci const d3d12_video_decode_output_conversion_arguments &conversionArguments) 1008bf215546Sopenharmony_ci{ 1009bf215546Sopenharmony_ci uint32_t width; 1010bf215546Sopenharmony_ci uint32_t height; 1011bf215546Sopenharmony_ci uint16_t maxDPB; 1012bf215546Sopenharmony_ci bool isInterlaced; 1013bf215546Sopenharmony_ci d3d12_video_decoder_get_frame_info(pD3D12Dec, &width, &height, &maxDPB, isInterlaced); 1014bf215546Sopenharmony_ci 1015bf215546Sopenharmony_ci ID3D12Resource *pPipeD3D12DstResource = d3d12_resource_resource(pD3D12VideoBuffer->texture); 1016bf215546Sopenharmony_ci D3D12_RESOURCE_DESC outputResourceDesc = GetDesc(pPipeD3D12DstResource); 1017bf215546Sopenharmony_ci 1018bf215546Sopenharmony_ci pD3D12VideoBuffer->base.interlaced = isInterlaced; 1019bf215546Sopenharmony_ci D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE interlaceTypeRequested = 1020bf215546Sopenharmony_ci isInterlaced ? D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_FIELD_BASED : D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE; 1021bf215546Sopenharmony_ci if ((pD3D12Dec->m_decodeFormat != outputResourceDesc.Format) || 1022bf215546Sopenharmony_ci (pD3D12Dec->m_decoderDesc.Configuration.InterlaceType != interlaceTypeRequested)) { 1023bf215546Sopenharmony_ci // Copy current pD3D12Dec->m_decoderDesc, modify decodeprofile and re-create decoder. 1024bf215546Sopenharmony_ci D3D12_VIDEO_DECODER_DESC decoderDesc = pD3D12Dec->m_decoderDesc; 1025bf215546Sopenharmony_ci decoderDesc.Configuration.InterlaceType = interlaceTypeRequested; 1026bf215546Sopenharmony_ci decoderDesc.Configuration.DecodeProfile = 1027bf215546Sopenharmony_ci d3d12_video_decoder_resolve_profile(pD3D12Dec->m_d3d12DecProfileType); 1028bf215546Sopenharmony_ci pD3D12Dec->m_spVideoDecoder.Reset(); 1029bf215546Sopenharmony_ci HRESULT hr = 1030bf215546Sopenharmony_ci pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoder(&decoderDesc, 1031bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spVideoDecoder.GetAddressOf())); 1032bf215546Sopenharmony_ci if (FAILED(hr)) { 1033bf215546Sopenharmony_ci debug_printf( 1034bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_decoder_reconfigure_dpb - CreateVideoDecoder failed with HR %x\n", 1035bf215546Sopenharmony_ci hr); 1036bf215546Sopenharmony_ci return false; 1037bf215546Sopenharmony_ci } 1038bf215546Sopenharmony_ci // Update state after CreateVideoDecoder succeeds only. 1039bf215546Sopenharmony_ci pD3D12Dec->m_decoderDesc = decoderDesc; 1040bf215546Sopenharmony_ci } 1041bf215546Sopenharmony_ci 1042bf215546Sopenharmony_ci if (!pD3D12Dec->m_spDPBManager || !pD3D12Dec->m_spVideoDecoderHeap || 1043bf215546Sopenharmony_ci pD3D12Dec->m_decodeFormat != outputResourceDesc.Format || pD3D12Dec->m_decoderHeapDesc.DecodeWidth != width || 1044bf215546Sopenharmony_ci pD3D12Dec->m_decoderHeapDesc.DecodeHeight != height || 1045bf215546Sopenharmony_ci pD3D12Dec->m_decoderHeapDesc.MaxDecodePictureBufferCount < maxDPB) { 1046bf215546Sopenharmony_ci // Detect the combination of AOT/ReferenceOnly to configure the DPB manager 1047bf215546Sopenharmony_ci uint16_t referenceCount = (conversionArguments.Enable) ? (uint16_t) conversionArguments.ReferenceFrameCount + 1048bf215546Sopenharmony_ci 1 /*extra slot for current picture*/ : 1049bf215546Sopenharmony_ci maxDPB; 1050bf215546Sopenharmony_ci d3d12_video_decode_dpb_descriptor dpbDesc = {}; 1051bf215546Sopenharmony_ci dpbDesc.Width = (conversionArguments.Enable) ? conversionArguments.ReferenceInfo.Width : width; 1052bf215546Sopenharmony_ci dpbDesc.Height = (conversionArguments.Enable) ? conversionArguments.ReferenceInfo.Height : height; 1053bf215546Sopenharmony_ci dpbDesc.Format = 1054bf215546Sopenharmony_ci (conversionArguments.Enable) ? conversionArguments.ReferenceInfo.Format.Format : outputResourceDesc.Format; 1055bf215546Sopenharmony_ci dpbDesc.fArrayOfTexture = 1056bf215546Sopenharmony_ci ((pD3D12Dec->m_ConfigDecoderSpecificFlags & d3d12_video_decode_config_specific_flag_array_of_textures) != 0); 1057bf215546Sopenharmony_ci dpbDesc.dpbSize = referenceCount; 1058bf215546Sopenharmony_ci dpbDesc.m_NodeMask = pD3D12Dec->m_NodeMask; 1059bf215546Sopenharmony_ci dpbDesc.fReferenceOnly = ((pD3D12Dec->m_ConfigDecoderSpecificFlags & 1060bf215546Sopenharmony_ci d3d12_video_decode_config_specific_flag_reference_only_textures_required) != 0); 1061bf215546Sopenharmony_ci 1062bf215546Sopenharmony_ci // Create DPB manager 1063bf215546Sopenharmony_ci if (pD3D12Dec->m_spDPBManager == nullptr) { 1064bf215546Sopenharmony_ci pD3D12Dec->m_spDPBManager.reset(new d3d12_video_decoder_references_manager(pD3D12Dec->m_pD3D12Screen, 1065bf215546Sopenharmony_ci pD3D12Dec->m_NodeMask, 1066bf215546Sopenharmony_ci pD3D12Dec->m_d3d12DecProfileType, 1067bf215546Sopenharmony_ci dpbDesc)); 1068bf215546Sopenharmony_ci } 1069bf215546Sopenharmony_ci 1070bf215546Sopenharmony_ci // 1071bf215546Sopenharmony_ci // (Re)-create decoder heap 1072bf215546Sopenharmony_ci // 1073bf215546Sopenharmony_ci D3D12_VIDEO_DECODER_HEAP_DESC decoderHeapDesc = {}; 1074bf215546Sopenharmony_ci decoderHeapDesc.NodeMask = pD3D12Dec->m_NodeMask; 1075bf215546Sopenharmony_ci decoderHeapDesc.Configuration = pD3D12Dec->m_decoderDesc.Configuration; 1076bf215546Sopenharmony_ci decoderHeapDesc.DecodeWidth = dpbDesc.Width; 1077bf215546Sopenharmony_ci decoderHeapDesc.DecodeHeight = dpbDesc.Height; 1078bf215546Sopenharmony_ci decoderHeapDesc.Format = dpbDesc.Format; 1079bf215546Sopenharmony_ci decoderHeapDesc.MaxDecodePictureBufferCount = maxDPB; 1080bf215546Sopenharmony_ci pD3D12Dec->m_spVideoDecoderHeap.Reset(); 1081bf215546Sopenharmony_ci HRESULT hr = pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoderHeap( 1082bf215546Sopenharmony_ci &decoderHeapDesc, 1083bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Dec->m_spVideoDecoderHeap.GetAddressOf())); 1084bf215546Sopenharmony_ci if (FAILED(hr)) { 1085bf215546Sopenharmony_ci debug_printf( 1086bf215546Sopenharmony_ci "[d3d12_video_decoder] d3d12_video_decoder_reconfigure_dpb - CreateVideoDecoderHeap failed with HR %x\n", 1087bf215546Sopenharmony_ci hr); 1088bf215546Sopenharmony_ci return false; 1089bf215546Sopenharmony_ci } 1090bf215546Sopenharmony_ci // Update pD3D12Dec after CreateVideoDecoderHeap succeeds only. 1091bf215546Sopenharmony_ci pD3D12Dec->m_decoderHeapDesc = decoderHeapDesc; 1092bf215546Sopenharmony_ci } 1093bf215546Sopenharmony_ci 1094bf215546Sopenharmony_ci pD3D12Dec->m_decodeFormat = outputResourceDesc.Format; 1095bf215546Sopenharmony_ci 1096bf215546Sopenharmony_ci return true; 1097bf215546Sopenharmony_ci} 1098bf215546Sopenharmony_ci 1099bf215546Sopenharmony_civoid 1100bf215546Sopenharmony_cid3d12_video_decoder_refresh_dpb_active_references(struct d3d12_video_decoder *pD3D12Dec) 1101bf215546Sopenharmony_ci{ 1102bf215546Sopenharmony_ci switch (pD3D12Dec->m_d3d12DecProfileType) { 1103bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 1104bf215546Sopenharmony_ci { 1105bf215546Sopenharmony_ci d3d12_video_decoder_refresh_dpb_active_references_h264(pD3D12Dec); 1106bf215546Sopenharmony_ci } break; 1107bf215546Sopenharmony_ci 1108bf215546Sopenharmony_ci default: 1109bf215546Sopenharmony_ci { 1110bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 1111bf215546Sopenharmony_ci } break; 1112bf215546Sopenharmony_ci } 1113bf215546Sopenharmony_ci} 1114bf215546Sopenharmony_ci 1115bf215546Sopenharmony_civoid 1116bf215546Sopenharmony_cid3d12_video_decoder_get_frame_info( 1117bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec, uint32_t *pWidth, uint32_t *pHeight, uint16_t *pMaxDPB, bool &isInterlaced) 1118bf215546Sopenharmony_ci{ 1119bf215546Sopenharmony_ci *pWidth = 0; 1120bf215546Sopenharmony_ci *pHeight = 0; 1121bf215546Sopenharmony_ci *pMaxDPB = 0; 1122bf215546Sopenharmony_ci isInterlaced = false; 1123bf215546Sopenharmony_ci 1124bf215546Sopenharmony_ci switch (pD3D12Dec->m_d3d12DecProfileType) { 1125bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 1126bf215546Sopenharmony_ci { 1127bf215546Sopenharmony_ci d3d12_video_decoder_get_frame_info_h264(pD3D12Dec, pWidth, pHeight, pMaxDPB, isInterlaced); 1128bf215546Sopenharmony_ci } break; 1129bf215546Sopenharmony_ci 1130bf215546Sopenharmony_ci default: 1131bf215546Sopenharmony_ci { 1132bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 1133bf215546Sopenharmony_ci } break; 1134bf215546Sopenharmony_ci } 1135bf215546Sopenharmony_ci 1136bf215546Sopenharmony_ci if (pD3D12Dec->m_ConfigDecoderSpecificFlags & d3d12_video_decode_config_specific_flag_alignment_height) { 1137bf215546Sopenharmony_ci const uint32_t AlignmentMask = 31; 1138bf215546Sopenharmony_ci *pHeight = (*pHeight + AlignmentMask) & ~AlignmentMask; 1139bf215546Sopenharmony_ci } 1140bf215546Sopenharmony_ci} 1141bf215546Sopenharmony_ci 1142bf215546Sopenharmony_ci/// 1143bf215546Sopenharmony_ci/// Returns the number of bytes starting from [buf.data() + buffsetOffset] where the _targetCode_ is found 1144bf215546Sopenharmony_ci/// Returns -1 if start code not found 1145bf215546Sopenharmony_ci/// 1146bf215546Sopenharmony_ciint 1147bf215546Sopenharmony_cid3d12_video_decoder_get_next_startcode_offset(std::vector<uint8_t> &buf, 1148bf215546Sopenharmony_ci unsigned int bufferOffset, 1149bf215546Sopenharmony_ci unsigned int targetCode, 1150bf215546Sopenharmony_ci unsigned int targetCodeBitSize, 1151bf215546Sopenharmony_ci unsigned int numBitsToSearchIntoBuffer) 1152bf215546Sopenharmony_ci{ 1153bf215546Sopenharmony_ci struct vl_vlc vlc = { 0 }; 1154bf215546Sopenharmony_ci 1155bf215546Sopenharmony_ci // Shorten the buffer to be [buffetOffset, endOfBuf) 1156bf215546Sopenharmony_ci unsigned int bufSize = buf.size() - bufferOffset; 1157bf215546Sopenharmony_ci uint8_t *bufPtr = buf.data(); 1158bf215546Sopenharmony_ci bufPtr += bufferOffset; 1159bf215546Sopenharmony_ci 1160bf215546Sopenharmony_ci /* search the first numBitsToSearchIntoBuffer bytes for a startcode */ 1161bf215546Sopenharmony_ci vl_vlc_init(&vlc, 1, (const void *const *) &bufPtr, &bufSize); 1162bf215546Sopenharmony_ci for (uint i = 0; i < numBitsToSearchIntoBuffer && vl_vlc_bits_left(&vlc) >= targetCodeBitSize; ++i) { 1163bf215546Sopenharmony_ci if (vl_vlc_peekbits(&vlc, targetCodeBitSize) == targetCode) 1164bf215546Sopenharmony_ci return i; 1165bf215546Sopenharmony_ci vl_vlc_eatbits(&vlc, 8); // Stride is 8 bits = 1 byte 1166bf215546Sopenharmony_ci vl_vlc_fillbits(&vlc); 1167bf215546Sopenharmony_ci } 1168bf215546Sopenharmony_ci 1169bf215546Sopenharmony_ci return -1; 1170bf215546Sopenharmony_ci} 1171bf215546Sopenharmony_ci 1172bf215546Sopenharmony_civoid 1173bf215546Sopenharmony_cid3d12_video_decoder_store_converted_dxva_picparams_from_pipe_input( 1174bf215546Sopenharmony_ci struct d3d12_video_decoder *codec, // input argument, current decoder 1175bf215546Sopenharmony_ci struct pipe_picture_desc 1176bf215546Sopenharmony_ci *picture, // input argument, base structure of pipe_XXX_picture_desc where XXX is the codec name 1177bf215546Sopenharmony_ci struct d3d12_video_buffer *pD3D12VideoBuffer // input argument, target video buffer 1178bf215546Sopenharmony_ci) 1179bf215546Sopenharmony_ci{ 1180bf215546Sopenharmony_ci assert(picture); 1181bf215546Sopenharmony_ci assert(codec); 1182bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec; 1183bf215546Sopenharmony_ci 1184bf215546Sopenharmony_ci d3d12_video_decode_profile_type profileType = 1185bf215546Sopenharmony_ci d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(codec->base.profile); 1186bf215546Sopenharmony_ci switch (profileType) { 1187bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 1188bf215546Sopenharmony_ci { 1189bf215546Sopenharmony_ci size_t dxvaPicParamsBufferSize = sizeof(DXVA_PicParams_H264); 1190bf215546Sopenharmony_ci pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture; 1191bf215546Sopenharmony_ci ID3D12Resource *pPipeD3D12DstResource = d3d12_resource_resource(pD3D12VideoBuffer->texture); 1192bf215546Sopenharmony_ci D3D12_RESOURCE_DESC outputResourceDesc = GetDesc(pPipeD3D12DstResource); 1193bf215546Sopenharmony_ci DXVA_PicParams_H264 dxvaPicParamsH264 = 1194bf215546Sopenharmony_ci d3d12_video_decoder_dxva_picparams_from_pipe_picparams_h264(pD3D12Dec->m_fenceValue, 1195bf215546Sopenharmony_ci codec->base.profile, 1196bf215546Sopenharmony_ci outputResourceDesc.Width, 1197bf215546Sopenharmony_ci outputResourceDesc.Height, 1198bf215546Sopenharmony_ci pPicControlH264); 1199bf215546Sopenharmony_ci 1200bf215546Sopenharmony_ci d3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(codec, 1201bf215546Sopenharmony_ci &dxvaPicParamsH264, 1202bf215546Sopenharmony_ci dxvaPicParamsBufferSize); 1203bf215546Sopenharmony_ci 1204bf215546Sopenharmony_ci size_t dxvaQMatrixBufferSize = sizeof(DXVA_Qmatrix_H264); 1205bf215546Sopenharmony_ci DXVA_Qmatrix_H264 dxvaQmatrixH264 = {}; 1206bf215546Sopenharmony_ci d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_h264((pipe_h264_picture_desc *) picture, 1207bf215546Sopenharmony_ci dxvaQmatrixH264); 1208bf215546Sopenharmony_ci d3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(codec, &dxvaQmatrixH264, dxvaQMatrixBufferSize); 1209bf215546Sopenharmony_ci } break; 1210bf215546Sopenharmony_ci default: 1211bf215546Sopenharmony_ci { 1212bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 1213bf215546Sopenharmony_ci } break; 1214bf215546Sopenharmony_ci } 1215bf215546Sopenharmony_ci} 1216bf215546Sopenharmony_ci 1217bf215546Sopenharmony_civoid 1218bf215546Sopenharmony_cid3d12_video_decoder_prepare_dxva_slices_control( 1219bf215546Sopenharmony_ci struct d3d12_video_decoder *pD3D12Dec, // input argument, current decoder 1220bf215546Sopenharmony_ci struct pipe_picture_desc *picture 1221bf215546Sopenharmony_ci) 1222bf215546Sopenharmony_ci{ 1223bf215546Sopenharmony_ci d3d12_video_decode_profile_type profileType = 1224bf215546Sopenharmony_ci d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(pD3D12Dec->base.profile); 1225bf215546Sopenharmony_ci switch (profileType) { 1226bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 1227bf215546Sopenharmony_ci { 1228bf215546Sopenharmony_ci 1229bf215546Sopenharmony_ci std::vector<DXVA_Slice_H264_Short> pOutSliceControlBuffers; 1230bf215546Sopenharmony_ci struct pipe_h264_picture_desc* picture_h264 = (struct pipe_h264_picture_desc*) picture; 1231bf215546Sopenharmony_ci d3d12_video_decoder_prepare_dxva_slices_control_h264(pD3D12Dec, pOutSliceControlBuffers, picture_h264); 1232bf215546Sopenharmony_ci 1233bf215546Sopenharmony_ci assert(sizeof(pOutSliceControlBuffers.data()[0]) == sizeof(DXVA_Slice_H264_Short)); 1234bf215546Sopenharmony_ci uint64_t DXVAStructSize = pOutSliceControlBuffers.size() * sizeof((pOutSliceControlBuffers.data()[0])); 1235bf215546Sopenharmony_ci assert((DXVAStructSize % sizeof(DXVA_Slice_H264_Short)) == 0); 1236bf215546Sopenharmony_ci d3d12_video_decoder_store_dxva_slicecontrol_in_slicecontrol_buffer(pD3D12Dec, 1237bf215546Sopenharmony_ci pOutSliceControlBuffers.data(), 1238bf215546Sopenharmony_ci DXVAStructSize); 1239bf215546Sopenharmony_ci assert(pD3D12Dec->m_SliceControlBuffer.size() == DXVAStructSize); 1240bf215546Sopenharmony_ci } break; 1241bf215546Sopenharmony_ci default: 1242bf215546Sopenharmony_ci { 1243bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 1244bf215546Sopenharmony_ci } break; 1245bf215546Sopenharmony_ci } 1246bf215546Sopenharmony_ci} 1247bf215546Sopenharmony_ci 1248bf215546Sopenharmony_civoid 1249bf215546Sopenharmony_cid3d12_video_decoder_store_dxva_slicecontrol_in_slicecontrol_buffer(struct d3d12_video_decoder *pD3D12Dec, 1250bf215546Sopenharmony_ci void *pDXVAStruct, 1251bf215546Sopenharmony_ci uint64_t DXVAStructSize) 1252bf215546Sopenharmony_ci{ 1253bf215546Sopenharmony_ci if (pD3D12Dec->m_SliceControlBuffer.capacity() < DXVAStructSize) { 1254bf215546Sopenharmony_ci pD3D12Dec->m_SliceControlBuffer.reserve(DXVAStructSize); 1255bf215546Sopenharmony_ci } 1256bf215546Sopenharmony_ci 1257bf215546Sopenharmony_ci pD3D12Dec->m_SliceControlBuffer.resize(DXVAStructSize); 1258bf215546Sopenharmony_ci memcpy(pD3D12Dec->m_SliceControlBuffer.data(), pDXVAStruct, DXVAStructSize); 1259bf215546Sopenharmony_ci} 1260bf215546Sopenharmony_ci 1261bf215546Sopenharmony_civoid 1262bf215546Sopenharmony_cid3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(struct d3d12_video_decoder *pD3D12Dec, 1263bf215546Sopenharmony_ci void *pDXVAStruct, 1264bf215546Sopenharmony_ci uint64_t DXVAStructSize) 1265bf215546Sopenharmony_ci{ 1266bf215546Sopenharmony_ci if (pD3D12Dec->m_InverseQuantMatrixBuffer.capacity() < DXVAStructSize) { 1267bf215546Sopenharmony_ci pD3D12Dec->m_InverseQuantMatrixBuffer.reserve(DXVAStructSize); 1268bf215546Sopenharmony_ci } 1269bf215546Sopenharmony_ci 1270bf215546Sopenharmony_ci pD3D12Dec->m_InverseQuantMatrixBuffer.resize(DXVAStructSize); 1271bf215546Sopenharmony_ci memcpy(pD3D12Dec->m_InverseQuantMatrixBuffer.data(), pDXVAStruct, DXVAStructSize); 1272bf215546Sopenharmony_ci} 1273bf215546Sopenharmony_ci 1274bf215546Sopenharmony_civoid 1275bf215546Sopenharmony_cid3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(struct d3d12_video_decoder *pD3D12Dec, 1276bf215546Sopenharmony_ci void *pDXVAStruct, 1277bf215546Sopenharmony_ci uint64_t DXVAStructSize) 1278bf215546Sopenharmony_ci{ 1279bf215546Sopenharmony_ci if (pD3D12Dec->m_picParamsBuffer.capacity() < DXVAStructSize) { 1280bf215546Sopenharmony_ci pD3D12Dec->m_picParamsBuffer.reserve(DXVAStructSize); 1281bf215546Sopenharmony_ci } 1282bf215546Sopenharmony_ci 1283bf215546Sopenharmony_ci pD3D12Dec->m_picParamsBuffer.resize(DXVAStructSize); 1284bf215546Sopenharmony_ci memcpy(pD3D12Dec->m_picParamsBuffer.data(), pDXVAStruct, DXVAStructSize); 1285bf215546Sopenharmony_ci} 1286bf215546Sopenharmony_ci 1287bf215546Sopenharmony_cibool 1288bf215546Sopenharmony_cid3d12_video_decoder_supports_aot_dpb(D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT decodeSupport, 1289bf215546Sopenharmony_ci d3d12_video_decode_profile_type profileType) 1290bf215546Sopenharmony_ci{ 1291bf215546Sopenharmony_ci bool supportedProfile = false; 1292bf215546Sopenharmony_ci switch (profileType) { 1293bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 1294bf215546Sopenharmony_ci supportedProfile = true; 1295bf215546Sopenharmony_ci break; 1296bf215546Sopenharmony_ci default: 1297bf215546Sopenharmony_ci supportedProfile = false; 1298bf215546Sopenharmony_ci break; 1299bf215546Sopenharmony_ci } 1300bf215546Sopenharmony_ci 1301bf215546Sopenharmony_ci return (decodeSupport.DecodeTier >= D3D12_VIDEO_DECODE_TIER_2) && supportedProfile; 1302bf215546Sopenharmony_ci} 1303bf215546Sopenharmony_ci 1304bf215546Sopenharmony_cid3d12_video_decode_profile_type 1305bf215546Sopenharmony_cid3d12_video_decoder_convert_pipe_video_profile_to_profile_type(enum pipe_video_profile profile) 1306bf215546Sopenharmony_ci{ 1307bf215546Sopenharmony_ci switch (profile) { 1308bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE: 1309bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE: 1310bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: 1311bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED: 1312bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: 1313bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: 1314bf215546Sopenharmony_ci return d3d12_video_decode_profile_type_h264; 1315bf215546Sopenharmony_ci default: 1316bf215546Sopenharmony_ci { 1317bf215546Sopenharmony_ci unreachable("Unsupported pipe video profile"); 1318bf215546Sopenharmony_ci } break; 1319bf215546Sopenharmony_ci } 1320bf215546Sopenharmony_ci} 1321bf215546Sopenharmony_ci 1322bf215546Sopenharmony_ciGUID 1323bf215546Sopenharmony_cid3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(enum pipe_video_profile profile) 1324bf215546Sopenharmony_ci{ 1325bf215546Sopenharmony_ci switch (profile) { 1326bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE: 1327bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE: 1328bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: 1329bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED: 1330bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: 1331bf215546Sopenharmony_ci case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: 1332bf215546Sopenharmony_ci return D3D12_VIDEO_DECODE_PROFILE_H264; 1333bf215546Sopenharmony_ci default: 1334bf215546Sopenharmony_ci return {}; 1335bf215546Sopenharmony_ci } 1336bf215546Sopenharmony_ci} 1337bf215546Sopenharmony_ci 1338bf215546Sopenharmony_ciGUID 1339bf215546Sopenharmony_cid3d12_video_decoder_resolve_profile(d3d12_video_decode_profile_type profileType) 1340bf215546Sopenharmony_ci{ 1341bf215546Sopenharmony_ci switch (profileType) { 1342bf215546Sopenharmony_ci case d3d12_video_decode_profile_type_h264: 1343bf215546Sopenharmony_ci return D3D12_VIDEO_DECODE_PROFILE_H264; 1344bf215546Sopenharmony_ci break; 1345bf215546Sopenharmony_ci default: 1346bf215546Sopenharmony_ci { 1347bf215546Sopenharmony_ci unreachable("Unsupported d3d12_video_decode_profile_type"); 1348bf215546Sopenharmony_ci } break; 1349bf215546Sopenharmony_ci } 1350bf215546Sopenharmony_ci} 1351