Untitled
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$
Leave a Comment