Skip to content

Commit

Permalink
Working compositor
Browse files Browse the repository at this point in the history
  • Loading branch information
shg8 committed Nov 11, 2024
1 parent 30dfd73 commit f6e0d57
Show file tree
Hide file tree
Showing 16 changed files with 497 additions and 173 deletions.
22 changes: 22 additions & 0 deletions cmake/CMakeRC.cmake
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
# MIT License
#
# Copyright (c) 2017 vector-of-bool <[email protected]>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# This block is executed when generating an intermediate resource file, not when
# running in CMake configure mode
if(_CMRC_GENERATE_MODE)
Expand Down
14 changes: 13 additions & 1 deletion examples/example_app/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include <chrono>

#include "bifrost/bifrost_client.h"
#include <iostream>
#include <thread>

typedef unsigned int Rgb;
inline constexpr Rgb Rgba(int r, int g, int b, int a)
Expand All @@ -25,13 +28,22 @@ int main()
for (int i = 0; i < 10; i++) {
for (int y = i * 100; y < (i + 1) * 100; y++) {
for (int x = 0; x < 100; x++) {
image[y * extent.first + x] = Rgba(255, i % 3 == 0 ? 0 : 255, i % 3 == 1 ? 0 : 255, 255);
if (i % 3 == 0) {
image[y * extent.first + x] = Rgba(255, 255, 0, 255);
} else if (i % 3 == 1) {
image[y * extent.first + x] = Rgba(255, 0, 0, 255);
} else {
image[y * extent.first + x] = Rgba(0, 0, 255, 255);
}
}
}
}

std::cout << "Submitting frame" << std::endl;
client.submit_frame(image_index, 0, 0, 100, 1000, COLOR_FAST);
std::cout << "Submitted frame" << std::endl;

std::this_thread::sleep_for(std::chrono::seconds(100));

return 0;
}
2 changes: 1 addition & 1 deletion include/bifrost/global_constants.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef GLOBAL_CONSTANTS_H
#define GLOBAL_CONSTANTS_H

enum refresh_type {
enum refresh_type : int {
MONOCHROME = 0,
COLOR_ANIMATION = 1,
COLOR_FAST = 2,
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ add_library(rmBifrost_compositor SHARED entrypoint.cpp
resources.h
gui/system_ui.cpp
gui/system_ui.h
gui/components/message_box.cpp
gui/components/message_box.h
)

add_library(rmBifrost::compositor ALIAS rmBifrost_compositor)
Expand Down
166 changes: 95 additions & 71 deletions src/compositor/compositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
#include "../gui/boot_screen.h"

#include <utility>

compositor::compositor(display_config cfg)
: cfg(cfg)
, socket(std::make_unique<unix_socket>("/run/bifrost_comp_ctl.sock", true))
, renderer(std::make_shared<lvgl_renderer>(
, socket(std::make_unique<unix_socket>("/run/bifrost_comp_ctl.sock", true))
, renderer(std::make_shared<lvgl_renderer>(
cfg.fb,
fb_mutex,
std::bind(&compositor::request_refresh, this, std::placeholders::_1, std::placeholders::_2)))
{
[this](auto &&PH1, auto &&PH2) {
request_refresh(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
})) {
cfg.fb->fill(QColor(255, 255, 255));
renderer->initialize();
}

void compositor::start()
{
void compositor::start() {
spdlog::info("Starting bifrost compositor");
running = true;

Expand All @@ -27,16 +27,32 @@ void compositor::start()
while (running) {
render_clients();
renderer->tick();
for (const auto& [req_region, req_type] : pending_refresh_requests) {

for (auto &buffer: canvas_buf_deletion_queue) {
delete[] buffer;
}
canvas_buf_deletion_queue.clear();

for (const auto &[req_region, req_type]: pending_refresh_requests) {
refresh(req_region.p1, req_region.p2, req_type);
}
pending_refresh_requests.clear();
long now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
long now = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count();
long sleep_time = freq - (now - last_tick);
if (sleep_time > 0) {
std::this_thread::sleep_for(std::chrono::microseconds(sleep_time));
}
last_tick = now;

if (std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now() - last_fps_update).count() >= 1) {
spdlog::info("FPS: {}", fps);
fps = 0;
last_fps_update = std::chrono::system_clock::now();
} else {
fps++;
}
}
});

Expand Down Expand Up @@ -66,104 +82,112 @@ void compositor::start()
render_thread.join();
}

void compositor::request_refresh(rect update_region, refresh_type type)
{
void compositor::request_refresh(rect update_region, refresh_type type) {
if (pending_refresh_requests.empty()) {
pending_refresh_requests.push_back({ update_region, type });
pending_refresh_requests.emplace_back(update_region, type);
} else {
for (auto& [req_region, req_type] : pending_refresh_requests) {
for (auto &[req_region, req_type]: pending_refresh_requests) {
if (req_region.intersects(update_region)) {
req_region = req_region.union_(update_region);
req_type = std::max(req_type, type);
return;
}
}
pending_refresh_requests.push_back({ update_region, type });
pending_refresh_requests.emplace_back(update_region, type);
}
}

void compositor::render_clients()
{
void compositor::render_clients() {
std::lock_guard lock(client_mutex);

if (system_ui_inst && system_ui_inst->requested_application_exit()) {
active_client->stop();
set_active_client(nullptr);
}

// Remove disconnected clients
clients.erase(std::remove_if(clients.begin(), clients.end(), [](const auto& client) {
clients.erase(std::remove_if(clients.begin(), clients.end(), [this](const auto &client) {
if (client->state == compositor_client::client_state::DISCONNECTED) {
spdlog::info("Client {} has disconnected", client->application_name);
canvas_buf_deletion_queue.push_back(client->lvgl_canvas_buffer);
return true;
}
return false;
}), clients.end());

for (const auto& client : clients) {
auto swapchain_image = client->get_swapchain_image();
if (!swapchain_image) {
for (const auto &client: clients) {
auto refresh_area = client->blit_to_canvas();
if (!refresh_area) {
return;
}
auto [frame_id, submit_frame, composite_region, image_data] = *swapchain_image;

void* image_base_ptr = reinterpret_cast<void*>(image_data);
rect src_update_region = submit_frame.dirty_rect;
rect dst_update_region = { composite_region.p1 + src_update_region.p1, composite_region.p1 + src_update_region.p2 };
spdlog::debug("Rendering client {} with src_update_region [{},{},{},{}] and dst_update_region [{},{},{},{}]", client->application_name, src_update_region.p1.x, src_update_region.p1.y, src_update_region.p2.x, src_update_region.p2.y, dst_update_region.p1.x, dst_update_region.p1.y, dst_update_region.p2.x, dst_update_region.p2.y);
for (uint32_t y = dst_update_region.p1.y; y <= dst_update_region.p2.y; y++) {
QRgb* line = reinterpret_cast<QRgb*>(cfg.fb->scanLine(y));
uint8_t* dst_line_ptr = reinterpret_cast<uint8_t*>(line);
uint8_t* src_line_ptr = reinterpret_cast<uint8_t*>(image_base_ptr) + (y - composite_region.p1.y) * composite_region.width() * 4;
spdlog::debug("Copying line {}; first pixel is {}", y, *reinterpret_cast<uint32_t*>(src_line_ptr));
std::memcpy(dst_line_ptr + dst_update_region.p1.x * 4, src_line_ptr + src_update_region.p1.x * 4, (dst_update_region.p2.x - dst_update_region.p1.x + 1) * 4);
}

request_refresh(dst_update_region, submit_frame.preferred_refresh_type);
request_refresh(refresh_area->first, refresh_area->second);
}
}

client->release_swapchain_image(frame_id);
void compositor::set_active_client(const std::shared_ptr<compositor_client> &client) {
if (client) {
system_ui_inst->set_content({system_ui::content_type::APPLICATION, client->window_title});
} else {
system_ui_inst->set_content({system_ui::content_type::BIFROST, "Bifrost"});
}
active_client = client;
}

void compositor::stop()
{
void compositor::stop() {
running = false;
for (const auto& client : clients) {
for (const auto &client: clients) {
client->stop();
}
listener_thread.join();
}

void compositor::listener()
{
void compositor::listener() {
while (running) {
spdlog::debug("Waiting for connection");
auto connection = socket->accept_connection();
spdlog::debug("Accepted connection");
auto client = std::make_shared<compositor_client>(std::move(connection), compositor_client::compositor_client_config {
.title_bar_height = 100,
});
clients.push_back(client);
auto client = std::make_shared<compositor_client>(std::move(connection),
compositor_client::compositor_client_config{
.id = next_client_id++,
.navbar_height = 100,
.swapchain_extent = {SCREEN_WIDTH, SCREEN_HEIGHT},
.pos = {0, 0}
});

{
std::lock_guard lock(client_mutex);
clients.push_back(client);
set_active_client(client);
}

client->start();
}
}

void compositor::refresh(point p1, point p2, refresh_type type)
{
void compositor::refresh(const point p1, const point p2, const refresh_type type) const {
spdlog::debug("Refreshing area: {}x{}-{}x{} with type {}", p1.x, p1.y, p2.x, p2.y, static_cast<int>(type));
switch (type) {
case MONOCHROME:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 0, 0, 0);
break;
case COLOR_ANIMATION:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 0, 0);
break;
case COLOR_CONTENT:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 4, 0);
break;
case COLOR_FAST:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 1, 0);
break;
case COLOR_1:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 3, 0);
break;
case COLOR_2:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 5, 0);
break;
case FULL:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 4, 1);
break;
case MONOCHROME:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 0, 0, 0);
break;
case COLOR_ANIMATION:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 0, 0);
break;
case COLOR_CONTENT:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 4, 0);
break;
case COLOR_FAST:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 1, 0);
break;
case COLOR_1:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 3, 0);
break;
case COLOR_2:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 5, 0);
break;
case FULL:
cfg.screen_update_func(cfg.epfb_inst, p1, p2, 1, 4, 1);
break;
default: break;
}
}
}

uint32_t compositor::next_client_id = 0;
15 changes: 12 additions & 3 deletions src/compositor/compositor.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ class compositor {

void start();
void stop();
void request_refresh(rect update_region, refresh_type type);
private:
static uint32_t next_client_id;
std::atomic<bool> running = false;

display_config cfg;
Expand All @@ -31,14 +31,23 @@ class compositor {
std::unique_ptr<unix_socket> socket;
std::thread listener_thread;
std::thread render_thread;
std::mutex fb_mutex;

std::mutex client_mutex;
std::vector<std::shared_ptr<compositor_client>> clients;
std::shared_ptr<compositor_client> active_client;

std::vector<std::pair<rect, refresh_type>> pending_refresh_requests;

int fps = 0;
std::chrono::time_point<std::chrono::system_clock> last_fps_update;

std::vector<uint8_t *> canvas_buf_deletion_queue;

void listener();
void refresh(point p1, point p2, refresh_type type);
void refresh(point p1, point p2, refresh_type type) const;
void render_clients();
void set_active_client(const std::shared_ptr<compositor_client> &client);
void request_refresh(rect update_region, refresh_type type);
};


Expand Down
Loading

0 comments on commit f6e0d57

Please sign in to comment.