golang-ui / nuklear

This project provides Go bindings for nuklear.h — a small ANSI C GUI library.
https://github.com/vurtun/nuklear
MIT License
1.57k stars 98 forks source link

Draw only if anything changed #52

Open Oneiros90 opened 6 years ago

Oneiros90 commented 6 years ago

Thanks for this Go wrapper, it is awesome. I am trying to change the drawing logic in order to achieve better performance in a simple desktop application. I would like to limit the GL draw calls to actual user interactions or render buffer changes. In the c nuklear documentation I see that it is possible by defining NK_ZERO_COMMAND_MEMORY and by comparing the last draw commands with the new ones, using memcmp and memcpy.

Here's my attempt at it, by modifying impl_glfw_gl3.go:

NK_ZERO_COMMAND_MEMORY definition:

#define NK_IMPLEMENTATION
#define NK_GLFW_GL3_IMPLEMENTATION
#define NK_ZERO_COMMAND_MEMORY

#include "nuklear.h"
*/
import "C"

memcmp and memcpy wrappers:

func memcmp(arg0 *Buffer, arg1 *Buffer, csize _Ctype_ulonglong) int32 {
    carg0, _ := (unsafe.Pointer(arg0)), cgoAllocsUnknown
    carg1, _ := (unsafe.Pointer(arg1)), cgoAllocsUnknown
    cresu, _ := C.memcmp(carg0, carg1, csize)
    return int32(cresu)
}

func memcpy(arg0 *Buffer, arg1 *Buffer, csize _Ctype_ulonglong) {
    carg0, _ := (unsafe.Pointer(arg0)), cgoAllocsUnknown
    carg1, _ := (unsafe.Pointer(arg1)), cgoAllocsUnknown
    C.memcpy(carg0, carg1, csize)
}

Definition of a buffer for the last frame commands:

type platformDevice struct {
    cmds     *Buffer
    lastCmds *Buffer
...

Initialization:

func deviceCreate() {
    dev := state.ogl
    dev.cmds = NewBuffer()
    NkBufferInitDefault(dev.cmds)
    dev.lastCmds = NewBuffer()
    NkBufferInitDefault(dev.lastCmds)
...

And finally, the comparison and copy in the NkPlatformRender function:

gl.UnmapBuffer(gl.ARRAY_BUFFER)
gl.UnmapBuffer(gl.ARRAY_BUFFER)
gl.UnmapBuffer(gl.ELEMENT_ARRAY_BUFFER)

if memcmp(dev.cmds, dev.lastCmds, state.ctx.memory.allocated) != 0 {

    memcpy(dev.lastCmds, dev.cmds, state.ctx.memory.allocated)

    var offset uintptr

    // iterate over and execute each draw command
    NkDrawForeach(state.ctx, dev.cmds, func(cmd *DrawCommand) {
....

Unfortunately this doesn't look to work on the demo application... all I see is a blue background (the default color). I tried to debug and memcmp returns -1 only the first time, then always 0... weird.

Any thought about this attempt?

xlab commented 6 years ago

Good attempt, should help to save some CPU on mobile devices. I'll look into it using your code when I have some time, can't promise at this point.