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

Remove Cgo dependency on Windows #102

Closed
wants to merge 12 commits into from
Closed

Conversation

hajimehoshi
Copy link
Member

@hajimehoshi hajimehoshi commented Nov 12, 2018

Fixes go-gl/gl#109

Design Document

https://docs.google.com/document/d/1mqquznil9fR2amtb3eTC2ObCx3A8Af_5INqKjO-pKDg/edit?usp=sharing

tl;dr

I propose to eliminate Cgo usages on Windows from go-gl/gl by fixing go-gl/glow to generate code using syscall.Syscall.

@hajimehoshi
Copy link
Member Author

hajimehoshi commented Nov 12, 2018

Please take a look: @slimsag @dmitshur

functions.go Outdated Show resolved Hide resolved
functions.go Outdated Show resolved Hide resolved
@hajimehoshi
Copy link
Member Author

friendly ping

@hajimehoshi
Copy link
Member Author

hajimehoshi commented Dec 4, 2018

That's really sad that there has not been any feedback in the last 22 days. This change is really important (at least to me) e.g. in order to make compiling time shorten on Windows.

@pwaller
Copy link
Member

pwaller commented Dec 4, 2018

Hi @hajimehoshi, thanks very much for your contribution. Sorry it is taking time, but please be aware that no one is paid to maintain these packages. It's a best effort in our spare time and we can only give so much. Please have patience and faith that we will get to it. Feel free to continue to send pings!

tmpl/conversions.tmpl Outdated Show resolved Hide resolved
hajimehoshi added a commit to hajimehoshi/ebiten that referenced this pull request Dec 8, 2018
type.go Outdated
return fmt.Sprintf("uintptr(math.Float64bits(%s))", name)
}
case "GLDEBUGPROC", "GLDEBUGPROCARB", "GLDEBUGPROCKHR":
return fmt.Sprintf("syscall.NewCallback(%s)", name)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be NewCallbackCDecl?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@silbinarywolf
Copy link

@pwaller @kjozic or @errcw

Are any of you able to set aside some time and review this?
Being able to not rely on CGo on Windows would be amazing and help with simplifying the build process of my game engine for less experienced users.

Copy link
Member

@errcw errcw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick first pass...

}

// Syscall returns a syscall expression for Windows.
func (f Function) Syscall() string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this would be more idiomatic/clear if it returned an error when !IsImplementedForSyscall (rather than having a separate func that needs to be called)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called at templates to generate Syscall calling, then returning error here would not make sense.

@@ -0,0 +1,110 @@
//glow:keepspace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me why this conversion code, or the debug code, needs to be forked across Windows/not-Windows.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#102 (comment) is the reason: using this conversions_windows.tmpl version at Cgo caused errors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way we can reduce the duplication by factoring out the parts that are the same? (Or am I misreading and all the implementations are subtly different?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (created the common conversion.tmpl)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting back to this now (finally, sorry for the delay)...

  1. Are the changes to conversions.tmpl platform agnostic and should be used everywhere?
  2. I still don't quite understand why debug needs to be forked.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick reply: go-gl/gl#80 might be related, but I am not sure. I'll take a look later.

Copy link
Member Author

@hajimehoshi hajimehoshi Apr 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like if we can make conversions.tmpl pure Go first, we should do this before merging this PR. Wdyt?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm all for updating conversions to work across the board.

@@ -68,14 +68,29 @@ func (pkg *Package) GeneratePackage(dir string) error {
if err := pkg.generateFile("package", dir); err != nil {
return err
}
if err := pkg.generateFile("conversions", dir); err != nil {
if err := pkg.generateFile("package_notwindows", dir); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having all these files is super unfortunate, but I'm not sure whether there is anything to be done for it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps something like:

for _, v := range []string{"package", "package_notwindows", "package_windows",
  "conversions", "conversions_notwindows", "conversions_windows",
  "procaddr_notwindows", "procaddr_windows"} {
  if err := pkg.generateFile(v, dir); err != nil {
	  return err
  }
}

// #cgo linux freebsd LDFLAGS: -lGL
// #cgo windows LDFLAGS: -lopengl32
//
// #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

presumably these windows-specific bits are no longer necessary in the not-windows files?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@hajimehoshi
Copy link
Member Author

I think I have addressed all the issues. Please take a look. Thank you!

@hajimehoshi
Copy link
Member Author

Oops, I need to rebase this

@hajimehoshi
Copy link
Member Author

Done. PTAL

// in order to free the memory.
//
// If no strings are provided as a parameter this function will panic.
func Strs(strs ...string) (cstrs **uint8, free func()) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@errcw My concern was that **uint8 would be a Go pointer to a Go pointer, which is not allowed to pass to C world. (This is fine to pass this to Syscall on Windows as long as we care the lifetime of the object). That's why I separated the implementation for Windows and non-Windows. Do you have any suggestions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm so sorry for the slow responses here. The amount of free time I have is vanishingly small these days. The cstrs **unit8 return value is actually a set of pointers into malloc'ed C memory, which I believe is safe?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for responding! Our plan is to make this function in pure Go (no cgo in any environment), right? If so, we would not be able to use C allocator.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, right, of course. So I'm clear, on Windows, we're using Syscall which is inherently safe to accept values that are Go pointers to Go pointers? Whereas on other platforms those same values are unsafe because they cross the Cgo boundary? If so, sounds good.

Copy link
Member Author

@hajimehoshi hajimehoshi Apr 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on Windows, we're using Syscall which is inherently safe to accept values that are Go pointers to Go pointers?

Yes, there is no warning, and we can assure the lifetime of the objects (by runtime.KeepAlive).

Whereas on other platforms those same values are unsafe because they cross the Cgo boundary?

This is unsafe, and unfortunately Go runtime suspends the execution with warning messages. That's the problem.

Then, I think it would be inevitable to split the implementation for Windows and non-Windows. My suggestion is to split the allocation part to minimize the split code. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, sounds good.

So, you are fine with splitting the code? :-)

@neclepsio
Copy link

@hajimehoshi thank you very much for this. I can't understand why it has been abandoned.

I created a pull request on your nocgo branch to sync with master, implementing overloads.

Moreover, I found a bug, not linked to overloads, in function:

func DebugMessageCallback(callback DebugProc, userParam unsafe.Pointer) {
	syscall.Syscall(gpDebugMessageCallback, 2, syscall.NewCallbackCDecl(callback), uintptr(userParam), 0)
}

panic: compileCallback: expected function with one uintptr-sized result

This happens while creating a debug context with glfw 3.3; it works fine with cgo version.

If I succeed in fixing it, I will make another pull request on your branch.

@Zyl9393
Copy link

Zyl9393 commented Oct 3, 2020

I would like everyone to take notice that using syscall will double the call overhead, because syscall always calls GetLastError() on Windows, even if you use it to invoke non-WINAPI functions. If your CPU is bottlenecking (which is likely because we already experience a ~70ns overhead due to CGO) it would then bottleneck doubly, without gaining anything in the process. This will then further cement the fact that Golang projects which use OpenGL must be able to make do with a fraction of the calls that a C program could use.

@zwang
Copy link
Contributor

zwang commented Mar 5, 2021

Does this change limit glow only to generating Golang GL bindings using desktop OpenGL? Thanks

@hajimehoshi
Copy link
Member Author

thank you very much for this. I can't understand why it has been abandoned.

Oh I forgot I created this PR... I was waiting for the reviews but reviewers seemed pretty busy.

If there are reviewers, I'm fine to continue this PR.

@Jacalz
Copy link
Contributor

Jacalz commented Oct 24, 2021

We at Fyne would certainly be interested at testing this once it is ready. It has been suggested a few times in the past that we should remove CGo on Windows (see fyne-io/fyne#911).

Copy link
Contributor

@Jacalz Jacalz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really much of a review. Just a small note on a comment :)

@@ -10,6 +13,33 @@ type Function struct {
Return Type
}

// IsImplementedForSyscall reports whether the function is implemented for syscall or not.
func (f Function) IsImplementedForSyscall() bool {
// TODO: Use syscall.Syscall18 when Go 1.12 is the minimum supported version.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like Go 1.12 is the lowest supported version now.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least in glow. The gl package's mod file still says 1.9. Also, in 1.18 all the syscall functions except SyscallN are deprecated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, go-gl/gl#144

@MatejMagat305
Copy link

Friedly ping ...

@hajimehoshi
Copy link
Member Author

I'm quite busy to work on this. I'm fine if someone takes over this

@hajimehoshi hajimehoshi reopened this Feb 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

remove dependency on cgo