Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: CEF use dirty rectangles #1519

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
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