Untitled
unknown
plain_text
10 months ago
23 kB
4
Indexable
light@light:~/wayfire/subprojects/wlroots/backend/rdprail$ ls
meson.build rdprail_backend.c rdprail_output.h
rdprail.c rdprail_backend.h rdprail_surface.c
rdprail.h rdprail_output.c rdprail_surface.h
light@light:~/wayfire/subprojects/wlroots/backend/rdprail$ cat meson.build rdprail.h rdprail_backend.h rdprail_output.h rdprail.c rdprail_backend.c rdprail_output.c
# subprojects/wlroots/backend/rdprail/meson.build
rdprail_files = files(
'rdprail.c',
'rdprail_output.c',
'rdprail_backend.c'
)
# Check for RDP dependencies
dep_freerdp = dependency('freerdp-server2', required: false)
dep_winpr = dependency('winpr2', required: false)
dep_gbm = dependency('gbm', required: false)
# Optional RDP backend support
if get_option('backends').contains('rdprail') or get_option('backends').contains('auto')
if dep_freerdp.found() and dep_winpr.found() and dep_gbm.found()
wlr_files += rdprail_files
wlr_deps += [dep_freerdp, dep_winpr, dep_gbm]
else
if not dep_freerdp.found()
error('FreerRDP not found. Disable RDP backend or install freerdp-server2.')
endif
if not dep_winpr.found()
error('WinPR not found. Disable RDP backend or install winpr2.')
endif
if not dep_gbm.found()
error('GBM not found. Disable RDP backend or install libgbm.')
endif
endif
endif
/* rdprail.h */
#ifndef WLR_RENDER_ALLOCATOR_RDPRAIL_H
#define WLR_RENDER_ALLOCATOR_RDPRAIL_H
#define _GNU_SOURCE // For memfd_create
#include <stdint.h>
#include <wlr/render/allocator.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/interfaces/wlr_buffer.h>
// Define RECTANGLE_16 structure first
typedef struct {
uint16_t left;
uint16_t top;
uint16_t right;
uint16_t bottom;
} RECTANGLE_16;
// RDP-specific PDU structures
typedef struct {
uint32_t poolId;
} GFXREDIR_OPEN_POOL_PDU;
typedef struct {
uint32_t poolId;
uint32_t bufferId;
int width;
int height;
int format;
} GFXREDIR_CREATE_BUFFER_PDU;
// Surface command definition
#define GFX_REDIR_SURFACE_COMMAND_UPDATEREGION 1
// Context structure
struct _GfxRedirServerContext {
int (*OpenPool)(struct _GfxRedirServerContext *ctx,
GFXREDIR_OPEN_POOL_PDU *open_pool);
int (*CreateBuffer)(struct _GfxRedirServerContext *ctx,
GFXREDIR_CREATE_BUFFER_PDU *create_buffer);
int (*SurfaceCommand)(struct _GfxRedirServerContext *ctx,
void *surface_data,
int command,
RECTANGLE_16 *rect,
void *buffer_data);
};
typedef struct _GfxRedirServerContext GfxRedirServerContext;
struct wlr_rdp_allocator {
struct wlr_allocator base;
GfxRedirServerContext *redir_ctx;
};
struct wlr_rdp_buffer {
struct wlr_buffer buffer;
uint32_t pool_id;
uint32_t buffer_id;
void *rdp_memory;
size_t rdp_memory_size;
int width;
int height;
int fd; // File descriptor for shared memory
bool data_access_in_progress;
};
// Function declarations
void* rdp_get_shared_memory(uint32_t pool_id, size_t *size, int *fd);
struct wlr_allocator *wlr_rdp_allocator_create(GfxRedirServerContext *redir_ctx);
#endif // WLR_RENDER_ALLOCATOR_RDPRAIL_H#ifndef WLR_BACKEND_RDP_H
#define WLR_BACKEND_RDP_H
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/allocator.h>
#include "rdprail.h"
// Forward declarations
struct wlr_rdp_surface;
// Function declarations
struct wlr_backend *wlr_rdp_backend_create(
struct wl_display *display,
struct wlr_session *session,
void *redir_ctx
);
struct wlr_rdp_backend *get_rdp_backend_from_backend(
struct wlr_backend *backend
);
struct wlr_rdp_backend {
struct wlr_backend base;
GfxRedirServerContext *redir_ctx;
struct wl_display *display;
struct wlr_session *session;
struct wlr_allocator *allocator;
struct {
struct wl_signal destroy;
struct wl_signal new_output;
struct wl_signal new_input;
} events;
struct wl_list outputs; // wlr_rdp_output::link
struct wl_list surfaces; // wlr_rdp_surface::link
bool started;
};
#endif // WLR_BACKEND_RDP_H
/* rdprail_output.h */
#ifndef WLR_RDP_OUTPUT_H
#define WLR_RDP_OUTPUT_H
#include <wayland-server-core.h>
#include <wlr/interfaces/wlr_output.h>
#include <pixman.h>
#include "rdprail_backend.h"
struct wlr_rdp_backend; // Forward declaration
struct wlr_rdp_output {
struct wlr_output base;
struct wlr_rdp_backend *backend;
struct wl_list link;
int width, height;
int refresh_rate;
bool initialized;
struct wlr_rdp_output_state {
struct wlr_buffer *pending_buffer;
bool damaged;
pixman_region32_t damage;
} pending;
struct {
struct wl_signal destroy;
} events;
};
struct wlr_rdp_output *wlr_rdp_output_create(struct wlr_rdp_backend *backend);
void wlr_rdp_output_set_refresh_rate(struct wlr_rdp_output *output, int refresh);
#endif
/* rdprail.c */
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <linux/memfd.h>
#include <wlr/render/allocator.h>
#include <wlr/render/drm_format_set.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <wlr/util/log.h>
#include <drm/drm_fourcc.h>
#include <stdio.h>
#include "rdprail.h"
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <fcntl.h> // For open() and O_RDWR
#include <gbm.h> // For gbm_create_device and gbm_device_destroy
#include <wayland-server.h> // For wl_event_loop functions
#include "backend/rdprail/rdprail.h" // For RDP backend functions
#include "backend/backend.h"
void wlr_rdp_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer);
// Rest of the existing code remains the same, but add these function implementations if they're not already defined
/*
void wlr_rdp_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
// Implement the function body, likely similar to other buffer access end functions in wlroots
// This might involve releasing locks, syncing memory, or other cleanup
}*/
// Logging function for debugging
static void log_buffer_state(struct wlr_buffer *buffer, const char *context) {
fprintf(stderr, "Buffer state at %s:\n", context);
fprintf(stderr, " Width: %d\n", buffer->width);
fprintf(stderr, " Height: %d\n", buffer->height);
fprintf(stderr, " Impl: %p\n", (void*)buffer->impl);
fprintf(stderr, " Dropped: %s\n", buffer->dropped ? "true" : "false");
fprintf(stderr, " Locks: %zu\n", buffer->n_locks);
fprintf(stderr, " Accessing data ptr: %s\n",
buffer->accessing_data_ptr ? "true" : "false");
}
// Placeholder implementation for shared memory retrieval
/*void* rdp_get_shared_memory(uint32_t pool_id, size_t *size, int *fd) {
// Use syscall for memfd_create as a fallback
*fd = syscall(SYS_memfd_create, "rdp_buffer", MFD_CLOEXEC);
// If syscall fails, fall back to temporary file
if (*fd == -1) {
char temp_path[] = "/tmp/rdp_buffer_XXXXXX";
*fd = mkstemp(temp_path);
if (*fd == -1) {
wlr_log(WLR_ERROR, "Failed to create shared memory");
return NULL;
}
// Unlink the temporary file so it's not visible in the filesystem
unlink(temp_path);
}
// Set size
*size = 1024 * 1024; // 1MB
// Resize the file descriptor
if (ftruncate(*fd, *size) == -1) {
wlr_log(WLR_ERROR, "Failed to resize shared memory");
close(*fd);
return NULL;
}
// Map the shared memory
void *memory = mmap(NULL, *size, PROT_READ | PROT_WRITE, MAP_SHARED, *fd, 0);
if (memory == MAP_FAILED) {
wlr_log(WLR_ERROR, "Failed to map shared memory");
close(*fd);
return NULL;
}
return memory;
}*/
void* rdp_get_shared_memory(uint32_t pool_id, size_t *size, int *fd) {
*size = 640 * 480 * 4; // Calculate exact size needed
// Create memfd with specific size
*fd = syscall(SYS_memfd_create, "rdp_buffer", MFD_CLOEXEC);
if (*fd == -1) {
char temp_path[] = "/tmp/rdp_buffer_XXXXXX";
*fd = mkstemp(temp_path);
if (*fd == -1) {
return NULL;
}
unlink(temp_path);
}
// Set the size
if (ftruncate(*fd, *size) == -1) {
close(*fd);
return NULL;
}
// Map the memory with proper protection flags
void *memory = mmap(NULL, *size, PROT_READ | PROT_WRITE,
MAP_SHARED, *fd, 0);
if (memory == MAP_FAILED) {
close(*fd);
return NULL;
}
// Clear the memory
memset(memory, 0, *size);
return memory;
}
// Mock RDP context functions
static int mock_open_pool(struct _GfxRedirServerContext *ctx,
GFXREDIR_OPEN_POOL_PDU *open_pool) {
static uint32_t next_pool_id = 1;
open_pool->poolId = next_pool_id++;
fprintf(stderr, "RDP Mock: Created pool %u\n", open_pool->poolId);
return 0;
}
static int mock_create_buffer(struct _GfxRedirServerContext *ctx,
GFXREDIR_CREATE_BUFFER_PDU *create_buffer) {
static uint32_t next_buffer_id = 1;
create_buffer->bufferId = next_buffer_id++;
fprintf(stderr, "RDP Mock: Created buffer %u in pool %u\n",
create_buffer->bufferId, create_buffer->poolId);
return 0;
}
// Buffer method implementations
/*static void wlr_rdp_buffer_destroy(struct wlr_buffer *buffer) {
struct wlr_rdp_buffer *rdp_buffer =
wl_container_of(buffer, rdp_buffer, buffer);
fprintf(stderr, "Destroying RDP buffer\n");
// Ensure no data access in progress
if (buffer->accessing_data_ptr) {
wlr_log(WLR_ERROR, "Destroying buffer while data access in progress");
}
// Unmap and close shared memory
if (rdp_buffer->rdp_memory) {
munmap(rdp_buffer->rdp_memory, rdp_buffer->rdp_memory_size);
}
if (rdp_buffer->fd != -1) {
close(rdp_buffer->fd);
}
// Free the buffer struct
free(rdp_buffer);
}*/
static void wlr_rdp_buffer_destroy(struct wlr_buffer *buffer) {
struct wlr_rdp_buffer *rdp_buffer = wl_container_of(buffer, rdp_buffer, buffer);
// Wait for any ongoing data access to complete
if (rdp_buffer->data_access_in_progress) {
wlr_rdp_buffer_end_data_ptr_access(buffer);
}
// Clean up memory
if (rdp_buffer->rdp_memory && rdp_buffer->rdp_memory_size > 0) {
munmap(rdp_buffer->rdp_memory, rdp_buffer->rdp_memory_size);
rdp_buffer->rdp_memory = NULL;
}
if (rdp_buffer->fd >= 0) {
close(rdp_buffer->fd);
rdp_buffer->fd = -1;
}
free(rdp_buffer);
}
static bool wlr_rdp_buffer_get_dmabuf(
struct wlr_buffer *wlr_buffer,
struct wlr_dmabuf_attributes *attribs
) {
// No DMA-BUF support for this buffer type
return false;
}
static bool wlr_rdp_buffer_get_shm(
struct wlr_buffer *wlr_buffer,
struct wlr_shm_attributes *attribs
) {
struct wlr_rdp_buffer *rdp_buffer =
wl_container_of(wlr_buffer, rdp_buffer, buffer);
if (!rdp_buffer->rdp_memory) {
return false;
}
attribs->fd = rdp_buffer->fd;
attribs->format = DRM_FORMAT_ARGB8888;
attribs->width = rdp_buffer->width;
attribs->height = rdp_buffer->height;
attribs->stride = rdp_buffer->width * 4;
attribs->offset = 0;
return true;
}
static bool wlr_rdp_buffer_begin_data_ptr_access(
struct wlr_buffer *wlr_buffer,
uint32_t flags,
void **data,
uint32_t *format,
size_t *stride
) {
struct wlr_rdp_buffer *rdp_buffer =
wl_container_of(wlr_buffer, rdp_buffer, buffer);
fprintf(stderr, "Beginning data ptr access\n");
log_buffer_state(wlr_buffer, "Begin data ptr access");
// Additional safety checks
if (wlr_buffer->accessing_data_ptr) {
wlr_log(WLR_ERROR, "Attempting to access buffer data while already in access");
return false;
}
if (!rdp_buffer->rdp_memory) {
wlr_log(WLR_ERROR, "No memory allocated for RDP buffer");
return false;
}
if (data) {
*data = rdp_buffer->rdp_memory;
fprintf(stderr, "Data pointer set to %p\n", *data);
}
if (format) {
*format = DRM_FORMAT_ARGB8888;
fprintf(stderr, "Format set to %u\n", *format);
}
if (stride) {
*stride = rdp_buffer->width * 4; // 4 bytes per pixel
fprintf(stderr, "Stride set to %zu\n", *stride);
}
// Mark that data access is in progress
rdp_buffer->data_access_in_progress = true;
return true;
}
void wlr_rdp_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
struct wlr_rdp_buffer *rdp_buffer =
wl_container_of(wlr_buffer, rdp_buffer, buffer);
fprintf(stderr, "Ending data ptr access\n");
log_buffer_state(wlr_buffer, "End data ptr access");
// Reset data access flag
rdp_buffer->data_access_in_progress = false;
}
// Define the buffer implementation matching wlr_buffer_impl
static const struct wlr_buffer_impl wlr_rdp_buffer_impl = {
.destroy = wlr_rdp_buffer_destroy,
.get_dmabuf = wlr_rdp_buffer_get_dmabuf,
.get_shm = wlr_rdp_buffer_get_shm,
.begin_data_ptr_access = wlr_rdp_buffer_begin_data_ptr_access,
.end_data_ptr_access = wlr_rdp_buffer_end_data_ptr_access,
};
// Allocator creation methods
static struct wlr_buffer *rdp_allocator_create_buffer(
struct wlr_allocator *alloc, int width, int height,
const struct wlr_drm_format *format) {
struct wlr_rdp_allocator *rdp_alloc =
wl_container_of(alloc, rdp_alloc, base);
fprintf(stderr, "Creating RDP buffer: %dx%d\n", width, height);
// Create RDP pool and buffer
GFXREDIR_OPEN_POOL_PDU open_pool = {0};
if (rdp_alloc->redir_ctx->OpenPool(rdp_alloc->redir_ctx, &open_pool) != 0) {
wlr_log(WLR_ERROR, "Failed to open RDP pool");
return NULL;
}
GFXREDIR_CREATE_BUFFER_PDU create_buffer = {
.poolId = open_pool.poolId,
.width = width,
.height = height,
.format = 1 // Placeholder for GFXREDIR_BUFFER_PIXEL_FORMAT_ARGB_8888
};
if (rdp_alloc->redir_ctx->CreateBuffer(rdp_alloc->redir_ctx, &create_buffer) != 0) {
wlr_log(WLR_ERROR, "Failed to create RDP buffer");
return NULL;
}
// Allocate RDP buffer struct
struct wlr_rdp_buffer *rdp_buffer = calloc(1, sizeof(struct wlr_rdp_buffer));
if (!rdp_buffer) {
wlr_log(WLR_ERROR, "Failed to allocate wlr_rdp_buffer");
return NULL;
}
rdp_buffer->pool_id = open_pool.poolId;
rdp_buffer->buffer_id = create_buffer.bufferId;
rdp_buffer->width = width;
rdp_buffer->height = height;
rdp_buffer->fd = -1;
rdp_buffer->data_access_in_progress = false;
// Acquire shared memory
rdp_buffer->rdp_memory = rdp_get_shared_memory(
open_pool.poolId, &rdp_buffer->rdp_memory_size, &rdp_buffer->fd);
if (!rdp_buffer->rdp_memory) {
wlr_log(WLR_ERROR, "Failed to get shared memory for RDP buffer");
free(rdp_buffer);
return NULL;
}
// Initialize the buffer with our implementation
wlr_buffer_init(
&rdp_buffer->buffer,
&wlr_rdp_buffer_impl,
width, height
);
fprintf(stderr, "RDP buffer created successfully\n");
return &rdp_buffer->buffer;
}
static void rdp_allocator_destroy(struct wlr_allocator *alloc) {
struct wlr_rdp_allocator *rdp_alloc =
wl_container_of(alloc, rdp_alloc, base);
fprintf(stderr, "Destroying RDP allocator\n");
free(rdp_alloc);
}
static const struct wlr_allocator_interface rdp_allocator_impl = {
.create_buffer = rdp_allocator_create_buffer,
.destroy = rdp_allocator_destroy,
};
struct wlr_allocator *wlr_rdp_allocator_create(
GfxRedirServerContext *redir_ctx) {
fprintf(stderr, "Creating RDP allocator\n");
if (!redir_ctx) {
wlr_log(WLR_ERROR, "Invalid RDP context");
return NULL;
}
struct wlr_rdp_allocator *alloc =
calloc(1, sizeof(struct wlr_rdp_allocator));
if (!alloc) {
wlr_log(WLR_ERROR, "Failed to allocate RDP allocator");
return NULL;
}
// Initialize allocator
wlr_allocator_init(&alloc->base, &rdp_allocator_impl,
WLR_BUFFER_CAP_DATA_PTR | WLR_BUFFER_CAP_SHM);
// Store RDP context
alloc->redir_ctx = redir_ctx;
fprintf(stderr, "RDP allocator created successfully\n");
return &alloc->base;
}
#include <assert.h>
#include <stdlib.h>
#include <wlr/backend.h>
#include <wlr/util/log.h>
#include <wayland-server-core.h>
#include "rdprail.h"
#include "rdprail_backend.h"
#include "rdprail_output.h"
// Function prototypes
static void handle_display_destroy(struct wl_listener *listener, void *data);
static bool rdp_backend_start(struct wlr_backend *wlr_backend);
static void rdp_backend_destroy(struct wlr_backend *wlr_backend);
// Backend implementation structure
static const struct wlr_backend_impl backend_impl = {
.start = rdp_backend_start,
.destroy = rdp_backend_destroy,
};
static bool rdp_backend_start(struct wlr_backend *wlr_backend) {
struct wlr_rdp_backend *backend =
wl_container_of(wlr_backend, backend, base);
if (backend->started) {
return true;
}
// Create an initial output
if (!wlr_rdp_output_create(backend)) {
wlr_log(WLR_ERROR, "Failed to create RDP output");
return false;
}
backend->started = true;
return true;
}
static void rdp_backend_destroy(struct wlr_backend *wlr_backend) {
struct wlr_rdp_backend *backend =
wl_container_of(wlr_backend, backend, base);
if (!backend) {
return;
}
// Remove display destroy listener
wl_list_remove(&backend->listeners.display_destroy.link);
// Emit destroy signal before cleanup
wlr_signal_emit_safe(&backend->events.destroy, backend);
// Destroy allocator if it exists
if (backend->allocator) {
wlr_allocator_destroy(backend->allocator);
}
free(backend);
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_rdp_backend *backend =
wl_container_of(listener, backend, listeners.display_destroy);
// Clean up backend resources
wlr_backend_destroy(&backend->base);
}
struct wlr_backend *wlr_rdp_backend_create(struct wl_display *display,
struct wlr_session *session, void *redir_ctx) {
struct wlr_rdp_backend *backend = calloc(1, sizeof(*backend));
if (!backend) {
wlr_log(WLR_ERROR, "Failed to allocate RDP backend");
return NULL;
}
// Initialize backend
backend->base.impl = &backend_impl;
backend->display = display;
backend->session = session;
backend->redir_ctx = (GfxRedirServerContext *)redir_ctx;
// Initialize lists
wl_list_init(&backend->outputs);
// Initialize signals
wl_signal_init(&backend->events.destroy);
wl_signal_init(&backend->events.new_output);
wl_signal_init(&backend->events.new_input);
// Setup display destruction listener
backend->listeners.display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &backend->listeners.display_destroy);
return &backend->base;
}
bool wlr_backend_is_rdp(struct wlr_backend *backend) {
return backend && backend->impl == &backend_impl;
}
struct wlr_rdp_backend *get_rdp_backend_from_backend(struct wlr_backend *backend) {
if (!wlr_backend_is_rdp(backend)) {
return NULL;
}
return wl_container_of(backend, backend, base);
}// rdprail_output.c
#include <assert.h>
#include <stdlib.h>
#include <wlr/interfaces/wlr_output.h>
#include <wlr/util/log.h>
#include "backend/rdprail/rdprail_output.h"
// Remove the gamma size function as it's not needed
// rdprail_output.c
static bool output_test(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
return true; // Always allow test state
}
static bool output_commit(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
struct wlr_rdp_output *output = (struct wlr_rdp_output *)wlr_output;
if (state->committed & WLR_OUTPUT_STATE_BUFFER && state->buffer) {
void *data;
uint32_t format;
size_t stride;
if (wlr_buffer_begin_data_ptr_access(state->buffer, 0,
&data, &format, &stride)) {
// Get damage region
pixman_box32_t *rects;
int n_rects;
rects = pixman_region32_rectangles(&output->pending.damage, &n_rects);
for (int i = 0; i < n_rects; i++) {
RECTANGLE_16 rect = {
.left = (uint16_t)rects[i].x1,
.top = (uint16_t)rects[i].y1,
.right = (uint16_t)rects[i].x2,
.bottom = (uint16_t)rects[i].y2
};
output->backend->redir_ctx->SurfaceCommand(
output->backend->redir_ctx,
output,
GFX_REDIR_SURFACE_COMMAND_UPDATEREGION,
&rect,
data);
}
wlr_buffer_end_data_ptr_access(state->buffer);
}
}
return true;
}
static void output_destroy(struct wlr_output *wlr_output) {
struct wlr_rdp_output *output = (struct wlr_rdp_output *)wlr_output;
wl_list_remove(&output->link);
free(output);
}
static const struct wlr_output_impl output_impl = {
.destroy = output_destroy,
.test = output_test,
.commit = output_commit,
};
struct wlr_rdp_output *wlr_rdp_output_create(struct wlr_rdp_backend *backend) {
struct wlr_rdp_output *output = calloc(1, sizeof(*output));
if (!output) {
return NULL;
}
struct wl_event_loop *event_loop =
wl_display_get_event_loop(backend->display);
wlr_output_init(&output->base,
&backend->base, // backend
&output_impl, // impl
event_loop, // event_loop
NULL); // state
output->backend = backend;
output->width = 1920;
output->height = 1080;
output->refresh_rate = 60000;
pixman_region32_init(&output->pending.damage);
wl_list_insert(&backend->outputs, &output->link);
wlr_signal_emit_safe(&backend->events.new_output, output);
return output;
}light@light:~/wayfire/subprojects/wlroots/backend/rdprail$Editor is loading...
Leave a Comment