Skip to content
2 changes: 2 additions & 0 deletions src/accelerator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(SOURCES
ogl/image/image_kernel.cpp
ogl/image/image_mixer.cpp
ogl/image/image_shader.cpp
ogl/image/frame_pool.cpp

ogl/util/buffer.cpp
ogl/util/device.cpp
Expand All @@ -17,6 +18,7 @@ set(HEADERS
ogl/image/image_kernel.h
ogl/image/image_mixer.h
ogl/image/image_shader.h
ogl/image/frame_pool.h

ogl/util/buffer.h
ogl/util/device.h
Expand Down
94 changes: 94 additions & 0 deletions src/accelerator/ogl/image/frame_pool.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2011 Sveriges Television AB <[email protected]>
*
* This file is part of CasparCG (www.casparcg.com).
*
* CasparCG is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CasparCG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Julian Waller, [email protected]
*/

#include "frame_pool.h"

#include <utility>

namespace caspar::accelerator::ogl {

frame_pool::frame_pool(std::shared_ptr<frame_factory_gl> frame_factory, const void* tag, core::pixel_format_desc desc)
: frame_factory_(std::move(frame_factory))
, tag_(tag)
, desc_(std::move(desc))
{
}

std::pair<core::mutable_frame, std::any&> frame_pool::create_frame()
{
// TODO - is there risk of order issues with the atomics?

std::shared_ptr<pooled_buffer> frame;

// Find a frame which is not in use
for (const std::shared_ptr<pooled_buffer>& candidate : pool_) {
if (!candidate->in_use) {
frame = candidate;
break;
}
}

// Add a new buffer to the pool
if (!frame) {
frame = std::make_shared<pooled_buffer>();

for (const core::pixel_format_desc::plane& plane : desc_.planes) {
frame->buffers.push_back(frame_factory_->create_buffer(plane.size));
}

pool_.push_back(frame);
}

frame->in_use = true;

// Make copies of the buffers
std::vector<caspar::array<uint8_t>> buffers;
for (const caspar::array<std::uint8_t>& buffer : frame->buffers) {
buffers.push_back(buffer.clone());
}

auto drop_hook = std::shared_ptr<void>(nullptr, [frame](void*) {
// This means the copy of each buffer has completed, and is no longer in use
frame->in_use = false;
});

auto new_frame = frame_factory_->import_buffers(tag_, desc_, std::move(buffers), std::move(drop_hook));

return std::make_pair(std::move(new_frame), std::ref(frame->data));
}

void frame_pool::for_each(const std::function<void(std::any& data)>& fn)
{
for (std::shared_ptr<pooled_buffer>& candidate : pool_) {
fn(candidate->data);
}
}

void frame_pool::pixel_format(core::pixel_format_desc desc)
{
desc_ = desc;

pool_.clear();
}

const core::pixel_format_desc& frame_pool::pixel_format() const { return desc_; }

} // namespace caspar::accelerator::ogl
67 changes: 67 additions & 0 deletions src/accelerator/ogl/image/frame_pool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2011 Sveriges Television AB <[email protected]>
*
* This file is part of CasparCG (www.casparcg.com).
*
* CasparCG is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CasparCG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Julian Waller, [email protected]
*/

#pragma once

#include <core/frame/frame.h>
#include <core/frame/frame_transform.h>
#include <core/frame/geometry.h>
#include <core/frame/pixel_format.h>
#include <core/video_format.h>

#include "image_mixer.h"

namespace caspar::accelerator::ogl {

struct pooled_buffer
{
std::vector<caspar::array<std::uint8_t>> buffers;
std::atomic<bool> in_use;

std::any data;
};

class frame_pool : public core::frame_pool
{
public:
frame_pool(std::shared_ptr<frame_factory_gl> frame_factory, const void* tag, core::pixel_format_desc desc);
frame_pool(const frame_pool&) = delete;

~frame_pool() override = default;

frame_pool& operator=(const frame_pool&) = delete;

std::pair<core::mutable_frame, std::any&> create_frame() override;

void for_each(const std::function<void(std::any& data)>& fn) override;

void pixel_format(core::pixel_format_desc desc) override;
[[nodiscard]] const core::pixel_format_desc& pixel_format() const override;

private:
const std::shared_ptr<frame_factory_gl> frame_factory_;
const void* tag_;
core::pixel_format_desc desc_;

std::vector<std::shared_ptr<pooled_buffer>> pool_;
};

} // namespace caspar::accelerator::ogl
44 changes: 35 additions & 9 deletions src/accelerator/ogl/image/image_mixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/
#include "image_mixer.h"

#include "frame_pool.h"
#include "image_kernel.h"

#include "../util/buffer.h"
Expand Down Expand Up @@ -222,7 +223,7 @@ class image_renderer
};

struct image_mixer::impl
: public core::frame_factory
: public frame_factory_gl
, public std::enable_shared_from_this<impl>
{
spl::shared_ptr<device> ogl_;
Expand Down Expand Up @@ -281,7 +282,8 @@ struct image_mixer::impl
item.textures.emplace_back(ogl_->copy_async(frame.image_data(n),
item.pix_desc.planes[n].width,
item.pix_desc.planes[n].height,
item.pix_desc.planes[n].stride));
item.pix_desc.planes[n].stride,
nullptr));
}
}

Expand All @@ -299,32 +301,52 @@ struct image_mixer::impl
return renderer_(std::move(layers_), format_desc);
}

core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override
caspar::array<std::uint8_t> create_buffer(int size) override { return ogl_->create_array(size); }

core::mutable_frame import_buffers(const void* tag,
const core::pixel_format_desc& desc,
std::vector<caspar::array<std::uint8_t>> buffers,
std::shared_ptr<void> drop_hook) override
{
std::vector<array<std::uint8_t>> image_data;
for (auto& plane : desc.planes) {
image_data.push_back(ogl_->create_array(plane.size));
if (desc.planes.size() != buffers.size()) {
CASPAR_THROW_EXCEPTION(caspar_exception() << msg_info(L"Mismatch in number of buffers and planes"));
}

std::weak_ptr<image_mixer::impl> weak_self = shared_from_this();
return core::mutable_frame(
tag,
std::move(image_data),
std::move(buffers),
array<int32_t>{},
desc,
[weak_self, desc](std::vector<array<const std::uint8_t>> image_data) -> std::any {
[weak_self, desc, drop_hook = std::move(drop_hook)](
std::vector<array<const std::uint8_t>> image_data) -> std::any {
auto self = weak_self.lock();
if (!self) {
return std::any{};
}
std::vector<future_texture> textures;
for (int n = 0; n < static_cast<int>(desc.planes.size()); ++n) {
textures.emplace_back(self->ogl_->copy_async(
image_data[n], desc.planes[n].width, desc.planes[n].height, desc.planes[n].stride));
image_data[n], desc.planes[n].width, desc.planes[n].height, desc.planes[n].stride, drop_hook));
}
return std::make_shared<decltype(textures)>(std::move(textures));
});
}

core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override
{
std::vector<array<std::uint8_t>> image_data;
for (auto& plane : desc.planes) {
image_data.push_back(ogl_->create_array(plane.size));
}

return import_buffers(tag, desc, std::move(image_data), nullptr);
}

std::unique_ptr<core::frame_pool> create_frame_pool(const void* tag, const core::pixel_format_desc& desc) override
{
return std::make_unique<frame_pool>(shared_from_this(), tag, desc);
}
};

image_mixer::image_mixer(const spl::shared_ptr<device>& ogl, const int channel_id, const size_t max_frame_size)
Expand All @@ -343,5 +365,9 @@ core::mutable_frame image_mixer::create_frame(const void* tag, const core::pixel
{
return impl_->create_frame(tag, desc);
}
std::unique_ptr<core::frame_pool> image_mixer::create_frame_pool(const void* tag, const core::pixel_format_desc& desc)
{
return impl_->create_frame_pool(tag, desc);
}

}}} // namespace caspar::accelerator::ogl
8 changes: 8 additions & 0 deletions src/accelerator/ogl/image/image_mixer.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@

namespace caspar { namespace accelerator { namespace ogl {

class frame_factory_gl: public core::frame_factory {
public:
virtual caspar::array<std::uint8_t> create_buffer(int size) = 0;
virtual core::mutable_frame import_buffers(const void* tag, const core::pixel_format_desc& desc, std::vector<caspar::array<std::uint8_t>> buffers, std::shared_ptr<void> drop_hook) = 0;
};

class image_mixer final : public core::image_mixer
{
public:
Expand All @@ -46,6 +52,8 @@ class image_mixer final : public core::image_mixer
std::future<array<const std::uint8_t>> operator()(const core::video_format_desc& format_desc) override;
core::mutable_frame create_frame(const void* tag, const core::pixel_format_desc& desc) override;

std::unique_ptr<core::frame_pool> create_frame_pool(const void* tag, const core::pixel_format_desc& desc) override;

// core::image_mixer

void push(const core::frame_transform& frame) override;
Expand Down
15 changes: 9 additions & 6 deletions src/accelerator/ogl/util/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,9 @@ struct device::impl : public std::enable_shared_from_this<impl>
}

std::future<std::shared_ptr<texture>>
copy_async(const array<const uint8_t>& source, int width, int height, int stride)
copy_async(const array<const uint8_t>& source, int width, int height, int stride, std::shared_ptr<void> drop_hook)
{
return dispatch_async([=] {
return dispatch_async([=, drop_hook = std::move(drop_hook)] {
std::shared_ptr<buffer> buf;

auto tmp = source.storage<std::shared_ptr<buffer>>();
Expand Down Expand Up @@ -427,11 +427,14 @@ std::shared_ptr<texture> device::create_texture(int width, int height, int strid
{
return impl_->create_texture(width, height, stride, true);
}
array<uint8_t> device::create_array(int size) { return impl_->create_array(size); }
std::future<std::shared_ptr<texture>>
device::copy_async(const array<const uint8_t>& source, int width, int height, int stride)
array<uint8_t> device::create_array(int size) { return impl_->create_array(size); }
std::future<std::shared_ptr<texture>> device::copy_async(const array<const uint8_t>& source,
int width,
int height,
int stride,
std::shared_ptr<void> drop_hook)
{
return impl_->copy_async(source, width, height, stride);
return impl_->copy_async(source, width, height, stride, drop_hook);
}
std::future<array<const uint8_t>> device::copy_async(const std::shared_ptr<texture>& source)
{
Expand Down
2 changes: 1 addition & 1 deletion src/accelerator/ogl/util/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class device final
array<uint8_t> create_array(int size);

std::future<std::shared_ptr<class texture>>
copy_async(const array<const uint8_t>& source, int width, int height, int stride);
copy_async(const array<const uint8_t>& source, int width, int height, int stride, std::shared_ptr<void> drop_hook);
std::future<array<const uint8_t>> copy_async(const std::shared_ptr<class texture>& source);
template <typename Func>
auto dispatch_async(Func&& func)
Expand Down
9 changes: 9 additions & 0 deletions src/common/array.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ class array final
return *this;
}

// Explicitly make a copy of the array, with shared backing storage
array<T> clone() const {
caspar::array<T> cloned;
cloned.ptr_ = ptr_;
cloned.size_ = size_;
cloned.storage_ = storage_;
return cloned;
}

T* begin() const { return ptr_; }
T* data() const { return ptr_; }
T* end() const { return ptr_ + size_; }
Expand Down
24 changes: 23 additions & 1 deletion src/core/frame/frame_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,40 @@

#pragma once

#include <any>

namespace caspar { namespace core {

class frame_pool
{
public:
frame_pool() = default;
frame_pool& operator=(const frame_pool&) = delete;
virtual ~frame_pool() = default;

frame_pool(const frame_pool&) = delete;

virtual std::pair<class mutable_frame, std::any&> create_frame() = 0;

virtual void for_each(const std::function<void(std::any& data)>& fn) = 0;

virtual void pixel_format(core::pixel_format_desc desc) = 0;
[[nodiscard]] virtual const core::pixel_format_desc& pixel_format() const = 0;
};

class frame_factory
{
public:
frame_factory() = default;
frame_factory() = default;
frame_factory& operator=(const frame_factory&) = delete;
virtual ~frame_factory() = default;

frame_factory(const frame_factory&) = delete;

virtual class mutable_frame create_frame(const void* video_stream_tag, const struct pixel_format_desc& desc) = 0;

virtual std::unique_ptr<frame_pool> create_frame_pool(const void* video_stream_tag,
const struct pixel_format_desc& desc) = 0;
};

}} // namespace caspar::core
Loading