简体   繁体   English

如何 map 视频 memory 从 python 到 Z4A8A08F09D37B73795649038408B5F3

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

I have been fooling around with some simple graphics things in Python, but to improve performance, I'd like to do some stuff in C.我一直在Python中玩弄一些简单的图形东西,但是为了提高性能,我想在C中做一些事情。

I know how to transfer arrays and stuff back and forth.我知道如何来回传输 arrays 和东西。 That's no biggie.这没什么大不了的。 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 the rest is done in C. 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 中完成。 Possibly asynchronously, but I don̈́'t know if that matters.可能是异步的,但我不知道这是否重要。

Is this possible, and does it make sense?这可能吗,这有意义吗? Or am I on the completely wrong track?还是我走错了路?

My efforts so far:到目前为止我的努力:

# 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)

And

// 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;
    }
}

This didn't work and ended up with a crash.这没有用,最终导致崩溃。 I'm not surprised, but well, it's what I've got so far.我并不感到惊讶,但是,这就是我到目前为止所得到的。

It's not strictly necessary to use Python.并非绝对必须使用 Python。 But I do want to use C.但我确实想使用 C。 And I'm also aware that in most cases, my approach is not the best one, but I do enjoy coding in C and doing stuff old school.而且我也知道,在大多数情况下,我的方法并不是最好的方法,但我确实喜欢在 C 中编码并做一些老派的事情。

Essentially, you want to share a buffer with the Python application.本质上,您希望与 Python 应用程序共享一个缓冲区。 There is a buffer protocol which exists for this exact purpose.有一个缓冲区协议就是为了这个目的而存在的。 Essentially, you share a Py_buffer object which has a buf and len field.本质上,您共享一个具有buflen字段的Py_buffer object。 (I didn't read through the whole thing, but you can for more info.) (我没有通读全文,但您可以了解更多信息。)

It turns out, that Surface.get_buffer() already returns such a buffer object.事实证明, Surface.get_buffer()已经返回了这样一个缓冲区 object。 In other words, you can directly pass it to your external function:换句话说,您可以直接将其传递给您的外部 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()

The key here is:这里的关键是:

engine.paint_gray(screen.get_buffer())

This isn't exactly what you were doing, but I think you should keep the loop in the Python application to be able to handle events.这不完全是您所做的,但我认为您应该在 Python 应用程序中保留循环以便能够处理事件。 Therefore, this function simply paints on the buffer.因此,这个 function 只是在缓冲区上绘制。 This is how this is implemented in C:这是在 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);
}

Note that I am also calling pygame.display.flip() .请注意,我也在调用pygame.display.flip() This is necessary, because pygame keeps two buffers one front buffer that is drawn on the screen and one back buffer that can be modified.这是必要的,因为 pygame 保留了两个缓冲区,一个在屏幕上绘制的前缓冲区和一个可以修改的后缓冲区。

Most GUI toolkits and game libraries will provide one way or another of getting access to the pixel buffer.大多数 GUI 工具包和游戏库将提供一种或另一种访问像素缓冲区的方法。

An easy way to get started would be with pygame.一个简单的入门方法是使用 pygame。 The get_buffer().raw array of pygame's Surface can be passed into a C program. 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