文件路径:camx\src\core\hal\camxhaldevice.cpp
CamxResult HALDevice::ProcessCaptureRequest(
Camera3CaptureRequest* pRequest)
{
CamxResult result = CamxResultEFailed;
if (TRUE == IsCHIModuleInitialized())
{
// Keep track of information related to request for error conditions
PopulateFrameworkRequestBuffer(pRequest);
result = GetCHIAppCallbacks()->chi_override_process_request(reinterpret_cast<const camera3_device*>(&m_camera3Device),reinterpret_cast<camera3_capture_request_t*>(pRequest),NULL);
if (CamxResultSuccess != result)
{
// Remove the request from the framework data list if the request fails
RemoveFrameworkRequestBuffer(pRequest);
}
}
return result;
}
文件路径:chi-cdk\core\chiframework\chxextensioninterface.cpp
static CDKResult chi_override_process_request(
const camera3_device_t* camera3_device,
camera3_capture_request_t* capture_request,
void* priv)
{
ExtensionModule* pExtensionModule = ExtensionModule::GetInstance();
return pExtensionModule->OverrideProcessRequest(camera3_device, capture_request, priv);
}
文件路径:chi-cdk\core\chiframework\chxextensioninterface.cpp
usecase对象存在之后,开始真正的capturerequest请求,首次的时候没有usecase对象,需要创建use case对象。
CDKResult ExtensionModule::OverrideProcessRequest(
const camera3_device_t* camera3_device,
camera3_capture_request_t* pCaptureRequest,
VOID* pPriv)
{
CDKResult result = CDKResultSuccess;
for (UINT32 i = 0; i < pCaptureRequest->num_output_buffers; i++)
{
if (NULL != pCaptureRequest->output_buffers)
{
ChxUtils::WaitOnAcquireFence(&pCaptureRequest->output_buffers[i]);
INT* pAcquireFence = (INT*)&pCaptureRequest->output_buffers[i].acquire_fence;
*pAcquireFence = -1;
}
}
UINT32 logicalCameraId = GetCameraIdfromDevice(camera3_device);
if (CDKInvalidId != logicalCameraId)
{
if (NULL != pCaptureRequest->settings)
{
FreeLastKnownRequestSetting(logicalCameraId);
m_pLastKnownRequestSettings[logicalCameraId] = allocate_copy_camera_metadata_checked(pCaptureRequest->settings,
get_camera_metadata_size(pCaptureRequest->settings));
}
// 如果设置不可用,则在刷新后设置有效的metadata
if ((TRUE == m_hasFlushOccurred[logicalCameraId]) &&
(NULL == pCaptureRequest->settings))
{
pCaptureRequest->settings = m_pLastKnownRequestSettings[logicalCameraId];
m_hasFlushOccurred[logicalCameraId] = FALSE;
}
if (TRUE == static_cast<BOOL>(ChxUtils::AtomicLoadU32(&m_aFlushInProgress[logicalCameraId])))
{
HandleProcessRequestErrorAllPCRs(pCaptureRequest, logicalCameraId);
return CDKResultSuccess;
}
if (ChxUtils::AndroidMetadata::IsLongExposureCapture(const_cast<camera_metadata_t*>(pCaptureRequest->settings)))
{
ChxUtils::AtomicStoreU32(&m_aLongExposureInProgress, TRUE);
m_longExposureFrame = pCaptureRequest->frame_number;
}
m_pRecoveryLock[logicalCameraId]->Lock();
if (TRUE == m_RecoveryInProgress[logicalCameraId])
{
m_pRecoveryCondition[logicalCameraId]->Wait(m_pRecoveryLock[logicalCameraId]->GetNativeHandle());
}
m_pRecoveryLock[logicalCameraId]->Unlock();
// Save the original metadata
const camera_metadata_t* pOriginalMetadata = pCaptureRequest->settings;
(VOID)pPriv;
m_pPCRLock[logicalCameraId]->Lock();
if (NULL != m_pSelectedUsecase[logicalCameraId])
{
m_originalFrameWorkNumber[logicalCameraId] = pCaptureRequest->frame_number;
// 如果框架没有发送任何metadata,则发生恢复,发送有效的元数据
if (m_firstFrameAfterRecovery[logicalCameraId] == pCaptureRequest->frame_number &&
NULL == pCaptureRequest->settings)
{
pCaptureRequest->settings = m_pLastKnownRequestSettings[logicalCameraId];
m_firstFrameAfterRecovery[logicalCameraId] = 0;
}
if (pCaptureRequest->output_buffers != NULL)
{
for (UINT i = 0; i < pCaptureRequest->num_output_buffers; i++)
{
if ((NULL != m_pPerfLockManager[logicalCameraId]) &&
(pCaptureRequest->output_buffers[i].stream->format == ChiStreamFormatBlob) &&
((pCaptureRequest->output_buffers[i].stream->data_space ==
static_cast<android_dataspace_t>(DataspaceV0JFIF)) ||
(pCaptureRequest->output_buffers[i].stream->data_space ==
static_cast<android_dataspace_t>(DataspaceJFIF))))
{
m_pPerfLockManager[logicalCameraId]->AcquirePerfLock(PERF_LOCK_SNAPSHOT_CAPTURE, 2000);
break;
}
if ((NULL != m_pPerfLockManager[logicalCameraId]) &&
TRUE == UsecaseSelector::IsHEIFStream(pCaptureRequest->output_buffers[i].stream))
{
m_pPerfLockManager[logicalCameraId]->AcquirePerfLock(PERF_LOCK_SNAPSHOT_CAPTURE, 2000);
break;
}
}
}
result = m_pSelectedUsecase[logicalCameraId]->ProcessCaptureRequest(pCaptureRequest);
}
if (pCaptureRequest->settings != NULL)
{
// Restore the original metadata pointer that came from the framework
pCaptureRequest->settings = pOriginalMetadata;
}
// Need to return success on PCR to allow FW to continue sending requests
if (result == CDKResultEBusy)
{
result = CDKResultSuccess;
}
if (result == CamxResultECancelledRequest)
{
// Ignore the Failure if flush or recovery returned CamcelRequest
CHX_LOG("Flush/Recovery is in progress %d and so ignore failure", pCaptureRequest->frame_number);
result = CDKResultSuccess;
}
m_pPCRLock[logicalCameraId]->Unlock();
}
else
{
CHX_LOG_ERROR("Invalid logical camera id device:%p!!", camera3_device);
}
return result;
}
文件路径:vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp
这里从chxusecase.cpp基类中ProcessCaptureRequest直接调用过来的
CDKResult CameraUsecaseBase::ExecuteCaptureRequest(
camera3_capture_request_t* pRequest)
{
// Base implementation finds the buffers that go to each output and invokes SubmitRequest for each pipeline with outputs
// If the advanced class wishes to use this function, but not invoke all the pipelines, the output produced from the disired
// inactive pipeline should be removed from the pRequest->output_buffers
CDKResult result = CDKResultSuccess;
CHX_LOG("CameraUsecaseBase::ExecuteCaptureRequest for frame %d with %d output buffers",
pRequest->frame_number, pRequest->num_output_buffers);
static const UINT32 NumOutputBuffers = 5;
UINT frameIndex = pRequest->frame_number % MaxOutstandingRequests;
if (InvalidId != m_rtSessionIndex)
{
UINT32 rtPipeline = m_sessions[m_rtSessionIndex].rtPipelineIndex;
if (InvalidId != rtPipeline)
{
m_selectedSensorModeIndex =
m_sessions[m_rtSessionIndex].pipelines[rtPipeline].pPipeline->GetSensorModeInfo()->modeIndex;
result = UpdateSensorModeIndex(const_cast<camera_metadata_t*>(pRequest->settings));
}
}
for (UINT session = 0; session < MaxSessions; session++)
{
BOOL bIsOffline = FALSE;
for (UINT pipeline = 0; pipeline < m_sessions[session].numPipelines; pipeline++)
{
if (NULL != pRequest->input_buffer)
{
bIsOffline = TRUE;
result = WaitForDeferThread();
if (CDKResultSuccess != result)
{
CHX_LOG_ERROR("Defer thread failure");
break;
}
// Skip submitting to realtime pipelines when an input buffer is provided
if (TRUE == m_sessions[session].pipelines[pipeline].pPipeline->IsRealTime())
{
continue;
}
}
else
{
// Skip submitting to offline pipelines when an input buffer is not provided
if (FALSE == m_sessions[session].pipelines[pipeline].pPipeline->IsRealTime())
{
continue;
}
}
CHISTREAMBUFFER outputBuffers[NumOutputBuffers] = { { 0 } };
UINT32 outputCount = 0;
PipelineData* pPipelineData = &m_sessions[session].pipelines[pipeline];
for (UINT32 buffer = 0; buffer < pRequest->num_output_buffers; buffer++)
{
for (UINT stream = 0; stream < pPipelineData->numStreams; stream++)
{
if ( (TRUE == bIsOffline) &&
(FALSE == m_sessions[session].pipelines[pipeline].pPipeline->IsRealTime()) &&
(TRUE == m_bCloningNeeded) )
{
UINT index = 0;
if (TRUE == IsThisClonedStream(m_pClonedStream, pPipelineData->pStreams[stream], &index))
{
if ((reinterpret_cast<CHISTREAM*>(pRequest->output_buffers[buffer].stream) ==
m_pFrameworkOutStreams[index]))
{
ChxUtils::PopulateHALToChiStreamBuffer(&pRequest->output_buffers[buffer],
&outputBuffers[outputCount]);
outputBuffers[outputCount].pStream = pPipelineData->pStreams[stream];
outputCount++;
}
}
}
else
{
if (reinterpret_cast<CHISTREAM*>(pRequest->output_buffers[buffer].stream) ==
pPipelineData->pStreams[stream])
{
ChxUtils::PopulateHALToChiStreamBuffer(&pRequest->output_buffers[buffer],
&outputBuffers[outputCount]);
outputCount++;
}
}
}
}
if (0 < outputCount)
{
CHICAPTUREREQUEST request = { 0 };
CHISTREAMBUFFER inputBuffer = { 0 };
UINT32 sensorModeIndex;
if (NULL != pRequest->input_buffer)
{
request.numInputs = 1;
ChxUtils::PopulateHALToChiStreamBuffer(pRequest->input_buffer, &inputBuffer);
request.pInputBuffers = &inputBuffer;
}
request.frameNumber = pRequest->frame_number;
request.hPipelineHandle = reinterpret_cast<CHIPIPELINEHANDLE>(
m_sessions[session].pSession->GetPipelineHandle());
request.numOutputs = outputCount;
request.pOutputBuffers = outputBuffers;
request.pPrivData = &m_privData[frameIndex];
UpdateMetadataBuffers(pRequest, pPipelineData->id, &request, session, pipeline, !bIsOffline);
CHIPIPELINEREQUEST submitRequest = { 0 };
submitRequest.pSessionHandle = reinterpret_cast<CHIHANDLE>(
m_sessions[session].pSession->GetSessionHandle());
submitRequest.numRequests = 1;
submitRequest.pCaptureRequests = &request;
UINT32 numPCRsBeforeStreamOn = ExtensionModule::GetInstance()->GetNumPCRsBeforeStreamOn();
if (1 > numPCRsBeforeStreamOn)
{
// Activate pipeline before submitting request when EarlyPCR disabled
CheckAndActivatePipeline(m_sessions[session].pSession);
}
CHX_LOG("Submitting request to Session %d Pipeline %d outputCount=%d", session, pipeline, outputCount);
CHX_LOG_REQMAP("frame: %u <==> (chiFrameNum) chiOverrideFrameNum: %" PRIu64,
GetAppFrameNum(request.frameNumber),
request.frameNumber);
result = SubmitRequest(&submitRequest);
if (CDKResultSuccess != result)
{
CHX_LOG_ERROR("Submit request failure for session:%d", session);
break;
}
if (0 < numPCRsBeforeStreamOn)
{
// Activate pipeline after submitting request when EarlyPCR enabled
CheckAndActivatePipeline(m_sessions[session].pSession);
}
}
}
if (CDKResultSuccess != result)
{
CHX_LOG_ERROR("Defer thread or submit request failure for session:%d", session);
break;
}
}
return result;
}
文件路径:vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp
Feature* AdvancedCameraUsecase::SelectFeatureToExecuteCaptureRequest(
camera3_capture_request_t* pRequest,
UINT32 physicalCameraIndex)
{
// OEM to change
// @todo add logic to select the feature to run the request
Feature* pFeature = NULL;
UINT32 enabledAdvanceFeatures = ExtensionModule::GetInstance()->GetAdvanceFeatureMask();
if (m_enabledFeaturesCount[physicalCameraIndex] == 0)
{
return NULL;
}
BOOL isMultiframefeature = FALSE;
BOOL isHDRSceneMode = FALSE;
UINT32 burstShotFps = 0;
UINT32 customNoiseReduction = 0;
camera_metadata_t *metadata = const_cast<camera_metadata_t*>(pRequest->settings);
camera_metadata_entry_t entry = { 0 };
entry.tag = ExtensionModule::GetInstance()->GetVendorTagId(VendorTag::BurstFps);
INT32 status = find_camera_metadata_entry(metadata, entry.tag, &entry);
if (0 == status)
{
burstShotFps = static_cast<UINT32>(*(entry.data.u8));
CHX_LOG_INFO("Burst mode selected %d", burstShotFps);
}
entry.tag = ExtensionModule::GetInstance()->GetVendorTagId(VendorTag::CustomNoiseReduction);
status = find_camera_metadata_entry(metadata, entry.tag, &entry);
if (0 == status)
{
customNoiseReduction = static_cast<UINT32>(*(entry.data.u8));
CHX_LOG_INFO("Custom Noise Reduction %d", customNoiseReduction);
}
entry.tag = ANDROID_NOISE_REDUCTION_MODE;
status = find_camera_metadata_entry(metadata, entry.tag, &entry);
if (0 == status)
{
INT32 controlNoiseReductionMode = static_cast<INT32>(*(entry.data.i32));
CHX_LOG_INFO("Noise Reduction Mode %d", controlNoiseReductionMode);
isMultiframefeature =
(ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY == controlNoiseReductionMode) ? TRUE : FALSE;
}
entry.tag = ANDROID_CONTROL_SCENE_MODE;
status = find_camera_metadata_entry(metadata, entry.tag, &entry);
if (0 == status)
{
INT32 controlSceneMode = static_cast<INT32>(*(entry.data.i32));
CHX_LOG_INFO("Scene Mode %d", controlSceneMode);
isHDRSceneMode =
(ANDROID_CONTROL_SCENE_MODE_HDR == controlSceneMode) ? TRUE : FALSE;
}
if ((TRUE == isHDRSceneMode) && (TRUE == isMultiframefeature))
{
// If both HDR and Noise Reduction High quality enabled, give priority to HDR
isMultiframefeature = FALSE;
}
if ((NULL != m_pLastSnapshotFeature) &&
(FeatureStatus::BUSY == m_pLastSnapshotFeature->GetFeatureStatus()))
{
CHX_LOG_INFO("Mark to reject snapshot request for frame number=%d", pRequest->frame_number);
m_rejectedSnapshotRequestList[pRequest->frame_number % MaxOutstandingRequests] = TRUE;
}
else
{
for (UINT32 i = 0; i < m_enabledFeaturesCount[physicalCameraIndex]; i++)
{
if (AdvanceFeature2Wrapper == (enabledAdvanceFeatures & AdvanceFeature2Wrapper))
{
if (FeatureType::Feature2 == m_enabledFeatures[physicalCameraIndex][i]->GetFeatureType())
{
pFeature = m_enabledFeatures[physicalCameraIndex][i];
break;
}
}
else if ((0 == burstShotFps) &&
(NULL == pRequest->input_buffer) &&
(1 == customNoiseReduction))
{
if (TRUE == isMultiframefeature)
{
// Select enabled multiframe feature
if ((FeatureType::MFNR == m_enabledFeatures[physicalCameraIndex][i]->GetFeatureType()) ||
(FeatureType::SWMF == m_enabledFeatures[physicalCameraIndex][i]->GetFeatureType()))
{
pFeature = m_enabledFeatures[physicalCameraIndex][i];
break;
}
}
if (TRUE == isHDRSceneMode)
{
// Select HDR feature
if (FeatureType::HDR == m_enabledFeatures[physicalCameraIndex][i]->GetFeatureType())
{
pFeature = m_enabledFeatures[physicalCameraIndex][i];
break;
}
}
}
}
if (NULL == pFeature)
{
if (FALSE == IsMultiCameraUsecase())
{
// By default choose ZSL/yuvcb feature for Single camera
// By default SAT will be choosen for Dual Camera
pFeature = m_enabledFeatures[physicalCameraIndex][0];
}
}
m_pLastSnapshotFeature = pFeature;
}
if ((UsecaseId::QuadCFA == m_usecaseId) &&
(0 == (enabledAdvanceFeatures & AdvanceFeature2Wrapper)) &&
(0 == (enabledAdvanceFeatures & AdvanceFeatureSWMF)))
{
// Feature QuadCFA is selected when iso gain is below pre-defined threshold,
// in order to trigger remosaic snapshot (non-zsl).
//
// If a multi-frame feature is selected according to above rules,
// it will be added as a sub feature after qcfa remosaic snapshot,
// other wise single remosaic snapshot will be triggered
Feature* pFeaturebyGain = PickAdvanceFeatureByGain(m_rdiStreamIndex);
if ((NULL != pFeaturebyGain) && (FeatureType::QuadCFA == pFeaturebyGain->GetFeatureType()))
{
UINT32 frameIndex = pRequest->frame_number % MaxOutstandingRequests;
m_snapshotFeatures[frameIndex].appFrameNum = pRequest->frame_number;
m_snapshotFeatures[frameIndex].featureInfo[m_snapshotFeatures[frameIndex].numOfFeatures].pFeature = pFeaturebyGain;
m_snapshotFeatures[frameIndex].numOfFeatures++;
// currently only support comination of qcfa + mfnr
if ((NULL != pFeature) && (FeatureType::MFNR == pFeature->GetFeatureType()))
{
UINT32 index = m_snapshotFeatures[frameIndex].numOfFeatures;
m_snapshotFeatures[frameIndex].featureInfo[index].pFeature = pFeature;
m_snapshotFeatures[frameIndex].numOfFeatures++;
CHX_LOG("Multi frame remosaic snapshot, sub Feature: pFeature:%p, type:%d",
pFeature, pFeature->GetFeatureType());
}
else
{
CHX_LOG_INFO("Single remosaic snapshot");
}
// set FeatureQuadCFA as first Feature
pFeature = pFeaturebyGain;
}
}
// Uncomment following code to enable MFNR/MFSR testing
// pFeature = PickAdvanceFeature(pRequest);
if (NULL != pFeature)
{
CHX_LOG("Select Feature %p type %d for request:%d", pFeature, pFeature->GetFeatureType(),
pRequest->frame_number);
}
else
{
CHX_LOG_ERROR("no feature selected for request=%d", pRequest->frame_number);
}
// return the first Feature
return pFeature;
}
文件路径:vendor\qcom\proprietary\chi-cdk\core\chiusecase\chxadvancedcamerausecase.cpp
CDKResult CameraUsecaseBase::ExecuteCaptureRequest(
camera3_capture_request_t* pRequest)
{
// Base implementation finds the buffers that go to each output and invokes SubmitRequest for each pipeline with outputs
// If the advanced class wishes to use this function, but not invoke all the pipelines, the output produced from the disired
// inactive pipeline should be removed from the pRequest->output_buffers
CDKResult result = CDKResultSuccess;
CHX_LOG("CameraUsecaseBase::ExecuteCaptureRequest for frame %d with %d output buffers",
pRequest->frame_number, pRequest->num_output_buffers);
static const UINT32 NumOutputBuffers = 5;
UINT frameIndex = pRequest->frame_number % MaxOutstandingRequests;
if (InvalidId != m_rtSessionIndex)
{
UINT32 rtPipeline = m_sessions[m_rtSessionIndex].rtPipelineIndex;
if (InvalidId != rtPipeline)
{
m_selectedSensorModeIndex =
m_sessions[m_rtSessionIndex].pipelines[rtPipeline].pPipeline->GetSensorModeInfo()->modeIndex;
result = UpdateSensorModeIndex(const_cast<camera_metadata_t*>(pRequest->settings));
}
}
for (UINT session = 0; session < MaxSessions; session++)
{
BOOL bIsOffline = FALSE;
for (UINT pipeline = 0; pipeline < m_sessions[session].numPipelines; pipeline++)
{
if (NULL != pRequest->input_buffer)
{
bIsOffline = TRUE;
result = WaitForDeferThread();
if (CDKResultSuccess != result)
{
CHX_LOG_ERROR("Defer thread failure");
break;
}
// Skip submitting to realtime pipelines when an input buffer is provided
if (TRUE == m_sessions[session].pipelines[pipeline].pPipeline->IsRealTime())
{
continue;
}
}
else
{
// Skip submitting to offline pipelines when an input buffer is not provided
if (FALSE == m_sessions[session].pipelines[pipeline].pPipeline->IsRealTime())
{
continue;
}
}
CHISTREAMBUFFER outputBuffers[NumOutputBuffers] = { { 0 } };
UINT32 outputCount = 0;
PipelineData* pPipelineData = &m_sessions[session].pipelines[pipeline];
for (UINT32 buffer = 0; buffer < pRequest->num_output_buffers; buffer++)
{
for (UINT stream = 0; stream < pPipelineData->numStreams; stream++)
{
if ( (TRUE == bIsOffline) &&
(FALSE == m_sessions[session].pipelines[pipeline].pPipeline->IsRealTime()) &&
(TRUE == m_bCloningNeeded) )
{
UINT index = 0;
if (TRUE == IsThisClonedStream(m_pClonedStream, pPipelineData->pStreams[stream], &index))
{
if ((reinterpret_cast<CHISTREAM*>(pRequest->output_buffers[buffer].stream) ==
m_pFrameworkOutStreams[index]))
{
ChxUtils::PopulateHALToChiStreamBuffer(&pRequest->output_buffers[buffer],
&outputBuffers[outputCount]);
outputBuffers[outputCount].pStream = pPipelineData->pStreams[stream];
outputCount++;
}
}
}
else
{
if (reinterpret_cast<CHISTREAM*>(pRequest->output_buffers[buffer].stream) ==
pPipelineData->pStreams[stream])
{
ChxUtils::PopulateHALToChiStreamBuffer(&pRequest->output_buffers[buffer],
&outputBuffers[outputCount]);
outputCount++;
}
}
}
}
if (0 < outputCount)
{
CHICAPTUREREQUEST request = { 0 };
CHISTREAMBUFFER inputBuffer = { 0 };
UINT32 sensorModeIndex;
if (NULL != pRequest->input_buffer)
{
request.numInputs = 1;
ChxUtils::PopulateHALToChiStreamBuffer(pRequest->input_buffer, &inputBuffer);
request.pInputBuffers = &inputBuffer;
}
request.frameNumber = pRequest->frame_number;
request.hPipelineHandle = reinterpret_cast<CHIPIPELINEHANDLE>(
m_sessions[session].pSession->GetPipelineHandle());
request.numOutputs = outputCount;
request.pOutputBuffers = outputBuffers;
request.pPrivData = &m_privData[frameIndex];
UpdateMetadataBuffers(pRequest, pPipelineData->id, &request, session, pipeline, !bIsOffline);
CHIPIPELINEREQUEST submitRequest = { 0 };
submitRequest.pSessionHandle = reinterpret_cast<CHIHANDLE>(
m_sessions[session].pSession->GetSessionHandle());
submitRequest.numRequests = 1;
submitRequest.pCaptureRequests = &request;
UINT32 numPCRsBeforeStreamOn = ExtensionModule::GetInstance()->GetNumPCRsBeforeStreamOn();
if (1 > numPCRsBeforeStreamOn)
{
// Activate pipeline before submitting request when EarlyPCR disabled
CheckAndActivatePipeline(m_sessions[session].pSession);
}
CHX_LOG("Submitting request to Session %d Pipeline %d outputCount=%d", session, pipeline, outputCount);
CHX_LOG_REQMAP("frame: %u <==> (chiFrameNum) chiOverrideFrameNum: %" PRIu64,
GetAppFrameNum(request.frameNumber),
request.frameNumber);
result = SubmitRequest(&submitRequest);
if (CDKResultSuccess != result)
{
CHX_LOG_ERROR("Submit request failure for session:%d", session);
break;
}
if (0 < numPCRsBeforeStreamOn)
{
// Activate pipeline after submitting request when EarlyPCR enabled
CheckAndActivatePipeline(m_sessions[session].pSession);
}
}
}
if (CDKResultSuccess != result)
{
CHX_LOG_ERROR("Defer thread or submit request failure for session:%d", session);
break;
}
}
return result;
}
CDKResult ExtensionModule::ActivatePipeline(
CHIHANDLE sessionHandle,
CHIPIPELINEDESCRIPTOR pipelineHandle)
{
return g_chiContextOps.pActivatePipeline(m_hCHIContext, sessionHandle, pipelineHandle, NULL);
static CDKResult ChiActivatePipeline(
CHIHANDLE hChiContext,
CHIHANDLE hSession,
CHIHANDLE hPipeline,
CHISENSORMODEINFO* pModeInfo)
{
CDKResult result = CDKResultSuccess;
ChiContext* pChiContext = GetChiContext(hChiContext);
CHISession* pChiSession = GetChiSession(hSession);
CHIPIPELINEHANDLE hPipelineDescriptor = hPipeline;
CAMX_UNREFERENCED_PARAM(pModeInfo);
result = pChiContext->ActivatePipeline(pChiSession, hPipelineDescriptor);
return result;
}
CamxResult ChiContext::ActivatePipeline(
CHISession* pChiSession,
CHIPIPELINEHANDLE hPipelineDescriptor)
{
CAMX_ASSERT(NULL != pChiSession);
CAMX_ASSERT(NULL != hPipelineDescriptor);
CamxResult result = CamxResultSuccess;
if (TRUE == pChiSession->UsingResourceManager(0))
{
ResourceID resourceId = static_cast<ResourceID>(ResourceType::RealtimePipeline);
GetResourceManager()->CheckAndAcquireResource(resourceId, static_cast<VOID*>(hPipelineDescriptor), 0);
}
result = pChiSession->StreamOn(hPipelineDescriptor);
return result;
}
CamxResult Session::StreamOn(
CHIPIPELINEHANDLE hPipelineDescriptor)
{
UINT32 index = 0;
CamxResult result = CamxResultSuccess;
// input pipelineIndex not really match the index recorded by Session, so use Descriptor to find it.
for (index = 0; index < m_numPipelines; index++)
{
if (hPipelineDescriptor == m_pipelineData[index].pPipelineDescriptor)
{
// found corresponding pipeline can use index to get to it
break;
}
}
CAMX_ASSERT(index < m_numPipelines);
Pipeline* pPipeline = m_pipelineData[index].pPipeline;
m_pStreamOnOffLock->Lock();
if ((NULL != pPipeline) && (PipelineStatus::STREAM_ON != pPipeline->GetPipelineStatus()))
{
PipelineStatus pipelineStatus = pPipeline->GetPipelineStatus();
if (PipelineStatus::FINALIZED > pipelineStatus)
{
result = FinalizeDeferPipeline(index);
pipelineStatus = pPipeline->GetPipelineStatus();
CAMX_LOG_INFO(CamxLogGroupCore, "FinalizeDeferPipeline result: %d pipelineStatus: %d",
result, pipelineStatus);
}
if (CamxResultSuccess != result)
{
CAMX_LOG_ERROR(CamxLogGroupCore, "FinalizeDeferPipeline() unsuccessful, Session StreamOn() is failed !!");
pPipeline->ReleaseResources();
}
else
{
if (PipelineStatus::FINALIZED <= pipelineStatus)
{
result = pPipeline->StreamOn();
if (CamxResultSuccess == result)
{
if (TRUE == pPipeline->IsRealTime())
{
m_numStreamedOnRealtimePipelines++;
CheckAndSyncLinks();
}
}
else
{
CAMX_LOG_ERROR(CamxLogGroupCore, "Pipeline %s failed to stream on.",
pPipeline->GetPipelineName());
}
}
}
}
m_pStreamOnOffLock->Unlock();
return result;
}
static CDKResult ChiSubmitPipelineRequest(
CHIHANDLE hChiContext,
CHIPIPELINEREQUEST* pRequest)
{
CDKResult result = CDKResultSuccess;
ChiContext* pChiContext = GetChiContext(hChiContext);
CHISession* pChiSession = GetChiSession(pRequest->pSessionHandle);
if ((NULL == pChiContext) || (NULL == pChiSession))
{
CAMX_LOG_ERROR(CamxLogGroupChi, "Invalid Argument - ChiContext: %p ChiSession: %p", pChiContext, pChiSession);
result = CDKResultEInvalidArg;
}
if (CDKResultSuccess == result)
{
result = pChiContext->SubmitRequest(pChiSession, pRequest);
if (CDKResultSuccess != result)
{
CAMX_LOG_ERROR(CamxLogGroupChi, "Submit request failed with error %d.", result);
}
}
return result;
}
文件路径:vendor\qcom\proprietary\camx\src\core\chi\camxchicontext.cpp
CamxResult ChiContext::SubmitRequest(
CHISession* pSession,
ChiPipelineRequest* pRequest)
{
CamxResult result = CamxResultSuccess;
// Validate requests
for (UINT i = 0; i < pRequest->numRequests; i++)
{
if (0 != pRequest->pCaptureRequests[i].hPipelineHandle)
{
result = pSession->CheckValidInputRequest(&pRequest->pCaptureRequests[i]);
if (CamxResultSuccess == result)
{
// Fall back to non optimized stream on before PCR logic if 0 or for non real time pipelines
if ((FALSE == pSession->IsPipelineRealTime(pRequest->pCaptureRequests[i].hPipelineHandle)))
{
result = pSession->StreamOn(pRequest->pCaptureRequests[i].hPipelineHandle);
}
}
else
{
CAMX_ASSERT_ALWAYS_MESSAGE("Request batch index %u is not valid.", i);
break;
}
}
}
// Submit requests to session.
// For multi-camera, batch of requests for different pipeline are sent to session together.
if (CamxResultSuccess == result)
{
result = pSession->ProcessCaptureRequest(pRequest);
if (CamxResultSuccess != result)
{
CAMX_LOG_ERROR(CamxLogGroupChi, "Request %llu failed when submitting requests.",
pRequest->pCaptureRequests[0].frameNumber);
}
}
return result;
}
result = pSession->ProcessCaptureRequest(pRequest);
m_pRequestQueue–>EnqueueWait(&m_captureRequest)将capturerequest请求入列,然后执行一个jobHandler线程,在另外一个线程中执行m_pRequestQueue–>Dequeue()
CamxResult Pipeline::ProcessRequest(
PipelineProcessRequestData* pPipelineRequestData)
{
CAMX_ASSERT(NULL != pPipelineRequestData);
CAMX_ASSERT(NULL != pPipelineRequestData->pCaptureRequest);
CAMX_ASSERT(NULL != pPipelineRequestData->pPerBatchedFrameInfo);
CAMX_ENTRYEXIT_SCOPE_ID(CamxLogGroupCore,
SCOPEEventTopologyProcessRequest,
pPipelineRequestData->pCaptureRequest->requestId);
CamxResult result = CamxResultSuccess;
CaptureRequest* pCaptureRequest = pPipelineRequestData->pCaptureRequest;
UINT currentActiveStreamIdMask = 0;
UINT64 requestId = pCaptureRequest->requestId;
UINT perRequestIdIndex = (requestId % MaxPerRequestInfo);
// Must have recieved all fences created back and freed their node in the LDLL
CAMX_ASSERT(0 == m_perRequestInfo[perRequestIdIndex].fences.NumNodes());
UINT32* pSequenceId = m_perRequestInfo[perRequestIdIndex].pSequenceId;
Utils::Memset(pSequenceId, 0, sizeof(UINT32) * GetBatchedHALOutputNum());
CAMX_ASSERT(GetBatchedHALOutputNum() >= pCaptureRequest->GetBatchedHALOutputNum(pCaptureRequest));
m_perRequestInfo[perRequestIdIndex].pSequenceId = pSequenceId;
m_perRequestInfo[perRequestIdIndex].aMetadataReady = 0;
m_perRequestInfo[perRequestIdIndex].isSofDispatched = FALSE;
m_perRequestInfo[perRequestIdIndex].numNodesRequestIdDone = 0;
m_perRequestInfo[perRequestIdIndex].numNodesMetadataDone = 0;
m_perRequestInfo[perRequestIdIndex].numNodesPartialMetadataDone = 0;
m_perRequestInfo[perRequestIdIndex].numNodesConfigDone = 0;
m_perRequestInfo[perRequestIdIndex].batchFrameIntervalNanoSeconds = 0;
m_perRequestInfo[perRequestIdIndex].bufferDone = 0;
m_perRequestInfo[perRequestIdIndex].fences.FreeAllNodesAndTheirClientData();
m_perRequestInfo[perRequestIdIndex].isSlowdownPresent = FALSE;
CAMX_ASSERT(m_perRequestInfo[perRequestIdIndex].request.pStreamBuffers ==
&m_pStreamBufferBlob[perRequestIdIndex * GetBatchedHALOutputNum()]);
result = CaptureRequest::PartialDeepCopy(&m_perRequestInfo[perRequestIdIndex].request, pCaptureRequest);
UINT* pCurrentActiveStreams = NULL;
BOOL differentStreams = FALSE;
PerBatchedFrameInfo* pPerBatchedFrameInfo = NULL;
if (CamxResultSuccess == result)
{
for (UINT batchIndex = 0; batchIndex < pCaptureRequest->GetBatchedHALOutputNum(pCaptureRequest); batchIndex++)
{
// Create mapping between request id and framework frame number.
m_perRequestInfo[perRequestIdIndex].pSequenceId[batchIndex] =
pPipelineRequestData->pPerBatchedFrameInfo[batchIndex].sequenceId;
CAMX_LOG_VERBOSE(CamxLogGroupCore,
"%s In perRequestInfo[%d], map request id %lld with sequence id %d",
GetPipelineIdentifierString(),
perRequestIdIndex,
requestId,
pPipelineRequestData->pPerBatchedFrameInfo[batchIndex].sequenceId);
}
/// @note It is assumed the first batchInfo will have all the streams that can possibly be enabled in other batches
pPerBatchedFrameInfo = &pPipelineRequestData->pPerBatchedFrameInfo[0];
#if ASSERTS_ENABLED
/// Validate assumption that the first batchInfo will have all the streams that can possibly be enabled
for (UINT batchIndex = 1; batchIndex < pCaptureRequest->GetBatchedHALOutputNum(pCaptureRequest); batchIndex++)
{
if ((pPerBatchedFrameInfo[batchIndex].activeStreamIdMask | pPerBatchedFrameInfo[0].activeStreamIdMask) !=
pPerBatchedFrameInfo[0].activeStreamIdMask)
{
CAMX_ASSERT_ALWAYS_MESSAGE("Pipeline-ERROR: First batch index does not have all the streams possible");
}
}
#endif // ASSERTS_ENABLED
currentActiveStreamIdMask = pPerBatchedFrameInfo->activeStreamIdMask;
differentStreams = FALSE;
if (m_lastRequestActiveStreamIdMask != currentActiveStreamIdMask)
{
differentStreams = TRUE;
m_lastRequestActiveStreamIdMask = currentActiveStreamIdMask;
}
pCurrentActiveStreams = ¤tActiveStreamIdMask;
if (TRUE == m_pChiContext->GetHwContext()->GetImageSensorModuleData(m_cameraId)->IsExternalSensor())
{
PublishSensorModeInformation(pCaptureRequest->requestId);
}
// Init debug/tuning data buffer
if (TRUE == HAL3MetadataUtil::IsDebugDataEnable())
{
InitializeDebugDataBuffer(requestId);
}
// Use this table to find the correct request ID from CSL sync ID when CSL callback comes
m_pCSLSyncIDToRequestId[pCaptureRequest->CSLSyncID % (MaxPerRequestInfo * GetBatchedHALOutputNum())] =
pCaptureRequest->requestId;
if (FALSE == IsRealTime())
{
UINT64 requestIdInner = pCaptureRequest->requestId;
MetadataSlot* pInputSlot = m_pInputPool->GetSlot(requestIdInner);
MetadataSlot* pMainSlot = m_pMainPool->GetSlot(requestIdInner);
UINT32 tag = SensorTimestamp;
if (NULL != pInputSlot)
{
UINT64* pTimestamp = static_cast<UINT64*>(pInputSlot->GetMetadataByTag(tag));
if (NULL != pTimestamp)
{
pMainSlot->SetMetadataByTag(tag, pTimestamp, 1, GetPipelineIdentifierString());
}
else
{
UINT64 timeStamp = 0;
pMainSlot->SetMetadataByTag(tag, &timeStamp, 1, GetPipelineIdentifierString());
CAMX_LOG_WARN(CamxLogGroupCore, "Timestamp tag found! %p", pTimestamp);
}
pMainSlot->PublishMetadataList(&tag, 1);
SendOfflineShutterNotification(requestIdInner, pTimestamp);
}
else
{
CAMX_LOG_ERROR(CamxLogGroupCore, "Pipeline::%s Metadata slots not found input %p main %p",
GetPipelineIdentifierString(), pInputSlot, pMainSlot);
}
}
// Publish vendor tag to indicate if request has video buffer or not
PublishRequestHasVideoBufferTag(pPipelineRequestData);
}
else
{
CAMX_LOG_ERROR(CamxLogGroupCore, "PartialDeepCopy() failed perRequestIdIndex=%u", perRequestIdIndex);
}
m_lastSubmittedRequestId = CamX::Utils::MaxUINT64(pCaptureRequest->requestId, m_lastSubmittedRequestId);
CAMX_LOG_VERBOSE(CamxLogGroupCore, "Pipeline::%s last submitted request updated to %llu",
GetPipelineIdentifierString(), m_lastSubmittedRequestId);
// Check if node recources acquired before process request, Acquire node recources if not yet acquired
// This can happen in early PCR usecase
if (CamxResultSuccess == result)
{
result = CallNodeAcquireResources();
if (CamxResultSuccess != result)
{
CAMX_LOG_ERROR(CamxLogGroupCore, "Pipeline::%s Acquire resources failed",
GetPipelineIdentifierString());
}
}
// For PCRs with input buffer(s), shall we assume that the HAL have successfully waited on (all) the input
// acquire fence(s) before forwarding such a request to the topology? If YES, the topology need not wait on
// any fences on the SourceBuffer nodes. If NO, then the fence will have to be waited on.
// Since CSLCreateNativeFence is not implemented, it is expected that a CSLFence is created and passed on
// with each Input Buffer of an Offline/Reprocess PCR
if (CamxResultSuccess == result)
{
CAMX_ASSERT_MESSAGE(32 >= m_nodeCount, "Using a 32 bit bitmask to track node enable, and there are too many nodes");
// If this is too costly, try to check for flush within the loop and partially setup requests.
UINT32 nodesEnabled = 0;
for (UINT nodeIndex = 0; nodeIndex < m_nodeCount; nodeIndex++)
{
m_ppNodes[nodeIndex]->InvalidateRequest();
}
for (UINT nodeIndex = 0; nodeIndex < m_orderedNodeCount; nodeIndex++)
{
BOOL isNodeEnabled = FALSE;
m_ppOrderedNodes[nodeIndex]->SetupRequest(pPerBatchedFrameInfo,
pCurrentActiveStreams,
differentStreams,
requestId,
pCaptureRequest->CSLSyncID,
&isNodeEnabled);
if (TRUE == isNodeEnabled)
{
nodesEnabled = Utils::BitSet(nodesEnabled, nodeIndex);
}
else
{
CAMX_LOG_DRQ("Failed to setup Node %s for Pipeline %u RequestId %llu Session %p",
m_ppOrderedNodes[nodeIndex]->NodeIdentifierString(),
m_pipelineIndex, requestId, m_pSession);
}
}
// Queueing the nodes is deferred to ensure all nodes have completed setup before any are invoked, which could happen
// in the event of a previous request kicking the queue
UINT32 nodesSentToDRQ = 0;
for (UINT nodeIndex = 0; nodeIndex < m_orderedNodeCount ; nodeIndex++)
{
if (TRUE == Utils::IsBitSet(nodesEnabled, nodeIndex))
{
if (FALSE == GetFlushStatus())
{
CAMX_LOG_DRQ("Queueing Node: %s on pipeline: %d for new requestId: %llu",
m_ppOrderedNodes[nodeIndex]->NodeIdentifierString(),
m_pipelineIndex, requestId);
result = m_pDeferredRequestQueue->AddDeferredNode(requestId,
m_ppOrderedNodes[nodeIndex], NULL);
if (CamxResultSuccess == result)
{
nodesSentToDRQ = Utils::BitSet(nodesSentToDRQ, nodeIndex);
}
}
else
{
CAMX_LOG_DRQ("Skipping Node: %s on pipeline: %d for new requestId: %llu as Session %p in Flush state",
m_ppOrderedNodes[nodeIndex]->NodeIdentifierString(),
m_pipelineIndex, requestId, m_pSession);
m_ppOrderedNodes[nodeIndex]->Flush(requestId);
}
}
}
if (0 != nodesSentToDRQ)
{
// Consider any nodes now ready
m_pDeferredRequestQueue->DispatchReadyNodes();
}
// If no nodes got setup, a flush was called right before the setup, no nodes were sent to DRQ. Notify the session.
if (0 == nodesEnabled)
{
CAMX_LOG_ERROR(CamxLogGroupCore, "Returning Cancelled. Equal to flush");
result = CamxResultECancelledRequest;
}
}
if (CamxResultSuccess != result)
{
// If the request is cancelled/flushed, the next request stream setup should happen again.
CAMX_LOG_ERROR(CamxLogGroupCore, "Cancelling request. Reset the streamMask. res = %d", result);
m_lastRequestActiveStreamIdMask = 0;
}
if ((TRUE == GetFlushStatus()) && (result == CamxResultECancelledRequest))
{
CAMX_LOG_CONFIG(CamxLogGroupCore,
"Flush status is set for %s with cancel request, trigger request error for reqid %d",
GetPipelineIdentifierString(), requestId);
TriggerRequestError(requestId);
}
return result;
}
CamxResult Node::SetupRequest(
PerBatchedFrameInfo* pPerBatchedFrameInfo,
UINT* pCurrentActiveStreams,
BOOL differentStreams,
UINT64 requestId,
UINT64 syncId,
BOOL* pIsNodeEnabled)
{
CAMX_ASSERT(NULL != pIsNodeEnabled);
CAMX_ASSERT(NULL != pPerBatchedFrameInfo);
BOOL needPortsSetupUpdate = FALSE;
UINT requestIdIndex = requestId % MaxRequestQueueDepth;
PerRequestActivePorts* pRequestPorts = &m_perRequestInfo[requestIdIndex].activePorts;
m_tRequestId = requestId;
CamxResult result = CamxResultSuccess;
m_perRequestInfo[requestIdIndex].numUnsignaledFences = 0;
m_perRequestInfo[requestIdIndex].numUnprocessedFences = 0;
m_perRequestInfo[requestIdIndex].requestId = requestId;
m_perRequestInfo[requestIdIndex].partialMetadataComplete = 0;
m_perRequestInfo[requestIdIndex].metadataComplete = 0;
m_perRequestInfo[requestIdIndex].requestComplete = 0;
m_perRequestInfo[requestIdIndex].partialPublishedSet.clear();
memset(m_perRequestInfo[requestIdIndex].nodeProcessingStages, 0,
sizeof(m_perRequestInfo[requestIdIndex].nodeProcessingStages));
PerRequestOutputPortInfo* pPort = m_perRequestInfo[requestIdIndex].activePorts.pOutputPorts;
for (UINT portidx = 0; portidx < m_outputPortsData.numPorts; portidx++)
{
pPort[portidx].numPerReqInputPortsDisabled = 0;
}
SetRequestStatus(requestId, PerRequestNodeStatus::Setup);
// Set the CSL sync ID for this request ID
SetCSLSyncId(requestId, syncId);
if (NULL != pCurrentActiveStreams)
{
if (FALSE == IsRealTime())
{
// update node ports status if overriden by node due to limitations
needPortsSetupUpdate = IsPortStatusUpdatedByOverride();
// update node parameters which depends on status of ports
// This vitual function currently used by IPE node only to update number of passes.
// When node is dynamically enabled/disabled, there is corner case where m_numPasses do not set back for currently
// enabled Ports.
// Suppose for a request, offiline pipeline's node is disabled, and it disables all the ports in
// DisablePerRequestOutputPortLink().
// Once the node is enabled for a request, IsPortStatusUpdatedByOverride() updates m_inputPortDisableMask based
// on current active ports. Accordingly m_numPasses should be updated to correct value based on final
// m_inputPortDisableMask.
// Below API makes a call in IPE node and update the m_numPasses correctly.
UpdateNodeParamsOnPortStatus();
}
// Has the active streams or port status changed since the last request
if ((TRUE == differentStreams) || (TRUE == needPortsSetupUpdate))
{
CAMX_LOG_INFO(CamxLogGroupCore, "Setup Active streams afresh");
NewActiveStreamsSetup(*pCurrentActiveStreams);
}
}
// The new set of streams for the current request may have disabled the node. For e.g. if this is a Node with
// one sink port and that sink port is not active for the current request then the entire node is disabled
if (TRUE == IsNodeEnabled())
{
result = SetupRequestOutputPorts(pPerBatchedFrameInfo);
result = SetupRequestInputPorts(pPerBatchedFrameInfo);
*pIsNodeEnabled = TRUE;
}
else
{
UINT tag = GetNodeCompleteProperty();
const UINT one = 1;
const VOID* pOne[1] = { &one };
WriteDataList(&tag, pOne, &one, 1);
SetRequestStatus(requestId, PerRequestNodeStatus::Running);
ProcessPartialMetadataDone(m_tRequestId);
ProcessMetadataDone(m_tRequestId);
ProcessRequestIdDone(m_tRequestId);
DisablePerRequestOutputPortLink(m_tRequestId);
*pIsNodeEnabled = FALSE;
}
return result;
}
mark当前的camxnode和requestId,将两者绑定在一起
result = m_pDeferredRequestQueue->AddDeferredNode(requestId,
m_ppOrderedNodes[nodeIndex], NULL);
vendor\qcom\proprietary\camx\src\core\camxdeferredrequestqueue.cpp
VOID DeferredRequestQueue::DispatchReadyNodes()
{
CAMX_TRACE_SYNC_BEGIN_F(CamxLogGroupCore, "DeferredRequestQueue::DispatchReadyNodes");
// If preempt dependency enabled and dependency registered for preemption,
// clear node dependency in deferred list first.
if (TRUE == m_preemptDependency.isPreemptDependencyEnabled)
{
m_pDeferredQueueLock->Lock();
LightweightDoublyLinkedListNode* pDeferred = m_deferredNodes.Head();
while (NULL != pDeferred)
{
Dependency* pDependency = static_cast<Dependency*>(pDeferred->pData);
if ((NULL != pDependency) &&
(((TRUE == pDependency->preemptable) &&
(FALSE == pDependency->isInternalDependency) &&
(FALSE == m_preemptDependency.pipelineDepenency)) ||
((TRUE == m_preemptDependency.pipelineDepenency) &&
(m_preemptDependency.pipelineIndex == pDependency->pNode->GetPipelineId()))))
{
CAMX_LOG_DRQ("Remove dependencies for Node: %s, request: %llu, seqID %d",
pDependency->pNode->NodeIdentifierString(),
pDependency->requestId,
pDependency->processSequenceId);
RemoveAllDependencies(pDependency);
}
if (NULL != (m_deferredNodes.FindByValue(pDependency)))
{
pDeferred = LightweightDoublyLinkedList::NextNode(pDeferred);
}
else
{
// pDeferred is removed from deferred list to ready list
pDeferred = NULL;
}
}
m_pDeferredQueueLock->Unlock();
}
while (0 < m_readyNodes.NumNodes())
{
LightweightDoublyLinkedListNode* pReady = NULL;
Dependency* pDependency = NULL;
m_pReadyQueueLock->Lock();
if (0 < m_readyNodes.NumNodes())
{
pReady = m_readyNodes.Head();
pDependency = static_cast<Dependency*>(pReady->pData);
m_readyNodes.RemoveNode(pReady);
}
m_pReadyQueueLock->Unlock();
// Dispatch and remove all completed subscribers from the deferred node subscription list
if (NULL != pReady)
{
CAMX_FREE(pReady);
CAMX_ASSERT(NULL != pDependency);
if (NULL != pDependency)
{
if (NULL != pDependency->pChiFenceCallback)
{
pDependency->pChiFenceCallback(pDependency->pChiFences[0]->hChiFence, pDependency->pUserData);
}
UINT64 id = reinterpret_cast<UINT64>(pDependency);
CAMX_TRACE_ASYNC_END_F(CamxLogGroupDRQ, id, "Deferred Node %s", pDependency->pNode->NodeIdentifierString());
CAMX_LOG_DRQ("Posting job for Node %s, request %llu seqID %d",
pDependency->pNode->NodeIdentifierString(),
pDependency->requestId,
pDependency->processSequenceId);
// Fire the deferred node processing
VOID* pData[] = {pDependency, NULL};
CamxResult result = m_pThreadManager->PostJob(m_hDeferredWorker, NULL, &pData[0], FALSE, FALSE);
if (CamxResultSuccess != result)
{
if (NULL != pDependency)
{
CAMX_LOG_ERROR(CamxLogGroupCore, "Failed to post ProcessRequest job for Node %s, request %llu seqID %d",
pDependency->pNode->NodeIdentifierString(),
pDependency->requestId, pDependency->processSequenceId);
}
}
}
else
{
// No data for the entry to exist to track
CAMX_LOG_ERROR(CamxLogGroupDRQ, "No dependencies");
}
}
}
CAMX_TRACE_SYNC_END(CamxLogGroupCore);
}
m_pThreadManager–>PostJob(m_hDeferredWorker,…),其中m_hDeferredWorker注册的执行回调是DeferredWorkerWrapper函数
CamxResult DeferredRequestQueue::DeferredWorkerCore(
Dependency* pDependency)
{
CAMX_ASSERT(pDependency->pNode != NULL);
CamxResult result = CamxResultSuccess;
NodeProcessRequestData processRequest = { 0 };
Node* pNode = pDependency->pNode;
processRequest.processSequenceId = pDependency->processSequenceId;
processRequest.bindIOBuffers = pDependency->bindIOBuffers;
processRequest.isSequenceIdInternal = pDependency->isInternalDependency;
if (NULL != pNode)
{
CAMX_LOG_DRQ("DRQ dispatching node=%d Node::%s, request=%llu, seqId=%d, bindIOBuffers=%d",
pNode->Type(),
pNode->NodeIdentifierString(),
pDependency->requestId,
pDependency->processSequenceId,
pDependency->bindIOBuffers);
result = pNode->ProcessRequest(&processRequest, pDependency->requestId);
CAMX_LOG_DRQ("DRQ execute complete node=%d Node::%s, request=%llu, seqId=%d",
pNode->Type(),
pNode->NodeIdentifierString(),
pDependency->requestId,
pDependency->processSequenceId);
if (CamxResultSuccess == result)
{
CAMX_ASSERT_MESSAGE(processRequest.numDependencyLists <= MaxDependencies,
"Number of Dependency: %d is greater Max: %d",
processRequest.numDependencyLists, MaxDependencies);
for (UINT index = 0; index < processRequest.numDependencyLists; index++)
{
DependencyUnit* pDependencyInfo = &processRequest.dependencyInfo[index];
// Nodes should have an actual dependency if they report a dependency count. Any that doesnt may have messed up
// filling in the dependencies. e.g. set dependencies in index 1, expecting dependencies in index 0, but only
// incrementing numDependencyLists by one, for which adding the deferred node would skip the actual dependencies
// Loop below checks that nodes didnt set dependencies above the count as well
// Disabling this assert by default as nodes are now allowed to report a dependency without setting a mask bit
// CAMX_ASSERT_MESSAGE(TRUE == Node::HasAnyDependency(pDependencyInfo),
// "Node %s reported dependency %u without actual dependency", pNode->Name(), index);
result = AddDeferredNode(pDependency->requestId, pNode, pDependencyInfo);
}
#if ASSERTS_ENABLED
for (UINT index = processRequest.numDependencyLists; index < MaxDependencies; index++)
{
// Any dependencies set in entries outside of numDependencyLists will not be considered, will be dropped, and
// processing expected to occurred will not
CAMX_ASSERT(FALSE == Node::HasAnyDependency(pDependencyInfo));
}
#endif // ASSERTS_ENABLED
}
else if (CamxResultECancelledRequest == result)
{
// returning success as request is intended to be dropped for flush call
result = CamxResultSuccess;
}
}
else
{
CAMX_LOG_PERF_INFO(CamxLogGroupCore, "DRQ dispatching Chi fence callback");
// suport only one chi fence for now
CAMX_ASSERT(1 == pDependency->chiFenceCount);
pDependency->pChiFenceCallback(pDependency->pChiFences[0]->hChiFence, pDependency->pUserData);
}
// Consider any nodes ready immediately
DispatchReadyNodes();
return result;
}
CamxResult Node::ProcessRequest(
NodeProcessRequestData* pNodeRequestData,
UINT64 requestId)
{
CAMX_ASSERT(pNodeRequestData != NULL);
// Saving the value of m_parallelProcessRequests in a local bool variable parallelProcessRequests in order to ensure that
// any change in m_parallelProcessRequests does not cause the m_pProcessRequestLock mutex to be always in locked state.
const BOOL parallelProcessRequests = m_parallelProcessRequests;
if (FALSE == parallelProcessRequests)
{
m_pProcessRequestLock->Lock();
}
// copy the requestId after acquiring the lock to avoid synchronization issues
m_tRequestId = requestId;
BOOL inErrorState = m_pPipeline->RequestInErrorState(requestId);
CamxResult result = CamxResultEFailed;
UINT requestIdIndex = requestId % MaxRequestQueueDepth;
INT32 processSequenceId = pNodeRequestData->processSequenceId;
BOOL bindIOBuffers = pNodeRequestData->bindIOBuffers;
BOOL isSequenceIdInternal = pNodeRequestData->isSequenceIdInternal;
UINT32 pipelineId = GetPipelineId();
pNodeRequestData->pCaptureRequest = m_pPipeline->GetRequest(requestId);
CAMX_TRACE_SYNC_BEGIN_F(CamxLogGroupCore,
"Node::%s ProcessRequest %llu Sequence %d bindIOBuffers %d",
NodeIdentifierString(),
requestId,
pNodeRequestData->processSequenceId,
pNodeRequestData->bindIOBuffers);
CAMX_LOG_DRQ("Node::%s ProcessRequest %llu", NodeIdentifierString(), m_tRequestId);
// Initially, set dependency pipeline id to own one
for (UINT32 i = 0; i < MaxDependencies; i++)
{
for (UINT32 j = 0; j < MaxProperties; j++)
{
pNodeRequestData->dependencyInfo[i].propertyDependency.pipelineIds[j] = pipelineId;
}
}
PerRequestActivePorts* pRequestPorts = &m_perRequestInfo[requestIdIndex].activePorts;
ExecuteProcessRequestData executeProcessData = { 0 };
executeProcessData.pNodeProcessRequestData = pNodeRequestData;
executeProcessData.pEnabledPortsInfo = pRequestPorts;
result = FillTuningModeData(reinterpret_cast<VOID**>(&executeProcessData.pTuningModeData));
CAMX_ASSERT(CamxResultSuccess == result);
if (0 == executeProcessData.pNodeProcessRequestData->processSequenceId)
{
if (TRUE == NodeHasDelayedNotification())
{
ProcessPartialMetadataDone(requestId);
ProcessMetadataDone(requestId);
}
// Set start of node processing of sequenceId 0
SetNodeProcessingTime(m_tRequestId, executeProcessData.pNodeProcessRequestData->processSequenceId, NodeStage::Start);
// Set buffer dependency for ports that has bypassable parent Node
SetPendingBufferDependency(&executeProcessData);
}
else if (TRUE == pNodeRequestData->isSequenceIdInternal)
{
InternalDependencySequenceId id;
id = static_cast<InternalDependencySequenceId>(executeProcessData.pNodeProcessRequestData->processSequenceId);
switch (id)
{
case ResolveDeferredInputBuffers:
// Update image buffer info for the port waiting on buffer dependency
UpdateBufferInfoforPendingInputPorts(pRequestPorts);
break;
default:
CAMX_LOG_ERROR(CamxLogGroupCore, "%s Unknown internal request sequence id: %d, reqid %llu",
NodeIdentifierString(), id, requestId);
result = CamxResultEInvalidState;
break;
}
if ((TRUE == CanDRQPreemptOnStopRecording()) && (TRUE == IsEndoOfStreamEnabled()))
{
// Check if current request has end of stream flag set for preempable node,
// If so set processSequenceId = -1.
CAMX_LOG_VERBOSE(CamxLogGroupCore, "Is end of stream enabled %d, reqid end of stream enabled on %llu",
IsEndoOfStreamEnabled(), GetEndoOfStreamRequestId());
pNodeRequestData->processSequenceId = -1;
}
else
{
// Reset sequenceId to 0 so derived node will not see base Node sequenceIds
pNodeRequestData->processSequenceId = 0;
}
}
BOOL hasInternalDependency = (TRUE == (pNodeRequestData->numDependencyLists > 0)) &&
(TRUE == pNodeRequestData->dependencyInfo[0].dependencyFlags.isInternalDependency);
if (TRUE == hasInternalDependency)
{
CAMX_LOG_VERBOSE(CamxLogGroupCore,
"%s has internal dependency for request: %llu. Bypassing EPR until dependency is met.",
NodeIdentifierString(),
requestId);
}
else
{
if (TRUE == m_pPipeline->GetFlushStatus())
{
result = CamxResultECancelledRequest;
}
if ((CamxResultSuccess == result) && (FALSE == inErrorState))
{
if (TRUE == executeProcessData.pNodeProcessRequestData->bindIOBuffers)
{
// If LateBinding is enabled, input and output ImageBuffers may not have backing buffers yet.
// If derived nodes set needBuffersOnDependencyMet for this sequenceId, that means, derived
// node is going to access input, output buffers now. Lets bind buffers to ImageBuffers if not yet.
result = BindInputOutputBuffers(executeProcessData.pEnabledPortsInfo, TRUE, TRUE);
if (CamxResultSuccess != result)
{
CAMX_LOG_ERROR(CamxLogGroupCore,
"Node::%s Req[%llu] processSequenceId[%d] Failed in Binding backing buffers "
"to input, output ImageBuffers, result=%s",
NodeIdentifierString(),
requestId, executeProcessData.pNodeProcessRequestData->processSequenceId,
Utils::CamxResultToString(result));
}
}
if (CamxResultSuccess == result)
{
SetNodeProcessingTime(m_tRequestId, executeProcessData.pNodeProcessRequestData->processSequenceId,
NodeStage::DependenciesMet);
SetRequestStatus(requestId, PerRequestNodeStatus::Running);
result = ExecuteProcessRequest(&executeProcessData);
SetNodeProcessingTime(m_tRequestId, executeProcessData.pNodeProcessRequestData->processSequenceId,
NodeStage::EPReqEnd);
}
}
// Flush the request if it was cancelled or completely failed
if ((CamxResultSuccess != result) || (TRUE == inErrorState))
{
CAMX_LOG_CONFIG(CamxLogGroupCore,
"Flush called on Node %s requestId %llu Sequence %u",
NodeIdentifierString(),
m_tRequestId,
pNodeRequestData->processSequenceId);
Flush(requestId);
}
// Print the log message with the right level and update the request status accordingly.
if ((CamxResultSuccess != result) || (TRUE == inErrorState))
{
if (CamxResultECancelledRequest == result)
{
CAMX_LOG_CONFIG(CamxLogGroupCore,
"Canceling RequestId %llu Sequence %u for Node: %s is in flush state.",
m_tRequestId,
pNodeRequestData->processSequenceId,
NodeIdentifierString());
SetRequestStatus(requestId, PerRequestNodeStatus::Cancelled);
}
else
{
CAMX_LOG_ERROR(CamxLogGroupCore,
"An Error occured with RequestId %llu Sequence %u for Node: %s inErrorState: %d"
" ExecuteProcessRequest returned with %s.",
m_tRequestId,
pNodeRequestData->processSequenceId,
NodeIdentifierString(),
inErrorState,
Utils::CamxResultToString(result));
SetRequestStatus(requestId, PerRequestNodeStatus::Error);
}
}
if ((CamxResultSuccess == result) && (FALSE == inErrorState))
{
// Check if node is registered for config done, send config done notification if no dependencies
if (0 == executeProcessData.pNodeProcessRequestData->numDependencyLists)
{
if (TRUE == m_nodeFlags.callNotifyConfigDone)
{
m_pPipeline->NotifyNodeConfigDone(requestId);
}
if (FALSE == m_perRequestInfo[requestId % MaxRequestQueueDepth].requestComplete)
{
SetRequestStatus(requestId, PerRequestNodeStatus::Submit);
CAMX_LOG_INFO(CamxLogGroupCore, "Submitted to HW: %s Id: %d", NodeIdentifierString(), requestId);
}
}
for (UINT index = 0; index < executeProcessData.pNodeProcessRequestData->numDependencyLists; index++)
{
// Start of next sequenceId
DependencyUnit* pDependencyInfo = &executeProcessData.pNodeProcessRequestData->dependencyInfo[index];
SetNodeProcessingTime(m_tRequestId, pDependencyInfo->processSequenceId,
NodeStage::Start);
}
}
if ((FALSE == m_derivedNodeHandlesMetaDone) || (CamxResultSuccess != result) || (TRUE == inErrorState))
{
BOOL hasDependency = FALSE;
for (UINT index = 0; index < executeProcessData.pNodeProcessRequestData->numDependencyLists; index++)
{
DependencyUnit* pDependencyInfo = &executeProcessData.pNodeProcessRequestData->dependencyInfo[index];
if (TRUE == HasAnyDependency(pDependencyInfo))
{
hasDependency = TRUE;
break;
}
}
if (FALSE == hasDependency)
{
ProcessPartialMetadataDone(requestId);
ProcessMetadataDone(requestId);
}
}
if ((0 == pNodeRequestData->numDependencyLists) || (CamxResultSuccess != result))
{
UINT tag = GetNodeCompleteProperty();
const UINT one = 1;
const VOID* pOne[1] = { &one };
WriteDataList(&tag, pOne, &one, 1);
}
// If node is not having any partial Tags to be published then node should send
// Notification to Pipeline
if ((0 == m_publishTagArray.partialTagCount) ||
(m_perRequestInfo[requestIdIndex].partialPublishedSet.size() == m_publishTagArray.partialTagCount))
{
CAMX_LOG_VERBOSE(CamxLogGroupCore, "partialTagCount = %d partialPublishedSet.size=%d",
m_publishTagArray.partialTagCount, m_perRequestInfo[requestIdIndex].partialPublishedSet.size());
ProcessPartialMetadataDone(requestId);
}
// For offline/reprocess requests, as the fence for a source buffer node is external we don't have the callback
// We need to do either of the following -
// 1) Release the input ImageBuffer when all the output buffer fences are signaled for the source buffer node,
// but that may be deemed too defensive, OR
// 2) Use a pool (large enough) for container ImageBuffers for offline requests and recycle the LRU one
// Going for (1) now, but need to be discussed further
CAMX_LOG_CONFIG(CamxLogGroupCore, "%s Complete ProcessRequest %llu", NodeIdentifierString(), requestId);
}
CAMX_TRACE_SYNC_END(CamxLogGroupCore);
if (FALSE == parallelProcessRequests)
{
m_pProcessRequestLock->Unlock();
}
UINT nodeId = Type();
UINT nodeInstanceId = InstanceID();
auto hPipeline = m_pPipeline->GetPipelineDescriptor();
BINARY_LOG(LogEvent::Node_ProcessRequest, hPipeline, nodeId, nodeInstanceId, requestId, inErrorState, processSequenceId,
isSequenceIdInternal, bindIOBuffers, hasInternalDependency, result);
return result;
}
CamxResult ChiNodeWrapper::ExecuteProcessRequest(
ExecuteProcessRequestData* pExecuteProcessRequestData)
{}
根据设置的nodecallbace会回调到算法node中,这里开始进入算法流程
CDKResult cdkResult = m_nodeCallbacks.pProcessRequest(&info)