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_common.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "d3d12_util.h" 27bf215546Sopenharmony_ci#include "d3d12_context.h" 28bf215546Sopenharmony_ci#include "d3d12_format.h" 29bf215546Sopenharmony_ci#include "d3d12_resource.h" 30bf215546Sopenharmony_ci#include "d3d12_screen.h" 31bf215546Sopenharmony_ci#include "d3d12_surface.h" 32bf215546Sopenharmony_ci#include "d3d12_video_enc.h" 33bf215546Sopenharmony_ci#include "d3d12_video_enc_h264.h" 34bf215546Sopenharmony_ci#include "d3d12_video_buffer.h" 35bf215546Sopenharmony_ci#include "d3d12_video_texture_array_dpb_manager.h" 36bf215546Sopenharmony_ci#include "d3d12_video_array_of_textures_dpb_manager.h" 37bf215546Sopenharmony_ci#include "d3d12_video_encoder_references_manager_h264.h" 38bf215546Sopenharmony_ci#include "d3d12_residency.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "vl/vl_video_buffer.h" 41bf215546Sopenharmony_ci#include "util/format/u_format.h" 42bf215546Sopenharmony_ci#include "util/u_inlines.h" 43bf215546Sopenharmony_ci#include "util/u_memory.h" 44bf215546Sopenharmony_ci#include "util/u_video.h" 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci#include <cmath> 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci/** 49bf215546Sopenharmony_ci * flush any outstanding command buffers to the hardware 50bf215546Sopenharmony_ci * should be called before a video_buffer is acessed by the gallium frontend again 51bf215546Sopenharmony_ci */ 52bf215546Sopenharmony_civoid 53bf215546Sopenharmony_cid3d12_video_encoder_flush(struct pipe_video_codec *codec) 54bf215546Sopenharmony_ci{ 55bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; 56bf215546Sopenharmony_ci assert(pD3D12Enc); 57bf215546Sopenharmony_ci assert(pD3D12Enc->m_spD3D12VideoDevice); 58bf215546Sopenharmony_ci assert(pD3D12Enc->m_spEncodeCommandQueue); 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci // Flush buffer_subdata batch and Wait the m_spEncodeCommandQueue for GPU upload completion 61bf215546Sopenharmony_ci // before recording EncodeFrame below. 62bf215546Sopenharmony_ci struct pipe_fence_handle *completion_fence = NULL; 63bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - Flushing pD3D12Enc->base.context and GPU sync between Video/Context queues before flushing Video Encode Queue.\n"); 64bf215546Sopenharmony_ci pD3D12Enc->base.context->flush(pD3D12Enc->base.context, &completion_fence, PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH); 65bf215546Sopenharmony_ci assert(completion_fence); 66bf215546Sopenharmony_ci struct d3d12_fence *casted_completion_fence = d3d12_fence(completion_fence); 67bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandQueue->Wait(casted_completion_fence->cmdqueue_fence, casted_completion_fence->value); 68bf215546Sopenharmony_ci pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base, &completion_fence, NULL); 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ci if (!pD3D12Enc->m_needsGPUFlush) { 71bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush started. Nothing to flush, all up to date.\n"); 72bf215546Sopenharmony_ci } else { 73bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush started. Will flush video queue work and CPU wait " 74bf215546Sopenharmony_ci "on fenceValue: %d\n", 75bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason(); 78bf215546Sopenharmony_ci if (hr != S_OK) { 79bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush" 80bf215546Sopenharmony_ci " - D3D12Device was removed BEFORE commandlist " 81bf215546Sopenharmony_ci "execution with HR %x.\n", 82bf215546Sopenharmony_ci hr); 83bf215546Sopenharmony_ci goto flush_fail; 84bf215546Sopenharmony_ci } 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci // Close and execute command list and wait for idle on CPU blocking 87bf215546Sopenharmony_ci // this method before resetting list and allocator for next submission. 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci if (pD3D12Enc->m_transitionsBeforeCloseCmdList.size() > 0) { 90bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(pD3D12Enc->m_transitionsBeforeCloseCmdList.size(), 91bf215546Sopenharmony_ci pD3D12Enc->m_transitionsBeforeCloseCmdList.data()); 92bf215546Sopenharmony_ci pD3D12Enc->m_transitionsBeforeCloseCmdList.clear(); 93bf215546Sopenharmony_ci } 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci hr = pD3D12Enc->m_spEncodeCommandList->Close(); 96bf215546Sopenharmony_ci if (FAILED(hr)) { 97bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - Can't close command list with HR %x\n", hr); 98bf215546Sopenharmony_ci goto flush_fail; 99bf215546Sopenharmony_ci } 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci ID3D12CommandList *ppCommandLists[1] = { pD3D12Enc->m_spEncodeCommandList.Get() }; 102bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandQueue->ExecuteCommandLists(1, ppCommandLists); 103bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandQueue->Signal(pD3D12Enc->m_spFence.Get(), pD3D12Enc->m_fenceValue); 104bf215546Sopenharmony_ci pD3D12Enc->m_spFence->SetEventOnCompletion(pD3D12Enc->m_fenceValue, nullptr); 105bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - ExecuteCommandLists finished on signal with " 106bf215546Sopenharmony_ci "fenceValue: %d\n", 107bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 108bf215546Sopenharmony_ci 109bf215546Sopenharmony_ci hr = pD3D12Enc->m_spCommandAllocator->Reset(); 110bf215546Sopenharmony_ci if (FAILED(hr)) { 111bf215546Sopenharmony_ci debug_printf( 112bf215546Sopenharmony_ci "[d3d12_video_encoder] d3d12_video_encoder_flush - resetting ID3D12CommandAllocator failed with HR %x\n", 113bf215546Sopenharmony_ci hr); 114bf215546Sopenharmony_ci goto flush_fail; 115bf215546Sopenharmony_ci } 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci hr = pD3D12Enc->m_spEncodeCommandList->Reset(pD3D12Enc->m_spCommandAllocator.Get()); 118bf215546Sopenharmony_ci if (FAILED(hr)) { 119bf215546Sopenharmony_ci debug_printf( 120bf215546Sopenharmony_ci "[d3d12_video_encoder] d3d12_video_encoder_flush - resetting ID3D12GraphicsCommandList failed with HR %x\n", 121bf215546Sopenharmony_ci hr); 122bf215546Sopenharmony_ci goto flush_fail; 123bf215546Sopenharmony_ci } 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci // Validate device was not removed 126bf215546Sopenharmony_ci hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason(); 127bf215546Sopenharmony_ci if (hr != S_OK) { 128bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush" 129bf215546Sopenharmony_ci " - D3D12Device was removed AFTER commandlist " 130bf215546Sopenharmony_ci "execution with HR %x, but wasn't before.\n", 131bf215546Sopenharmony_ci hr); 132bf215546Sopenharmony_ci goto flush_fail; 133bf215546Sopenharmony_ci } 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci debug_printf( 136bf215546Sopenharmony_ci "[d3d12_video_encoder] d3d12_video_encoder_flush - GPU signaled execution finalized for fenceValue: %d\n", 137bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue++; 140bf215546Sopenharmony_ci pD3D12Enc->m_needsGPUFlush = false; 141bf215546Sopenharmony_ci } 142bf215546Sopenharmony_ci return; 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ciflush_fail: 145bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush failed for fenceValue: %d\n", pD3D12Enc->m_fenceValue); 146bf215546Sopenharmony_ci assert(false); 147bf215546Sopenharmony_ci} 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci/** 150bf215546Sopenharmony_ci * Destroys a d3d12_video_encoder 151bf215546Sopenharmony_ci * Call destroy_XX for applicable XX nested member types before deallocating 152bf215546Sopenharmony_ci * Destroy methods should check != nullptr on their input target argument as this method can be called as part of 153bf215546Sopenharmony_ci * cleanup from failure on the creation method 154bf215546Sopenharmony_ci */ 155bf215546Sopenharmony_civoid 156bf215546Sopenharmony_cid3d12_video_encoder_destroy(struct pipe_video_codec *codec) 157bf215546Sopenharmony_ci{ 158bf215546Sopenharmony_ci if (codec == nullptr) { 159bf215546Sopenharmony_ci return; 160bf215546Sopenharmony_ci } 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci d3d12_video_encoder_flush(codec); // Flush pending work before destroying. 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci // Call d3d12_video_encoder dtor to make ComPtr and other member's destructors work 167bf215546Sopenharmony_ci delete pD3D12Enc; 168bf215546Sopenharmony_ci} 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_civoid 171bf215546Sopenharmony_cid3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder *pD3D12Enc, 172bf215546Sopenharmony_ci struct pipe_video_buffer * srcTexture, 173bf215546Sopenharmony_ci struct pipe_picture_desc * picture) 174bf215546Sopenharmony_ci{ 175bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams = 176bf215546Sopenharmony_ci d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 179bf215546Sopenharmony_ci bool bUsedAsReference = false; 180bf215546Sopenharmony_ci switch (codec) { 181bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 182bf215546Sopenharmony_ci { 183bf215546Sopenharmony_ci d3d12_video_encoder_update_current_frame_pic_params_info_h264(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference); 184bf215546Sopenharmony_ci } break; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci default: 187bf215546Sopenharmony_ci { 188bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 189bf215546Sopenharmony_ci } break; 190bf215546Sopenharmony_ci } 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci pD3D12Enc->m_upDPBManager->begin_frame(currentPicParams, bUsedAsReference); 193bf215546Sopenharmony_ci} 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_cibool 196bf215546Sopenharmony_cid3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D12Enc, 197bf215546Sopenharmony_ci struct pipe_video_buffer * srcTexture, 198bf215546Sopenharmony_ci struct pipe_picture_desc * picture) 199bf215546Sopenharmony_ci{ 200bf215546Sopenharmony_ci bool codecChanged = 201bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_codec) != 0); 202bf215546Sopenharmony_ci bool profileChanged = 203bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_profile) != 0); 204bf215546Sopenharmony_ci bool levelChanged = 205bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_level) != 0); 206bf215546Sopenharmony_ci bool codecConfigChanged = 207bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_codec_config) != 0); 208bf215546Sopenharmony_ci bool inputFormatChanged = 209bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_input_format) != 0); 210bf215546Sopenharmony_ci bool resolutionChanged = 211bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_resolution) != 0); 212bf215546Sopenharmony_ci bool rateControlChanged = 213bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_rate_control) != 0); 214bf215546Sopenharmony_ci bool slicesChanged = 215bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_slices) != 0); 216bf215546Sopenharmony_ci bool gopChanged = 217bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_gop) != 0); 218bf215546Sopenharmony_ci bool motionPrecisionLimitChanged = ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & 219bf215546Sopenharmony_ci d3d12_video_encoder_config_dirty_flag_motion_precision_limit) != 0); 220bf215546Sopenharmony_ci 221bf215546Sopenharmony_ci // Events that that trigger a re-creation of the reference picture manager 222bf215546Sopenharmony_ci // Stores codec agnostic textures so only input format, resolution and gop (num dpb references) affects this 223bf215546Sopenharmony_ci if (!pD3D12Enc->m_upDPBManager 224bf215546Sopenharmony_ci // || codecChanged 225bf215546Sopenharmony_ci // || profileChanged 226bf215546Sopenharmony_ci // || levelChanged 227bf215546Sopenharmony_ci // || codecConfigChanged 228bf215546Sopenharmony_ci || inputFormatChanged || 229bf215546Sopenharmony_ci resolutionChanged 230bf215546Sopenharmony_ci // || rateControlChanged 231bf215546Sopenharmony_ci // || slicesChanged 232bf215546Sopenharmony_ci || gopChanged 233bf215546Sopenharmony_ci // || motionPrecisionLimitChanged 234bf215546Sopenharmony_ci ) { 235bf215546Sopenharmony_ci if (!pD3D12Enc->m_upDPBManager) { 236bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating Reference " 237bf215546Sopenharmony_ci "Pictures Manager for the first time\n"); 238bf215546Sopenharmony_ci } else { 239bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating Reference Pictures Manager\n"); 240bf215546Sopenharmony_ci } 241bf215546Sopenharmony_ci 242bf215546Sopenharmony_ci D3D12_RESOURCE_FLAGS resourceAllocFlags = 243bf215546Sopenharmony_ci D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE; 244bf215546Sopenharmony_ci bool fArrayOfTextures = ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 245bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) == 0); 246bf215546Sopenharmony_ci uint32_t texturePoolSize = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc) + 247bf215546Sopenharmony_ci 1u; // adding an extra slot as we also need to count the current frame output recon 248bf215546Sopenharmony_ci // allocation along max reference frame allocations 249bf215546Sopenharmony_ci assert(texturePoolSize < UINT16_MAX); 250bf215546Sopenharmony_ci if (fArrayOfTextures) { 251bf215546Sopenharmony_ci pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_array_of_textures_dpb_manager>( 252bf215546Sopenharmony_ci static_cast<uint16_t>(texturePoolSize), 253bf215546Sopenharmony_ci pD3D12Enc->m_pD3D12Screen->dev, 254bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format, 255bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_currentResolution, 256bf215546Sopenharmony_ci (D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE), 257bf215546Sopenharmony_ci true, // setNullSubresourcesOnAllZero - D3D12 Video Encode expects nullptr pSubresources if AoT, 258bf215546Sopenharmony_ci pD3D12Enc->m_NodeMask, 259bf215546Sopenharmony_ci /*use underlying pool, we can't reuse upper level allocations, need D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY*/ 260bf215546Sopenharmony_ci true); 261bf215546Sopenharmony_ci } else { 262bf215546Sopenharmony_ci pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_texture_array_dpb_manager>( 263bf215546Sopenharmony_ci static_cast<uint16_t>(texturePoolSize), 264bf215546Sopenharmony_ci pD3D12Enc->m_pD3D12Screen->dev, 265bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format, 266bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_currentResolution, 267bf215546Sopenharmony_ci resourceAllocFlags, 268bf215546Sopenharmony_ci pD3D12Enc->m_NodeMask); 269bf215546Sopenharmony_ci } 270bf215546Sopenharmony_ci d3d12_video_encoder_create_reference_picture_manager(pD3D12Enc); 271bf215546Sopenharmony_ci } 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci bool reCreatedEncoder = false; 274bf215546Sopenharmony_ci // Events that that trigger a re-creation of the encoder 275bf215546Sopenharmony_ci if (!pD3D12Enc->m_spVideoEncoder || codecChanged || 276bf215546Sopenharmony_ci profileChanged 277bf215546Sopenharmony_ci // || levelChanged // Only affects encoder heap 278bf215546Sopenharmony_ci || codecConfigChanged || 279bf215546Sopenharmony_ci inputFormatChanged 280bf215546Sopenharmony_ci // || resolutionChanged // Only affects encoder heap 281bf215546Sopenharmony_ci // Only re-create if there is NO SUPPORT for reconfiguring rateControl on the fly 282bf215546Sopenharmony_ci || (rateControlChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 283bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) == 284bf215546Sopenharmony_ci 0 /*checking the flag is NOT set*/)) 285bf215546Sopenharmony_ci // Only re-create if there is NO SUPPORT for reconfiguring slices on the fly 286bf215546Sopenharmony_ci || (slicesChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 287bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) == 288bf215546Sopenharmony_ci 0 /*checking the flag is NOT set*/)) 289bf215546Sopenharmony_ci // Only re-create if there is NO SUPPORT for reconfiguring gop on the fly 290bf215546Sopenharmony_ci || (gopChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 291bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) == 292bf215546Sopenharmony_ci 0 /*checking the flag is NOT set*/)) || 293bf215546Sopenharmony_ci motionPrecisionLimitChanged) { 294bf215546Sopenharmony_ci if (!pD3D12Enc->m_spVideoEncoder) { 295bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating " 296bf215546Sopenharmony_ci "D3D12VideoEncoder for the first time\n"); 297bf215546Sopenharmony_ci } else { 298bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating D3D12VideoEncoder\n"); 299bf215546Sopenharmony_ci reCreatedEncoder = true; 300bf215546Sopenharmony_ci } 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_DESC encoderDesc = { pD3D12Enc->m_NodeMask, 303bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_FLAG_NONE, 304bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc, 305bf215546Sopenharmony_ci d3d12_video_encoder_get_current_profile_desc(pD3D12Enc), 306bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format, 307bf215546Sopenharmony_ci d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc), 308bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit }; 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci // Create encoder 311bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CreateVideoEncoder(&encoderDesc, 312bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spVideoEncoder.GetAddressOf())); 313bf215546Sopenharmony_ci if (FAILED(hr)) { 314bf215546Sopenharmony_ci debug_printf("CreateVideoEncoder failed with HR %x\n", hr); 315bf215546Sopenharmony_ci return false; 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci } 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci bool reCreatedEncoderHeap = false; 320bf215546Sopenharmony_ci // Events that that trigger a re-creation of the encoder heap 321bf215546Sopenharmony_ci if (!pD3D12Enc->m_spVideoEncoderHeap || codecChanged || profileChanged || 322bf215546Sopenharmony_ci levelChanged 323bf215546Sopenharmony_ci // || codecConfigChanged // Only affects encoder 324bf215546Sopenharmony_ci || inputFormatChanged // Might affect internal textures in the heap 325bf215546Sopenharmony_ci || resolutionChanged 326bf215546Sopenharmony_ci // Only re-create if there is NO SUPPORT for reconfiguring rateControl on the fly 327bf215546Sopenharmony_ci || (rateControlChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 328bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) == 329bf215546Sopenharmony_ci 0 /*checking the flag is NOT set*/)) 330bf215546Sopenharmony_ci // Only re-create if there is NO SUPPORT for reconfiguring slices on the fly 331bf215546Sopenharmony_ci || (slicesChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 332bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) == 333bf215546Sopenharmony_ci 0 /*checking the flag is NOT set*/)) 334bf215546Sopenharmony_ci // Only re-create if there is NO SUPPORT for reconfiguring gop on the fly 335bf215546Sopenharmony_ci || (gopChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 336bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) == 337bf215546Sopenharmony_ci 0 /*checking the flag is NOT set*/)) 338bf215546Sopenharmony_ci // || motionPrecisionLimitChanged // Only affects encoder 339bf215546Sopenharmony_ci ) { 340bf215546Sopenharmony_ci if (!pD3D12Enc->m_spVideoEncoderHeap) { 341bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating " 342bf215546Sopenharmony_ci "D3D12VideoEncoderHeap for the first time\n"); 343bf215546Sopenharmony_ci } else { 344bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating D3D12VideoEncoderHeap\n"); 345bf215546Sopenharmony_ci reCreatedEncoderHeap = true; 346bf215546Sopenharmony_ci } 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_HEAP_DESC heapDesc = { pD3D12Enc->m_NodeMask, 349bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE, 350bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc, 351bf215546Sopenharmony_ci d3d12_video_encoder_get_current_profile_desc(pD3D12Enc), 352bf215546Sopenharmony_ci d3d12_video_encoder_get_current_level_desc(pD3D12Enc), 353bf215546Sopenharmony_ci // resolution list count 354bf215546Sopenharmony_ci 1, 355bf215546Sopenharmony_ci // resolution list 356bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_currentResolution }; 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci // Create encoder heap 359bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CreateVideoEncoderHeap(&heapDesc, 360bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spVideoEncoderHeap.GetAddressOf())); 361bf215546Sopenharmony_ci if (FAILED(hr)) { 362bf215546Sopenharmony_ci debug_printf("CreateVideoEncoderHeap failed with HR %x\n", hr); 363bf215546Sopenharmony_ci return false; 364bf215546Sopenharmony_ci } 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci // If on-the-fly reconfiguration happened without object recreation, set 368bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_*_CHANGED reconfiguration flags in EncodeFrame 369bf215546Sopenharmony_ci if (rateControlChanged && 370bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 371bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) != 372bf215546Sopenharmony_ci 0 /*checking if the flag it's actually set*/) && 373bf215546Sopenharmony_ci (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) { 374bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RATE_CONTROL_CHANGE; 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci if (slicesChanged && 378bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 379bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) != 380bf215546Sopenharmony_ci 0 /*checking if the flag it's actually set*/) && 381bf215546Sopenharmony_ci (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) { 382bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_SUBREGION_LAYOUT_CHANGE; 383bf215546Sopenharmony_ci } 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci if (gopChanged && 386bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags & 387bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) != 388bf215546Sopenharmony_ci 0 /*checking if the flag it's actually set*/) && 389bf215546Sopenharmony_ci (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) { 390bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_GOP_SEQUENCE_CHANGE; 391bf215546Sopenharmony_ci } 392bf215546Sopenharmony_ci return true; 393bf215546Sopenharmony_ci} 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_civoid 396bf215546Sopenharmony_cid3d12_video_encoder_create_reference_picture_manager(struct d3d12_video_encoder *pD3D12Enc) 397bf215546Sopenharmony_ci{ 398bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 399bf215546Sopenharmony_ci switch (codec) { 400bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 401bf215546Sopenharmony_ci { 402bf215546Sopenharmony_ci bool gopHasPFrames = 403bf215546Sopenharmony_ci (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.PPicturePeriod > 0) && 404bf215546Sopenharmony_ci ((pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.GOPLength == 0) || 405bf215546Sopenharmony_ci (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.PPicturePeriod < 406bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.GOPLength)); 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_h264>( 409bf215546Sopenharmony_ci gopHasPFrames, 410bf215546Sopenharmony_ci *pD3D12Enc->m_upDPBStorageManager, 411bf215546Sopenharmony_ci // Max number of frames to be used as a reference, without counting the current recon picture 412bf215546Sopenharmony_ci d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc) 413bf215546Sopenharmony_ci ); 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>(); 416bf215546Sopenharmony_ci } break; 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_ci default: 419bf215546Sopenharmony_ci { 420bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 421bf215546Sopenharmony_ci } break; 422bf215546Sopenharmony_ci } 423bf215546Sopenharmony_ci} 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA 426bf215546Sopenharmony_cid3d12_video_encoder_get_current_slice_param_settings(struct d3d12_video_encoder *pD3D12Enc) 427bf215546Sopenharmony_ci{ 428bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 429bf215546Sopenharmony_ci switch (codec) { 430bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 431bf215546Sopenharmony_ci { 432bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregionData = {}; 433bf215546Sopenharmony_ci if (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode != 434bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME) { 435bf215546Sopenharmony_ci subregionData.pSlicesPartition_H264 = 436bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264; 437bf215546Sopenharmony_ci subregionData.DataSize = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES); 438bf215546Sopenharmony_ci } 439bf215546Sopenharmony_ci return subregionData; 440bf215546Sopenharmony_ci } break; 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci default: 443bf215546Sopenharmony_ci { 444bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 445bf215546Sopenharmony_ci } break; 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci} 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA 450bf215546Sopenharmony_cid3d12_video_encoder_get_current_picture_param_settings(struct d3d12_video_encoder *pD3D12Enc) 451bf215546Sopenharmony_ci{ 452bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 453bf215546Sopenharmony_ci switch (codec) { 454bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 455bf215546Sopenharmony_ci { 456bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {}; 457bf215546Sopenharmony_ci curPicParamsData.pH264PicData = &pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData; 458bf215546Sopenharmony_ci curPicParamsData.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData); 459bf215546Sopenharmony_ci return curPicParamsData; 460bf215546Sopenharmony_ci } break; 461bf215546Sopenharmony_ci 462bf215546Sopenharmony_ci default: 463bf215546Sopenharmony_ci { 464bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 465bf215546Sopenharmony_ci } break; 466bf215546Sopenharmony_ci } 467bf215546Sopenharmony_ci} 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_RATE_CONTROL 470bf215546Sopenharmony_cid3d12_video_encoder_get_current_rate_control_settings(struct d3d12_video_encoder *pD3D12Enc) 471bf215546Sopenharmony_ci{ 472bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_RATE_CONTROL curRateControlDesc = {}; 473bf215546Sopenharmony_ci curRateControlDesc.Mode = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode; 474bf215546Sopenharmony_ci curRateControlDesc.Flags = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags; 475bf215546Sopenharmony_ci curRateControlDesc.TargetFrameRate = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate; 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci switch (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode) { 478bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_ABSOLUTE_QP_MAP: 479bf215546Sopenharmony_ci { 480bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.pConfiguration_CQP = nullptr; 481bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.DataSize = 0; 482bf215546Sopenharmony_ci } break; 483bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP: 484bf215546Sopenharmony_ci { 485bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.pConfiguration_CQP = 486bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP; 487bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.DataSize = 488bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP); 489bf215546Sopenharmony_ci } break; 490bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR: 491bf215546Sopenharmony_ci { 492bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.pConfiguration_CBR = 493bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR; 494bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.DataSize = 495bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR); 496bf215546Sopenharmony_ci } break; 497bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR: 498bf215546Sopenharmony_ci { 499bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.pConfiguration_VBR = 500bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR; 501bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.DataSize = 502bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR); 503bf215546Sopenharmony_ci } break; 504bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR: 505bf215546Sopenharmony_ci { 506bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.pConfiguration_QVBR = 507bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR; 508bf215546Sopenharmony_ci curRateControlDesc.ConfigParams.DataSize = 509bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR); 510bf215546Sopenharmony_ci } break; 511bf215546Sopenharmony_ci default: 512bf215546Sopenharmony_ci { 513bf215546Sopenharmony_ci unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE"); 514bf215546Sopenharmony_ci } break; 515bf215546Sopenharmony_ci } 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_ci return curRateControlDesc; 518bf215546Sopenharmony_ci} 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_LEVEL_SETTING 521bf215546Sopenharmony_cid3d12_video_encoder_get_current_level_desc(struct d3d12_video_encoder *pD3D12Enc) 522bf215546Sopenharmony_ci{ 523bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 524bf215546Sopenharmony_ci switch (codec) { 525bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 526bf215546Sopenharmony_ci { 527bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_LEVEL_SETTING curLevelDesc = {}; 528bf215546Sopenharmony_ci curLevelDesc.pH264LevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting; 529bf215546Sopenharmony_ci curLevelDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting); 530bf215546Sopenharmony_ci return curLevelDesc; 531bf215546Sopenharmony_ci } break; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci default: 534bf215546Sopenharmony_ci { 535bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 536bf215546Sopenharmony_ci } break; 537bf215546Sopenharmony_ci } 538bf215546Sopenharmony_ci} 539bf215546Sopenharmony_ci 540bf215546Sopenharmony_ciuint32_t 541bf215546Sopenharmony_cid3d12_video_encoder_build_codec_headers(struct d3d12_video_encoder *pD3D12Enc) 542bf215546Sopenharmony_ci{ 543bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 544bf215546Sopenharmony_ci switch (codec) { 545bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 546bf215546Sopenharmony_ci { 547bf215546Sopenharmony_ci return d3d12_video_encoder_build_codec_headers_h264(pD3D12Enc); 548bf215546Sopenharmony_ci 549bf215546Sopenharmony_ci } break; 550bf215546Sopenharmony_ci 551bf215546Sopenharmony_ci default: 552bf215546Sopenharmony_ci { 553bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 554bf215546Sopenharmony_ci } break; 555bf215546Sopenharmony_ci } 556bf215546Sopenharmony_ci return 0u; 557bf215546Sopenharmony_ci} 558bf215546Sopenharmony_ci 559bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE 560bf215546Sopenharmony_cid3d12_video_encoder_get_current_gop_desc(struct d3d12_video_encoder *pD3D12Enc) 561bf215546Sopenharmony_ci{ 562bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 563bf215546Sopenharmony_ci switch (codec) { 564bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 565bf215546Sopenharmony_ci { 566bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE curGOPDesc = {}; 567bf215546Sopenharmony_ci curGOPDesc.pH264GroupOfPictures = 568bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures; 569bf215546Sopenharmony_ci curGOPDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures); 570bf215546Sopenharmony_ci return curGOPDesc; 571bf215546Sopenharmony_ci } break; 572bf215546Sopenharmony_ci 573bf215546Sopenharmony_ci default: 574bf215546Sopenharmony_ci { 575bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 576bf215546Sopenharmony_ci } break; 577bf215546Sopenharmony_ci } 578bf215546Sopenharmony_ci} 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_CODEC_CONFIGURATION 581bf215546Sopenharmony_cid3d12_video_encoder_get_current_codec_config_desc(struct d3d12_video_encoder *pD3D12Enc) 582bf215546Sopenharmony_ci{ 583bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 584bf215546Sopenharmony_ci switch (codec) { 585bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 586bf215546Sopenharmony_ci { 587bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codecConfigDesc = {}; 588bf215546Sopenharmony_ci codecConfigDesc.pH264Config = &pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config; 589bf215546Sopenharmony_ci codecConfigDesc.DataSize = 590bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config); 591bf215546Sopenharmony_ci return codecConfigDesc; 592bf215546Sopenharmony_ci } break; 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci default: 595bf215546Sopenharmony_ci { 596bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 597bf215546Sopenharmony_ci } break; 598bf215546Sopenharmony_ci } 599bf215546Sopenharmony_ci} 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_CODEC 602bf215546Sopenharmony_cid3d12_video_encoder_get_current_codec(struct d3d12_video_encoder *pD3D12Enc) 603bf215546Sopenharmony_ci{ 604bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 605bf215546Sopenharmony_ci switch (codec) { 606bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 607bf215546Sopenharmony_ci { 608bf215546Sopenharmony_ci return D3D12_VIDEO_ENCODER_CODEC_H264; 609bf215546Sopenharmony_ci } break; 610bf215546Sopenharmony_ci default: 611bf215546Sopenharmony_ci { 612bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 613bf215546Sopenharmony_ci } break; 614bf215546Sopenharmony_ci } 615bf215546Sopenharmony_ci} 616bf215546Sopenharmony_ci 617bf215546Sopenharmony_ci/// 618bf215546Sopenharmony_ci/// Call d3d12_video_encoder_query_d3d12_driver_caps and see if any optional feature requested 619bf215546Sopenharmony_ci/// is not supported, disable it, query again until finding a negotiated cap/feature set 620bf215546Sopenharmony_ci/// Note that with fallbacks, the upper layer will not get exactly the encoding seetings they requested 621bf215546Sopenharmony_ci/// but for very particular settings it's better to continue with warnings than failing the whole encoding process 622bf215546Sopenharmony_ci/// 623bf215546Sopenharmony_cibool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT &capEncoderSupportData) { 624bf215546Sopenharmony_ci 625bf215546Sopenharmony_ci /// 626bf215546Sopenharmony_ci /// Check for general support 627bf215546Sopenharmony_ci /// Check for validation errors (some drivers return general support but also validation errors anyways, work around for those unexpected cases) 628bf215546Sopenharmony_ci /// 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci bool configSupported = d3d12_video_encoder_query_d3d12_driver_caps(pD3D12Enc, /*inout*/ capEncoderSupportData) 631bf215546Sopenharmony_ci && (((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0) 632bf215546Sopenharmony_ci && (capEncoderSupportData.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE)); 633bf215546Sopenharmony_ci 634bf215546Sopenharmony_ci /// 635bf215546Sopenharmony_ci /// If rate control config is not supported, try falling back and check for caps again 636bf215546Sopenharmony_ci /// 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & (D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_CONFIGURATION_NOT_SUPPORTED | D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_MODE_NOT_SUPPORTED)) != 0) { 639bf215546Sopenharmony_ci 640bf215546Sopenharmony_ci if (D3D12_VIDEO_ENC_FALLBACK_RATE_CONTROL_CONFIG){ // Check if fallback mode is enabled, or we should just fail without support 641bf215546Sopenharmony_ci 642bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] WARNING: Requested rate control is not supported, trying fallback to unsetting optional features\n"); 643bf215546Sopenharmony_ci 644bf215546Sopenharmony_ci bool isRequestingVBVSizesSupported = ((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_VBV_SIZE_CONFIG_AVAILABLE) != 0); 645bf215546Sopenharmony_ci bool isClientRequestingVBVSizes = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES) != 0); 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci if(isClientRequestingVBVSizes && !isRequestingVBVSizesSupported) { 648bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES with VBVCapacity (bits): %" PRIu64 " and InitialVBVFullness (bits) %" PRIu64 " is not supported, will continue encoding unsetting this feature as fallback.\n", 649bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity, 650bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness); 651bf215546Sopenharmony_ci 652bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES; 653bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity = 0; 654bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness = 0; 655bf215546Sopenharmony_ci } 656bf215546Sopenharmony_ci 657bf215546Sopenharmony_ci bool isRequestingPeakFrameSizeSupported = ((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0); 658bf215546Sopenharmony_ci bool isClientRequestingPeakFrameSize = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE) != 0); 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_ci if(isClientRequestingPeakFrameSize && !isRequestingPeakFrameSizeSupported) { 661bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE with MaxFrameBitSize %" PRIu64 " but the feature is not supported, will continue encoding unsetting this feature as fallback.\n", 662bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize); 663bf215546Sopenharmony_ci 664bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE; 665bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize = 0; 666bf215546Sopenharmony_ci } 667bf215546Sopenharmony_ci 668bf215546Sopenharmony_ci /// 669bf215546Sopenharmony_ci /// Try fallback configuration 670bf215546Sopenharmony_ci /// 671bf215546Sopenharmony_ci configSupported = d3d12_video_encoder_query_d3d12_driver_caps(pD3D12Enc, /*inout*/ capEncoderSupportData) 672bf215546Sopenharmony_ci && (((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0) 673bf215546Sopenharmony_ci && (capEncoderSupportData.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE)); 674bf215546Sopenharmony_ci 675bf215546Sopenharmony_ci } else { 676bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] WARNING: Requested rate control is not supported. To continue with a fallback, must enable the OS environment variable D3D12_VIDEO_ENC_FALLBACK_RATE_CONTROL_CONFIG\n"); 677bf215546Sopenharmony_ci } 678bf215546Sopenharmony_ci } 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_ci if(!configSupported) { 681bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Cap negotiation failed, see more details below:\n"); 682bf215546Sopenharmony_ci 683bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_NOT_SUPPORTED) != 0) { 684bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested codec is not supported\n"); 685bf215546Sopenharmony_ci } 686bf215546Sopenharmony_ci 687bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & 688bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RESOLUTION_NOT_SUPPORTED_IN_LIST) != 0) { 689bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested resolution is not supported\n"); 690bf215546Sopenharmony_ci } 691bf215546Sopenharmony_ci 692bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & 693bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_CONFIGURATION_NOT_SUPPORTED) != 0) { 694bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested bitrate or rc config is not supported\n"); 695bf215546Sopenharmony_ci } 696bf215546Sopenharmony_ci 697bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & 698bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_CONFIGURATION_NOT_SUPPORTED) != 0) { 699bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested codec config is not supported\n"); 700bf215546Sopenharmony_ci } 701bf215546Sopenharmony_ci 702bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & 703bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_MODE_NOT_SUPPORTED) != 0) { 704bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested rate control mode is not supported\n"); 705bf215546Sopenharmony_ci } 706bf215546Sopenharmony_ci 707bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & 708bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INTRA_REFRESH_MODE_NOT_SUPPORTED) != 0) { 709bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested intra refresh config is not supported\n"); 710bf215546Sopenharmony_ci } 711bf215546Sopenharmony_ci 712bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & 713bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED) != 0) { 714bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested subregion layout mode is not supported\n"); 715bf215546Sopenharmony_ci } 716bf215546Sopenharmony_ci 717bf215546Sopenharmony_ci if ((capEncoderSupportData.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INPUT_FORMAT_NOT_SUPPORTED) != 718bf215546Sopenharmony_ci 0) { 719bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Requested input dxgi format is not supported\n"); 720bf215546Sopenharmony_ci } 721bf215546Sopenharmony_ci } 722bf215546Sopenharmony_ci 723bf215546Sopenharmony_ci return configSupported; 724bf215546Sopenharmony_ci} 725bf215546Sopenharmony_ci 726bf215546Sopenharmony_cibool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT &capEncoderSupportData) { 727bf215546Sopenharmony_ci capEncoderSupportData.NodeIndex = pD3D12Enc->m_NodeIndex; 728bf215546Sopenharmony_ci capEncoderSupportData.Codec = d3d12_video_encoder_get_current_codec(pD3D12Enc); 729bf215546Sopenharmony_ci capEncoderSupportData.InputFormat = pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format; 730bf215546Sopenharmony_ci capEncoderSupportData.RateControl = d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc); 731bf215546Sopenharmony_ci capEncoderSupportData.IntraRefresh = pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.Mode; 732bf215546Sopenharmony_ci capEncoderSupportData.SubregionFrameEncoding = pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode; 733bf215546Sopenharmony_ci capEncoderSupportData.ResolutionsListCount = 1; 734bf215546Sopenharmony_ci capEncoderSupportData.pResolutionList = &pD3D12Enc->m_currentEncodeConfig.m_currentResolution; 735bf215546Sopenharmony_ci capEncoderSupportData.CodecGopSequence = d3d12_video_encoder_get_current_gop_desc(pD3D12Enc); 736bf215546Sopenharmony_ci capEncoderSupportData.MaxReferenceFramesInDPB = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc); 737bf215546Sopenharmony_ci capEncoderSupportData.CodecConfiguration = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc); 738bf215546Sopenharmony_ci 739bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 740bf215546Sopenharmony_ci switch (codec) { 741bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 742bf215546Sopenharmony_ci { 743bf215546Sopenharmony_ci capEncoderSupportData.SuggestedProfile.pH264Profile = 744bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile; 745bf215546Sopenharmony_ci capEncoderSupportData.SuggestedProfile.DataSize = 746bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile); 747bf215546Sopenharmony_ci capEncoderSupportData.SuggestedLevel.pH264LevelSetting = 748bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting; 749bf215546Sopenharmony_ci capEncoderSupportData.SuggestedLevel.DataSize = 750bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting); 751bf215546Sopenharmony_ci } break; 752bf215546Sopenharmony_ci 753bf215546Sopenharmony_ci default: 754bf215546Sopenharmony_ci { 755bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 756bf215546Sopenharmony_ci } break; 757bf215546Sopenharmony_ci } 758bf215546Sopenharmony_ci 759bf215546Sopenharmony_ci // prepare inout storage for the resolution dependent result. 760bf215546Sopenharmony_ci capEncoderSupportData.pResolutionDependentSupport = 761bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps; 762bf215546Sopenharmony_ci 763bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT, 764bf215546Sopenharmony_ci &capEncoderSupportData, 765bf215546Sopenharmony_ci sizeof(capEncoderSupportData)); 766bf215546Sopenharmony_ci if (FAILED(hr)) { 767bf215546Sopenharmony_ci debug_printf("CheckFeatureSupport failed with HR %x\n", hr); 768bf215546Sopenharmony_ci return false; 769bf215546Sopenharmony_ci } 770bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags = capEncoderSupportData.SupportFlags; 771bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ValidationFlags = capEncoderSupportData.ValidationFlags; 772bf215546Sopenharmony_ci return true; 773bf215546Sopenharmony_ci} 774bf215546Sopenharmony_ci 775bf215546Sopenharmony_cibool d3d12_video_encoder_check_subregion_mode_support(struct d3d12_video_encoder *pD3D12Enc, 776bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode 777bf215546Sopenharmony_ci ) 778bf215546Sopenharmony_ci{ 779bf215546Sopenharmony_ci D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = { }; 780bf215546Sopenharmony_ci capDataSubregionLayout.NodeIndex = pD3D12Enc->m_NodeIndex; 781bf215546Sopenharmony_ci capDataSubregionLayout.Codec = d3d12_video_encoder_get_current_codec(pD3D12Enc); 782bf215546Sopenharmony_ci capDataSubregionLayout.Profile = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc); 783bf215546Sopenharmony_ci capDataSubregionLayout.Level = d3d12_video_encoder_get_current_level_desc(pD3D12Enc); 784bf215546Sopenharmony_ci capDataSubregionLayout.SubregionMode = requestedSlicesMode; 785bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE, &capDataSubregionLayout, sizeof(capDataSubregionLayout)); 786bf215546Sopenharmony_ci if (FAILED(hr)) { 787bf215546Sopenharmony_ci debug_printf("CheckFeatureSupport failed with HR %x\n", hr); 788bf215546Sopenharmony_ci return false; 789bf215546Sopenharmony_ci } 790bf215546Sopenharmony_ci return capDataSubregionLayout.IsSupported; 791bf215546Sopenharmony_ci} 792bf215546Sopenharmony_ci 793bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_PROFILE_DESC 794bf215546Sopenharmony_cid3d12_video_encoder_get_current_profile_desc(struct d3d12_video_encoder *pD3D12Enc) 795bf215546Sopenharmony_ci{ 796bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 797bf215546Sopenharmony_ci switch (codec) { 798bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 799bf215546Sopenharmony_ci { 800bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PROFILE_DESC curProfDesc = {}; 801bf215546Sopenharmony_ci curProfDesc.pH264Profile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile; 802bf215546Sopenharmony_ci curProfDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile); 803bf215546Sopenharmony_ci return curProfDesc; 804bf215546Sopenharmony_ci } break; 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_ci default: 807bf215546Sopenharmony_ci { 808bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 809bf215546Sopenharmony_ci } break; 810bf215546Sopenharmony_ci } 811bf215546Sopenharmony_ci} 812bf215546Sopenharmony_ci 813bf215546Sopenharmony_ciuint32_t 814bf215546Sopenharmony_cid3d12_video_encoder_get_current_max_dpb_capacity(struct d3d12_video_encoder *pD3D12Enc) 815bf215546Sopenharmony_ci{ 816bf215546Sopenharmony_ci return pD3D12Enc->base.max_references; 817bf215546Sopenharmony_ci} 818bf215546Sopenharmony_ci 819bf215546Sopenharmony_cibool 820bf215546Sopenharmony_cid3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encoder *pD3D12Enc, 821bf215546Sopenharmony_ci struct pipe_video_buffer * srcTexture, 822bf215546Sopenharmony_ci struct pipe_picture_desc * picture) 823bf215546Sopenharmony_ci{ 824bf215546Sopenharmony_ci enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); 825bf215546Sopenharmony_ci switch (codec) { 826bf215546Sopenharmony_ci case PIPE_VIDEO_FORMAT_MPEG4_AVC: 827bf215546Sopenharmony_ci { 828bf215546Sopenharmony_ci return d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTexture, picture); 829bf215546Sopenharmony_ci } break; 830bf215546Sopenharmony_ci 831bf215546Sopenharmony_ci default: 832bf215546Sopenharmony_ci { 833bf215546Sopenharmony_ci unreachable("Unsupported pipe_video_format"); 834bf215546Sopenharmony_ci } break; 835bf215546Sopenharmony_ci } 836bf215546Sopenharmony_ci} 837bf215546Sopenharmony_ci 838bf215546Sopenharmony_cibool 839bf215546Sopenharmony_cid3d12_video_encoder_create_command_objects(struct d3d12_video_encoder *pD3D12Enc) 840bf215546Sopenharmony_ci{ 841bf215546Sopenharmony_ci assert(pD3D12Enc->m_spD3D12VideoDevice); 842bf215546Sopenharmony_ci 843bf215546Sopenharmony_ci D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE }; 844bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommandQueue( 845bf215546Sopenharmony_ci &commandQueueDesc, 846bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spEncodeCommandQueue.GetAddressOf())); 847bf215546Sopenharmony_ci if (FAILED(hr)) { 848bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateCommandQueue " 849bf215546Sopenharmony_ci "failed with HR %x\n", 850bf215546Sopenharmony_ci hr); 851bf215546Sopenharmony_ci return false; 852bf215546Sopenharmony_ci } 853bf215546Sopenharmony_ci 854bf215546Sopenharmony_ci hr = pD3D12Enc->m_pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pD3D12Enc->m_spFence)); 855bf215546Sopenharmony_ci if (FAILED(hr)) { 856bf215546Sopenharmony_ci debug_printf( 857bf215546Sopenharmony_ci "[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateFence failed with HR %x\n", 858bf215546Sopenharmony_ci hr); 859bf215546Sopenharmony_ci return false; 860bf215546Sopenharmony_ci } 861bf215546Sopenharmony_ci 862bf215546Sopenharmony_ci hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommandAllocator( 863bf215546Sopenharmony_ci D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE, 864bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spCommandAllocator.GetAddressOf())); 865bf215546Sopenharmony_ci if (FAILED(hr)) { 866bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to " 867bf215546Sopenharmony_ci "CreateCommandAllocator failed with HR %x\n", 868bf215546Sopenharmony_ci hr); 869bf215546Sopenharmony_ci return false; 870bf215546Sopenharmony_ci } 871bf215546Sopenharmony_ci 872bf215546Sopenharmony_ci hr = 873bf215546Sopenharmony_ci pD3D12Enc->m_pD3D12Screen->dev->CreateCommandList(0, 874bf215546Sopenharmony_ci D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE, 875bf215546Sopenharmony_ci pD3D12Enc->m_spCommandAllocator.Get(), 876bf215546Sopenharmony_ci nullptr, 877bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spEncodeCommandList.GetAddressOf())); 878bf215546Sopenharmony_ci 879bf215546Sopenharmony_ci if (FAILED(hr)) { 880bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateCommandList " 881bf215546Sopenharmony_ci "failed with HR %x\n", 882bf215546Sopenharmony_ci hr); 883bf215546Sopenharmony_ci return false; 884bf215546Sopenharmony_ci } 885bf215546Sopenharmony_ci 886bf215546Sopenharmony_ci return true; 887bf215546Sopenharmony_ci} 888bf215546Sopenharmony_ci 889bf215546Sopenharmony_cistruct pipe_video_codec * 890bf215546Sopenharmony_cid3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pipe_video_codec *codec) 891bf215546Sopenharmony_ci{ 892bf215546Sopenharmony_ci /// 893bf215546Sopenharmony_ci /// Initialize d3d12_video_encoder 894bf215546Sopenharmony_ci /// 895bf215546Sopenharmony_ci 896bf215546Sopenharmony_ci // Not using new doesn't call ctor and the initializations in the class declaration are lost 897bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = new d3d12_video_encoder; 898bf215546Sopenharmony_ci 899bf215546Sopenharmony_ci pD3D12Enc->base = *codec; 900bf215546Sopenharmony_ci pD3D12Enc->m_screen = context->screen; 901bf215546Sopenharmony_ci pD3D12Enc->base.context = context; 902bf215546Sopenharmony_ci pD3D12Enc->base.width = codec->width; 903bf215546Sopenharmony_ci pD3D12Enc->base.height = codec->height; 904bf215546Sopenharmony_ci pD3D12Enc->base.max_references = codec->max_references; 905bf215546Sopenharmony_ci // Only fill methods that are supported by the d3d12 encoder, leaving null the rest (ie. encode_* / encode_macroblock) 906bf215546Sopenharmony_ci pD3D12Enc->base.destroy = d3d12_video_encoder_destroy; 907bf215546Sopenharmony_ci pD3D12Enc->base.begin_frame = d3d12_video_encoder_begin_frame; 908bf215546Sopenharmony_ci pD3D12Enc->base.encode_bitstream = d3d12_video_encoder_encode_bitstream; 909bf215546Sopenharmony_ci pD3D12Enc->base.end_frame = d3d12_video_encoder_end_frame; 910bf215546Sopenharmony_ci pD3D12Enc->base.flush = d3d12_video_encoder_flush; 911bf215546Sopenharmony_ci pD3D12Enc->base.get_feedback = d3d12_video_encoder_get_feedback; 912bf215546Sopenharmony_ci 913bf215546Sopenharmony_ci struct d3d12_context *pD3D12Ctx = (struct d3d12_context *) context; 914bf215546Sopenharmony_ci pD3D12Enc->m_pD3D12Screen = d3d12_screen(pD3D12Ctx->base.screen); 915bf215546Sopenharmony_ci 916bf215546Sopenharmony_ci if (FAILED(pD3D12Enc->m_pD3D12Screen->dev->QueryInterface( 917bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spD3D12VideoDevice.GetAddressOf())))) { 918bf215546Sopenharmony_ci debug_printf( 919bf215546Sopenharmony_ci "[d3d12_video_encoder] d3d12_video_encoder_create_encoder - D3D12 Device has no Video encode support\n"); 920bf215546Sopenharmony_ci goto failed; 921bf215546Sopenharmony_ci } 922bf215546Sopenharmony_ci 923bf215546Sopenharmony_ci if (!d3d12_video_encoder_create_command_objects(pD3D12Enc)) { 924bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_encoder - Failure on " 925bf215546Sopenharmony_ci "d3d12_video_encoder_create_command_objects\n"); 926bf215546Sopenharmony_ci goto failed; 927bf215546Sopenharmony_ci } 928bf215546Sopenharmony_ci 929bf215546Sopenharmony_ci return &pD3D12Enc->base; 930bf215546Sopenharmony_ci 931bf215546Sopenharmony_cifailed: 932bf215546Sopenharmony_ci if (pD3D12Enc != nullptr) { 933bf215546Sopenharmony_ci d3d12_video_encoder_destroy((struct pipe_video_codec *) pD3D12Enc); 934bf215546Sopenharmony_ci } 935bf215546Sopenharmony_ci 936bf215546Sopenharmony_ci return nullptr; 937bf215546Sopenharmony_ci} 938bf215546Sopenharmony_ci 939bf215546Sopenharmony_cibool 940bf215546Sopenharmony_cid3d12_video_encoder_prepare_output_buffers(struct d3d12_video_encoder *pD3D12Enc, 941bf215546Sopenharmony_ci struct pipe_video_buffer * srcTexture, 942bf215546Sopenharmony_ci struct pipe_picture_desc * picture) 943bf215546Sopenharmony_ci{ 944bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.NodeIndex = pD3D12Enc->m_NodeIndex; 945bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.Codec = 946bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc; 947bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.Profile = 948bf215546Sopenharmony_ci d3d12_video_encoder_get_current_profile_desc(pD3D12Enc); 949bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.InputFormat = 950bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format; 951bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.PictureTargetResolution = 952bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_currentResolution; 953bf215546Sopenharmony_ci 954bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport( 955bf215546Sopenharmony_ci D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS, 956bf215546Sopenharmony_ci &pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps, 957bf215546Sopenharmony_ci sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps)); 958bf215546Sopenharmony_ci 959bf215546Sopenharmony_ci if (FAILED(hr)) { 960bf215546Sopenharmony_ci debug_printf("CheckFeatureSupport failed with HR %x\n", hr); 961bf215546Sopenharmony_ci return false; 962bf215546Sopenharmony_ci } 963bf215546Sopenharmony_ci 964bf215546Sopenharmony_ci if (!pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.IsSupported) { 965bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS arguments are not supported.\n"); 966bf215546Sopenharmony_ci return false; 967bf215546Sopenharmony_ci } 968bf215546Sopenharmony_ci 969bf215546Sopenharmony_ci d3d12_video_encoder_calculate_metadata_resolved_buffer_size( 970bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput, 971bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize); 972bf215546Sopenharmony_ci 973bf215546Sopenharmony_ci D3D12_HEAP_PROPERTIES Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); 974bf215546Sopenharmony_ci if ((pD3D12Enc->m_spResolvedMetadataBuffer == nullptr) || 975bf215546Sopenharmony_ci (GetDesc(pD3D12Enc->m_spResolvedMetadataBuffer.Get()).Width < 976bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize)) { 977bf215546Sopenharmony_ci CD3DX12_RESOURCE_DESC resolvedMetadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer( 978bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize); 979bf215546Sopenharmony_ci 980bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource( 981bf215546Sopenharmony_ci &Properties, 982bf215546Sopenharmony_ci D3D12_HEAP_FLAG_NONE, 983bf215546Sopenharmony_ci &resolvedMetadataBufferDesc, 984bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 985bf215546Sopenharmony_ci nullptr, 986bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spResolvedMetadataBuffer.GetAddressOf())); 987bf215546Sopenharmony_ci 988bf215546Sopenharmony_ci if (FAILED(hr)) { 989bf215546Sopenharmony_ci debug_printf("CreateCommittedResource failed with HR %x\n", hr); 990bf215546Sopenharmony_ci return false; 991bf215546Sopenharmony_ci } 992bf215546Sopenharmony_ci } 993bf215546Sopenharmony_ci 994bf215546Sopenharmony_ci if ((pD3D12Enc->m_spMetadataOutputBuffer == nullptr) || 995bf215546Sopenharmony_ci (GetDesc(pD3D12Enc->m_spMetadataOutputBuffer.Get()).Width < 996bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.MaxEncoderOutputMetadataBufferSize)) { 997bf215546Sopenharmony_ci CD3DX12_RESOURCE_DESC metadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer( 998bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.MaxEncoderOutputMetadataBufferSize); 999bf215546Sopenharmony_ci 1000bf215546Sopenharmony_ci HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource( 1001bf215546Sopenharmony_ci &Properties, 1002bf215546Sopenharmony_ci D3D12_HEAP_FLAG_NONE, 1003bf215546Sopenharmony_ci &metadataBufferDesc, 1004bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1005bf215546Sopenharmony_ci nullptr, 1006bf215546Sopenharmony_ci IID_PPV_ARGS(pD3D12Enc->m_spMetadataOutputBuffer.GetAddressOf())); 1007bf215546Sopenharmony_ci 1008bf215546Sopenharmony_ci if (FAILED(hr)) { 1009bf215546Sopenharmony_ci debug_printf("CreateCommittedResource failed with HR %x\n", hr); 1010bf215546Sopenharmony_ci return false; 1011bf215546Sopenharmony_ci } 1012bf215546Sopenharmony_ci } 1013bf215546Sopenharmony_ci return true; 1014bf215546Sopenharmony_ci} 1015bf215546Sopenharmony_ci 1016bf215546Sopenharmony_cibool 1017bf215546Sopenharmony_cid3d12_video_encoder_reconfigure_session(struct d3d12_video_encoder *pD3D12Enc, 1018bf215546Sopenharmony_ci struct pipe_video_buffer * srcTexture, 1019bf215546Sopenharmony_ci struct pipe_picture_desc * picture) 1020bf215546Sopenharmony_ci{ 1021bf215546Sopenharmony_ci assert(pD3D12Enc->m_spD3D12VideoDevice); 1022bf215546Sopenharmony_ci if(!d3d12_video_encoder_update_current_encoder_config_state(pD3D12Enc, srcTexture, picture)) { 1023bf215546Sopenharmony_ci debug_printf("d3d12_video_encoder_update_current_encoder_config_state failed!\n"); 1024bf215546Sopenharmony_ci return false; 1025bf215546Sopenharmony_ci } 1026bf215546Sopenharmony_ci if(!d3d12_video_encoder_reconfigure_encoder_objects(pD3D12Enc, srcTexture, picture)) { 1027bf215546Sopenharmony_ci debug_printf("d3d12_video_encoder_reconfigure_encoder_objects failed!\n"); 1028bf215546Sopenharmony_ci return false; 1029bf215546Sopenharmony_ci } 1030bf215546Sopenharmony_ci d3d12_video_encoder_update_picparams_tracking(pD3D12Enc, srcTexture, picture); 1031bf215546Sopenharmony_ci if(!d3d12_video_encoder_prepare_output_buffers(pD3D12Enc, srcTexture, picture)) { 1032bf215546Sopenharmony_ci debug_printf("d3d12_video_encoder_prepare_output_buffers failed!\n"); 1033bf215546Sopenharmony_ci return false; 1034bf215546Sopenharmony_ci } 1035bf215546Sopenharmony_ci return true; 1036bf215546Sopenharmony_ci} 1037bf215546Sopenharmony_ci 1038bf215546Sopenharmony_ci/** 1039bf215546Sopenharmony_ci * start encoding of a new frame 1040bf215546Sopenharmony_ci */ 1041bf215546Sopenharmony_civoid 1042bf215546Sopenharmony_cid3d12_video_encoder_begin_frame(struct pipe_video_codec * codec, 1043bf215546Sopenharmony_ci struct pipe_video_buffer *target, 1044bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 1045bf215546Sopenharmony_ci{ 1046bf215546Sopenharmony_ci // Do nothing here. Initialize happens on encoder creation, re-config (if any) happens in 1047bf215546Sopenharmony_ci // d3d12_video_encoder_encode_bitstream 1048bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; 1049bf215546Sopenharmony_ci assert(pD3D12Enc); 1050bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame started for fenceValue: %d\n", 1051bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1052bf215546Sopenharmony_ci 1053bf215546Sopenharmony_ci if (!d3d12_video_encoder_reconfigure_session(pD3D12Enc, target, picture)) { 1054bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame - Failure on " 1055bf215546Sopenharmony_ci "d3d12_video_encoder_reconfigure_session\n"); 1056bf215546Sopenharmony_ci goto fail; 1057bf215546Sopenharmony_ci } 1058bf215546Sopenharmony_ci 1059bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame finalized for fenceValue: %d\n", 1060bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1061bf215546Sopenharmony_ci return; 1062bf215546Sopenharmony_ci 1063bf215546Sopenharmony_cifail: 1064bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame failed for fenceValue: %d\n", 1065bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1066bf215546Sopenharmony_ci assert(false); 1067bf215546Sopenharmony_ci} 1068bf215546Sopenharmony_ci 1069bf215546Sopenharmony_civoid 1070bf215546Sopenharmony_cid3d12_video_encoder_calculate_metadata_resolved_buffer_size(uint32_t maxSliceNumber, size_t &bufferSize) 1071bf215546Sopenharmony_ci{ 1072bf215546Sopenharmony_ci bufferSize = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) + 1073bf215546Sopenharmony_ci (maxSliceNumber * sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA)); 1074bf215546Sopenharmony_ci} 1075bf215546Sopenharmony_ci 1076bf215546Sopenharmony_ci// Returns the number of slices that the output will contain for fixed slicing modes 1077bf215546Sopenharmony_ci// and the maximum number of slices the output might contain for dynamic slicing modes (eg. max bytes per slice) 1078bf215546Sopenharmony_ciuint32_t 1079bf215546Sopenharmony_cid3d12_video_encoder_calculate_max_slices_count_in_output( 1080bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE slicesMode, 1081bf215546Sopenharmony_ci const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *slicesConfig, 1082bf215546Sopenharmony_ci uint32_t MaxSubregionsNumberFromCaps, 1083bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC sequenceTargetResolution, 1084bf215546Sopenharmony_ci uint32_t SubregionBlockPixelsSize) 1085bf215546Sopenharmony_ci{ 1086bf215546Sopenharmony_ci uint32_t pic_width_in_subregion_units = 1087bf215546Sopenharmony_ci static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Width / static_cast<double>(SubregionBlockPixelsSize))); 1088bf215546Sopenharmony_ci uint32_t pic_height_in_subregion_units = 1089bf215546Sopenharmony_ci static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Height / static_cast<double>(SubregionBlockPixelsSize))); 1090bf215546Sopenharmony_ci uint32_t total_picture_subregion_units = pic_width_in_subregion_units * pic_height_in_subregion_units; 1091bf215546Sopenharmony_ci uint32_t maxSlices = 0u; 1092bf215546Sopenharmony_ci switch (slicesMode) { 1093bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME: 1094bf215546Sopenharmony_ci { 1095bf215546Sopenharmony_ci maxSlices = 1u; 1096bf215546Sopenharmony_ci } break; 1097bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION: 1098bf215546Sopenharmony_ci { 1099bf215546Sopenharmony_ci maxSlices = MaxSubregionsNumberFromCaps; 1100bf215546Sopenharmony_ci } break; 1101bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED: 1102bf215546Sopenharmony_ci { 1103bf215546Sopenharmony_ci maxSlices = static_cast<uint32_t>( 1104bf215546Sopenharmony_ci std::ceil(total_picture_subregion_units / static_cast<double>(slicesConfig->NumberOfCodingUnitsPerSlice))); 1105bf215546Sopenharmony_ci } break; 1106bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION: 1107bf215546Sopenharmony_ci { 1108bf215546Sopenharmony_ci maxSlices = static_cast<uint32_t>( 1109bf215546Sopenharmony_ci std::ceil(pic_height_in_subregion_units / static_cast<double>(slicesConfig->NumberOfRowsPerSlice))); 1110bf215546Sopenharmony_ci } break; 1111bf215546Sopenharmony_ci case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME: 1112bf215546Sopenharmony_ci { 1113bf215546Sopenharmony_ci maxSlices = slicesConfig->NumberOfSlicesPerFrame; 1114bf215546Sopenharmony_ci } break; 1115bf215546Sopenharmony_ci default: 1116bf215546Sopenharmony_ci { 1117bf215546Sopenharmony_ci unreachable("Unsupported D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE"); 1118bf215546Sopenharmony_ci } break; 1119bf215546Sopenharmony_ci } 1120bf215546Sopenharmony_ci 1121bf215546Sopenharmony_ci return maxSlices; 1122bf215546Sopenharmony_ci} 1123bf215546Sopenharmony_ci 1124bf215546Sopenharmony_ci/** 1125bf215546Sopenharmony_ci * encode a bitstream 1126bf215546Sopenharmony_ci */ 1127bf215546Sopenharmony_civoid 1128bf215546Sopenharmony_cid3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec, 1129bf215546Sopenharmony_ci struct pipe_video_buffer *source, 1130bf215546Sopenharmony_ci struct pipe_resource * destination, 1131bf215546Sopenharmony_ci void ** feedback) 1132bf215546Sopenharmony_ci{ 1133bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; 1134bf215546Sopenharmony_ci assert(pD3D12Enc); 1135bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream started for fenceValue: %d\n", 1136bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1137bf215546Sopenharmony_ci assert(pD3D12Enc->m_spD3D12VideoDevice); 1138bf215546Sopenharmony_ci assert(pD3D12Enc->m_spEncodeCommandQueue); 1139bf215546Sopenharmony_ci assert(pD3D12Enc->m_pD3D12Screen); 1140bf215546Sopenharmony_ci 1141bf215546Sopenharmony_ci struct d3d12_video_buffer *pInputVideoBuffer = (struct d3d12_video_buffer *) source; 1142bf215546Sopenharmony_ci assert(pInputVideoBuffer); 1143bf215546Sopenharmony_ci ID3D12Resource *pInputVideoD3D12Res = d3d12_resource_resource(pInputVideoBuffer->texture); 1144bf215546Sopenharmony_ci uint32_t inputVideoD3D12Subresource = 0u; 1145bf215546Sopenharmony_ci 1146bf215546Sopenharmony_ci struct d3d12_resource *pOutputBitstreamBuffer = (struct d3d12_resource *) destination; 1147bf215546Sopenharmony_ci assert(pOutputBitstreamBuffer); 1148bf215546Sopenharmony_ci ID3D12Resource *pOutputBufferD3D12Res = d3d12_resource_resource(pOutputBitstreamBuffer); 1149bf215546Sopenharmony_ci 1150bf215546Sopenharmony_ci // Make them permanently resident for video use 1151bf215546Sopenharmony_ci d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pOutputBitstreamBuffer); 1152bf215546Sopenharmony_ci d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pInputVideoBuffer->texture); 1153bf215546Sopenharmony_ci 1154bf215546Sopenharmony_ci /// 1155bf215546Sopenharmony_ci /// Record Encode operation 1156bf215546Sopenharmony_ci /// 1157bf215546Sopenharmony_ci 1158bf215546Sopenharmony_ci /// 1159bf215546Sopenharmony_ci /// pInputVideoD3D12Res and pOutputBufferD3D12Res are unwrapped from pipe_resource objects that are passed externally 1160bf215546Sopenharmony_ci /// and could be tracked by pipe_context and have pending ops. Flush any work on them and transition to 1161bf215546Sopenharmony_ci /// D3D12_RESOURCE_STATE_COMMON before issuing work in Video command queue below. After the video work is done in the 1162bf215546Sopenharmony_ci /// GPU, transition back to D3D12_RESOURCE_STATE_COMMON 1163bf215546Sopenharmony_ci /// 1164bf215546Sopenharmony_ci /// Note that unlike the D3D12TranslationLayer codebase, the state tracker here doesn't (yet) have any kind of 1165bf215546Sopenharmony_ci /// multi-queue support, so it wouldn't implicitly synchronize when trying to transition between a graphics op and a 1166bf215546Sopenharmony_ci /// video op. 1167bf215546Sopenharmony_ci /// 1168bf215546Sopenharmony_ci 1169bf215546Sopenharmony_ci d3d12_transition_resource_state( 1170bf215546Sopenharmony_ci d3d12_context(pD3D12Enc->base.context), 1171bf215546Sopenharmony_ci pInputVideoBuffer->texture, // d3d12_resource wrapper for pInputVideoD3D12Res 1172bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1173bf215546Sopenharmony_ci D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 1174bf215546Sopenharmony_ci d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context), 1175bf215546Sopenharmony_ci pOutputBitstreamBuffer, // d3d12_resource wrapped for pOutputBufferD3D12Res 1176bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1177bf215546Sopenharmony_ci D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 1178bf215546Sopenharmony_ci d3d12_apply_resource_states(d3d12_context(pD3D12Enc->base.context), false); 1179bf215546Sopenharmony_ci 1180bf215546Sopenharmony_ci d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), 1181bf215546Sopenharmony_ci pInputVideoBuffer->texture, 1182bf215546Sopenharmony_ci false /*wantToWrite*/); 1183bf215546Sopenharmony_ci d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pOutputBitstreamBuffer, true /*wantToWrite*/); 1184bf215546Sopenharmony_ci 1185bf215546Sopenharmony_ci std::vector<D3D12_RESOURCE_BARRIER> rgCurrentFrameStateTransitions = { 1186bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pInputVideoD3D12Res, 1187bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1188bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ), 1189bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pOutputBufferD3D12Res, 1190bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1191bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE), 1192bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spMetadataOutputBuffer.Get(), 1193bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1194bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE) 1195bf215546Sopenharmony_ci }; 1196bf215546Sopenharmony_ci 1197bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(rgCurrentFrameStateTransitions.size(), 1198bf215546Sopenharmony_ci rgCurrentFrameStateTransitions.data()); 1199bf215546Sopenharmony_ci 1200bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE reconPicOutputTextureDesc = 1201bf215546Sopenharmony_ci pD3D12Enc->m_upDPBManager->get_current_frame_recon_pic_output_allocation(); 1202bf215546Sopenharmony_ci D3D12_VIDEO_ENCODE_REFERENCE_FRAMES referenceFramesDescriptor = 1203bf215546Sopenharmony_ci pD3D12Enc->m_upDPBManager->get_current_reference_frames(); 1204bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAGS picCtrlFlags = D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_NONE; 1205bf215546Sopenharmony_ci 1206bf215546Sopenharmony_ci // Transition DPB reference pictures to read mode 1207bf215546Sopenharmony_ci uint32_t maxReferences = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc); 1208bf215546Sopenharmony_ci std::vector<D3D12_RESOURCE_BARRIER> rgReferenceTransitions(maxReferences); 1209bf215546Sopenharmony_ci if ((referenceFramesDescriptor.NumTexture2Ds > 0) || 1210bf215546Sopenharmony_ci (pD3D12Enc->m_upDPBManager->is_current_frame_used_as_reference())) { 1211bf215546Sopenharmony_ci rgReferenceTransitions.clear(); 1212bf215546Sopenharmony_ci rgReferenceTransitions.reserve(maxReferences); 1213bf215546Sopenharmony_ci 1214bf215546Sopenharmony_ci // Check if array of textures vs texture array 1215bf215546Sopenharmony_ci 1216bf215546Sopenharmony_ci if (referenceFramesDescriptor.pSubresources == nullptr) { 1217bf215546Sopenharmony_ci 1218bf215546Sopenharmony_ci // Array of resources mode for reference pictures 1219bf215546Sopenharmony_ci 1220bf215546Sopenharmony_ci // Transition all subresources of each reference frame independent resource allocation 1221bf215546Sopenharmony_ci for (uint32_t referenceIdx = 0; referenceIdx < referenceFramesDescriptor.NumTexture2Ds; referenceIdx++) { 1222bf215546Sopenharmony_ci rgReferenceTransitions.push_back( 1223bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(referenceFramesDescriptor.ppTexture2Ds[referenceIdx], 1224bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1225bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ)); 1226bf215546Sopenharmony_ci } 1227bf215546Sopenharmony_ci 1228bf215546Sopenharmony_ci // Transition all subresources the output recon pic independent resource allocation 1229bf215546Sopenharmony_ci if (reconPicOutputTextureDesc.pReconstructedPicture != nullptr) { 1230bf215546Sopenharmony_ci picCtrlFlags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE; 1231bf215546Sopenharmony_ci 1232bf215546Sopenharmony_ci rgReferenceTransitions.push_back( 1233bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(reconPicOutputTextureDesc.pReconstructedPicture, 1234bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1235bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)); 1236bf215546Sopenharmony_ci } 1237bf215546Sopenharmony_ci } else if (referenceFramesDescriptor.NumTexture2Ds > 0) { 1238bf215546Sopenharmony_ci 1239bf215546Sopenharmony_ci // texture array mode for reference pictures 1240bf215546Sopenharmony_ci 1241bf215546Sopenharmony_ci // In Texture array mode, the dpb storage allocator uses the same texture array for all the input 1242bf215546Sopenharmony_ci // reference pics in ppTexture2Ds and also for the pReconstructedPicture output allocations, just different 1243bf215546Sopenharmony_ci // subresources. 1244bf215546Sopenharmony_ci 1245bf215546Sopenharmony_ci CD3DX12_RESOURCE_DESC referencesTexArrayDesc(GetDesc(referenceFramesDescriptor.ppTexture2Ds[0])); 1246bf215546Sopenharmony_ci 1247bf215546Sopenharmony_ci for (uint32_t referenceSubresource = 0; referenceSubresource < referencesTexArrayDesc.DepthOrArraySize; 1248bf215546Sopenharmony_ci referenceSubresource++) { 1249bf215546Sopenharmony_ci 1250bf215546Sopenharmony_ci // all reference frames inputs should be all the same texarray allocation 1251bf215546Sopenharmony_ci assert(referenceFramesDescriptor.ppTexture2Ds[0] == 1252bf215546Sopenharmony_ci referenceFramesDescriptor.ppTexture2Ds[referenceSubresource]); 1253bf215546Sopenharmony_ci 1254bf215546Sopenharmony_ci // the reconpic output should be all the same texarray allocation 1255bf215546Sopenharmony_ci assert(referenceFramesDescriptor.ppTexture2Ds[0] == reconPicOutputTextureDesc.pReconstructedPicture); 1256bf215546Sopenharmony_ci 1257bf215546Sopenharmony_ci uint32_t MipLevel, PlaneSlice, ArraySlice; 1258bf215546Sopenharmony_ci D3D12DecomposeSubresource(referenceSubresource, 1259bf215546Sopenharmony_ci referencesTexArrayDesc.MipLevels, 1260bf215546Sopenharmony_ci referencesTexArrayDesc.ArraySize(), 1261bf215546Sopenharmony_ci MipLevel, 1262bf215546Sopenharmony_ci ArraySlice, 1263bf215546Sopenharmony_ci PlaneSlice); 1264bf215546Sopenharmony_ci 1265bf215546Sopenharmony_ci for (PlaneSlice = 0; PlaneSlice < pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.PlaneCount; 1266bf215546Sopenharmony_ci PlaneSlice++) { 1267bf215546Sopenharmony_ci 1268bf215546Sopenharmony_ci uint32_t planeOutputSubresource = 1269bf215546Sopenharmony_ci referencesTexArrayDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice); 1270bf215546Sopenharmony_ci 1271bf215546Sopenharmony_ci rgReferenceTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition( 1272bf215546Sopenharmony_ci // Always same allocation in texarray mode 1273bf215546Sopenharmony_ci referenceFramesDescriptor.ppTexture2Ds[0], 1274bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1275bf215546Sopenharmony_ci // If this is the subresource for the reconpic output allocation, transition to ENCODE_WRITE 1276bf215546Sopenharmony_ci // Otherwise, it's a subresource for an input reference picture, transition to ENCODE_READ 1277bf215546Sopenharmony_ci (referenceSubresource == reconPicOutputTextureDesc.ReconstructedPictureSubresource) ? 1278bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE : 1279bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, 1280bf215546Sopenharmony_ci planeOutputSubresource)); 1281bf215546Sopenharmony_ci } 1282bf215546Sopenharmony_ci } 1283bf215546Sopenharmony_ci } 1284bf215546Sopenharmony_ci 1285bf215546Sopenharmony_ci if (rgReferenceTransitions.size() > 0) { 1286bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(rgReferenceTransitions.size()), 1287bf215546Sopenharmony_ci rgReferenceTransitions.data()); 1288bf215546Sopenharmony_ci } 1289bf215546Sopenharmony_ci } 1290bf215546Sopenharmony_ci 1291bf215546Sopenharmony_ci // Update current frame pic params state after reconfiguring above. 1292bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams = 1293bf215546Sopenharmony_ci d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc); 1294bf215546Sopenharmony_ci pD3D12Enc->m_upDPBManager->get_current_frame_picture_control_data(currentPicParams); 1295bf215546Sopenharmony_ci 1296bf215546Sopenharmony_ci uint32_t prefixGeneratedHeadersByteSize = d3d12_video_encoder_build_codec_headers(pD3D12Enc); 1297bf215546Sopenharmony_ci 1298bf215546Sopenharmony_ci // If driver needs offset alignment for bitstream resource, we will pad zeroes on the codec header to this end. 1299bf215546Sopenharmony_ci if ( 1300bf215546Sopenharmony_ci (pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment > 1) 1301bf215546Sopenharmony_ci && ((prefixGeneratedHeadersByteSize % pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment) != 0) 1302bf215546Sopenharmony_ci ) { 1303bf215546Sopenharmony_ci prefixGeneratedHeadersByteSize = ALIGN(prefixGeneratedHeadersByteSize, pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment); 1304bf215546Sopenharmony_ci pD3D12Enc->m_BitstreamHeadersBuffer.resize(prefixGeneratedHeadersByteSize, 0); 1305bf215546Sopenharmony_ci } 1306bf215546Sopenharmony_ci 1307bf215546Sopenharmony_ci const D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS inputStreamArguments = { 1308bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC 1309bf215546Sopenharmony_ci { // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS 1310bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_seqFlags, 1311bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_INTRA_REFRESH 1312bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh, 1313bf215546Sopenharmony_ci d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc), 1314bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC 1315bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_currentResolution, 1316bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode, 1317bf215546Sopenharmony_ci d3d12_video_encoder_get_current_slice_param_settings(pD3D12Enc), 1318bf215546Sopenharmony_ci d3d12_video_encoder_get_current_gop_desc(pD3D12Enc) }, 1319bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_DESC 1320bf215546Sopenharmony_ci { // uint32_t IntraRefreshFrameIndex; 1321bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex, 1322bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAGS Flags; 1323bf215546Sopenharmony_ci picCtrlFlags, 1324bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA PictureControlCodecData; 1325bf215546Sopenharmony_ci currentPicParams, 1326bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODE_REFERENCE_FRAMES ReferenceFrames; 1327bf215546Sopenharmony_ci referenceFramesDescriptor }, 1328bf215546Sopenharmony_ci pInputVideoD3D12Res, 1329bf215546Sopenharmony_ci inputVideoD3D12Subresource, 1330bf215546Sopenharmony_ci prefixGeneratedHeadersByteSize // hint for driver to know header size in final bitstream for rate control internal 1331bf215546Sopenharmony_ci // budgeting. - User can also calculate headers fixed size beforehand (eg. no VUI, 1332bf215546Sopenharmony_ci // etc) and build them with final values after EncodeFrame is executed 1333bf215546Sopenharmony_ci }; 1334bf215546Sopenharmony_ci 1335bf215546Sopenharmony_ci const D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS outputStreamArguments = { 1336bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM 1337bf215546Sopenharmony_ci { 1338bf215546Sopenharmony_ci pOutputBufferD3D12Res, 1339bf215546Sopenharmony_ci prefixGeneratedHeadersByteSize, // Start writing after the reserved interval [0, 1340bf215546Sopenharmony_ci // prefixGeneratedHeadersByteSize) for bitstream headers 1341bf215546Sopenharmony_ci }, 1342bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE 1343bf215546Sopenharmony_ci reconPicOutputTextureDesc, 1344bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_ENCODE_OPERATION_METADATA_BUFFER 1345bf215546Sopenharmony_ci { pD3D12Enc->m_spMetadataOutputBuffer.Get(), 0 } 1346bf215546Sopenharmony_ci }; 1347bf215546Sopenharmony_ci 1348bf215546Sopenharmony_ci // Upload the CPU buffers with the bitstream headers to the compressed bitstream resource in the interval [0, 1349bf215546Sopenharmony_ci // prefixGeneratedHeadersByteSize) 1350bf215546Sopenharmony_ci assert(prefixGeneratedHeadersByteSize == pD3D12Enc->m_BitstreamHeadersBuffer.size()); 1351bf215546Sopenharmony_ci 1352bf215546Sopenharmony_ci pD3D12Enc->base.context->buffer_subdata( 1353bf215546Sopenharmony_ci pD3D12Enc->base.context, // context 1354bf215546Sopenharmony_ci destination, // dst buffer - "destination" is the pipe_resource object 1355bf215546Sopenharmony_ci // wrapping pOutputBitstreamBuffer and eventually pOutputBufferD3D12Res 1356bf215546Sopenharmony_ci PIPE_MAP_WRITE, // usage PIPE_MAP_x 1357bf215546Sopenharmony_ci 0, // offset 1358bf215546Sopenharmony_ci pD3D12Enc->m_BitstreamHeadersBuffer.size(), 1359bf215546Sopenharmony_ci pD3D12Enc->m_BitstreamHeadersBuffer.data()); 1360bf215546Sopenharmony_ci 1361bf215546Sopenharmony_ci // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately 1362bf215546Sopenharmony_ci // Will flush and sync this batch in d3d12_video_encoder_flush with the rest of the Video Encode Queue GPU work 1363bf215546Sopenharmony_ci 1364bf215546Sopenharmony_ci // Record EncodeFrame 1365bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->EncodeFrame(pD3D12Enc->m_spVideoEncoder.Get(), 1366bf215546Sopenharmony_ci pD3D12Enc->m_spVideoEncoderHeap.Get(), 1367bf215546Sopenharmony_ci &inputStreamArguments, 1368bf215546Sopenharmony_ci &outputStreamArguments); 1369bf215546Sopenharmony_ci 1370bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER rgResolveMetadataStateTransitions[] = { 1371bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spResolvedMetadataBuffer.Get(), 1372bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON, 1373bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE), 1374bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spMetadataOutputBuffer.Get(), 1375bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, 1376bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ), 1377bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pInputVideoD3D12Res, 1378bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, 1379bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON), 1380bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pOutputBufferD3D12Res, 1381bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, 1382bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON) 1383bf215546Sopenharmony_ci }; 1384bf215546Sopenharmony_ci 1385bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgResolveMetadataStateTransitions), 1386bf215546Sopenharmony_ci rgResolveMetadataStateTransitions); 1387bf215546Sopenharmony_ci 1388bf215546Sopenharmony_ci const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS inputMetadataCmd = { 1389bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc, 1390bf215546Sopenharmony_ci d3d12_video_encoder_get_current_profile_desc(pD3D12Enc), 1391bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format, 1392bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC 1393bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeConfig.m_currentResolution, 1394bf215546Sopenharmony_ci { pD3D12Enc->m_spMetadataOutputBuffer.Get(), 0 } 1395bf215546Sopenharmony_ci }; 1396bf215546Sopenharmony_ci 1397bf215546Sopenharmony_ci const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS outputMetadataCmd = { 1398bf215546Sopenharmony_ci /*If offset were to change, has to be aligned to pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.EncoderMetadataBufferAccessAlignment*/ 1399bf215546Sopenharmony_ci { pD3D12Enc->m_spResolvedMetadataBuffer.Get(), 0 } 1400bf215546Sopenharmony_ci }; 1401bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResolveEncoderOutputMetadata(&inputMetadataCmd, &outputMetadataCmd); 1402bf215546Sopenharmony_ci 1403bf215546Sopenharmony_ci // Transition DPB reference pictures back to COMMON 1404bf215546Sopenharmony_ci if ((referenceFramesDescriptor.NumTexture2Ds > 0) || 1405bf215546Sopenharmony_ci (pD3D12Enc->m_upDPBManager->is_current_frame_used_as_reference())) { 1406bf215546Sopenharmony_ci for (auto &BarrierDesc : rgReferenceTransitions) { 1407bf215546Sopenharmony_ci std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter); 1408bf215546Sopenharmony_ci } 1409bf215546Sopenharmony_ci 1410bf215546Sopenharmony_ci if (rgReferenceTransitions.size() > 0) { 1411bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(rgReferenceTransitions.size()), 1412bf215546Sopenharmony_ci rgReferenceTransitions.data()); 1413bf215546Sopenharmony_ci } 1414bf215546Sopenharmony_ci } 1415bf215546Sopenharmony_ci 1416bf215546Sopenharmony_ci D3D12_RESOURCE_BARRIER rgRevertResolveMetadataStateTransitions[] = { 1417bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spResolvedMetadataBuffer.Get(), 1418bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE, 1419bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON), 1420bf215546Sopenharmony_ci CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spMetadataOutputBuffer.Get(), 1421bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ, 1422bf215546Sopenharmony_ci D3D12_RESOURCE_STATE_COMMON), 1423bf215546Sopenharmony_ci }; 1424bf215546Sopenharmony_ci 1425bf215546Sopenharmony_ci pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgRevertResolveMetadataStateTransitions), 1426bf215546Sopenharmony_ci rgRevertResolveMetadataStateTransitions); 1427bf215546Sopenharmony_ci 1428bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream finalized for fenceValue: %d\n", 1429bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1430bf215546Sopenharmony_ci} 1431bf215546Sopenharmony_ci 1432bf215546Sopenharmony_civoid 1433bf215546Sopenharmony_cid3d12_video_encoder_get_feedback(struct pipe_video_codec *codec, void *feedback, unsigned *size) 1434bf215546Sopenharmony_ci{ 1435bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; 1436bf215546Sopenharmony_ci assert(pD3D12Enc); 1437bf215546Sopenharmony_ci 1438bf215546Sopenharmony_ci if (pD3D12Enc->m_needsGPUFlush) { 1439bf215546Sopenharmony_ci d3d12_video_encoder_flush(codec); 1440bf215546Sopenharmony_ci } 1441bf215546Sopenharmony_ci 1442bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_OUTPUT_METADATA encoderMetadata; 1443bf215546Sopenharmony_ci std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> pSubregionsMetadata; 1444bf215546Sopenharmony_ci d3d12_video_encoder_extract_encode_metadata( 1445bf215546Sopenharmony_ci pD3D12Enc, 1446bf215546Sopenharmony_ci pD3D12Enc->m_spResolvedMetadataBuffer.Get(), 1447bf215546Sopenharmony_ci pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize, 1448bf215546Sopenharmony_ci encoderMetadata, 1449bf215546Sopenharmony_ci pSubregionsMetadata); 1450bf215546Sopenharmony_ci 1451bf215546Sopenharmony_ci // Read metadata from encoderMetadata 1452bf215546Sopenharmony_ci if (encoderMetadata.EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) { 1453bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] Encode GPU command failed - EncodeErrorFlags: %" PRIu64 "\n", 1454bf215546Sopenharmony_ci encoderMetadata.EncodeErrorFlags); 1455bf215546Sopenharmony_ci *size = 0; 1456bf215546Sopenharmony_ci } 1457bf215546Sopenharmony_ci 1458bf215546Sopenharmony_ci assert(encoderMetadata.EncodedBitstreamWrittenBytesCount > 0u); 1459bf215546Sopenharmony_ci *size = (pD3D12Enc->m_BitstreamHeadersBuffer.size() + encoderMetadata.EncodedBitstreamWrittenBytesCount); 1460bf215546Sopenharmony_ci} 1461bf215546Sopenharmony_ci 1462bf215546Sopenharmony_civoid 1463bf215546Sopenharmony_cid3d12_video_encoder_extract_encode_metadata( 1464bf215546Sopenharmony_ci struct d3d12_video_encoder * pD3D12Enc, 1465bf215546Sopenharmony_ci ID3D12Resource * pResolvedMetadataBuffer, // input 1466bf215546Sopenharmony_ci size_t resourceMetadataSize, // input 1467bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_OUTPUT_METADATA & parsedMetadata, // output 1468bf215546Sopenharmony_ci std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> &pSubregionsMetadata // output 1469bf215546Sopenharmony_ci) 1470bf215546Sopenharmony_ci{ 1471bf215546Sopenharmony_ci struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pD3D12Enc->m_pD3D12Screen; 1472bf215546Sopenharmony_ci assert(pD3D12Screen); 1473bf215546Sopenharmony_ci pipe_resource *pPipeResolvedMetadataBuffer = 1474bf215546Sopenharmony_ci d3d12_resource_from_resource(&pD3D12Screen->base, pResolvedMetadataBuffer); 1475bf215546Sopenharmony_ci assert(pPipeResolvedMetadataBuffer); 1476bf215546Sopenharmony_ci assert(resourceMetadataSize < INT_MAX); 1477bf215546Sopenharmony_ci struct pipe_box box = { 1478bf215546Sopenharmony_ci 0, // x 1479bf215546Sopenharmony_ci 0, // y 1480bf215546Sopenharmony_ci 0, // z 1481bf215546Sopenharmony_ci static_cast<int>(resourceMetadataSize), // width 1482bf215546Sopenharmony_ci 1, // height 1483bf215546Sopenharmony_ci 1 // depth 1484bf215546Sopenharmony_ci }; 1485bf215546Sopenharmony_ci struct pipe_transfer *mapTransfer; 1486bf215546Sopenharmony_ci unsigned mapUsage = PIPE_MAP_READ; 1487bf215546Sopenharmony_ci void * pMetadataBufferSrc = pD3D12Enc->base.context->buffer_map(pD3D12Enc->base.context, 1488bf215546Sopenharmony_ci pPipeResolvedMetadataBuffer, 1489bf215546Sopenharmony_ci 0, 1490bf215546Sopenharmony_ci mapUsage, 1491bf215546Sopenharmony_ci &box, 1492bf215546Sopenharmony_ci &mapTransfer); 1493bf215546Sopenharmony_ci 1494bf215546Sopenharmony_ci assert(mapUsage & PIPE_MAP_READ); 1495bf215546Sopenharmony_ci assert(pPipeResolvedMetadataBuffer->usage == PIPE_USAGE_DEFAULT); 1496bf215546Sopenharmony_ci // Note: As we're calling buffer_map with PIPE_MAP_READ on a pPipeResolvedMetadataBuffer which has pipe_usage_default 1497bf215546Sopenharmony_ci // buffer_map itself will do all the synchronization and waits so once the function returns control here 1498bf215546Sopenharmony_ci // the contents of mapTransfer are ready to be accessed. 1499bf215546Sopenharmony_ci 1500bf215546Sopenharmony_ci // Clear output 1501bf215546Sopenharmony_ci memset(&parsedMetadata, 0, sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA)); 1502bf215546Sopenharmony_ci 1503bf215546Sopenharmony_ci // Calculate sizes 1504bf215546Sopenharmony_ci size_t encoderMetadataSize = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA); 1505bf215546Sopenharmony_ci 1506bf215546Sopenharmony_ci // Copy buffer to the appropriate D3D12_VIDEO_ENCODER_OUTPUT_METADATA memory layout 1507bf215546Sopenharmony_ci parsedMetadata = *reinterpret_cast<D3D12_VIDEO_ENCODER_OUTPUT_METADATA *>(pMetadataBufferSrc); 1508bf215546Sopenharmony_ci 1509bf215546Sopenharmony_ci // As specified in D3D12 Encode spec, the array base for metadata for the slices 1510bf215546Sopenharmony_ci // (D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA[]) is placed in memory immediately after the 1511bf215546Sopenharmony_ci // D3D12_VIDEO_ENCODER_OUTPUT_METADATA structure 1512bf215546Sopenharmony_ci D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata = 1513bf215546Sopenharmony_ci reinterpret_cast<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *>(reinterpret_cast<uint8_t *>(pMetadataBufferSrc) + 1514bf215546Sopenharmony_ci encoderMetadataSize); 1515bf215546Sopenharmony_ci 1516bf215546Sopenharmony_ci // Copy fields into D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA 1517bf215546Sopenharmony_ci assert(parsedMetadata.WrittenSubregionsCount < SIZE_MAX); 1518bf215546Sopenharmony_ci pSubregionsMetadata.resize(static_cast<size_t>(parsedMetadata.WrittenSubregionsCount)); 1519bf215546Sopenharmony_ci for (uint32_t sliceIdx = 0; sliceIdx < parsedMetadata.WrittenSubregionsCount; sliceIdx++) { 1520bf215546Sopenharmony_ci pSubregionsMetadata[sliceIdx].bHeaderSize = pFrameSubregionMetadata[sliceIdx].bHeaderSize; 1521bf215546Sopenharmony_ci pSubregionsMetadata[sliceIdx].bSize = pFrameSubregionMetadata[sliceIdx].bSize; 1522bf215546Sopenharmony_ci pSubregionsMetadata[sliceIdx].bStartOffset = pFrameSubregionMetadata[sliceIdx].bStartOffset; 1523bf215546Sopenharmony_ci } 1524bf215546Sopenharmony_ci 1525bf215546Sopenharmony_ci // Unmap the buffer tmp storage 1526bf215546Sopenharmony_ci pipe_buffer_unmap(pD3D12Enc->base.context, mapTransfer); 1527bf215546Sopenharmony_ci} 1528bf215546Sopenharmony_ci 1529bf215546Sopenharmony_ci/** 1530bf215546Sopenharmony_ci * end encoding of the current frame 1531bf215546Sopenharmony_ci */ 1532bf215546Sopenharmony_civoid 1533bf215546Sopenharmony_cid3d12_video_encoder_end_frame(struct pipe_video_codec * codec, 1534bf215546Sopenharmony_ci struct pipe_video_buffer *target, 1535bf215546Sopenharmony_ci struct pipe_picture_desc *picture) 1536bf215546Sopenharmony_ci{ 1537bf215546Sopenharmony_ci struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; 1538bf215546Sopenharmony_ci assert(pD3D12Enc); 1539bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_end_frame started for fenceValue: %d\n", 1540bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1541bf215546Sopenharmony_ci 1542bf215546Sopenharmony_ci // Signal finish of current frame encoding to the picture management tracker 1543bf215546Sopenharmony_ci pD3D12Enc->m_upDPBManager->end_frame(); 1544bf215546Sopenharmony_ci 1545bf215546Sopenharmony_ci debug_printf("[d3d12_video_encoder] d3d12_video_encoder_end_frame finalized for fenceValue: %d\n", 1546bf215546Sopenharmony_ci pD3D12Enc->m_fenceValue); 1547bf215546Sopenharmony_ci 1548bf215546Sopenharmony_ci /// 1549bf215546Sopenharmony_ci /// Flush work to the GPU and blocking wait until encode finishes 1550bf215546Sopenharmony_ci /// 1551bf215546Sopenharmony_ci pD3D12Enc->m_needsGPUFlush = true; 1552bf215546Sopenharmony_ci d3d12_video_encoder_flush(codec); 1553bf215546Sopenharmony_ci} 1554