-
Notifications
You must be signed in to change notification settings - Fork 17
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
Add glReadPixels and image saving capabilties #75
Conversation
Thanks for your work on this @OhadRau !
Great idea! We don't have to write our own image diffing algorithm 🎉
@cryza was doing some work / had some ideas here (exposing buffers from the OCaml side). One possibility I could see would be adding an
I didn't understand this part - I was looking at this
If we went the I'm open to creating a separate function if it makes sense! But want to make sure I understand fully why it's not feasible to use One other challenge that will affect us next is that, currently, I'm not actually able to run OpenGL apps on any of our Azure CI machines (#76). I believe that, because they are VMs, they may not have the necessary OpenGL drivers - so they fail in getting a window context. Need to experiment with installing Mesa to see where it gets. Having the JS functionality would be helpful in the interim , because we could at least potentially run the browser version to get the image compare results. (Or, we could just use travis to generate the screenshot / run the compare) |
Thanks for the feedback. I'll try to clarify a few of the things you brought up.
Yeah, so this is basically what I was doing at first. The problem I saw was that the current
Huh.. I have no idea what I was looking at then. This should work fine I guess. I'll bring back in some of the original code and polish this up later today. |
Based on this, looks like the common subset of these two APIs would be:
@bryphe Should I try to support all the available modes and throw an error if it doesn't exist, or would you suggest just using this subset? https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glReadPixels.xhtml |
Actually, bumped into another issue. The WebGL version of |
Update on where we are -- I've reimplemented basically everything from the previous commit but using |
Ok, I'm making a lot of progress (I think) on the JS end but I'm still getting weird WebGL errors. AHHHH I just found the issue as soon as I posted this -- none of the major browsers support I got file downloads working as well, but at least in Firefox the endianness that the |
@bryphe Not sure if you've had a chance to look over this since your last comment. I've addressed most of the stuff you brought up and redesigned most of this code to be more general. Looks like the failing test is due to some issue in GLM compiling on Windows, I don't think that had to do with my code (but I could be wrong). Anyways, let me know if there's anything here you'd like me to change or add. I edited the main PR description to reflect the new API if you want a quick intro to what this will look like. |
@OhadRau - sorry for the slow response on my end! Really impressive work - that's awesome that you found a way to implement use It's amazing that we have a cross-platform way to create images, call Very happy with the way the API turned out, and I like the direction the |
Just going to test it on Windows, but the code looks great to me. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Works great on Windows - tested both the native strategy and chrome! 😍 It's really neat that the Image.save
"just works" as you'd expect in all these places - testament to your work. I'm just thinking now of the cool apps I could build with this...
I'll merge this to get around the CI issue, and see if that reason-gl-matrix
issue comes back up. Sorry about the issues with the build there. But it definitely doesn't look related to your code. Thanks again for all your work on this, @OhadRau !
Awesome! Thanks for reviewing this |
Currently, this PR adds the following functions:
Glfw.glReadPixels: (int, int, int, int, texturePixelDataFormat, glType, 'buffer) => unit
- Read pixels from the current framebuffer into the buffer givenImage.create: (~width: int, ~height: int, ~numChannels: int, ~channelSize: int) => Image.t
- Create an empty image object (provides a pixel buffer and allows for saving)Image.destroy : (Image.t) => unit
- Destroy an image object, freeing the memory from its bufferImage.getBuffer: (Image.t) => Image.pixelBuffer
- Get a pointer to the image's buffer, for use withGlfw.glReadPixels
Image.save: (Image.t, string) => unit
- Save an image object as a TGA file with the given name. In the browser, this will generate a file and trigger a download for it.Below is an example of how these can be used to capture a window's contents:
(All the stuff below this line is outdated)
This PR adds
Reglfw.Glfw.captureWindow: (Window.t, string) => unit
which takes the contents of the current window and saves it to a TGA file. Currently, the stub for this method is located inglfw_wrapper.cpp
but that may not be the best logical place for it. It also isn't implemented in JS. This could be added using theGL.readPixels()
call in the browser (note: this gives us far less control over the desired format that the realglReadPixels()
) and outputting the TGA file to a data URI, I just haven't put in the work for that yet.The primary motivation for this PR is for testing apps written using reason-glfw, since it allows us to capture the window at a certain frame (see the example, where it captures it every 60 frames). This can be used for UI regression tests as discussed in revery-ui/revery#156. For example, we provide a reference image for frame X and then take a screenshot at frame X when the program runs using this API. The two images are then diffed in a shell script (we can use
magick compare
for this), and if they don't match they're uploaded to some image host where we can compare the two.Note for some further discussion on this API: I was originally going to implement raw calls to
glReadPixels
but eventually decided against this for the following reasons:malloc
functionality to OCaml. The approach I thought would work best would be to create an image object, but I thought that might be confusing because we wouldn't be able to utilize any of stb_image for that.glReadPixels
is pretty different in JS, since it doesn't take any parameters and doesn't write into a buffer of any kind. It would also be weird to break this process up into multiple functions because they would have differing levels of JS compatibility along the way.glReadPixels
and then find a matching format to use for the TGA format.glReadPixels
seems to vary a lot between GL versions (not sure if this is normal). For example, in OpenGL 2 it supported aGL_ALPHA
format which seems to be removed in OpenGL 3/4.