174 lines
No EOL
4.9 KiB
C++
174 lines
No EOL
4.9 KiB
C++
/*
|
|
Crafter®.Graphics
|
|
Copyright (C) 2025 Catcrafts®
|
|
Catcrafts.net
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 3.0 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
module;
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <linux/input.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#include <wayland-cursor.h>
|
|
#include <xkbcommon/xkbcommon.h>
|
|
#include <vulkan/vulkan.h>
|
|
#include <vulkan/vulkan_wayland.h>
|
|
#include <wayland-client.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <print>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
#include <unistd.h>
|
|
#include <wayland-client.h>
|
|
#include <wayland-client-protocol.h>
|
|
#include <linux/input-event-codes.h>
|
|
|
|
export module Crafter.Graphics:WindowWaylandWayland_impl;
|
|
import :WindowWaylandWayland;
|
|
import std;
|
|
import Crafter.Event;
|
|
using namespace Crafter;
|
|
|
|
|
|
static void randname(char *buf) {
|
|
struct timespec ts;
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
long r = ts.tv_nsec;
|
|
for (int i = 0; i < 6; ++i) {
|
|
buf[i] = 'A'+(r&15)+(r&16)*2;
|
|
r >>= 5;
|
|
}
|
|
}
|
|
|
|
static int anonymous_shm_open(void) {
|
|
char name[] = "/hello-wayland-XXXXXX";
|
|
int retries = 100;
|
|
|
|
do {
|
|
randname(name + strlen(name) - 6);
|
|
|
|
--retries;
|
|
// shm_open guarantees that O_CLOEXEC is set
|
|
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
|
if (fd >= 0) {
|
|
shm_unlink(name);
|
|
return fd;
|
|
}
|
|
} while (retries > 0 && errno == EEXIST);
|
|
|
|
return -1;
|
|
}
|
|
|
|
int create_shm_file(off_t size) {
|
|
int fd = anonymous_shm_open();
|
|
if (fd < 0) {
|
|
return fd;
|
|
}
|
|
|
|
if (ftruncate(fd, size) < 0) {
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
|
|
void ScaleBitmapR8G8B8(Pixel_BU8_GU8_RU8_AU8* dst, const Pixel_BU8_GU8_RU8_AU8* src, std::uint32_t srcWidth, std::uint32_t srcHeight, std::uint32_t dstWidth, std::uint32_t dstHeight) {
|
|
for (std::uint32_t y = 0; y < dstHeight; y++) {
|
|
std::uint32_t srcY = y * srcHeight / dstHeight;
|
|
for (std::uint32_t x = 0; x < dstWidth; x++) {
|
|
std::uint32_t srcX = x * srcWidth / dstWidth;
|
|
const Pixel_BU8_GU8_RU8_AU8* srcPixel = src + (srcY * srcWidth + srcX);
|
|
Pixel_BU8_GU8_RU8_AU8* dstPixel = dst + (y * dstWidth + x);
|
|
dstPixel[0] = srcPixel[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
WindowWaylandWayland::WindowWaylandWayland(std::string name, std::uint32_t width, std::uint32_t height) : WindowWayland(name, width, height) {
|
|
// Create a wl_buffer, attach it to the surface and commit the surface
|
|
int stride = width * 4;
|
|
int size = stride * height;
|
|
|
|
// Allocate a shared memory file with the right size
|
|
int fd = create_shm_file(size);
|
|
if (fd < 0) {
|
|
fprintf(stderr, "creating a buffer file for %d B failed: %m\n", size);
|
|
}
|
|
|
|
// Map the shared memory file
|
|
framebuffer = reinterpret_cast<Pixel_BU8_GU8_RU8_AU8*>(mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
|
if (framebuffer == MAP_FAILED) {
|
|
fprintf(stderr, "mmap failed: %m\n");
|
|
close(fd);
|
|
}
|
|
|
|
// Create a wl_buffer from our shared memory file descriptor
|
|
wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
|
|
buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888);
|
|
wl_shm_pool_destroy(pool);
|
|
|
|
// Now that we've mapped the file and created the wl_buffer, we no longer
|
|
// need to keep file descriptor opened
|
|
close(fd);
|
|
|
|
if (buffer == NULL) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
wl_surface_attach(surface, buffer, 0, 0);
|
|
wl_surface_commit(surface);
|
|
}
|
|
|
|
WindowWaylandWayland::~WindowWaylandWayland() {
|
|
open = false;
|
|
thread.join();
|
|
}
|
|
|
|
void WindowWaylandWayland::StartAsync() {
|
|
thread = std::thread(&WindowWaylandWayland::StartSync, this);
|
|
}
|
|
|
|
void WindowWaylandWayland::StartSync() {
|
|
while (open && wl_display_dispatch(display) != -1) {
|
|
wl_surface_attach(surface, buffer, 0, 0);
|
|
for(const UiElement& element : elements) {
|
|
ScaleData data = ScaleElement(element);
|
|
std::vector<Pixel_BU8_GU8_RU8_AU8> scaled(data.width*data.height);
|
|
ScaleBitmapR8G8B8(scaled.data(), element.buffer.data(), element.bufferWidth, element.bufferHeight, data.width, data.height);
|
|
for(std::int32_t x = data.x; x-data.x < data.width; x++) {
|
|
for(std::int32_t y = data.y; y-data.y < data.height; y++) {
|
|
if(x > 0 && x < width && y > 0 && y < height) {
|
|
framebuffer[y*width+x] = scaled[(y-data.y)*data.width+(x-data.x)];
|
|
}
|
|
}
|
|
}
|
|
wl_surface_damage(surface, data.x, data.y, data.width, data.height);
|
|
}
|
|
wl_surface_commit(surface);
|
|
}
|
|
} |