linux直接渲染管理,使用Linux中的“直接渲染管理器”在dumbbuffer上调用mmap在使用C时失败...

有一段时间,我一直在使用 Linux‘ Direct Rendering Manager,这允许我们进行一些非常低级别的图形管理.这通常在C中完成,在 libdrm的帮助下,或直接使用 DRM headers.

我正在尝试在Rust中创建一个与libdrm等效的东西,它不仅仅是对C库的绑定,而是直接使用系统调用.这不是一项容易的任务,因为那里几乎没有DRM的文档,但我正在关注this example in C以获取从哪里开始的提示.

我现在到了我应该创建一个哑缓冲区并将其映射到内存中的点,所以我可以修改屏幕上显示的每像素像素数.为此,我必须使用mmap,但我得到一个非常奇怪的错误.

这是C中的最小工作代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main() {

// STEP 1: GET ACCESS TO DRM

int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);

if (fd < 0) {

printf("Error in function open(): %s\n", strerror(errno));

return 1;

}

// STEP 2: CREATE DUMBBUFFER

struct drm_mode_create_dumb dreq;

dreq.height = 1080,

dreq.width = 1920,

dreq.bpp = 32,

dreq.flags = 0,

dreq.handle = 0,

dreq.pitch = 0,

dreq.size = 0;

int ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dreq);

if (ret == -1) {

printf("Call to DRM_IOCTL_MODE_CREATE_DUMB failed: %s\n",

strerror(errno));

return 1;

}

// STEP 3: ADD FRAMEBUFFER

struct drm_mode_fb_cmd creq;

creq.fb_id = 0;

creq.width = dreq.width;

creq.height = dreq.height;

creq.pitch = dreq.pitch;

creq.bpp = dreq.bpp;

creq.depth = 24;

creq.handle = dreq.handle;

ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &creq);

if (ret == -1) {

printf("Call to DRM_IOCTL_MODE_ADDFB failed: %s\n", strerror(errno));

return 1;

}

// STEP 4: PREPARE FOR MAPPING

struct drm_mode_map_dumb mreq;

mreq.handle = dreq.handle;

mreq.pad = 0;

mreq.offset = 0;

ret = ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);

if (ret == -1) {

printf("Call to DRM_IOCTL_MODE_MAP_DUMB failed: %s\n", strerror(errno));

return 1;

}

// STEP 5: MAPPING PROPER

void *map = mmap(0, dreq.size, PROT_READ | PROT_WRITE, MAP_SHARED,

fd, mreq.offset);

if (map == MAP_FAILED) {

printf("Error in function mmap(): %s\n", strerror(errno));

return 1;

} else {

printf("Address of mapped data: 0x%x\n", map);

}

return 0;

}

这是Rust中完全相同的代码.当然,我的真实代码中有更多的东西,但这个最小的代码足以得到错误:

#![feature(libc)]

extern crate libc;

use self::libc::{c_char, c_int, c_ulong, c_void, off_t, size_t};

extern {

pub fn ioctl(fd : c_int, request : c_ulong, arg : *mut c_void) -> c_int;

}

fn errno() -> c_int {

unsafe { *libc::__errno_location() }

}

fn get_c_error() -> String {

unsafe {

let strerr = libc::strerror(errno()) as *mut u8;

let length = libc::strlen(strerr as *const c_char) as usize;

let mut string = String::with_capacity(length);

for i in 0..length {

let car = *strerr.offset(i as isize) as char;

if car == (0 as char) { break; }

string.push(car);

}

string

}

}

#[repr(C)]

struct CCreateDumb {

height : u32,

width : u32,

bpp : u32,

_flags : u32,

handle : u32,

pitch : u32,

size : u64,

}

#[repr(C)]

struct CFrameBuffer {

_fb_id : u32,

_width : u32,

_height : u32,

_pitch : u32,

_bpp : u32,

_depth : u32,

_handle : u32,

}

#[repr(C)]

struct CMapDumb {

_handle : u32,

_pad : u32,

offset : u32,

}

fn main() {

// STEP 1: GET ACCESS TO DRM

let pathname = "/dev/dri/card0".to_string();

let fd : c_int = unsafe {

libc::open(pathname.as_ptr() as *const c_char,

libc::O_RDWR | libc::O_CLOEXEC)

};

if fd < 0 {

panic!("Error in call of C function open(): {}", get_c_error());

}

// STEP 2: CREATE DUMBBUFFER

let mut dreq = CCreateDumb {

height : 1080,

width : 1920,

bpp : 32,

_flags : 0,

handle : 0,

pitch : 0,

size : 0,

};

// NB : 0xc02064b2 = DRM_IOCTL_MODE_CREATE_DUMB

let mut ret = unsafe {

ioctl(fd, 0xc02064b2 as c_ulong, &mut dreq as *mut _ as *mut c_void)

};

if ret == -1 {

panic!("Call to DRM_IOCTL_MODE_CREATE_DUMB failed: {}", get_c_error());

}

// STEP 3: ADD FRAMEBUFFER

let mut creq = CFrameBuffer {

_fb_id : 0,

_width : dreq.width,

_height : dreq.height,

_pitch : dreq.pitch,

_bpp : dreq.bpp,

_depth : 24,

_handle : dreq.handle,

};

// NB : 0xc01c64ae = DRM_IOCTL_MODE_ADDFB

ret = unsafe {

ioctl(fd, 0xc01c64ae as c_ulong, &mut creq as *mut _ as *mut c_void)

};

if ret == -1 {

panic!("Call to DRM_IOCTL_MODE_ADDFB failed: {}", get_c_error());

}

// STEP 4: PREPARE FOR MAPPING

let mut mreq = CMapDumb {

_handle : dreq.handle,

_pad : 0,

offset : 0,

};

// NB : 0xc01064b3 = DRM_IOCTL_MODE_MAP_DUMB

ret = unsafe {

ioctl(fd, 0xc01064b3 as c_ulong, &mut mreq as *mut _ as *mut c_void)

};

if ret == -1 {

panic!("Call to DRM_IOCTL_MODE_MAP_DUMB failed: {}", get_c_error());

}

// STEP 5: MAPPING PROPER

let map = unsafe {

libc::mmap(

0 as *mut c_void,

dreq.size as size_t,

libc::PROT_READ | libc::PROT_WRITE,

libc::MAP_SHARED,

fd,

mreq.offset as off_t

)

};

if map == libc::MAP_FAILED {

panic!("Error in call of C function mmap(): {}", get_c_error());

} else {

println!("Address of mapped data: 0x{:p}", map);

}

}

它编译得很好,但是当我执行它时,我得到了这个错误.

thread ” panicked at ‘Error in call of C function mmap(): Invalid argument’, memmapping.rs:139

note: Run with RUST_BACKTRACE=1 for a backtrace.

使用extern块直接链接到原始的C mmap函数而不是Rust的crate libc并不会改变任何东西.

我看了this project如何调用mmap,并尝试做同样的事情,以确保大小和偏移量是页面对齐的,但它没有改变任何东西,因为它们已经是页面对齐的.

This SO question使用名为std :: os :: MemoryMap的stdlib工具,但它不再存在.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值