summaryrefslogtreecommitdiff
path: root/stats/ipa_ipu3_stats.cpp
blob: c14bd7ec13fb3bc06a757013b5da74cf16c93635 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* SPDX-License-Identifier: Apache-2.0 */
/*
 * Copyright (C) 2017 Intel Corporation.
 *
 * IPAIPU3Stats.cpp: Generate statistics in IA AIQ consumable format.
 */

#include "ipa_ipu3_stats.h"

#include <libcamera/base/log.h>

#include "ipu3_all_stats.h"

namespace libcamera::ipa::ipu3 {

LOG_DEFINE_CATEGORY(IPAIPU3Stats)

IPAIPU3Stats::IPAIPU3Stats()
{
	aiqStatsInputParams_ = {};

	/* \todo: Is this fine here or we need separate helper? */
	rgbsGridBuffPool_ = std::make_shared<SharedItemPool<ia_aiq_rgbs_grid>>("RgbsGridBuffPool");
	afFilterBuffPool_ = std::make_shared<SharedItemPool<ia_aiq_af_grid>>("AfFilterBuffPool");
#define PUBLIC_STATS_POOL_SIZE 9 /* comes from CrOS */
	int ret = allocateStatBufferPools(PUBLIC_STATS_POOL_SIZE);
	if (ret < 0)
		LOG(IPAIPU3Stats, Error) << "Failed to allocate stats grid buffers";
}

IPAIPU3Stats::~IPAIPU3Stats()
{
	freeStatBufferPools();
	rgbsGridBuffPool_.reset();
	afFilterBuffPool_.reset();
}

ia_aiq_statistics_input_params *
IPAIPU3Stats::getInputStatsParams(int frame, aiq::AiqResults *results,
				  const ipu3_uapi_stats_3a *stats)
{
	aiqStatsInputParams_.frame_id = frame;
	aiqStatsInputParams_.frame_ae_parameters = results->ae();
	aiqStatsInputParams_.frame_af_parameters = results->af();
	aiqStatsInputParams_.awb_results = results->awb();
	aiqStatsInputParams_.frame_pa_parameters = results->pa();
	aiqStatsInputParams_.frame_sa_parameters = results->sa();
	aiqStatsInputParams_.camera_orientation = ia_aiq_camera_orientation_unknown;

	IPU3AllStats::ipu3_stats_all_stats outStats;
	memset(&outStats, 0, sizeof(IPU3AllStats::ipu3_stats_all_stats));
	IPU3AllStats::ipu3_stats_get_3a(&outStats, stats);

	std::shared_ptr<ia_aiq_rgbs_grid> rgbsGrid = nullptr;
	std::shared_ptr<ia_aiq_af_grid> afGrid = nullptr;
	int ret = afFilterBuffPool_->acquireItem(afGrid);
	ret |= rgbsGridBuffPool_->acquireItem(rgbsGrid);
	if (ret != 0 || afGrid.get() == nullptr || rgbsGrid.get() == nullptr) {
		LOG(IPAIPU3Stats, Error) << "Failed to acquire 3A buffers from pools";
		return nullptr;
	}

	IPU3AllStats::intel_skycam_statistics_convert(outStats.ia_css_4a_statistics,
						      rgbsGrid.get(), afGrid.get());

	const ia_aiq_rgbs_grid *rgbsGridPtr = rgbsGrid.get();
	const ia_aiq_af_grid *afGridPtr = afGrid.get();

	aiqStatsInputParams_.num_rgbs_grids = 1;
	aiqStatsInputParams_.rgbs_grids = &rgbsGridPtr;
	aiqStatsInputParams_.num_af_grids = 1;
	aiqStatsInputParams_.af_grids = &afGridPtr;

	aiqStatsInputParams_.hdr_rgbs_grid = nullptr;
	aiqStatsInputParams_.depth_grids = nullptr;

	return &aiqStatsInputParams_;
}

int IPAIPU3Stats::allocateStatBufferPools(int numBufs)
{
	int ret = afFilterBuffPool_->init(numBufs);
	ret |= rgbsGridBuffPool_->init(numBufs);
	if (ret != 0) {
		LOG(IPAIPU3Stats, Error) << "Failed to initialize 3A statistics pools";
		freeStatBufferPools();
		return -ENOMEM;
	}
#define IPU3_MAX_STATISTICS_WIDTH 80
#define IPU3_MAX_STATISTICS_HEIGHT 60
	int maxGridSize = IPU3_MAX_STATISTICS_WIDTH * IPU3_MAX_STATISTICS_HEIGHT;
	std::shared_ptr<ia_aiq_rgbs_grid> rgbsGrid = nullptr;
	std::shared_ptr<ia_aiq_af_grid> afGrid = nullptr;

	for (int allocated = 0; allocated < numBufs; allocated++) {
		ret = afFilterBuffPool_->acquireItem(afGrid);
		ret |= rgbsGridBuffPool_->acquireItem(rgbsGrid);

		if (ret != 0 || afGrid.get() == nullptr ||
		    rgbsGrid.get() == nullptr) {
			LOG(IPAIPU3Stats, Error) << "Failed to acquire memory from pools";
			freeStatBufferPools();
			return -ENOMEM;
		}

		rgbsGrid->blocks_ptr = new rgbs_grid_block[maxGridSize];
		rgbsGrid->grid_height = 0;
		rgbsGrid->grid_width = 0;

		afGrid->filter_response_1 = new int[maxGridSize];
		afGrid->filter_response_2 = new int[maxGridSize];
		afGrid->block_height = 0;
		afGrid->block_width = 0;
		afGrid->grid_height = 0;
		afGrid->grid_width = 0;
	}

	return 0;
}

void IPAIPU3Stats::freeStatBufferPools()
{
	if (!afFilterBuffPool_->isFull() || !rgbsGridBuffPool_->isFull()) {
		/* We will leak if we errored out in allocateStatBufferPools*/
		if (!afFilterBuffPool_->isFull())
			LOG(IPAIPU3Stats, Warning) << "AfFilterBuffPool is leaking";
		if (!rgbsGridBuffPool_->isFull())
			LOG(IPAIPU3Stats, Warning) << "RgbsGridBuffPool is leaking";
	}

	int ret;
	size_t availableItems = afFilterBuffPool_->availableItems();
	std::shared_ptr<ia_aiq_af_grid> afGrid = nullptr;
	for (size_t i = 0; i < availableItems; i++) {
		ret = afFilterBuffPool_->acquireItem(afGrid);
		if (ret == 0 && afGrid.get() != nullptr) {
			delete[] afGrid->filter_response_1;
			afGrid->filter_response_1 = nullptr;
			delete[] afGrid->filter_response_2;
			afGrid->filter_response_2 = nullptr;
		} else {
			LOG(IPAIPU3Stats, Warning)
				<< "Could not acquire AF filter response "
				<< i << "for deletion - leak?";
		}
	}

	availableItems = rgbsGridBuffPool_->availableItems();
	std::shared_ptr<ia_aiq_rgbs_grid> rgbsGrid = nullptr;
	for (size_t i = 0; i < availableItems; i++) {
		ret = rgbsGridBuffPool_->acquireItem(rgbsGrid);
		if (ret == 0 && rgbsGrid.get() != nullptr) {
			delete[] rgbsGrid->blocks_ptr;
			rgbsGrid->blocks_ptr = nullptr;
		} else {
			LOG(IPAIPU3Stats, Warning)
				<< "Could not acquire RGBS grid " << i
				<< "for deletion - leak?";
		}
	}
}

} /* namespace libcamera::ipa::ipu3 */