繁体   English   中英

如何 map 视频 memory 从 python 到 Z4A8A08F09D37B73795649038408B5F3

[英]How to map video memory from python to c?

我一直在Python中玩弄一些简单的图形东西,但是为了提高性能,我想在C中做一些事情。

我知道如何来回传输 arrays 和东西。 这没什么大不了的。 But I thought it might be beneficial if I could just create a windows with a canvas, pass a pointer to the video memory (of course not the physical video memory) and then let Python take care of just putting that memory to the screen, while rest 在 C 中完成。 可能是异步的,但我不知道这是否重要。

这可能吗,这有意义吗? 还是我走错了路?

到目前为止我的努力:

# graphics.py

import ctypes
import pygame

screen = pygame.display.set_mode((300,200))

f = ctypes.CDLL('/path/to/engine.so')

f.loop(screen._pixels_address)

// engine.c

#include <stdint.h>

void loop(void *mem) {
    while(1) {
        uint8_t *p = (uint8_t*) mem;
      
        // Was hoping this would make some pixels change
        for(int i=0; i<20000; i++)
            *p=127;
    }
}

这没有用,最终导致崩溃。 我并不感到惊讶,但是,这就是我到目前为止所得到的。

并非绝对必须使用 Python。 但我确实想使用 C。 而且我也知道,在大多数情况下,我的方法并不是最好的方法,但我确实喜欢在 C 中编码并做一些老派的事情。

本质上,您希望与 Python 应用程序共享一个缓冲区。 有一个缓冲区协议就是为了这个目的而存在的。 本质上,您共享一个具有buflen字段的Py_buffer object。 (我没有通读全文,但您可以了解更多信息。)

事实证明, Surface.get_buffer()已经返回了这样一个缓冲区 object。 换句话说,您可以直接将其传递给您的外部 function:

import pygame

background_colour = (255,255,255) # For the background color of your window
(width, height) = (300, 200) # Dimension of the window

screen = pygame.display.set_mode((width, height))

import engine # engine.so

b_running = True
while b_running:
    # Quit when 'X' button is pressed.
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            b_running = False

    # Add some amount of delay.
    pygame.time.wait(50)

    # Give the buffer object to C.
    engine.paint_gray(screen.get_buffer())
    pygame.display.flip()

这里的关键是:

engine.paint_gray(screen.get_buffer())

这不完全是您所做的,但我认为您应该在 Python 应用程序中保留循环以便能够处理事件。 因此,这个 function 只是在缓冲区上绘制。 这是在 C 中实现的方式:

// Related: https://docs.python.org/3/extending/extending.html

#define PY_SSIZE_T_CLEAN
#include <Python.h>

#include <stdint.h>
#include <assert.h>

static PyObject* engine_paint_gray(PyObject *self, PyObject *args)
{
    Py_buffer buffer;

    if (!PyArg_ParseTuple(args, "s*", &buffer))
        assert(0);

    uint8_t *raw_buffer = buffer.buf;
    for (int index=0; index<buffer.len; ++index)
        raw_buffer[index] = 127;

    return Py_None;
}

static PyMethodDef EngineMethods[] = {
    {"paint_gray", engine_paint_gray, METH_VARARGS, NULL},
    {NULL, NULL, 0, NULL} /* sentinel */
};

static struct PyModuleDef enginemodule = {
    PyModuleDef_HEAD_INIT,
    "engine",
    NULL,
    -1,
    EngineMethods
};

PyMODINIT_FUNC
PyInit_engine(void)
{
    return PyModule_Create(&enginemodule);
}

请注意,我也在调用pygame.display.flip() 这是必要的,因为 pygame 保留了两个缓冲区,一个在屏幕上绘制的前缓冲区和一个可以修改的后缓冲区。

大多数 GUI 工具包和游戏库将提供一种或另一种访问像素缓冲区的方法。

一个简单的入门方法是使用 pygame。 pygame 的Surfaceget_buffer().raw数组可以传入 C 程序。

import pygame

background_colour = (255,255,255) # For the background color of your window
(width, height) = (300, 200) # Dimension of the window

screen = pygame.display.set_mode((width, height))

f = CDLL('engine.so')
f.loop(screen.get_buffer().raw)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM