/* SPDX-License-Identifier: Apache-2.0 */ /* * Copyright (C) 2021, Google Inc. * * aiq_results.cpp - Intel IA Imaging library C++ wrapper * * AIQ results container, capable of depth copies and assignments * of the aiq result structures. */ #include "aiq/aiq_results.h" #include #include namespace libcamera { LOG_DEFINE_CATEGORY(AIQResults) namespace ipa::ipu3::aiq { AiqResults::AiqResults() { /* Initialise AE */ ae_.exposures = &aeExposureResult_; ae_.exposures->exposure = &aeExposureParameters_; ae_.exposures->sensor_exposure = &aeSensorParaemeters_; ae_.weight_grid = &aeWeightGrid_; ae_.weight_grid->weights = aeWeights_; ae_.flashes = aeFlashes_; /* GBCE */ gbce_.r_gamma_lut = RGammaLut_; gbce_.g_gamma_lut = GGammaLut_; gbce_.b_gamma_lut = BGammaLut_; gbce_.gamma_lut_size = MAX_GAMMA_LUT_SIZE; gbce_.tone_map_lut = toneMapLut_; gbce_.tone_map_lut_size = MAX_NUM_TONE_MAP_LUTS; /* Initialise afBracket */ afBracket_.distances_bracketing = &distanceBracketing_; afBracket_.lens_positions_bracketing = &lensPosBracketing_; /* Initialise PA */ pa_.preferred_acm = &prefAcm_; pa_.preferred_acm->hue_of_sectors = &hueOfSectors_; pa_.preferred_acm->advanced_color_conversion_matrices = &advancedColorConversionMatrices_; pa_.ir_weight = &irWeight_; pa_.ir_weight->ir_weight_grid_R = &irWeightGridR_; pa_.ir_weight->ir_weight_grid_G = &irWeightGridG_; pa_.ir_weight->ir_weight_grid_B = &irWeightGridB_; /* Initialise SA */ channelGr_.reserve(DEFAULT_LSC_SIZE); channelGb_.reserve(DEFAULT_LSC_SIZE); channelR_.reserve(DEFAULT_LSC_SIZE); channelB_.reserve(DEFAULT_LSC_SIZE); sa_.channel_gr = channelGr_.data(); sa_.channel_gb = channelGb_.data(); sa_.channel_r = channelR_.data(); sa_.channel_b = channelB_.data(); } AiqResults::AiqResults(const AiqResults &other) :AiqResults() { setAe(&other.ae_); setAf(&other.af_); setAfBracket(&other.afBracket_); setAwb(&other.awb_); setGbce(&other.gbce_); setDetectedSceneMode(other.detectedSceneMode_); setPa(&other.pa_); setSa(&other.sa_); } AiqResults& AiqResults::operator=(const AiqResults &other) { setAe(&other.ae_); setAf(&other.af_); setAfBracket(&other.afBracket_); setAwb(&other.awb_); setGbce(&other.gbce_); setDetectedSceneMode(other.detectedSceneMode_); setPa(&other.pa_); setSa(&other.sa_); return *this; } void AiqResults::setAe(const ia_aiq_ae_results *ae) { /* Todo: Potentially Requires copying * ia_aiq_aperture_control *aperture_control; */ ASSERT(ae); if (!ae) { LOG(AIQResults, Error) << "Invalid AE argument"; return; } ae_.lux_level_estimate = ae->lux_level_estimate; ae_.flicker_reduction_mode = ae->flicker_reduction_mode; ae_.multiframe = ae->multiframe; ae_.num_flashes = ae->num_flashes; ae_.num_exposures = ae->num_exposures; ae_.exposures->converged = ae->exposures->converged; ae_.exposures->distance_from_convergence = ae->exposures->distance_from_convergence; ae_.exposures->exposure_index = ae->exposures->exposure_index; if (ae_.exposures->exposure && ae->exposures->exposure) { *ae_.exposures->exposure = *ae->exposures->exposure; } else { LOG(AIQResults, Error) << "Not copying AE Exposure"; } if (ae_.exposures->sensor_exposure && ae->exposures->sensor_exposure) { *ae_.exposures->sensor_exposure = *ae->exposures->sensor_exposure; } else { LOG(AIQResults, Error) << "Not copying AE Sensor Exposure"; } // Copy weight grid if (ae_.weight_grid && ae->weight_grid && ae_.weight_grid->weights && ae->weight_grid->weights) { ae_.weight_grid->width = ae->weight_grid->width; ae_.weight_grid->height = ae->weight_grid->height; unsigned int gridElements = ae->weight_grid->width * ae->weight_grid->height; gridElements = std::clamp(gridElements, 1, MAX_AE_GRID_SIZE); std::copy_n(ae->weight_grid->weights, gridElements, ae_.weight_grid->weights); } else { LOG(AIQResults, Error) << "Not copying AE Weight Grids"; } // Copy the flash info structure if (ae_.flashes && ae->flashes) { std::copy_n(ae->flashes, NUM_FLASH_LEDS, ae_.flashes); } else { LOG(AIQResults, Error) << "Not copying AE Flashes"; } } void AiqResults::setAf(const ia_aiq_af_results *af) { ASSERT(af); af_.status = af->status; af_.current_focus_distance = af->current_focus_distance; af_.next_lens_position = af->next_lens_position; af_.lens_driver_action = af->lens_driver_action; af_.use_af_assist = af->use_af_assist; af_.final_lens_position_reached = af->final_lens_position_reached; } void AiqResults::setAfBracket(const ia_aiq_af_bracket_results *afBracket) { ASSERT(afBracket); /* todo: * Distances Bracketing and lens_positions_bracketing are arrays, * but it's not clear what size they are. */ afBracket_.distances_bracketing = afBracket->distances_bracketing; afBracket_.lens_positions_bracketing = afBracket->lens_positions_bracketing; } void AiqResults::setAwb(const ia_aiq_awb_results *awb) { ASSERT(awb); awb_.accurate_r_per_g = awb->accurate_r_per_g; awb_.accurate_b_per_g = awb->accurate_b_per_g; awb_.final_r_per_g = awb->final_r_per_g; awb_.final_b_per_g = awb->final_b_per_g; awb_.cct_estimate = awb->cct_estimate; awb_.distance_from_convergence = awb->distance_from_convergence; } void AiqResults::setGbce(const ia_aiq_gbce_results *gbce) { ASSERT(gbce); if (gbce->gamma_lut_size > 0) { ASSERT(gbce->gamma_lut_size <= MAX_GAMMA_LUT_SIZE); gbce_.gamma_lut_size = gbce->gamma_lut_size; std::copy_n(gbce->r_gamma_lut, gbce->gamma_lut_size, gbce_.r_gamma_lut); std::copy_n(gbce->b_gamma_lut, gbce->gamma_lut_size, gbce_.b_gamma_lut); std::copy_n(gbce->g_gamma_lut, gbce->gamma_lut_size, gbce_.g_gamma_lut); } else { LOG(AIQResults, Error) << "Not copying Gamma LUT channels"; } if (gbce->tone_map_lut_size > 0) { gbce_.tone_map_lut_size = gbce->tone_map_lut_size; std::copy_n(gbce->tone_map_lut, gbce->tone_map_lut_size, gbce_.tone_map_lut); } else { LOG(AIQResults, Error) << "Not copying Tone Mapping Gain LUT"; } } void AiqResults::setDetectedSceneMode(const ia_aiq_scene_mode dsm) { detectedSceneMode_ = dsm; } void AiqResults::setPa(const ia_aiq_pa_results *pa) { ASSERT(pa); std::copy_n(&pa->color_conversion_matrix[0][0], MAX_COLOR_CONVERSION_MATRIX * MAX_COLOR_CONVERSION_MATRIX, &pa_.color_conversion_matrix[0][0]); if (pa_.preferred_acm && pa->preferred_acm) { pa_.preferred_acm->sector_count = pa->preferred_acm->sector_count; std::copy_n(pa->preferred_acm->hue_of_sectors, pa->preferred_acm->sector_count, pa_.preferred_acm->hue_of_sectors); std::copy_n(pa->preferred_acm->advanced_color_conversion_matrices[0][0], pa->preferred_acm->sector_count, pa_.preferred_acm->advanced_color_conversion_matrices[0][0]); } else { LOG(AIQResults, Error) << "Not copying PA hue of sectors"; } if (pa_.ir_weight && pa->ir_weight) { pa_.ir_weight->height = pa->ir_weight->height; pa_.ir_weight->width = pa->ir_weight->width; std::copy_n(pa->ir_weight->ir_weight_grid_R, pa->ir_weight->height * pa->ir_weight->width, pa_.ir_weight->ir_weight_grid_R); std::copy_n(pa->ir_weight->ir_weight_grid_G, pa->ir_weight->height * pa->ir_weight->width, pa_.ir_weight->ir_weight_grid_G); std::copy_n(pa->ir_weight->ir_weight_grid_B, pa->ir_weight->height * pa->ir_weight->width, pa_.ir_weight->ir_weight_grid_B); } else { LOG(AIQResults, Error) << "Not copying IR weight"; } pa_.black_level = pa->black_level; pa_.color_gains = pa->color_gains; pa_.linearization = pa->linearization; pa_.saturation_factor = pa->saturation_factor; pa_.brightness_level = pa->brightness_level; } void AiqResults::setSa(const ia_aiq_sa_results *sa) { ASSERT(sa && sa->channel_r && sa->channel_gr && sa->channel_gb && sa->channel_b); sa_.width = sa->width; sa_.height = sa->height; sa_.lsc_update = sa->lsc_update; uint32_t lscGridSize = sa_.width * sa_.height; /* Check against one of the vectors but resize applicable to all. */ if (channelGr_.size() < lscGridSize) { channelGr_.resize(lscGridSize); channelGb_.resize(lscGridSize); channelR_.resize(lscGridSize); channelB_.resize(lscGridSize); /* Update the SA data pointers to new memory locations. */ sa_.channel_gr = channelGr_.data(); sa_.channel_gb = channelGb_.data(); sa_.channel_r = channelR_.data(); sa_.channel_b = channelB_.data(); } if (sa->lsc_update) { std::copy_n(sa->channel_gr, lscGridSize, sa_.channel_gr); std::copy_n(sa->channel_gb, lscGridSize, sa_.channel_gb); std::copy_n(sa->channel_r, lscGridSize, sa_.channel_r); std::copy_n(sa->channel_b, lscGridSize, sa_.channel_b); } else { LOG(AIQResults, Debug) << "Not copying LSC tables."; } std::copy_n(&sa->light_source[0], CMC_NUM_LIGHTSOURCES, &sa_.light_source[0]); sa_.scene_difficulty = sa->scene_difficulty; sa_.num_patches = sa->num_patches; sa_.covered_area = sa->covered_area; sa_.frame_params = sa->frame_params; } AiqResults& AiqResultsRingBuffer::operator[](unsigned int index) { return std::array::operator[](index % bufferSize); } const AiqResults& AiqResultsRingBuffer::operator[](unsigned int index) const { return std::array::operator[](index % bufferSize); } void AiqResultsRingBuffer::reset() { start_ = end_ = size_ = 0; } void AiqResultsRingBuffer::extendOne() { end_ = (end_ + 1) % bufferSize; size_ = std::min(size_ + 1, bufferSize); if (size_ == bufferSize) { start_ = end_; } } AiqResults& AiqResultsRingBuffer::latest() { unsigned int i = (end_ + bufferSize - 1) % bufferSize; return operator[](i); } AiqResults& AiqResultsRingBuffer::searchBackward( const std::function pred, AiqResults& def) { if (size_ == 0) return def; unsigned int i = (end_ + bufferSize - 1) % bufferSize; while (i != start_) { if (pred(operator[](i))) { return operator[](i); } i = (i + bufferSize - 1) % bufferSize; } return def; } } /* namespace ipa::ipu3::aiq */ } /* namespace libcamera */