Skip to content
Merged

Sim #49

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/pisp-verification.test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
clean: true

- name: Configure meson
run: meson setup build -Dbuildtype=debug
run: meson setup build -Dbuildtype=debug -Dexamples=true
timeout-minutes: 5

- name: Build
Expand All @@ -42,3 +42,7 @@ jobs:
- name: Run verification tests
run: LD_LIBRARY_PATH=${{github.workspace}}/build/src LIBPISP_BE_CONFIG_FILE="${{github.workspace}}/src/libpisp/backend/backend_default_config.json" ${{env.BE_TEST_DIR}}/run_be_tests.py --hw --logall --test ${{env.BE_TEST_DIR}}/be_test ${{env.TESTS_DIR}}/back_end
timeout-minutes: 20

- name: Run convert tests
run: LD_LIBRARY_PATH=${{github.workspace}}/build/src LIBPISP_BE_CONFIG_FILE="${{github.workspace}}/src/libpisp/backend/backend_default_config.json" python3 ${{github.workspace}}/utils/test_convert.py ${{github.workspace}}/build/src/examples/convert --out /tmp/ --in $HOME/libpisp_conv/ --ref ~/libpisp_conv/ref/
timeout-minutes: 10
6 changes: 4 additions & 2 deletions src/examples/convert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ int main(int argc, char *argv[])
be.Prepare(&config);

backend_device.Setup(config);
auto buffers = backend_device.GetBuffers();
auto buffers = backend_device.AcquireBuffers();

std::string input_filename = args["input"].as<std::string>();
std::ifstream in(input_filename, std::ios::binary);
Expand All @@ -382,7 +382,7 @@ int main(int argc, char *argv[])
i.stride);
in.close();

int ret = backend_device.Run();
int ret = backend_device.Run(buffers);
if (ret)
{
std::cerr << "Job run error!" << std::endl;
Expand All @@ -402,6 +402,8 @@ int main(int argc, char *argv[])
o.image.stride);
out.close();

backend_device.ReleaseBuffer(buffers);

std::cerr << "Writing " << output_file << " "
<< out_file.width << ":" << out_file.height << ":" << out_file.stride << ":" << out_file.format << std::endl;

Expand Down
92 changes: 67 additions & 25 deletions src/helpers/backend_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include <cstdint>
#include <cstring>

#include "libpisp/common/utils.hpp"

#include "backend_device.hpp"

using namespace libpisp::helpers;
Expand All @@ -24,65 +22,109 @@ BackendDevice::BackendDevice(const std::string &device)
// Allocate a config buffer to persist.
nodes_.at("pispbe-config").RequestBuffers(1);
nodes_.at("pispbe-config").StreamOn();
config_buffer_ = nodes_.at("pispbe-config").GetBuffer().value();
config_buffer_ = nodes_.at("pispbe-config").AcquireBuffer().value();
}

BackendDevice::~BackendDevice()
{
nodes_.at("pispbe-config").StreamOff();
}

void BackendDevice::Setup(const pisp_be_tiles_config &config)
void BackendDevice::Setup(const pisp_be_tiles_config &config, unsigned int buffer_count, bool use_opaque_format)
{
nodes_enabled_.clear();

if (config.config.global.rgb_enables & PISP_BE_RGB_ENABLE_INPUT)
if ((config.config.global.rgb_enables & PISP_BE_RGB_ENABLE_INPUT) ||
(config.config.global.bayer_enables & PISP_BE_BAYER_ENABLE_INPUT))
{
const pisp_image_format_config &f = config.config.input_format;
nodes_.at("pispbe-input").SetFormat(f.width, f.height, f.stride, f.stride2,
libpisp::get_pisp_image_format(f.format));
nodes_.at("pispbe-input").SetFormat(config.config.input_format, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-input").ReleaseBuffers();
nodes_.at("pispbe-input").RequestBuffers(1);
nodes_.at("pispbe-input").ReturnBuffers();
nodes_.at("pispbe-input").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-input");
buffers_["pispbe-input"] = nodes_.at("pispbe-input").GetBuffer().value();
}

if (config.config.global.rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT0)
{
const pisp_image_format_config &f = config.config.output_format[0].image;
nodes_.at("pispbe-output0").SetFormat(f.width, f.height, f.stride, f.stride2,
libpisp::get_pisp_image_format(f.format));
nodes_.at("pispbe-output0").SetFormat(config.config.output_format[0].image, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-output0").ReleaseBuffers();
nodes_.at("pispbe-output0").RequestBuffers(1);
nodes_.at("pispbe-output0").ReturnBuffers();
nodes_.at("pispbe-output0").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-output0");
buffers_["pispbe-output0"] = nodes_.at("pispbe-output0").GetBuffer().value();
}

if (config.config.global.rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT1)
{
const pisp_image_format_config &f = config.config.output_format[1].image;
nodes_.at("pispbe-output1").SetFormat(f.width, f.height, f.stride, f.stride2,
libpisp::get_pisp_image_format(f.format));
nodes_.at("pispbe-output1").SetFormat(config.config.output_format[1].image, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-output1").ReleaseBuffers();
nodes_.at("pispbe-output1").RequestBuffers(1);
nodes_.at("pispbe-output1").ReturnBuffers();
nodes_.at("pispbe-output1").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-output1");
buffers_["pispbe-output1"] = nodes_.at("pispbe-output1").GetBuffer().value();
}

if (config.config.global.bayer_enables & PISP_BE_BAYER_ENABLE_TDN_INPUT)
{
nodes_.at("pispbe-tdn_input").SetFormat(config.config.tdn_input_format, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-tdn_input").ReturnBuffers();
nodes_.at("pispbe-tdn_input").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-tdn_input");
}

if (config.config.global.bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT)
{
nodes_.at("pispbe-tdn_output").SetFormat(config.config.tdn_output_format, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-tdn_output").ReturnBuffers();
nodes_.at("pispbe-tdn_output").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-tdn_output");
}

if (config.config.global.bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_INPUT)
{
nodes_.at("pispbe-stitch_input").SetFormat(config.config.stitch_input_format, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-stitch_input").ReturnBuffers();
nodes_.at("pispbe-stitch_input").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-stitch_input");
}

if (config.config.global.bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT)
{
nodes_.at("pispbe-stitch_output").SetFormat(config.config.stitch_output_format, use_opaque_format);
// Release old/allocate a single buffer.
nodes_.at("pispbe-stitch_output").ReturnBuffers();
nodes_.at("pispbe-stitch_output").RequestBuffers(buffer_count);
nodes_enabled_.emplace("pispbe-stitch_output");
}

std::memcpy(reinterpret_cast<pisp_be_tiles_config *>(config_buffer_.mem[0]), &config, sizeof(config));
}

int BackendDevice::Run()
std::map<std::string, V4l2Device::Buffer> BackendDevice::AcquireBuffers()
{
std::map<std::string, V4l2Device::Buffer> buffers;

for (auto const &n : nodes_enabled_)
buffers[n] = nodes_.at(n).AcquireBuffer().value();

return buffers;
}

void BackendDevice::ReleaseBuffer(const std::map<std::string, V4l2Device::Buffer> &buffers)
{
for (auto const &[n, b] : buffers)
nodes_.at(n).ReleaseBuffer(b);
}

int BackendDevice::Run(const std::map<std::string, V4l2Device::Buffer> &buffers)
{
int ret = 0;

for (auto const &n : nodes_enabled_)
{
nodes_.at(n).StreamOn();
if (nodes_.at(n).QueueBuffer(buffers_.at(n).buffer.index))
if (nodes_.at(n).QueueBuffer(buffers.at(n).buffer.index))
ret = -1;
}

Expand Down
16 changes: 11 additions & 5 deletions src/helpers/backend_device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,24 @@ class BackendDevice
BackendDevice(const std::string &device);
~BackendDevice();

void Setup(const pisp_be_tiles_config &config);
int Run();
void Setup(const pisp_be_tiles_config &config, unsigned int buffer_count = 1, bool use_opaque_format = false);
int Run(const std::map<std::string, V4l2Device::Buffer> &buffers);

bool Valid() const
{
return valid_;
}

const std::map<std::string, V4l2Device::Buffer> &GetBuffers() const
V4l2Device &Node(const std::string &node)
{
return buffers_;
return nodes_.at(node);
}

std::map<std::string, V4l2Device::Buffer> AcquireBuffers();
void ReleaseBuffer(const std::map<std::string, V4l2Device::Buffer> &buffers);
V4l2Device::Buffer &ConfigBuffer()
{
return config_buffer_;
}

private:
Expand All @@ -41,7 +48,6 @@ class BackendDevice
MediaDevice devices_;
std::unordered_set<std::string> nodes_enabled_;
V4l2Device::Buffer config_buffer_;
std::map<std::string, V4l2Device::Buffer> buffers_;
};

} // namespace libpisp
67 changes: 51 additions & 16 deletions src/helpers/v4l2_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@
#include <sys/mman.h>
#include <time.h>

#include "libpisp/common/utils.hpp"

#include "v4l2_device.hpp"

using namespace libpisp::helpers;

namespace {

struct FormatInfo
{
unsigned int v4l2_pixfmt;
Expand All @@ -46,6 +50,8 @@ static FormatInfo get_v4l2_format(const std::string &format)
return it->second;
}

} // namespace

V4l2Device::V4l2Device(const std::string &device)
: fd_(device, O_RDWR | O_NONBLOCK | O_CLOEXEC), num_memory_planes_(1)
{
Expand All @@ -67,15 +73,15 @@ V4l2Device::V4l2Device(const std::string &device)

V4l2Device::~V4l2Device()
{
ReleaseBuffers();
ReturnBuffers();
Close();
}

int V4l2Device::RequestBuffers(unsigned int count)
{
int ret;

ReleaseBuffers();
ReturnBuffers();

v4l2_requestbuffers req_bufs {};

Expand Down Expand Up @@ -127,7 +133,7 @@ int V4l2Device::RequestBuffers(unsigned int count)
return v4l2_buffers_.size();
}

void V4l2Device::ReleaseBuffers()
void V4l2Device::ReturnBuffers()
{
v4l2_requestbuffers req_bufs {};

Expand All @@ -148,7 +154,7 @@ void V4l2Device::ReleaseBuffers()
v4l2_buffers_.clear();
}

std::optional<V4l2Device::Buffer> V4l2Device::GetBuffer()
std::optional<V4l2Device::Buffer> V4l2Device::AcquireBuffer()
{
if (available_buffers_.empty())
return {};
Expand All @@ -158,13 +164,18 @@ std::optional<V4l2Device::Buffer> V4l2Device::GetBuffer()
return findBuffer(index);
}

void V4l2Device::ReleaseBuffer(const Buffer &buffer)
{
available_buffers_.push(buffer.buffer.index);
}

int V4l2Device::QueueBuffer(unsigned int index)
{
std::optional<Buffer> buf = findBuffer(index);
if (!buf)
return -1;

v4l2_plane planes[VIDEO_MAX_PLANES];
v4l2_plane planes[VIDEO_MAX_PLANES] = {};
if (!isMeta())
{
buf->buffer.m.planes = planes;
Expand Down Expand Up @@ -216,31 +227,55 @@ int V4l2Device::DequeueBuffer(unsigned int timeout_ms)
if (ret)
return -1;

available_buffers_.push(buf.index);
return buf.index;
}

void V4l2Device::SetFormat(unsigned int width, unsigned int height, unsigned int stride, unsigned int stride2,
const std::string &format)
void V4l2Device::SetFormat(const pisp_image_format_config &format, bool use_opaque_format)
{
struct v4l2_format f = {};
FormatInfo info = get_v4l2_format(format);

assert(info.v4l2_pixfmt);
FormatInfo info = get_v4l2_format(libpisp::get_pisp_image_format(format.format));

num_memory_planes_ = info.num_memory_planes;

f.type = buf_type_;
f.fmt.pix_mp.width = width;
f.fmt.pix_mp.height = height;
f.fmt.pix_mp.width = format.width;
f.fmt.pix_mp.height = format.height;
f.fmt.pix_mp.pixelformat = info.v4l2_pixfmt;
f.fmt.pix_mp.field = V4L2_FIELD_NONE;
f.fmt.pix_mp.num_planes = num_memory_planes_;

for (unsigned int p = 0; p < num_memory_planes_; p++)
unsigned int num_image_planes = libpisp::num_planes((pisp_image_format)format.format);

if (use_opaque_format || info.v4l2_pixfmt == 0)
{
// This format is not specified by V4L2, we use an opaque buffer buffer as a workaround.
// Size the dimensions down so the kernel drive does not attempt to resize it.
f.fmt.pix_mp.width = 16;
f.fmt.pix_mp.height = 16;
f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV444M;
num_memory_planes_ = 3;
f.fmt.pix_mp.plane_fmt[0].bytesperline = format.stride;

f.fmt.pix_mp.plane_fmt[0].sizeimage = 0;
for (unsigned int i = 0; i < 3; i++)
f.fmt.pix_mp.plane_fmt[0].sizeimage += libpisp::get_plane_size(format, i);

f.fmt.pix_mp.plane_fmt[1].sizeimage = f.fmt.pix_mp.plane_fmt[2].sizeimage = f.fmt.pix_mp.plane_fmt[0].sizeimage;
f.fmt.pix_mp.plane_fmt[1].bytesperline = f.fmt.pix_mp.plane_fmt[2].bytesperline = format.stride2;
}
else
{
f.fmt.pix_mp.plane_fmt[p].bytesperline = p == 0 ? stride : stride2;
f.fmt.pix_mp.plane_fmt[p].sizeimage = 0;
unsigned int p = 0;
for (; p < num_memory_planes_; p++)
{
const unsigned int stride = p == 0 ? format.stride : format.stride2;
// Wallpaper stride is not something the V4L2 kernel knows about!
f.fmt.pix_mp.plane_fmt[p].bytesperline = stride;
f.fmt.pix_mp.plane_fmt[p].sizeimage = libpisp::get_plane_size(format, p);
}

for (; p < num_image_planes; p++)
f.fmt.pix_mp.plane_fmt[num_memory_planes_ - 1].sizeimage += libpisp::get_plane_size(format, p);
}

int ret = ioctl(fd_.Get(), VIDIOC_S_FMT, &f);
Expand Down
Loading
Loading