BurntSushi / xgb

The X Go Binding is a low-level API to communicate with the X server. It is modeled on XCB and supports many X extensions.
Other
489 stars 75 forks source link

Using shm.GetImage().Reply() #28

Open Jsewill opened 9 years ago

Jsewill commented 9 years ago

This is not a bug, just a lack of understanding on my part. I have put xproto.GetImage() to good use in a project I'm working on, but I'd like to use shm.GetImage() to get an image from the X server via SHM, where should I start? I apologize if it is inappropriate for me to post this as an issue, and I'd be glad to delete it if needed.

BurntSushi commented 9 years ago

Honestly, I don't know (but I'd like to). I've never used shm before. If I were to investigate, I'd probably look for examples in C that use XCB. XGB should hopefully be a straight-forward translation from that.

Jsewill commented 9 years ago

Indeed, that was the first place I went looking. It seems I need to brush up on tmpfs/shm, especially as it relates to X11 in general. I'll continue looking into it and reply with any findings.

BurntSushi commented 9 years ago

@Jsewill yes, please do! I'm personally quite carious. Even if you're findings are, "I found this good C example but I can't translate it to Go. Can you help?" :-)

Jsewill commented 9 years ago

Well, I was able to use shm.NewSegId(), shm.CreateSegment().Reply(), and shm.GetImage().Reply() without error. This gets me a segment ID and file descriptor (I think), and has X create the image in that segment. I'm not really sure how to read it.

In my research earlier in the week, I came across an example in C from the VLC project: https://github.com/videolan/vlc/blob/master/modules/access/screen/xcb.c . This is the best example I have found yet. Perhaps I need to attach and detach the segment to and from X and my program, though I was hoping this was happening automatically.

As far as I know, SHM related stuff was explicitly left out of Golang's builtin, "syscall". Short of using a Go wrapper for the C shm related functions, do you have any insight regarding all this?

Jsewill commented 9 years ago

I've made some progress, but now I'm hitting a wall. The X server comes back with "BadIDChoice" when attempting to attach an SHM segment, whether I create the segment using shm.CreateSegment() or wrapped C functions. Any ideas?

Jsewill commented 9 years ago

After revisiting this, I figured out the proper arguements and their order, and with that X stops complaining.

The current process is as such:

I still have a problem accessing the data from the segment yet, but I'll work through that when I have more time to work on it.

sai-prasanna commented 7 years ago

@Jsewill Can you post the code for this?

sai-prasanna commented 7 years ago

Here is working version, figured it out.

package main

/*
#include <sys/ipc.h>
#include <sys/shm.h>
*/
import "C"

import (
    "github.com/BurntSushi/xgb"
    "github.com/BurntSushi/xgb/shm"
    "github.com/BurntSushi/xgb/xproto"

        "fmt"
    "image"
    "time"
    "unsafe"
)

func main() {
    scr := newXgbShmScreen()
    for i := 0; i < 100; i++ {
        start := time.Now()
        scr.capture()
        elapsed := time.Since(start)
        fmt.Printf("%d\n", elapsed.Nanoseconds())
    }
    scr.Close()
}

type xgbShmScreen struct {
    conn    *xgb.Conn
    screen  *xproto.ScreenInfo
    shmId   int
    data    unsafe.Pointer
    shmSize int
    seg     shm.Seg
}

func newXgbShmScreen() *xgbShmScreen {
    var scr xgbShmScreen
    var err error
    scr.conn, err = xgb.NewConn()
    if err != nil || shm.Init(scr.conn) != nil {
        return nil
    }

    scr.screen = xproto.Setup(scr.conn).DefaultScreen(scr.conn)
    scr.shmSize = int(scr.screen.WidthInPixels) * int(scr.screen.HeightInPixels) * 4
    scr.shmId = int(C.shmget(C.IPC_PRIVATE, C.size_t(scr.shmSize), C.IPC_CREAT|0777))

    if scr.shmId == -1 {
        return nil
    }
    scr.data = C.shmat(C.int(scr.shmId), nil, 0)
    scr.seg, err = shm.NewSegId(scr.conn)
    if err != nil {
        return nil
    }

    shm.AttachChecked(scr.conn, scr.seg, uint32(scr.shmId), false)
    return &scr
}

func (scr *xgbShmScreen) capture() (imgData []byte, err error) {
    _, err = shm.GetImage(scr.conn, xproto.Drawable(scr.screen.Root), 0, 0, scr.screen.WidthInPixels, scr.screen.HeightInPixels, 0xffffffff, byte(xproto.ImageFormatZPixmap), scr.seg, 0).Reply()
    if err != nil {
        return nil, err
    }
    imgData = (*[1 << 30]byte)(scr.data)[:scr.shmSize:scr.shmSize]
    return imgData, nil
}

func (scr *xgbShmScreen) Close() {
    shm.Detach(scr.conn, scr.seg)
    C.shmctl(C.int(scr.shmId), C.IPC_RMID, nil)
    C.shmdt(scr.data)
    scr.conn.Close()
}

@BurntSushi

  1. Is this repo accepting contribs? will give a pull req for this as an example.
  2. Is xcb protocol frozen stable ? Would I be better off in long run using this or just using xcb via c go.