You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
211 lines
6.5 KiB
211 lines
6.5 KiB
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <pthread.h>
|
|
#include <chrono>
|
|
#include <ctime>
|
|
#include <iomanip>
|
|
#include <fcntl.h>
|
|
#include <fstream>
|
|
#include <log/log.h>
|
|
#include <memory>
|
|
#include <sstream>
|
|
#include <sys/epoll.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <tuple>
|
|
#include <unistd.h>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include <drm/msm_drm.h>
|
|
#include <drm/msm_drm_pp.h>
|
|
#include <xf86drm.h>
|
|
#include <xf86drmMode.h>
|
|
|
|
#include "histogram_collector.h"
|
|
#include "ringbuffer.h"
|
|
|
|
constexpr static auto implementation_defined_max_frame_ringbuffer = 300;
|
|
|
|
histogram::HistogramCollector::HistogramCollector() :
|
|
histogram(histogram::Ringbuffer::create(
|
|
implementation_defined_max_frame_ringbuffer, std::make_unique<histogram::DefaultTimeKeeper>())) {
|
|
}
|
|
|
|
histogram::HistogramCollector::~HistogramCollector() {
|
|
stop();
|
|
}
|
|
|
|
namespace {
|
|
static constexpr size_t numBuckets = 8;
|
|
static_assert((HIST_V_SIZE % numBuckets) == 0,
|
|
"histogram cannot be rebucketed to smaller number of buckets");
|
|
static constexpr int bucket_compression = HIST_V_SIZE / numBuckets;
|
|
|
|
std::array<uint64_t, numBuckets> rebucketTo8Buckets(std::array<uint64_t, HIST_V_SIZE> const& frame) {
|
|
std::array<uint64_t, numBuckets> bins;
|
|
bins.fill(0);
|
|
for (auto i = 0u; i < HIST_V_SIZE; i++)
|
|
bins[i / bucket_compression] += frame[i];
|
|
return bins;
|
|
}
|
|
}
|
|
|
|
std::string histogram::HistogramCollector::Dump() const {
|
|
uint64_t num_frames;
|
|
std::array<uint64_t, HIST_V_SIZE> all_sample_buckets;
|
|
std::tie(num_frames, all_sample_buckets) = histogram->collect_cumulative();
|
|
std::array<uint64_t, numBuckets> samples = rebucketTo8Buckets(all_sample_buckets);
|
|
|
|
std::stringstream ss;
|
|
ss << "Color Sampling, dark (0.0) to light (1.0): sampled frames: " << num_frames << '\n';
|
|
if (num_frames == 0) {
|
|
ss << "\tno color statistics collected\n";
|
|
return ss.str();
|
|
}
|
|
|
|
ss << std::fixed << std::setprecision(3);
|
|
ss << "\tbucket\t\t: # of displayed pixels at bucket value\n";
|
|
for (auto i = 0u; i < samples.size(); i++) {
|
|
ss << "\t" << i / static_cast<float>(samples.size()) <<
|
|
" to " << ( i + 1 ) / static_cast<float>(samples.size()) << "\t: " <<
|
|
samples[i] << '\n';
|
|
}
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
HWC2::Error histogram::HistogramCollector::collect(
|
|
uint64_t max_frames,
|
|
uint64_t timestamp,
|
|
int32_t out_samples_size[NUM_HISTOGRAM_COLOR_COMPONENTS],
|
|
uint64_t* out_samples[NUM_HISTOGRAM_COLOR_COMPONENTS],
|
|
uint64_t* out_num_frames) const {
|
|
|
|
if (!out_samples_size || !out_num_frames)
|
|
return HWC2::Error::BadParameter;
|
|
|
|
out_samples_size[0] = 0;
|
|
out_samples_size[1] = 0;
|
|
out_samples_size[2] = numBuckets;
|
|
out_samples_size[3] = 0;
|
|
|
|
uint64_t num_frames;
|
|
std::array<uint64_t, HIST_V_SIZE> samples;
|
|
|
|
if (max_frames == 0 && timestamp == 0) {
|
|
std::tie(num_frames, samples) = histogram->collect_cumulative();
|
|
} else if (max_frames == 0) {
|
|
std::tie(num_frames, samples) = histogram->collect_after(timestamp);
|
|
} else if (timestamp == 0) {
|
|
std::tie(num_frames, samples) = histogram->collect_max(max_frames);
|
|
} else {
|
|
std::tie(num_frames, samples) = histogram->collect_max_after(timestamp, max_frames);
|
|
}
|
|
|
|
auto samples_rebucketed = rebucketTo8Buckets(samples);
|
|
*out_num_frames = num_frames;
|
|
if (out_samples && out_samples[2])
|
|
memcpy(out_samples[2], samples_rebucketed.data(), sizeof(uint64_t) * samples_rebucketed.size());
|
|
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
HWC2::Error histogram::HistogramCollector::getAttributes(int32_t* format,
|
|
int32_t* dataspace,
|
|
uint8_t* supported_components) const {
|
|
if (!format || !dataspace || !supported_components)
|
|
return HWC2::Error::BadParameter;
|
|
|
|
*format = HAL_PIXEL_FORMAT_HSV_888;
|
|
*dataspace = HAL_DATASPACE_UNKNOWN;
|
|
*supported_components = HWC2_FORMAT_COMPONENT_2;
|
|
return HWC2::Error::None;
|
|
}
|
|
|
|
void histogram::HistogramCollector::start() {
|
|
start(implementation_defined_max_frame_ringbuffer);
|
|
}
|
|
|
|
void histogram::HistogramCollector::start(uint64_t max_frames) {
|
|
std::unique_lock<decltype(mutex)> lk(mutex);
|
|
if (started) {
|
|
return;
|
|
}
|
|
|
|
started = true;
|
|
histogram = histogram::Ringbuffer::create(max_frames, std::make_unique<histogram::DefaultTimeKeeper>());
|
|
monitoring_thread = std::thread(&HistogramCollector::blob_processing_thread, this);
|
|
}
|
|
|
|
void histogram::HistogramCollector::stop() {
|
|
std::unique_lock<decltype(mutex)> lk(mutex);
|
|
if (!started) {
|
|
return;
|
|
}
|
|
|
|
started = false;
|
|
cv.notify_all();
|
|
lk.unlock();
|
|
|
|
if (monitoring_thread.joinable())
|
|
monitoring_thread.join();
|
|
}
|
|
|
|
void histogram::HistogramCollector::notify_histogram_event(int blob_source_fd, BlobId id) {
|
|
std::unique_lock<decltype(mutex)> lk(mutex);
|
|
if (!started) {
|
|
ALOGW("Discarding event blob-id: %X", id);
|
|
return;
|
|
}
|
|
if (work_available) {
|
|
ALOGI("notified of histogram event before consuming last one. prior event discarded");
|
|
}
|
|
|
|
work_available = true;
|
|
blobwork = HistogramCollector::BlobWork{blob_source_fd, id};
|
|
cv.notify_all();
|
|
}
|
|
|
|
void histogram::HistogramCollector::blob_processing_thread() {
|
|
pthread_setname_np(pthread_self(), "histogram_blob");
|
|
|
|
std::unique_lock<decltype(mutex)> lk(mutex);
|
|
|
|
while (true) {
|
|
cv.wait(lk, [this] { return !started || work_available; });
|
|
if (!started) {
|
|
return;
|
|
}
|
|
|
|
auto work = blobwork;
|
|
work_available = false;
|
|
lk.unlock();
|
|
|
|
drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(work.fd, work.id);
|
|
if (!blob) {
|
|
lk.lock();
|
|
continue;
|
|
}
|
|
histogram->insert(*static_cast<struct drm_msm_hist*>(blob->data));
|
|
drmModeFreePropertyBlob(blob);
|
|
|
|
lk.lock();
|
|
}
|
|
}
|