Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIGSEGV when using *pixelgl.Canvas.Texture() #8

Closed
peterhellberg opened this issue Apr 28, 2017 · 5 comments
Closed

SIGSEGV when using *pixelgl.Canvas.Texture() #8

peterhellberg opened this issue Apr 28, 2017 · 5 comments

Comments

@peterhellberg
Copy link
Contributor

I keep getting SIGSEGV:s when using the texture of a *pixelgl.Canvas.

The methods Begin(), SetPixels() and End() all result in SIGSEV.

Minimal example using Begin()

package main

import (
	"github.com/faiface/pixel"
	"github.com/faiface/pixel/pixelgl"
)

func run() {
	bounds := pixel.R(0, 0, 256, 256)
	pixelgl.NewCanvas(bounds).Texture().Begin()
}

func main() {
	pixelgl.Run(run)
}

Output

$ go run minimal-pixelgl-canvas-crash.go
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x0]

runtime stack:
runtime.throw(0x4116932, 0x2a)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/panic.go:596 +0x95
runtime.sigpanic()
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/signal_unix.go:274 +0x2db
runtime.asmcgocall(0x40000, 0xc420053f01)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/asm_amd64.s:633 +0x70
runtime.mallocgc.func1()
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/malloc.go:690 +0x3e

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x40ca460, 0xc420053ce0, 0xc420096000)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/cgocall.go:131 +0xe2 fp=0xc420053ca0 sp=0xc420053c60
github.com/go-gl/gl/v3.3-core/gl._Cfunc_glowGenTextures(0x0, 0xc400000001, 0xc420092150)
	github.com/go-gl/gl/v3.3-core/gl/_obj/_cgo_gotypes.go:4702 +0x45 fp=0xc420053ce0 sp=0xc420053ca0
github.com/go-gl/gl/v3.3-core/gl.GenTextures(0x1, 0xc420092150)
	/Users/peter/Go/src/github.com/go-gl/gl/v3.3-core/gl/package.go:5989 +0x3f fp=0xc420053d08 sp=0xc420053ce0
github.com/faiface/glhf.NewTexture(0x100, 0x100, 0x40000, 0xc420096000, 0x40000, 0x40000, 0x0)
	/Users/peter/Go/src/github.com/faiface/glhf/texture.go:32 +0x93 fp=0xc420053d60 sp=0xc420053d08
github.com/faiface/glhf.NewFrame(0x100, 0x100, 0x4070000000000000, 0x4070000000000000)
	/Users/peter/Go/src/github.com/faiface/glhf/frame.go:37 +0x8c fp=0xc420053db8 sp=0xc420053d60
github.com/faiface/pixel/pixelgl.(*GLFrame).SetBounds.func1()
	/Users/peter/Go/src/github.com/faiface/pixel/pixelgl/glframe.go:35 +0x84 fp=0xc420053e30 sp=0xc420053db8
github.com/faiface/mainthread.Call.func1()
	/Users/peter/Go/src/github.com/faiface/mainthread/mainthread.go:64 +0x26 fp=0xc420053e70 sp=0xc420053e30
github.com/faiface/mainthread.Run(0x41180b0)
	/Users/peter/Go/src/github.com/faiface/mainthread/mainthread.go:46 +0x15f fp=0xc420053f30 sp=0xc420053e70
github.com/faiface/pixel/pixelgl.Run(0x41180b0)
	/Users/peter/Go/src/github.com/faiface/pixel/pixelgl/run.go:32 +0x5e fp=0xc420053f70 sp=0xc420053f30
main.main()
	/Users/peter/Go/src/experiments/pixel/minimal-pixelgl-canvas-crash.go:14 +0x2d fp=0xc420053f88 sp=0xc420053f70
runtime.main()
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/proc.go:185 +0x20a fp=0xc420053fe0 sp=0xc420053f88
runtime.goexit()
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc420053fe8 sp=0xc420053fe0

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/asm_amd64.s:2197 +0x1

goroutine 19 [chan receive]:
github.com/faiface/mainthread.Call(0xc420072240)
	/Users/peter/Go/src/github.com/faiface/mainthread/mainthread.go:67 +0xb3
github.com/faiface/pixel/pixelgl.(*GLFrame).SetBounds(0xc4200920a0, 0x0, 0x0, 0x4070000000000000, 0x4070000000000000)
	/Users/peter/Go/src/github.com/faiface/pixel/pixelgl/glframe.go:46 +0x111
github.com/faiface/pixel/pixelgl.NewGLFrame(0x0, 0x0, 0x4070000000000000, 0x4070000000000000, 0x0)
	/Users/peter/Go/src/github.com/faiface/pixel/pixelgl/glframe.go:21 +0x70
github.com/faiface/pixel/pixelgl.NewCanvas(0x0, 0x0, 0x4070000000000000, 0x4070000000000000, 0x0)
	/Users/peter/Go/src/github.com/faiface/pixel/pixelgl/canvas.go:35 +0x61
main.run()
	/Users/peter/Go/src/experiments/pixel/minimal-pixelgl-canvas-crash.go:10 +0x44
github.com/faiface/mainthread.Run.func1(0x41180b0, 0xc42006e180)
	/Users/peter/Go/src/github.com/faiface/mainthread/mainthread.go:39 +0x27
created by github.com/faiface/mainthread.Run
	/Users/peter/Go/src/github.com/faiface/mainthread/mainthread.go:41 +0xe5
exit status 2

Environment

$ go version
go version go1.8.1 darwin/amd64
$ system_profiler SPSoftwareDataType
Software:

    System Software Overview:

      System Version: macOS 10.12.4 (16E195)
      Kernel Version: Darwin 16.5.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
      Computer Name: Peter Hellbergs MacBook Pro
      User Name: Peter Hellberg (peter)
      Secure Virtual Memory: Enabled
      System Integrity Protection: Enabled
      Time since boot: 17 days 22:38
@peterhellberg
Copy link
Contributor Author

peterhellberg commented Apr 28, 2017

Calling canvas.Clear works

package main

import (
	"image"
	"image/color"
	"image/draw"
	"os"

	"github.com/faiface/pixel"
	"github.com/faiface/pixel/pixelgl"
)

var (
	w, h = 256, 256

	green  = color.RGBA{100, 255, 100, 255}
	orange = color.RGBA{255, 50, 0, 255}

	cfg = pixelgl.WindowConfig{
		Bounds:      pixel.R(0, 0, float64(w), float64(h)),
		VSync:       true,
		Undecorated: true,
	}
)

func run() {
	win, err := pixelgl.NewWindow(cfg)
	if err != nil {
		panic(err)
	}

	canvas := pixelgl.NewCanvas(win.Bounds())

	// This works just fine
	canvas.Clear(green)

	if os.Getenv("CRASH") == "yes" {
		// This results in a SIGSEGV
		canvas.Texture().SetPixels(0, 0, w, h, newUniformImage(w, h, orange).Pix)
	}

	for !win.Closed() {
		win.SetClosed(win.JustPressed(pixelgl.KeyEscape))

		canvas.Draw(win)
		win.Update()
	}
}

func newUniformImage(w, h int, c color.Color) *image.RGBA {
	m := image.NewRGBA(image.Rect(0, 0, w, h))

	draw.Draw(m, m.Bounds(), &image.Uniform{c}, image.ZP, draw.Src)

	return m
}

func main() {
	pixelgl.Run(run)
}

If running this code with CRASH=yes go run setpixels-crash.go it results in a SIGSEGV

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7fff7d66457c]

runtime stack:
runtime.throw(0x41634f9, 0x2a)
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/panic.go:596 +0x95
runtime.sigpanic()
	/usr/local/Cellar/go/1.8.1/libexec/src/runtime/signal_unix.go:274 +0x2db

exit status 21: syscall [locked] [Created by mainthread.Run @ mainthread.go:41]
    runtime    cgocall.go:131        cgocall(0x40f42d0, 0xc42003be48, 0x411c2e0)
    gl         _cgo_gotypes.go:10291 _Cfunc_glowTexSubImage2D(#5, 0xde1, 0, #3, #4, #2)
    gl         package.go:7443       TexSubImage2D.func1(140735297242449, 3553, 0, 1099511628032, 21994527529224, 842351583232)
    gl         package.go:7443       TexSubImage2D(3553, 0, 1099511628032, 21994527529224, 842351583232)
    glhf       texture.go:93         (*Texture).SetPixels(*Texture(0xc42001a320), 0, 0, 256, 256, []uint8(#2 len=262144 cap=262144))
    main       setpixels-crash.go:39 run()
    mainthread mainthread.go:39      Run.func1(func(#1))
    runtime    asm_amd64.s:2197      goexit()
1: select [locked]
    mainthread mainthread.go:44      Run(#1)
    pixelgl    run.go:32             Run(func(#1))
    main       setpixels-crash.go:59 main()
1: syscall [locked]
    runtime    asm_amd64.s:2197      goexit()

@faiface
Copy link
Owner

faiface commented Apr 28, 2017

Thanks for the issue! The trouble is, that Canvas.Texture() returns a *Texture value from the "github.com/faiface/glhf" package.

If we look at the docs of the GLHF package (https://godoc.org/github.com/faiface/glhf), we find this:

All calls should be done from the main thread using "github.com/faiface/mainthread" package.

The thing is, that OpenGL is thread sensitive and all of the OpenGL calls should be done from the main thread of your program. If you violate that, the program might crash. In your case, you certainly violated that.

Since no user of Pixel should really need to bother with the GLHF package and this functionality of "replacing the Canvas pixels" is really useful, I've added two methods to Canvas: SetPixels and Pixels.

Use those instead. If you're interested in how this whole thing should have been done, I recommend you taking a look at the source of those methods. It's quite easy.

@peterhellberg
Copy link
Contributor Author

I suspected that it had to do with being on the wrong thread, thank you for clarifying this and that you added the new methods.

@faiface
Copy link
Owner

faiface commented Apr 28, 2017

Cool. If there's no trouble with the new methods, I'll close this issue.

@peterhellberg
Copy link
Contributor Author

I have now verified that SetPixels work the way it is supposed to. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants