From a86a520cb24640a23168f416c844bf7163418585 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Wed, 10 Jul 2019 15:30:22 +0200 Subject: [PATCH 01/14] feat: add resource window --- application.go | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/application.go b/application.go index 4d16c4c4..3322776d 100644 --- a/application.go +++ b/application.go @@ -25,9 +25,10 @@ func Run(opt ...Option) (err error) { // Application provides the flutter engine in a user friendly matter. type Application struct { - config config - engine *embedder.FlutterEngine - window *glfw.Window + config config + engine *embedder.FlutterEngine + window *glfw.Window + resourceWindow *glfw.Window } // NewApplication creates a new application with provided options. @@ -45,7 +46,6 @@ func NewApplication(opt ...Option) *Application { opt = append(opt, AddPlugin(defaultPlatformPlugin)) opt = append(opt, AddPlugin(defaultTextinputPlugin)) opt = append(opt, AddPlugin(defaultLifecyclePlugin)) - opt = append(opt, AddPlugin(defaultKeyeventsPlugin)) // apply all configs @@ -56,6 +56,20 @@ func NewApplication(opt ...Option) *Application { return app } +// createResourceWindow creates an invisible GLFW window that shares the 'view' +// window's resource context. This window is used to upload resources in the +// background. Must be call after the 'view' window is created. +func createResourceWindow(window *glfw.Window) (*glfw.Window, error) { + glfw.WindowHint(glfw.Decorated, glfw.False) + glfw.WindowHint(glfw.Visible, glfw.False) + resourceWindow, err := glfw.CreateWindow(1, 1, "", nil, window) + if err != nil { + return nil, errors.Wrap(err, "creating glfw resource window") + } + glfw.DefaultWindowHints() + return resourceWindow, nil +} + // Run starts the application and waits for it to finish. func (a *Application) Run() error { runtime.LockOSThread() @@ -92,6 +106,11 @@ func (a *Application) Run() error { glfw.DefaultWindowHints() defer a.window.Destroy() + a.resourceWindow, err = createResourceWindow(a.window) + if a.resourceWindow != nil { + defer a.resourceWindow.Destroy() + } + if a.config.windowIconProvider != nil { images, err := a.config.windowIconProvider() if err != nil { @@ -171,7 +190,11 @@ func (a *Application) Run() error { return 0 } a.engine.GLMakeResourceCurrent = func() bool { - return false + if a.resourceWindow == nil { + return false + } + a.resourceWindow.MakeContextCurrent() + return true } a.engine.GLProcResolver = func(procName string) unsafe.Pointer { return glfw.GetProcAddress(procName) From e494cb017a94a65480f8a7bcdabcc135da3cadbb Mon Sep 17 00:00:00 2001 From: Drakirus Date: Mon, 15 Jul 2019 10:17:39 +0200 Subject: [PATCH 02/14] WIP external texture --- application.go | 17 +++++++++++ embedder/embedder.go | 35 ++++++++++++++++++---- embedder/embedder.h | 49 +++++++++++++++++++++++++++---- embedder/embedder_helper.c | 59 ++++++++++++++++++++------------------ embedder/embedder_proxy.go | 7 +++++ 5 files changed, 127 insertions(+), 40 deletions(-) diff --git a/application.go b/application.go index 3322776d..f905b81e 100644 --- a/application.go +++ b/application.go @@ -199,6 +199,13 @@ func (a *Application) Run() error { a.engine.GLProcResolver = func(procName string) unsafe.Pointer { return glfw.GetProcAddress(procName) } + a.engine.GLExternalTextureFrameCallback = func(textureID int64, + width int, + height int, + texture *embedder.FlutterOpenGLTexture) bool { + fmt.Println("\nFlutterOpenGLTexture\n") + return true + } a.engine.PlatfromMessage = messenger.handlePlatformMessage @@ -248,8 +255,18 @@ func (a *Application) Run() error { a.window.SetScrollCallback(m.glfwScrollCallback) defer a.engine.Shutdown() + frameI := int64(0) for !a.window.ShouldClose() { + frameI++ glfw.WaitEventsTimeout(0.016) // timeout to get 60fps-ish iterations + if frameI == 400 { + print("REGISTER: ") + print(a.engine.RegisterExternalTexture(frameI)) + } + if frameI == 600 { + print("New Frame: ") + print(a.engine.MarkExternalTextureFrameAvailable(frameI)) + } embedder.FlutterEngineFlushPendingTasksNow() defaultPlatformPlugin.glfwTasker.ExecuteTasks() messenger.engineTasker.ExecuteTasks() diff --git a/embedder/embedder.go b/embedder/embedder.go index 4cf793e3..aa0a8f22 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -52,6 +52,9 @@ const ( ResultInvalidArguments Result = C.kInvalidArguments ) +// FlutterOpenGLTexture corresponds to the C.FlutterOpenGLTexture struct. +type FlutterOpenGLTexture C.FlutterOpenGLTexture + // FlutterEngine corresponds to the C.FlutterEngine with his associated callback's method. type FlutterEngine struct { // Flutter Engine. @@ -61,12 +64,13 @@ type FlutterEngine struct { index int // GL callback functions - GLMakeCurrent func() bool - GLClearCurrent func() bool - GLPresent func() bool - GLFboCallback func() int32 - GLMakeResourceCurrent func() bool - GLProcResolver func(procName string) unsafe.Pointer + GLMakeCurrent func() bool + GLClearCurrent func() bool + GLPresent func() bool + GLFboCallback func() int32 + GLMakeResourceCurrent func() bool + GLProcResolver func(procName string) unsafe.Pointer + GLExternalTextureFrameCallback func(textureID int64, width int, height int, texture *FlutterOpenGLTexture) bool // platform message callback function PlatfromMessage func(message *PlatformMessage) @@ -286,6 +290,25 @@ func (flu *FlutterEngine) SendPlatformMessageResponse( return (Result)(res) } +// RegisterExternalTexture registers an external texture with a unique identifier. +func (flu *FlutterEngine) RegisterExternalTexture(textureID int64) Result { + res := C.FlutterEngineRegisterExternalTexture(flu.Engine, C.int64_t(textureID)) + return (Result)(res) +} + +// UnregisterExternalTexture unregisters a previous texture registration. +func (flu *FlutterEngine) UnregisterExternalTexture(textureID int64) Result { + res := C.FlutterEngineUnregisterExternalTexture(flu.Engine, C.int64_t(textureID)) + return (Result)(res) +} + +// MarkExternalTextureFrameAvailable marks that a new texture frame is +// available for a given texture identifier. +func (flu *FlutterEngine) MarkExternalTextureFrameAvailable(textureID int64) Result { + res := C.FlutterEngineMarkExternalTextureFrameAvailable(flu.Engine, C.int64_t(textureID)) + return (Result)(res) +} + // FlutterEngineFlushPendingTasksNow flush tasks on a message loop not // controlled by the Flutter engine. // diff --git a/embedder/embedder.h b/embedder/embedder.h index 3a4bc97d..f0107676 100644 --- a/embedder/embedder.h +++ b/embedder/embedder.h @@ -153,6 +153,10 @@ typedef enum { // |PageView| widget does not have implicit scrolling, so that users don't // navigate to the next page when reaching the end of the current one. kFlutterSemanticsFlagHasImplicitScrolling = 1 << 18, + // Whether the semantic node is read only. + // + // Only applicable when kFlutterSemanticsFlagIsTextField flag is on. + kFlutterSemanticsFlagIsReadOnly = 1 << 20, } FlutterSemanticsFlag; typedef enum { @@ -369,12 +373,11 @@ typedef struct { size_t struct_size; const char* channel; const uint8_t* message; - const size_t message_size; + size_t message_size; // The response handle on which to invoke - // |FlutterEngineSendPlatformMessageResponse| when the response is ready. This - // field is ignored for messages being sent from the embedder to the - // framework. |FlutterEngineSendPlatformMessageResponse| must be called for - // all messages received by the embedder. Failure to call + // |FlutterEngineSendPlatformMessageResponse| when the response is ready. + // |FlutterEngineSendPlatformMessageResponse| must be called for all messages + // received by the embedder. Failure to call // |FlutterEngineSendPlatformMessageResponse| will cause a memory leak. It is // not safe to send multiple responses on a single response object. const FlutterPlatformMessageResponseHandle* response_handle; @@ -384,6 +387,10 @@ typedef void (*FlutterPlatformMessageCallback)( const FlutterPlatformMessage* /* message*/, void* /* user data */); +typedef void (*FlutterDataCallback)(const uint8_t* /* data */, + size_t /* size */, + void* /* user data */); + typedef struct { double left; double top; @@ -646,6 +653,9 @@ typedef struct { // Path to a directory used to store data that is cached across runs of a // Flutter application (such as compiled shader programs used by Skia). // This is optional. The string must be NULL terminated. + // + // This is different from the cache-path-dir argument defined in switches.h, + // which is used in |flutter::Settings| as |temp_directory_path|. const char* persistent_cache_path; // If true, we'll only read the existing cache, but not write new ones. @@ -703,6 +713,33 @@ FlutterEngineResult FlutterEngineSendPlatformMessage( FlutterEngine engine, const FlutterPlatformMessage* message); +// Creates a platform message response handle that allows the embedder to set a +// native callback for a response to a message. This handle may be set on the +// |response_handle| field of any |FlutterPlatformMessage| sent to the engine. +// +// The handle must be collected via a call to +// |FlutterPlatformMessageReleaseResponseHandle|. This may be done immediately +// after a call to |FlutterEngineSendPlatformMessage| with a platform message +// whose response handle contains the handle created using this call. In case a +// handle is created but never sent in a message, the release call must still be +// made. Not calling release on the handle results in a small memory leak. +// +// The user data baton passed to the data callback is the one specified in this +// call as the third argument. +FLUTTER_EXPORT +FlutterEngineResult FlutterPlatformMessageCreateResponseHandle( + FlutterEngine engine, + FlutterDataCallback data_callback, + void* user_data, + FlutterPlatformMessageResponseHandle** response_out); + +// Collects the handle created using +// |FlutterPlatformMessageCreateResponseHandle|. +FLUTTER_EXPORT +FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle( + FlutterEngine engine, + FlutterPlatformMessageResponseHandle* response); + FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendPlatformMessageResponse( FlutterEngine engine, @@ -835,4 +872,4 @@ FlutterEngineResult FlutterEngineRunTask(FlutterEngine engine, } // extern "C" #endif -#endif // FLUTTER_EMBEDDER_H_ \ No newline at end of file +#endif // FLUTTER_EMBEDDER_H_ diff --git a/embedder/embedder_helper.c b/embedder/embedder_helper.c index 410f0530..31400e01 100644 --- a/embedder/embedder_helper.c +++ b/embedder/embedder_helper.c @@ -1,4 +1,5 @@ +#include #include #include "embedder.h" @@ -10,36 +11,38 @@ bool proxy_present(void *user_data); uint32_t proxy_fbo_callback(void *user_data); bool proxy_make_resource_current(void *user_data); void *proxy_gl_proc_resolver(void *user_data, const char *procname); -void proxy_platform_message_callback(const FlutterPlatformMessage *message, void *user_data); +void proxy_platform_message_callback(const FlutterPlatformMessage *message, + void *user_data); +bool proxy_gl_external_texture_frame_callback(void *user_data, + int64_t texture_id, size_t width, + size_t height, + FlutterOpenGLTexture *texture); // C helper -FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, FlutterProjectArgs *Args, - const char *const *vmArgs, int nVmAgrs) -{ - FlutterRendererConfig config = {}; - config.type = kOpenGL; - - config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); - config.open_gl.make_current = proxy_make_current; - config.open_gl.clear_current = proxy_clear_current; - config.open_gl.present = proxy_present; - config.open_gl.fbo_callback = proxy_fbo_callback; - config.open_gl.make_resource_current = proxy_make_resource_current; - config.open_gl.gl_proc_resolver = proxy_gl_proc_resolver; - - Args->command_line_argc = nVmAgrs; - Args->command_line_argv = vmArgs; - Args->platform_message_callback = proxy_platform_message_callback; - - return FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, Args, user_data, engine); +FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, + FlutterProjectArgs *Args, + const char *const *vmArgs, int nVmAgrs) { + FlutterRendererConfig config = {}; + config.type = kOpenGL; + + config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); + config.open_gl.make_current = proxy_make_current; + config.open_gl.clear_current = proxy_clear_current; + config.open_gl.present = proxy_present; + config.open_gl.fbo_callback = proxy_fbo_callback; + config.open_gl.make_resource_current = proxy_make_resource_current; + config.open_gl.gl_proc_resolver = proxy_gl_proc_resolver; + config.open_gl.gl_external_texture_frame_callback = + proxy_gl_external_texture_frame_callback; + + Args->command_line_argc = nVmAgrs; + Args->command_line_argv = vmArgs; + Args->platform_message_callback = proxy_platform_message_callback; + + return FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, Args, user_data, + engine); } -char **makeCharArray(int size) -{ - return calloc(sizeof(char *), size); -} +char **makeCharArray(int size) { return calloc(sizeof(char *), size); } -void setArrayString(char **a, char *s, int n) -{ - a[n] = s; -} +void setArrayString(char **a, char *s, int n) { a[n] = s; } diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index cf0999b9..fabed7c7 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -59,3 +59,10 @@ func proxy_gl_proc_resolver(userData unsafe.Pointer, procname *C.char) unsafe.Po flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) return flutterEngine.GLProcResolver(C.GoString(procname)) } + +//export proxy_gl_external_texture_frame_callback +func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, textureID int64, width int, height int, texture *FlutterOpenGLTexture) C.bool { + flutterEnginePointer := *(*uintptr)(userData) + flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) + return C.bool(flutterEngine.GLExternalTextureFrameCallback(textureID, width, height, texture)) +} From d14968c22287df62db53d5e022573af2975f55d8 Mon Sep 17 00:00:00 2001 From: Pierre Champion Date: Sat, 20 Jul 2019 00:21:48 +0200 Subject: [PATCH 03/14] Fix/mouse exit windows (#202) * fixes #198 * fixe weird edge case --- application.go | 5 +++++ glfw.go | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/application.go b/application.go index 42daaff5..8fdb40d9 100644 --- a/application.go +++ b/application.go @@ -237,6 +237,11 @@ func (a *Application) Run() error { a.window.SetRefreshCallback(m.glfwRefreshCallback) a.window.SetPosCallback(m.glfwPosCallback) + // flutter's PlatformMessage handler is registered through the dart:ui.Window + // interface. ui.Window must have at least paint one frame, before any + // platfrom message can be corectly handled by ui.Window.onPlatformMessage. + glfw.WaitEvents() + a.window.SetKeyCallback( func(window *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { defaultTextinputPlugin.glfwKeyCallback(window, key, scancode, action, mods) diff --git a/glfw.go b/glfw.go index 3ccdb108..0e73fda1 100644 --- a/glfw.go +++ b/glfw.go @@ -105,9 +105,17 @@ func (m *windowManager) glfwCursorEnterCallback(window *glfw.Window, entered boo x, y := window.GetCursorPos() if entered { m.sendPointerEvent(window, embedder.PointerPhaseAdd, x, y) - m.pointerPhase = embedder.PointerPhaseHover + // the mouse can enter the windows while having button pressed. + // if so, don't overwrite the phase. + if m.pointerButton == 0 { + m.pointerPhase = embedder.PointerPhaseHover + } } else { - m.sendPointerEvent(window, embedder.PointerPhaseRemove, x, y) + // if the mouse is still in 'phaseMove' outside the window (click-drag + // outside). Don't remove the cursor. + if m.pointerButton == 0 { + m.sendPointerEvent(window, embedder.PointerPhaseRemove, x, y) + } } } From 654cceb4c45d6a6c8ab3a98b1fd1fe8bd7c2d28b Mon Sep 17 00:00:00 2001 From: Drakirus Date: Mon, 15 Jul 2019 10:17:39 +0200 Subject: [PATCH 04/14] WIP external texture --- application.go | 17 +++++++++++ embedder/embedder.go | 35 ++++++++++++++++++---- embedder/embedder.h | 49 +++++++++++++++++++++++++++---- embedder/embedder_helper.c | 59 ++++++++++++++++++++------------------ embedder/embedder_proxy.go | 7 +++++ 5 files changed, 127 insertions(+), 40 deletions(-) diff --git a/application.go b/application.go index 8fdb40d9..522cfc54 100644 --- a/application.go +++ b/application.go @@ -202,6 +202,13 @@ func (a *Application) Run() error { a.engine.GLProcResolver = func(procName string) unsafe.Pointer { return glfw.GetProcAddress(procName) } + a.engine.GLExternalTextureFrameCallback = func(textureID int64, + width int, + height int, + texture *embedder.FlutterOpenGLTexture) bool { + fmt.Println("\nFlutterOpenGLTexture\n") + return true + } a.engine.PlatfromMessage = messenger.handlePlatformMessage @@ -257,8 +264,18 @@ func (a *Application) Run() error { a.window.SetScrollCallback(m.glfwScrollCallback) defer a.engine.Shutdown() + frameI := int64(0) for !a.window.ShouldClose() { + frameI++ glfw.WaitEventsTimeout(0.016) // timeout to get 60fps-ish iterations + if frameI == 400 { + print("REGISTER: ") + print(a.engine.RegisterExternalTexture(frameI)) + } + if frameI == 600 { + print("New Frame: ") + print(a.engine.MarkExternalTextureFrameAvailable(frameI)) + } embedder.FlutterEngineFlushPendingTasksNow() defaultPlatformPlugin.glfwTasker.ExecuteTasks() messenger.engineTasker.ExecuteTasks() diff --git a/embedder/embedder.go b/embedder/embedder.go index 95045ce8..3b4d3e7b 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -53,6 +53,9 @@ const ( ResultEngineNotRunning Result = -1 ) +// FlutterOpenGLTexture corresponds to the C.FlutterOpenGLTexture struct. +type FlutterOpenGLTexture C.FlutterOpenGLTexture + // FlutterEngine corresponds to the C.FlutterEngine with his associated callback's method. type FlutterEngine struct { // Flutter Engine. @@ -65,12 +68,13 @@ type FlutterEngine struct { index int // GL callback functions - GLMakeCurrent func() bool - GLClearCurrent func() bool - GLPresent func() bool - GLFboCallback func() int32 - GLMakeResourceCurrent func() bool - GLProcResolver func(procName string) unsafe.Pointer + GLMakeCurrent func() bool + GLClearCurrent func() bool + GLPresent func() bool + GLFboCallback func() int32 + GLMakeResourceCurrent func() bool + GLProcResolver func(procName string) unsafe.Pointer + GLExternalTextureFrameCallback func(textureID int64, width int, height int, texture *FlutterOpenGLTexture) bool // platform message callback function PlatfromMessage func(message *PlatformMessage) @@ -299,6 +303,25 @@ func (flu *FlutterEngine) SendPlatformMessageResponse( return (Result)(res) } +// RegisterExternalTexture registers an external texture with a unique identifier. +func (flu *FlutterEngine) RegisterExternalTexture(textureID int64) Result { + res := C.FlutterEngineRegisterExternalTexture(flu.Engine, C.int64_t(textureID)) + return (Result)(res) +} + +// UnregisterExternalTexture unregisters a previous texture registration. +func (flu *FlutterEngine) UnregisterExternalTexture(textureID int64) Result { + res := C.FlutterEngineUnregisterExternalTexture(flu.Engine, C.int64_t(textureID)) + return (Result)(res) +} + +// MarkExternalTextureFrameAvailable marks that a new texture frame is +// available for a given texture identifier. +func (flu *FlutterEngine) MarkExternalTextureFrameAvailable(textureID int64) Result { + res := C.FlutterEngineMarkExternalTextureFrameAvailable(flu.Engine, C.int64_t(textureID)) + return (Result)(res) +} + // FlutterEngineFlushPendingTasksNow flush tasks on a message loop not // controlled by the Flutter engine. // diff --git a/embedder/embedder.h b/embedder/embedder.h index 3a4bc97d..f0107676 100644 --- a/embedder/embedder.h +++ b/embedder/embedder.h @@ -153,6 +153,10 @@ typedef enum { // |PageView| widget does not have implicit scrolling, so that users don't // navigate to the next page when reaching the end of the current one. kFlutterSemanticsFlagHasImplicitScrolling = 1 << 18, + // Whether the semantic node is read only. + // + // Only applicable when kFlutterSemanticsFlagIsTextField flag is on. + kFlutterSemanticsFlagIsReadOnly = 1 << 20, } FlutterSemanticsFlag; typedef enum { @@ -369,12 +373,11 @@ typedef struct { size_t struct_size; const char* channel; const uint8_t* message; - const size_t message_size; + size_t message_size; // The response handle on which to invoke - // |FlutterEngineSendPlatformMessageResponse| when the response is ready. This - // field is ignored for messages being sent from the embedder to the - // framework. |FlutterEngineSendPlatformMessageResponse| must be called for - // all messages received by the embedder. Failure to call + // |FlutterEngineSendPlatformMessageResponse| when the response is ready. + // |FlutterEngineSendPlatformMessageResponse| must be called for all messages + // received by the embedder. Failure to call // |FlutterEngineSendPlatformMessageResponse| will cause a memory leak. It is // not safe to send multiple responses on a single response object. const FlutterPlatformMessageResponseHandle* response_handle; @@ -384,6 +387,10 @@ typedef void (*FlutterPlatformMessageCallback)( const FlutterPlatformMessage* /* message*/, void* /* user data */); +typedef void (*FlutterDataCallback)(const uint8_t* /* data */, + size_t /* size */, + void* /* user data */); + typedef struct { double left; double top; @@ -646,6 +653,9 @@ typedef struct { // Path to a directory used to store data that is cached across runs of a // Flutter application (such as compiled shader programs used by Skia). // This is optional. The string must be NULL terminated. + // + // This is different from the cache-path-dir argument defined in switches.h, + // which is used in |flutter::Settings| as |temp_directory_path|. const char* persistent_cache_path; // If true, we'll only read the existing cache, but not write new ones. @@ -703,6 +713,33 @@ FlutterEngineResult FlutterEngineSendPlatformMessage( FlutterEngine engine, const FlutterPlatformMessage* message); +// Creates a platform message response handle that allows the embedder to set a +// native callback for a response to a message. This handle may be set on the +// |response_handle| field of any |FlutterPlatformMessage| sent to the engine. +// +// The handle must be collected via a call to +// |FlutterPlatformMessageReleaseResponseHandle|. This may be done immediately +// after a call to |FlutterEngineSendPlatformMessage| with a platform message +// whose response handle contains the handle created using this call. In case a +// handle is created but never sent in a message, the release call must still be +// made. Not calling release on the handle results in a small memory leak. +// +// The user data baton passed to the data callback is the one specified in this +// call as the third argument. +FLUTTER_EXPORT +FlutterEngineResult FlutterPlatformMessageCreateResponseHandle( + FlutterEngine engine, + FlutterDataCallback data_callback, + void* user_data, + FlutterPlatformMessageResponseHandle** response_out); + +// Collects the handle created using +// |FlutterPlatformMessageCreateResponseHandle|. +FLUTTER_EXPORT +FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle( + FlutterEngine engine, + FlutterPlatformMessageResponseHandle* response); + FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendPlatformMessageResponse( FlutterEngine engine, @@ -835,4 +872,4 @@ FlutterEngineResult FlutterEngineRunTask(FlutterEngine engine, } // extern "C" #endif -#endif // FLUTTER_EMBEDDER_H_ \ No newline at end of file +#endif // FLUTTER_EMBEDDER_H_ diff --git a/embedder/embedder_helper.c b/embedder/embedder_helper.c index 410f0530..31400e01 100644 --- a/embedder/embedder_helper.c +++ b/embedder/embedder_helper.c @@ -1,4 +1,5 @@ +#include #include #include "embedder.h" @@ -10,36 +11,38 @@ bool proxy_present(void *user_data); uint32_t proxy_fbo_callback(void *user_data); bool proxy_make_resource_current(void *user_data); void *proxy_gl_proc_resolver(void *user_data, const char *procname); -void proxy_platform_message_callback(const FlutterPlatformMessage *message, void *user_data); +void proxy_platform_message_callback(const FlutterPlatformMessage *message, + void *user_data); +bool proxy_gl_external_texture_frame_callback(void *user_data, + int64_t texture_id, size_t width, + size_t height, + FlutterOpenGLTexture *texture); // C helper -FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, FlutterProjectArgs *Args, - const char *const *vmArgs, int nVmAgrs) -{ - FlutterRendererConfig config = {}; - config.type = kOpenGL; - - config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); - config.open_gl.make_current = proxy_make_current; - config.open_gl.clear_current = proxy_clear_current; - config.open_gl.present = proxy_present; - config.open_gl.fbo_callback = proxy_fbo_callback; - config.open_gl.make_resource_current = proxy_make_resource_current; - config.open_gl.gl_proc_resolver = proxy_gl_proc_resolver; - - Args->command_line_argc = nVmAgrs; - Args->command_line_argv = vmArgs; - Args->platform_message_callback = proxy_platform_message_callback; - - return FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, Args, user_data, engine); +FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, + FlutterProjectArgs *Args, + const char *const *vmArgs, int nVmAgrs) { + FlutterRendererConfig config = {}; + config.type = kOpenGL; + + config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); + config.open_gl.make_current = proxy_make_current; + config.open_gl.clear_current = proxy_clear_current; + config.open_gl.present = proxy_present; + config.open_gl.fbo_callback = proxy_fbo_callback; + config.open_gl.make_resource_current = proxy_make_resource_current; + config.open_gl.gl_proc_resolver = proxy_gl_proc_resolver; + config.open_gl.gl_external_texture_frame_callback = + proxy_gl_external_texture_frame_callback; + + Args->command_line_argc = nVmAgrs; + Args->command_line_argv = vmArgs; + Args->platform_message_callback = proxy_platform_message_callback; + + return FlutterEngineRun(FLUTTER_ENGINE_VERSION, &config, Args, user_data, + engine); } -char **makeCharArray(int size) -{ - return calloc(sizeof(char *), size); -} +char **makeCharArray(int size) { return calloc(sizeof(char *), size); } -void setArrayString(char **a, char *s, int n) -{ - a[n] = s; -} +void setArrayString(char **a, char *s, int n) { a[n] = s; } diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index cf0999b9..fabed7c7 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -59,3 +59,10 @@ func proxy_gl_proc_resolver(userData unsafe.Pointer, procname *C.char) unsafe.Po flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) return flutterEngine.GLProcResolver(C.GoString(procname)) } + +//export proxy_gl_external_texture_frame_callback +func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, textureID int64, width int, height int, texture *FlutterOpenGLTexture) C.bool { + flutterEnginePointer := *(*uintptr)(userData) + flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) + return C.bool(flutterEngine.GLExternalTextureFrameCallback(textureID, width, height, texture)) +} From 6b26a3411c15dafb379145248489e7f8251603c5 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Mon, 22 Jul 2019 11:54:25 +0200 Subject: [PATCH 05/14] WIP --- application.go | 11 ++++------- embedder/embedder_helper.c | 10 ++++++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/application.go b/application.go index 522cfc54..733350fe 100644 --- a/application.go +++ b/application.go @@ -265,16 +265,13 @@ func (a *Application) Run() error { defer a.engine.Shutdown() frameI := int64(0) + textureID := int64(1) + fmt.Printf("Texture: register result: %v\n", a.engine.RegisterExternalTexture(textureID) == embedder.ResultSuccess) for !a.window.ShouldClose() { frameI++ glfw.WaitEventsTimeout(0.016) // timeout to get 60fps-ish iterations - if frameI == 400 { - print("REGISTER: ") - print(a.engine.RegisterExternalTexture(frameI)) - } - if frameI == 600 { - print("New Frame: ") - print(a.engine.MarkExternalTextureFrameAvailable(frameI)) + if frameI%40 == 0 { + fmt.Printf("Texture: New Frame result: %v\n", a.engine.MarkExternalTextureFrameAvailable(textureID) == embedder.ResultSuccess) } embedder.FlutterEngineFlushPendingTasksNow() defaultPlatformPlugin.glfwTasker.ExecuteTasks() diff --git a/embedder/embedder_helper.c b/embedder/embedder_helper.c index 31400e01..488ce7bd 100644 --- a/embedder/embedder_helper.c +++ b/embedder/embedder_helper.c @@ -18,6 +18,13 @@ bool proxy_gl_external_texture_frame_callback(void *user_data, size_t height, FlutterOpenGLTexture *texture); +static bool OnAcquireExternalTexture(void *user_data, int64_t texture_id, + size_t width, size_t height, + FlutterOpenGLTexture *texture) { + printf("=== OnAcquireExternalTexture: %ld\n", texture_id); + return 1; +} + // C helper FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, FlutterProjectArgs *Args, @@ -32,8 +39,7 @@ FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, config.open_gl.fbo_callback = proxy_fbo_callback; config.open_gl.make_resource_current = proxy_make_resource_current; config.open_gl.gl_proc_resolver = proxy_gl_proc_resolver; - config.open_gl.gl_external_texture_frame_callback = - proxy_gl_external_texture_frame_callback; + config.open_gl.gl_external_texture_frame_callback = OnAcquireExternalTexture; Args->command_line_argc = nVmAgrs; Args->command_line_argv = vmArgs; From 4b64b461a49ca6072439f8fa1e034e3d70738c74 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Mon, 22 Jul 2019 15:53:22 +0200 Subject: [PATCH 06/14] WIP: the app is crasing at: `gl.GenTextures`. The crash might be related to the golang wrapper of GL --- application.go | 65 ++++++++++-- embedder/embedder.go | 8 +- embedder/embedder.h | 201 +++++++++++++++++-------------------- embedder/embedder_helper.c | 10 +- embedder/embedder_proxy.go | 12 ++- 5 files changed, 170 insertions(+), 126 deletions(-) diff --git a/application.go b/application.go index 733350fe..5691aade 100644 --- a/application.go +++ b/application.go @@ -2,11 +2,14 @@ package flutter import ( "fmt" + "image" + "image/draw" "os" "path/filepath" "runtime" "unsafe" + "github.com/go-gl/gl/v2.1/gl" "github.com/go-gl/glfw/v3.2/glfw" "github.com/pkg/errors" @@ -203,11 +206,59 @@ func (a *Application) Run() error { return glfw.GetProcAddress(procName) } a.engine.GLExternalTextureFrameCallback = func(textureID int64, - width int, - height int, - texture *embedder.FlutterOpenGLTexture) bool { - fmt.Println("\nFlutterOpenGLTexture\n") - return true + width int, height int, + ) (bool, embedder.FlutterOpenGLTexture) { + fmt.Printf("\nFlutterOpenGLTexture: %v, %v\n", width, height) + + a.window.MakeContextCurrent() + + file := "/tmp/square.png" + imgFile, err := os.Open(file) + if err != nil { + fmt.Printf("texture %q not found on disk: %v", file, err) + } + + img, _, err := image.Decode(imgFile) + if err != nil { + fmt.Printf("error decoding file %s:%v", file, err) + } + + rgba := image.NewRGBA(img.Bounds()) + if rgba.Stride != rgba.Rect.Size().X*4 { + fmt.Printf("unsupported stride") + } + + draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src) + + var texture uint32 + gl.GenTextures(1, &texture) + EF := embedder.FlutterOpenGLTexture{ + Target: gl.TEXTURE_2D, + Name: texture, + Format: gl.RGBA8, + } + return true, EF + + // set the texture wrapping parameters + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) + // set texture filtering parameters + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + + gl.BindTexture(gl.TEXTURE_2D, texture) + gl.TexImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + int32(width), + int32(height), + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + gl.Ptr(rgba.Pix)) + + return true, EF } a.engine.PlatfromMessage = messenger.handlePlatformMessage @@ -266,11 +317,11 @@ func (a *Application) Run() error { frameI := int64(0) textureID := int64(1) - fmt.Printf("Texture: register result: %v\n", a.engine.RegisterExternalTexture(textureID) == embedder.ResultSuccess) for !a.window.ShouldClose() { frameI++ glfw.WaitEventsTimeout(0.016) // timeout to get 60fps-ish iterations - if frameI%40 == 0 { + if frameI == 100 { + fmt.Printf("Texture: register result: %v\n", a.engine.RegisterExternalTexture(textureID) == embedder.ResultSuccess) fmt.Printf("Texture: New Frame result: %v\n", a.engine.MarkExternalTextureFrameAvailable(textureID) == embedder.ResultSuccess) } embedder.FlutterEngineFlushPendingTasksNow() diff --git a/embedder/embedder.go b/embedder/embedder.go index 3b4d3e7b..4884a62e 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -54,7 +54,11 @@ const ( ) // FlutterOpenGLTexture corresponds to the C.FlutterOpenGLTexture struct. -type FlutterOpenGLTexture C.FlutterOpenGLTexture +type FlutterOpenGLTexture struct { + Target uint32 + Name uint32 + Format uint32 +} // FlutterEngine corresponds to the C.FlutterEngine with his associated callback's method. type FlutterEngine struct { @@ -74,7 +78,7 @@ type FlutterEngine struct { GLFboCallback func() int32 GLMakeResourceCurrent func() bool GLProcResolver func(procName string) unsafe.Pointer - GLExternalTextureFrameCallback func(textureID int64, width int, height int, texture *FlutterOpenGLTexture) bool + GLExternalTextureFrameCallback func(textureID int64, width int, height int) (bool, FlutterOpenGLTexture) // platform message callback function PlatfromMessage func(message *PlatformMessage) diff --git a/embedder/embedder.h b/embedder/embedder.h index f0107676..3cb37bfc 100644 --- a/embedder/embedder.h +++ b/embedder/embedder.h @@ -15,7 +15,7 @@ extern "C" { #ifndef FLUTTER_EXPORT #define FLUTTER_EXPORT -#endif // FLUTTER_EXPORT +#endif // FLUTTER_EXPORT #define FLUTTER_ENGINE_VERSION 1 @@ -168,7 +168,7 @@ typedef enum { kFlutterTextDirectionLTR = 2, } FlutterTextDirection; -typedef struct _FlutterEngine* FlutterEngine; +typedef struct _FlutterEngine *FlutterEngine; typedef struct { // horizontal scale factor @@ -191,7 +191,7 @@ typedef struct { double pers2; } FlutterTransformation; -typedef void (*VoidCallback)(void* /* user data */); +typedef void (*VoidCallback)(void * /* user data */); typedef struct { // Target texture of the active texture unit (example GL_TEXTURE_2D). @@ -201,26 +201,25 @@ typedef struct { // The texture format (example GL_RGBA8). uint32_t format; // User data to be returned on the invocation of the destruction callback. - void* user_data; + void *user_data; // Callback invoked (on an engine managed thread) that asks the embedder to // collect the texture. VoidCallback destruction_callback; } FlutterOpenGLTexture; -typedef bool (*BoolCallback)(void* /* user data */); -typedef FlutterTransformation (*TransformationCallback)(void* /* user data */); -typedef uint32_t (*UIntCallback)(void* /* user data */); -typedef bool (*SoftwareSurfacePresentCallback)(void* /* user data */, - const void* /* allocation */, +typedef bool (*BoolCallback)(void * /* user data */); +typedef FlutterTransformation (*TransformationCallback)(void * /* user data */); +typedef uint32_t (*UIntCallback)(void * /* user data */); +typedef bool (*SoftwareSurfacePresentCallback)(void * /* user data */, + const void * /* allocation */, size_t /* row bytes */, size_t /* height */); -typedef void* (*ProcResolver)(void* /* user data */, const char* /* name */); -typedef bool (*TextureFrameCallback)(void* /* user data */, +typedef void *(*ProcResolver)(void * /* user data */, const char * /* name */); +typedef bool (*TextureFrameCallback)(void * /* user data */, int64_t /* texture identifier */, - size_t /* width */, - size_t /* height */, - FlutterOpenGLTexture* /* texture out */); -typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */); + size_t /* width */, size_t /* height */, + FlutterOpenGLTexture * /* texture out */); +typedef void (*VsyncCallback)(void * /* user data */, intptr_t /* baton */); typedef struct { // The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig). @@ -345,7 +344,7 @@ typedef struct { // The size of this struct. Must be sizeof(FlutterPointerEvent). size_t struct_size; FlutterPointerPhase phase; - size_t timestamp; // in microseconds. + size_t timestamp; // in microseconds. double x; double y; // An optional device identifier. If this is not specified, it is assumed that @@ -371,8 +370,8 @@ typedef struct _FlutterPlatformMessageResponseHandle typedef struct { // The size of this struct. Must be sizeof(FlutterPlatformMessage). size_t struct_size; - const char* channel; - const uint8_t* message; + const char *channel; + const uint8_t *message; size_t message_size; // The response handle on which to invoke // |FlutterEngineSendPlatformMessageResponse| when the response is ready. @@ -380,16 +379,14 @@ typedef struct { // received by the embedder. Failure to call // |FlutterEngineSendPlatformMessageResponse| will cause a memory leak. It is // not safe to send multiple responses on a single response object. - const FlutterPlatformMessageResponseHandle* response_handle; + const FlutterPlatformMessageResponseHandle *response_handle; } FlutterPlatformMessage; typedef void (*FlutterPlatformMessageCallback)( - const FlutterPlatformMessage* /* message*/, - void* /* user data */); + const FlutterPlatformMessage * /* message*/, void * /* user data */); -typedef void (*FlutterDataCallback)(const uint8_t* /* data */, - size_t /* size */, - void* /* user data */); +typedef void (*FlutterDataCallback)(const uint8_t * /* data */, + size_t /* size */, void * /* user data */); typedef struct { double left; @@ -438,17 +435,17 @@ typedef struct { // Describes how much space the semantics node takes up along the z-axis. double thickness; // A textual description of the node. - const char* label; + const char *label; // A brief description of the result of performing an action on the node. - const char* hint; + const char *hint; // A textual description of the current value of the node. - const char* value; + const char *value; // A value that |value| will have after a kFlutterSemanticsActionIncrease| // action has been performed. - const char* increased_value; + const char *increased_value; // A value that |value| will have after a kFlutterSemanticsActionDecrease| // action has been performed. - const char* decreased_value; + const char *decreased_value; // The reading direction for |label|, |value|, |hint|, |increasedValue|, and // |decreasedValue|. FlutterTextDirection text_direction; @@ -460,14 +457,14 @@ typedef struct { // The number of children this node has. size_t child_count; // Array of child node IDs in traversal order. Has length |child_count|. - const int32_t* children_in_traversal_order; + const int32_t *children_in_traversal_order; // Array of child node IDs in hit test order. Has length |child_count|. - const int32_t* children_in_hit_test_order; + const int32_t *children_in_hit_test_order; // The number of custom accessibility action associated with this node. size_t custom_accessibility_actions_count; // Array of |FlutterSemanticsCustomAction| IDs associated with this node. // Has length |custom_accessibility_actions_count|. - const int32_t* custom_accessibility_actions; + const int32_t *custom_accessibility_actions; } FlutterSemanticsNode; // |FlutterSemanticsCustomAction| ID used as a sentinel to signal the end of a @@ -493,20 +490,19 @@ typedef struct { // |FlutterSemanticsAction| to override. FlutterSemanticsAction override_action; // The user-readable name of this custom semantics action. - const char* label; + const char *label; // The hint description of this custom semantics action. - const char* hint; + const char *hint; } FlutterSemanticsCustomAction; typedef void (*FlutterUpdateSemanticsNodeCallback)( - const FlutterSemanticsNode* /* semantics node */, - void* /* user data */); + const FlutterSemanticsNode * /* semantics node */, void * /* user data */); typedef void (*FlutterUpdateSemanticsCustomActionCallback)( - const FlutterSemanticsCustomAction* /* semantics custom action */, - void* /* user data */); + const FlutterSemanticsCustomAction * /* semantics custom action */, + void * /* user data */); -typedef struct _FlutterTaskRunner* FlutterTaskRunner; +typedef struct _FlutterTaskRunner *FlutterTaskRunner; typedef struct { FlutterTaskRunner runner; @@ -514,9 +510,8 @@ typedef struct { } FlutterTask; typedef void (*FlutterTaskRunnerPostTaskCallback)( - FlutterTask /* task */, - uint64_t /* target time nanos */, - void* /* user data */); + FlutterTask /* task */, uint64_t /* target time nanos */, + void * /* user data */); // An interface used by the Flutter engine to execute tasks at the target time // on a specified thread. There should be a 1-1 relationship between a thread @@ -525,7 +520,7 @@ typedef void (*FlutterTaskRunnerPostTaskCallback)( typedef struct { // The size of this struct. Must be sizeof(FlutterTaskRunnerDescription). size_t struct_size; - void* user_data; + void *user_data; // May be called from any thread. Should return true if tasks posted on the // calling thread will be run on that same thread. // @@ -549,7 +544,7 @@ typedef struct { size_t struct_size; // Specify the task runner for the thread on which the |FlutterEngineRun| call // is made. - const FlutterTaskRunnerDescription* platform_task_runner; + const FlutterTaskRunnerDescription *platform_task_runner; } FlutterCustomTaskRunners; typedef struct { @@ -558,7 +553,7 @@ typedef struct { // The path to the Flutter assets directory containing project assets. The // string can be collected after the call to |FlutterEngineRun| returns. The // string must be NULL terminated. - const char* assets_path; + const char *assets_path; // The path to the Dart file containing the |main| entry point. // The string can be collected after the call to |FlutterEngineRun| returns. // The string must be NULL terminated. @@ -567,7 +562,7 @@ typedef struct { // Dart code should now be compiled to kernel form and will be loaded by from // |kernel_blob.bin| in the assets directory. This struct member is retained // for ABI stability. - const char* main_path__unused__; + const char *main_path__unused__; // The path to the |.packages| for the project. The string can be collected // after the call to |FlutterEngineRun| returns. The string must be NULL // terminated. @@ -576,11 +571,11 @@ typedef struct { // Dart code should now be compiled to kernel form and will be loaded by from // |kernel_blob.bin| in the assets directory. This struct member is retained // for ABI stability. - const char* packages_path__unused__; + const char *packages_path__unused__; // The path to the icudtl.dat file for the project. The string can be // collected after the call to |FlutterEngineRun| returns. The string must // be NULL terminated. - const char* icu_data_path; + const char *icu_data_path; // The command line argument count used to initialize the project. int command_line_argc; // The command line arguments used to initialize the project. The strings can @@ -594,7 +589,7 @@ typedef struct { // they may affect engine stability at runtime in the presence of unsanitized // input. The list of currently recognized engine flags and their descriptions // can be retrieved from the |switches.h| engine source file. - const char* const* command_line_argv; + const char *const *command_line_argv; // The callback invoked by the engine in order to give the embedder the chance // to respond to platform messages from the Dart application. The callback // will be invoked on the thread on which the |FlutterEngineRun| call is made. @@ -603,28 +598,28 @@ typedef struct { // mapped in as read-only. For more information refer to the documentation on // the Wiki at // https://github.com/flutter/flutter/wiki/Flutter-engine-operation-in-AOT-Mode - const uint8_t* vm_snapshot_data; + const uint8_t *vm_snapshot_data; // The size of the VM snapshot data buffer. size_t vm_snapshot_data_size; // The VM snapshot instructions buffer used in AOT operation. This buffer must // be mapped in as read-execute. For more information refer to the // documentation on the Wiki at // https://github.com/flutter/flutter/wiki/Flutter-engine-operation-in-AOT-Mode - const uint8_t* vm_snapshot_instructions; + const uint8_t *vm_snapshot_instructions; // The size of the VM snapshot instructions buffer. size_t vm_snapshot_instructions_size; // The isolate snapshot data buffer used in AOT operation. This buffer must be // mapped in as read-only. For more information refer to the documentation on // the Wiki at // https://github.com/flutter/flutter/wiki/Flutter-engine-operation-in-AOT-Mode - const uint8_t* isolate_snapshot_data; + const uint8_t *isolate_snapshot_data; // The size of the isolate snapshot data buffer. size_t isolate_snapshot_data_size; // The isolate snapshot instructions buffer used in AOT operation. This buffer // must be mapped in as read-execute. For more information refer to the // documentation on the Wiki at // https://github.com/flutter/flutter/wiki/Flutter-engine-operation-in-AOT-Mode - const uint8_t* isolate_snapshot_instructions; + const uint8_t *isolate_snapshot_instructions; // The size of the isolate snapshot instructions buffer. size_t isolate_snapshot_instructions_size; // The callback invoked by the engine in root isolate scope. Called @@ -656,7 +651,7 @@ typedef struct { // // This is different from the cache-path-dir argument defined in switches.h, // which is used in |flutter::Settings| as |temp_directory_path|. - const char* persistent_cache_path; + const char *persistent_cache_path; // If true, we'll only read the existing cache, but not write new ones. bool is_persistent_cache_read_only; @@ -679,39 +674,39 @@ typedef struct { // Care must be taken to ensure that the custom entrypoint is not tree-shaken // away. Usually, this is done using the `@pragma('vm:entry-point')` // decoration. - const char* custom_dart_entrypoint; + const char *custom_dart_entrypoint; // Typically the Flutter engine create and manages its internal threads. This // optional argument allows for the specification of task runner interfaces to // event loops managed by the embedder on threads it creates. - const FlutterCustomTaskRunners* custom_task_runners; + const FlutterCustomTaskRunners *custom_task_runners; } FlutterProjectArgs; FLUTTER_EXPORT FlutterEngineResult FlutterEngineRun(size_t version, - const FlutterRendererConfig* config, - const FlutterProjectArgs* args, - void* user_data, - FlutterEngine* engine_out); + const FlutterRendererConfig *config, + const FlutterProjectArgs *args, + void *user_data, + FlutterEngine *engine_out); FLUTTER_EXPORT FlutterEngineResult FlutterEngineShutdown(FlutterEngine engine); FLUTTER_EXPORT -FlutterEngineResult FlutterEngineSendWindowMetricsEvent( - FlutterEngine engine, - const FlutterWindowMetricsEvent* event); +FlutterEngineResult +FlutterEngineSendWindowMetricsEvent(FlutterEngine engine, + const FlutterWindowMetricsEvent *event); FLUTTER_EXPORT -FlutterEngineResult FlutterEngineSendPointerEvent( - FlutterEngine engine, - const FlutterPointerEvent* events, - size_t events_count); +FlutterEngineResult +FlutterEngineSendPointerEvent(FlutterEngine engine, + const FlutterPointerEvent *events, + size_t events_count); FLUTTER_EXPORT -FlutterEngineResult FlutterEngineSendPlatformMessage( - FlutterEngine engine, - const FlutterPlatformMessage* message); +FlutterEngineResult +FlutterEngineSendPlatformMessage(FlutterEngine engine, + const FlutterPlatformMessage *message); // Creates a platform message response handle that allows the embedder to set a // native callback for a response to a message. This handle may be set on the @@ -728,24 +723,19 @@ FlutterEngineResult FlutterEngineSendPlatformMessage( // call as the third argument. FLUTTER_EXPORT FlutterEngineResult FlutterPlatformMessageCreateResponseHandle( - FlutterEngine engine, - FlutterDataCallback data_callback, - void* user_data, - FlutterPlatformMessageResponseHandle** response_out); + FlutterEngine engine, FlutterDataCallback data_callback, void *user_data, + FlutterPlatformMessageResponseHandle **response_out); // Collects the handle created using // |FlutterPlatformMessageCreateResponseHandle|. FLUTTER_EXPORT FlutterEngineResult FlutterPlatformMessageReleaseResponseHandle( - FlutterEngine engine, - FlutterPlatformMessageResponseHandle* response); + FlutterEngine engine, FlutterPlatformMessageResponseHandle *response); FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendPlatformMessageResponse( - FlutterEngine engine, - const FlutterPlatformMessageResponseHandle* handle, - const uint8_t* data, - size_t data_length); + FlutterEngine engine, const FlutterPlatformMessageResponseHandle *handle, + const uint8_t *data, size_t data_length); // This API is only meant to be used by platforms that need to flush tasks on a // message loop not controlled by the Flutter engine. This API will be @@ -759,21 +749,21 @@ FlutterEngineResult __FlutterEngineFlushPendingTasksNow(); // mark that a frame is available by calling // |FlutterEngineMarkExternalTextureFrameAvailable|. FLUTTER_EXPORT -FlutterEngineResult FlutterEngineRegisterExternalTexture( - FlutterEngine engine, - int64_t texture_identifier); +FlutterEngineResult +FlutterEngineRegisterExternalTexture(FlutterEngine engine, + int64_t texture_identifier); // Unregister a previous texture registration. FLUTTER_EXPORT -FlutterEngineResult FlutterEngineUnregisterExternalTexture( - FlutterEngine engine, - int64_t texture_identifier); +FlutterEngineResult +FlutterEngineUnregisterExternalTexture(FlutterEngine engine, + int64_t texture_identifier); // Mark that a new texture frame is available for a given texture identifier. FLUTTER_EXPORT -FlutterEngineResult FlutterEngineMarkExternalTextureFrameAvailable( - FlutterEngine engine, - int64_t texture_identifier); +FlutterEngineResult +FlutterEngineMarkExternalTextureFrameAvailable(FlutterEngine engine, + int64_t texture_identifier); // Enable or disable accessibility semantics. // @@ -786,18 +776,16 @@ FlutterEngineResult FlutterEngineUpdateSemanticsEnabled(FlutterEngine engine, // Sets additional accessibility features. FLUTTER_EXPORT -FlutterEngineResult FlutterEngineUpdateAccessibilityFeatures( - FlutterEngine engine, - FlutterAccessibilityFeature features); +FlutterEngineResult +FlutterEngineUpdateAccessibilityFeatures(FlutterEngine engine, + FlutterAccessibilityFeature features); // Dispatch a semantics action to the specified semantics node. FLUTTER_EXPORT -FlutterEngineResult FlutterEngineDispatchSemanticsAction( - FlutterEngine engine, - uint64_t id, - FlutterSemanticsAction action, - const uint8_t* data, - size_t data_length); +FlutterEngineResult +FlutterEngineDispatchSemanticsAction(FlutterEngine engine, uint64_t id, + FlutterSemanticsAction action, + const uint8_t *data, size_t data_length); // Notify the engine that a vsync event occurred. A baton passed to the // platform via the vsync callback must be returned. This call must be made on @@ -816,8 +804,7 @@ FlutterEngineResult FlutterEngineDispatchSemanticsAction( // // That frame timepoints are in nanoseconds. FLUTTER_EXPORT -FlutterEngineResult FlutterEngineOnVsync(FlutterEngine engine, - intptr_t baton, +FlutterEngineResult FlutterEngineOnVsync(FlutterEngine engine, intptr_t baton, uint64_t frame_start_time_nanos, uint64_t frame_target_time_nanos); @@ -828,7 +815,7 @@ FlutterEngineResult FlutterEngineOnVsync(FlutterEngine engine, // Can be called on any thread. Strings passed into the function will NOT be // copied when added to the timeline. Only string literals may be passed in. FLUTTER_EXPORT -void FlutterEngineTraceEventDurationBegin(const char* name); +void FlutterEngineTraceEventDurationBegin(const char *name); // A profiling utility. Logs a trace duration end event to the timeline. If the // timeline is unavailable or disabled, this has no effect. This call must be @@ -838,14 +825,14 @@ void FlutterEngineTraceEventDurationBegin(const char* name); // NOT be copied when added to the timeline. Only string literals may be passed // in. FLUTTER_EXPORT -void FlutterEngineTraceEventDurationEnd(const char* name); +void FlutterEngineTraceEventDurationEnd(const char *name); // A profiling utility. Logs a trace duration instant event to the timeline. If // the timeline is unavailable or disabled, this has no effect. Can be called // on any thread. Strings passed into the function will NOT be copied when added // to the timeline. Only string literals may be passed in. FLUTTER_EXPORT -void FlutterEngineTraceEventInstant(const char* name); +void FlutterEngineTraceEventInstant(const char *name); // Posts a task onto the Flutter render thread. Typically, this may be called // from any thread as long as a |FlutterEngineShutdown| on the specific engine @@ -853,7 +840,7 @@ void FlutterEngineTraceEventInstant(const char* name); FLUTTER_EXPORT FlutterEngineResult FlutterEnginePostRenderThreadTask(FlutterEngine engine, VoidCallback callback, - void* callback_data); + void *callback_data); // Get the current time in nanoseconds from the clock used by the flutter // engine. This is the system monotonic clock. @@ -866,10 +853,10 @@ uint64_t FlutterEngineGetCurrentTime(); // the task before that time is undefined behavior. FLUTTER_EXPORT FlutterEngineResult FlutterEngineRunTask(FlutterEngine engine, - const FlutterTask* task); + const FlutterTask *task); #if defined(__cplusplus) -} // extern "C" +} // extern "C" #endif -#endif // FLUTTER_EMBEDDER_H_ +#endif // FLUTTER_EMBEDDER_H_ diff --git a/embedder/embedder_helper.c b/embedder/embedder_helper.c index 488ce7bd..31400e01 100644 --- a/embedder/embedder_helper.c +++ b/embedder/embedder_helper.c @@ -18,13 +18,6 @@ bool proxy_gl_external_texture_frame_callback(void *user_data, size_t height, FlutterOpenGLTexture *texture); -static bool OnAcquireExternalTexture(void *user_data, int64_t texture_id, - size_t width, size_t height, - FlutterOpenGLTexture *texture) { - printf("=== OnAcquireExternalTexture: %ld\n", texture_id); - return 1; -} - // C helper FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, FlutterProjectArgs *Args, @@ -39,7 +32,8 @@ FlutterEngineResult runFlutter(void *user_data, FlutterEngine *engine, config.open_gl.fbo_callback = proxy_fbo_callback; config.open_gl.make_resource_current = proxy_make_resource_current; config.open_gl.gl_proc_resolver = proxy_gl_proc_resolver; - config.open_gl.gl_external_texture_frame_callback = OnAcquireExternalTexture; + config.open_gl.gl_external_texture_frame_callback = + proxy_gl_external_texture_frame_callback; Args->command_line_argc = nVmAgrs; Args->command_line_argv = vmArgs; diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index fabed7c7..66baf0d5 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -61,8 +61,16 @@ func proxy_gl_proc_resolver(userData unsafe.Pointer, procname *C.char) unsafe.Po } //export proxy_gl_external_texture_frame_callback -func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, textureID int64, width int, height int, texture *FlutterOpenGLTexture) C.bool { +func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, + textureID int64, + width C.size_t, + height C.size_t, + texture *C.FlutterOpenGLTexture) C.bool { flutterEnginePointer := *(*uintptr)(userData) flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) - return C.bool(flutterEngine.GLExternalTextureFrameCallback(textureID, width, height, texture)) + res, embedderGLTexture := flutterEngine.GLExternalTextureFrameCallback(textureID, int(width), int(height)) + texture.target = C.uint32_t(embedderGLTexture.Target) + texture.name = C.uint32_t(embedderGLTexture.Name) + texture.format = C.uint32_t(embedderGLTexture.Format) + return C.bool(res) } From 3cc66608ac0423fb0288b42b82434ada6b9d5c2b Mon Sep 17 00:00:00 2001 From: Drakirus Date: Tue, 23 Jul 2019 16:10:34 +0200 Subject: [PATCH 07/14] WIP: looking good! need to implement Unregister, need to exposes: MarkExternalTextureFrameAvailable, RegisterExternalTexture in a good looking api --- application.go | 56 +++++------------ embedder/embedder.go | 2 +- embedder/embedder_helper.c | 1 - embedder/embedder_proxy.go | 3 + texture.go | 124 +++++++++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 42 deletions(-) create mode 100644 texture.go diff --git a/application.go b/application.go index 5691aade..f4fd72c2 100644 --- a/application.go +++ b/application.go @@ -9,7 +9,6 @@ import ( "runtime" "unsafe" - "github.com/go-gl/gl/v2.1/gl" "github.com/go-gl/glfw/v3.2/glfw" "github.com/pkg/errors" @@ -103,6 +102,11 @@ func (a *Application) Run() error { return errors.Errorf("invalid window mode %T", a.config.windowMode) } + glfw.WindowHint(glfw.ContextVersionMajor, 4) // OR 2 + glfw.WindowHint(glfw.ContextVersionMinor, 1) + glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) + glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) + a.window, err = glfw.CreateWindow(a.config.windowInitialDimensions.width, a.config.windowInitialDimensions.height, "Loading..", monitor, nil) if err != nil { return errors.Wrap(err, "creating glfw window") @@ -144,6 +148,8 @@ func (a *Application) Run() error { a.engine = embedder.NewFlutterEngine() messenger := newMessenger(a.engine) + texturer := newTexturer(a.window) + for _, p := range a.config.plugins { err = p.InitPlugin(messenger) if err != nil { @@ -205,14 +211,13 @@ func (a *Application) Run() error { a.engine.GLProcResolver = func(procName string) unsafe.Pointer { return glfw.GetProcAddress(procName) } - a.engine.GLExternalTextureFrameCallback = func(textureID int64, - width int, height int, - ) (bool, embedder.FlutterOpenGLTexture) { - fmt.Printf("\nFlutterOpenGLTexture: %v, %v\n", width, height) - a.window.MakeContextCurrent() + a.engine.PlatfromMessage = messenger.handlePlatformMessage + a.engine.GLExternalTextureFrameCallback = texturer.handleExternalTexture + + texturer.SetTextureHandler(1, func(width, height int) (bool, *PixelBuffer) { - file := "/tmp/square.png" + file := "/home/drakirus/Images/test.png" imgFile, err := os.Open(file) if err != nil { fmt.Printf("texture %q not found on disk: %v", file, err) @@ -229,39 +234,8 @@ func (a *Application) Run() error { } draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src) - - var texture uint32 - gl.GenTextures(1, &texture) - EF := embedder.FlutterOpenGLTexture{ - Target: gl.TEXTURE_2D, - Name: texture, - Format: gl.RGBA8, - } - return true, EF - - // set the texture wrapping parameters - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) - // set texture filtering parameters - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) - - gl.BindTexture(gl.TEXTURE_2D, texture) - gl.TexImage2D( - gl.TEXTURE_2D, - 0, - gl.RGBA, - int32(width), - int32(height), - 0, - gl.RGBA, - gl.UNSIGNED_BYTE, - gl.Ptr(rgba.Pix)) - - return true, EF - } - - a.engine.PlatfromMessage = messenger.handlePlatformMessage + return true, &PixelBuffer{Pix: rgba.Pix, Width: width, Height: height} + }) // Not very nice, but we can only really fix this when there's a pluggable // renderer. @@ -286,6 +260,8 @@ func (a *Application) Run() error { os.Exit(1) } + texturer.init() + defaultPlatformPlugin.glfwTasker = tasker.New() m := newWindowManager() diff --git a/embedder/embedder.go b/embedder/embedder.go index 4884a62e..4613c252 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -78,7 +78,7 @@ type FlutterEngine struct { GLFboCallback func() int32 GLMakeResourceCurrent func() bool GLProcResolver func(procName string) unsafe.Pointer - GLExternalTextureFrameCallback func(textureID int64, width int, height int) (bool, FlutterOpenGLTexture) + GLExternalTextureFrameCallback func(textureID int64, width int, height int) (bool, *FlutterOpenGLTexture) // platform message callback function PlatfromMessage func(message *PlatformMessage) diff --git a/embedder/embedder_helper.c b/embedder/embedder_helper.c index 31400e01..c177fa15 100644 --- a/embedder/embedder_helper.c +++ b/embedder/embedder_helper.c @@ -1,4 +1,3 @@ - #include #include diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index 66baf0d5..67d81c43 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -69,6 +69,9 @@ func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, flutterEnginePointer := *(*uintptr)(userData) flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) res, embedderGLTexture := flutterEngine.GLExternalTextureFrameCallback(textureID, int(width), int(height)) + if embedderGLTexture == nil { + return C.bool(res) + } texture.target = C.uint32_t(embedderGLTexture.Target) texture.name = C.uint32_t(embedderGLTexture.Name) texture.format = C.uint32_t(embedderGLTexture.Format) diff --git a/texture.go b/texture.go new file mode 100644 index 00000000..b7d9bb74 --- /dev/null +++ b/texture.go @@ -0,0 +1,124 @@ +package flutter + +import ( + "fmt" + "sync" + + "github.com/go-gl/gl/v4.6-core/gl" + "github.com/go-gl/glfw/v3.2/glfw" + "github.com/pkg/errors" + + "github.com/go-flutter-desktop/go-flutter/embedder" +) + +type texturer struct { + window *glfw.Window + channels map[int64]externalTextureHanlder + channelsLock sync.RWMutex +} + +func newTexturer(window *glfw.Window) *texturer { + return &texturer{ + window: window, + channels: make(map[int64]externalTextureHanlder), + } +} + +func (t *texturer) init() error { + t.window.MakeContextCurrent() + // Important! Call gl.Init only under the presence of an active OpenGL context, + // i.e., after MakeContextCurrent. + if err := gl.Init(); err != nil { + return errors.Wrap(err, "texturer gl init") + } + return nil +} + +// SetTextureHandler registers a handler to be invoked when the Flutter +// application want to get a PixelBuffer to draw into the scene. +// +// Registration overwrites any previous registration for the same textureID +// name. Use nil as handler to deregister. +func (t *texturer) SetTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) { + t.channelsLock.Lock() + if handler == nil { + delete(t.channels, textureID) + } else { + t.channels[textureID] = externalTextureHanlder{ + handle: handler, + } + } + t.channelsLock.Unlock() +} + +// ExternalTextureHanlderFunc describes the function that handles external +// Texture on a given ID. +type ExternalTextureHanlderFunc func(width int, height int) (bool, *PixelBuffer) + +type externalTextureHanlder struct { + // handle is called when flutter needs the PixelBuffer + handle ExternalTextureHanlderFunc + // gl texture to refer to for this handler + texture uint32 +} + +// PixelBuffer is an in-memory (RGBA) image. +type PixelBuffer struct { + // Pix holds the image's pixels, in R, G, B, A order. + Pix []uint8 + // Width and Height of the image's bounds + Width, Height int +} + +func (t *texturer) handleExternalTexture(textureID int64, + width int, height int) (bool, *embedder.FlutterOpenGLTexture) { + + t.channelsLock.RLock() + registration, registrationExists := t.channels[textureID] + t.channelsLock.RUnlock() + + if !registrationExists { + fmt.Printf("go-flutter: no texture handler found for Texture ID: %v\n", textureID) + return false, nil + } + res, pixelBuffer := registration.handle(width, height) + if !res || pixelBuffer == nil { + return false, nil + } + + if len(pixelBuffer.Pix) == 0 { + return false, nil + } + + t.window.MakeContextCurrent() + + if registration.texture == 0 { + gl.GenTextures(1, ®istration.texture) + gl.BindTexture(gl.TEXTURE_2D, registration.texture) + // set the texture wrapping parameters + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) + // set texture filtering parameters + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + } + + gl.BindTexture(gl.TEXTURE_2D, registration.texture) + gl.TexImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + int32(pixelBuffer.Width), + int32(pixelBuffer.Height), + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + gl.Ptr(pixelBuffer.Pix)) + + return true, &embedder.FlutterOpenGLTexture{ + Target: gl.TEXTURE_2D, + Name: registration.texture, + Format: gl.RGBA8, + } + +} From 382ac0826f47026fdee5de0ea7c7390c515d20be Mon Sep 17 00:00:00 2001 From: Drakirus Date: Tue, 23 Jul 2019 22:28:14 +0200 Subject: [PATCH 08/14] WIP: texturePlugin --- application.go | 35 ++++++++++------------------------- plugin.go | 18 +++++++++++++++++- texture.go | 23 +++++++++++++---------- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/application.go b/application.go index f4fd72c2..cb48e0c5 100644 --- a/application.go +++ b/application.go @@ -2,8 +2,6 @@ package flutter import ( "fmt" - "image" - "image/draw" "os" "path/filepath" "runtime" @@ -148,7 +146,7 @@ func (a *Application) Run() error { a.engine = embedder.NewFlutterEngine() messenger := newMessenger(a.engine) - texturer := newTexturer(a.window) + texturer := newRegistry(a.engine, a.window) for _, p := range a.config.plugins { err = p.InitPlugin(messenger) @@ -163,6 +161,15 @@ func (a *Application) Run() error { return errors.Wrap(err, "failed to initialize glfw plugin"+fmt.Sprintf("%T", p)) } } + + // Extra init call for plugins that satisfy the PluginTexture interface. + if glfwPlugin, ok := p.(PluginTexture); ok { + err = glfwPlugin.InitPluginTexture(texturer) + if err != nil { + return errors.Wrap(err, "failed to initialize texture plugin"+fmt.Sprintf("%T", p)) + } + } + } if a.config.flutterAssetsPath != "" { @@ -215,28 +222,6 @@ func (a *Application) Run() error { a.engine.PlatfromMessage = messenger.handlePlatformMessage a.engine.GLExternalTextureFrameCallback = texturer.handleExternalTexture - texturer.SetTextureHandler(1, func(width, height int) (bool, *PixelBuffer) { - - file := "/home/drakirus/Images/test.png" - imgFile, err := os.Open(file) - if err != nil { - fmt.Printf("texture %q not found on disk: %v", file, err) - } - - img, _, err := image.Decode(imgFile) - if err != nil { - fmt.Printf("error decoding file %s:%v", file, err) - } - - rgba := image.NewRGBA(img.Bounds()) - if rgba.Stride != rgba.Rect.Size().X*4 { - fmt.Printf("unsupported stride") - } - - draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src) - return true, &PixelBuffer{Pix: rgba.Pix, Width: width, Height: height} - }) - // Not very nice, but we can only really fix this when there's a pluggable // renderer. defaultTextinputPlugin.keyboardLayout = a.config.keyboardLayout diff --git a/plugin.go b/plugin.go index 0f44731e..c2ed325a 100644 --- a/plugin.go +++ b/plugin.go @@ -22,7 +22,7 @@ type Plugin interface { // PluginGLFW defines the interface for plugins that are GLFW-aware. Plugins may // implement this interface to receive access to the *glfw.Window. Note that // plugins must still implement the Plugin interface. The call to InitPluginGLFW -// is made afther the call to InitPlugin. +// is made after the call to InitPlugin. // // PluginGLFW is separated because not all plugins need to know about glfw, // Adding glfw.Window to the InitPlugin call would add glfw as dependency to @@ -37,3 +37,19 @@ type PluginGLFW interface { // returned it is printend the application is stopped. InitPluginGLFW(window *glfw.Window) error } + +// PluginTexture defines the interface for plugins that needs to create and +// manage backend textures. Plugins may implement this interface to receive +// access to the TextureRegistry. Note that plugins must still implement the +// Plugin interface. The call to PluginTexture is made after the call to +// PluginGLFW. +// +// PluginTexture is separated because not all plugins need to send raw pixel to +// the Flutter scene. +type PluginTexture interface { + // Any type inmplementing PluginTexture must also implement Plugin. + Plugin + // InitPluginTexture is called after the call to InitPlugin. When an error is + // returned it is printend the application is stopped. + InitPluginTexture(registry *TextureRegistry) error +} diff --git a/texture.go b/texture.go index b7d9bb74..a8e57590 100644 --- a/texture.go +++ b/texture.go @@ -11,25 +11,28 @@ import ( "github.com/go-flutter-desktop/go-flutter/embedder" ) -type texturer struct { +// TextureRegistry is a registry entry for a managed SurfaceTexture. +type TextureRegistry struct { window *glfw.Window - channels map[int64]externalTextureHanlder + engine *embedder.FlutterEngine + channels map[int64]*externalTextureHanlder channelsLock sync.RWMutex } -func newTexturer(window *glfw.Window) *texturer { - return &texturer{ +func newRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry { + return &TextureRegistry{ window: window, - channels: make(map[int64]externalTextureHanlder), + engine: engine, + channels: make(map[int64]*externalTextureHanlder), } } -func (t *texturer) init() error { +func (t *TextureRegistry) init() error { t.window.MakeContextCurrent() // Important! Call gl.Init only under the presence of an active OpenGL context, // i.e., after MakeContextCurrent. if err := gl.Init(); err != nil { - return errors.Wrap(err, "texturer gl init") + return errors.Wrap(err, "TextureRegistry gl init") } return nil } @@ -39,12 +42,12 @@ func (t *texturer) init() error { // // Registration overwrites any previous registration for the same textureID // name. Use nil as handler to deregister. -func (t *texturer) SetTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) { +func (t *TextureRegistry) SetTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) { t.channelsLock.Lock() if handler == nil { delete(t.channels, textureID) } else { - t.channels[textureID] = externalTextureHanlder{ + t.channels[textureID] = &externalTextureHanlder{ handle: handler, } } @@ -70,7 +73,7 @@ type PixelBuffer struct { Width, Height int } -func (t *texturer) handleExternalTexture(textureID int64, +func (t *TextureRegistry) handleExternalTexture(textureID int64, width int, height int) (bool, *embedder.FlutterOpenGLTexture) { t.channelsLock.RLock() From 4cec5ef08ec436323adf4decfbc4e476be4da86f Mon Sep 17 00:00:00 2001 From: Drakirus Date: Wed, 24 Jul 2019 00:27:19 +0200 Subject: [PATCH 09/14] WIP: nice plugin interface TODO: destroy the gl.GenTextures --- application.go | 34 +++--- embedder/embedder.go | 5 +- textinput_model.go => textinput-model.go | 0 texture-registry.go | 140 +++++++++++++++++++++++ texture.go | 132 ++++----------------- 5 files changed, 182 insertions(+), 129 deletions(-) rename textinput_model.go => textinput-model.go (100%) create mode 100644 texture-registry.go diff --git a/application.go b/application.go index cb48e0c5..8c5bc848 100644 --- a/application.go +++ b/application.go @@ -146,8 +146,6 @@ func (a *Application) Run() error { a.engine = embedder.NewFlutterEngine() messenger := newMessenger(a.engine) - texturer := newRegistry(a.engine, a.window) - for _, p := range a.config.plugins { err = p.InitPlugin(messenger) if err != nil { @@ -161,15 +159,6 @@ func (a *Application) Run() error { return errors.Wrap(err, "failed to initialize glfw plugin"+fmt.Sprintf("%T", p)) } } - - // Extra init call for plugins that satisfy the PluginTexture interface. - if glfwPlugin, ok := p.(PluginTexture); ok { - err = glfwPlugin.InitPluginTexture(texturer) - if err != nil { - return errors.Wrap(err, "failed to initialize texture plugin"+fmt.Sprintf("%T", p)) - } - } - } if a.config.flutterAssetsPath != "" { @@ -220,8 +209,12 @@ func (a *Application) Run() error { } a.engine.PlatfromMessage = messenger.handlePlatformMessage + + texturer := newRegistry(a.engine, a.window) a.engine.GLExternalTextureFrameCallback = texturer.handleExternalTexture + texturer.init() + // Not very nice, but we can only really fix this when there's a pluggable // renderer. defaultTextinputPlugin.keyboardLayout = a.config.keyboardLayout @@ -245,8 +238,6 @@ func (a *Application) Run() error { os.Exit(1) } - texturer.init() - defaultPlatformPlugin.glfwTasker = tasker.New() m := newWindowManager() @@ -261,6 +252,16 @@ func (a *Application) Run() error { // platfrom message can be corectly handled by ui.Window.onPlatformMessage. glfw.WaitEvents() + for _, p := range a.config.plugins { + // Extra init call for plugins that satisfy the PluginTexture interface. + if glfwPlugin, ok := p.(PluginTexture); ok { + err = glfwPlugin.InitPluginTexture(texturer) + if err != nil { + return errors.Wrap(err, "failed to initialize texture plugin"+fmt.Sprintf("%T", p)) + } + } + } + a.window.SetKeyCallback( func(window *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { defaultTextinputPlugin.glfwKeyCallback(window, key, scancode, action, mods) @@ -276,15 +277,8 @@ func (a *Application) Run() error { a.window.SetScrollCallback(m.glfwScrollCallback) defer a.engine.Shutdown() - frameI := int64(0) - textureID := int64(1) for !a.window.ShouldClose() { - frameI++ glfw.WaitEventsTimeout(0.016) // timeout to get 60fps-ish iterations - if frameI == 100 { - fmt.Printf("Texture: register result: %v\n", a.engine.RegisterExternalTexture(textureID) == embedder.ResultSuccess) - fmt.Printf("Texture: New Frame result: %v\n", a.engine.MarkExternalTextureFrameAvailable(textureID) == embedder.ResultSuccess) - } embedder.FlutterEngineFlushPendingTasksNow() defaultPlatformPlugin.glfwTasker.ExecuteTasks() messenger.engineTasker.ExecuteTasks() diff --git a/embedder/embedder.go b/embedder/embedder.go index 4613c252..d7f1727f 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -55,8 +55,11 @@ const ( // FlutterOpenGLTexture corresponds to the C.FlutterOpenGLTexture struct. type FlutterOpenGLTexture struct { + // Target texture of the active texture unit (example GL_TEXTURE_2D). Target uint32 - Name uint32 + // The name of the texture. + Name uint32 + // The texture format (example GL_RGBA8). Format uint32 } diff --git a/textinput_model.go b/textinput-model.go similarity index 100% rename from textinput_model.go rename to textinput-model.go diff --git a/texture-registry.go b/texture-registry.go new file mode 100644 index 00000000..61b2d74f --- /dev/null +++ b/texture-registry.go @@ -0,0 +1,140 @@ +package flutter + +import ( + "fmt" + "sync" + + "github.com/go-flutter-desktop/go-flutter/embedder" + "github.com/go-gl/gl/v4.6-core/gl" + "github.com/go-gl/glfw/v3.2/glfw" + "github.com/pkg/errors" +) + +// TextureRegistry is a registry entry for a managed SurfaceTexture. +type TextureRegistry struct { + window *glfw.Window + engine *embedder.FlutterEngine + channels map[int64]*externalTextureHanlder + channelsLock sync.RWMutex + + texture int64 + texturesLock sync.Mutex +} + +func newRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry { + return &TextureRegistry{ + window: window, + engine: engine, + channels: make(map[int64]*externalTextureHanlder), + } +} + +func (t *TextureRegistry) init() error { + t.window.MakeContextCurrent() + // Important! Call gl.Init only under the presence of an active OpenGL context, + // i.e., after MakeContextCurrent. + if err := gl.Init(); err != nil { + return errors.Wrap(err, "TextureRegistry gl init") + } + return nil +} + +// NewTexture creates a new Texture +func (t *TextureRegistry) NewTexture() Texture { + t.texturesLock.Lock() + defer t.texturesLock.Unlock() + t.texture++ + return Texture{ID: t.texture, registry: t} +} + +// ExternalTextureHanlderFunc describes the function that handles external +// Texture on a given ID. +type ExternalTextureHanlderFunc func(width int, height int) (bool, *PixelBuffer) + +// PixelBuffer is an in-memory (RGBA) image. +type PixelBuffer struct { + // Pix holds the image's pixels, in R, G, B, A order. + Pix []uint8 + // Width and Height of the image's bounds + Width, Height int +} + +type externalTextureHanlder struct { + // handle is called when flutter needs the PixelBuffer + handle ExternalTextureHanlderFunc + // gl texture to refer to for this handler + texture uint32 +} + +// setTextureHandler registers a handler to be invoked when the Flutter +// application want to get a PixelBuffer to draw into the scene. +// +// Registration overwrites any previous registration for the same textureID +// name. Use nil as handler to deregister. +func (t *TextureRegistry) setTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) { + t.channelsLock.Lock() + if handler == nil { + delete(t.channels, textureID) + } else { + t.channels[textureID] = &externalTextureHanlder{ + handle: handler, + } + } + t.channelsLock.Unlock() +} + +func (t *TextureRegistry) handleExternalTexture(textureID int64, + width int, height int) (bool, *embedder.FlutterOpenGLTexture) { + + t.channelsLock.RLock() + registration, registrationExists := t.channels[textureID] + t.channelsLock.RUnlock() + + if !registrationExists { + fmt.Printf("go-flutter: no texture handler found for Texture ID: %v\n", textureID) + return false, nil + } + res, pixelBuffer := registration.handle(width, height) + if !res || pixelBuffer == nil { + return false, nil + } + + if len(pixelBuffer.Pix) == 0 { + return false, nil + } + + t.window.MakeContextCurrent() + + if registration.texture == 0 { + gl.GenTextures(1, ®istration.texture) + gl.BindTexture(gl.TEXTURE_2D, registration.texture) + // set the texture wrapping parameters + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) + // set texture filtering parameters + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + } + + gl.BindTexture(gl.TEXTURE_2D, registration.texture) + // TODO(Drakirus) handle multiple format of the pixel data (RGB, Gray) and + // Texture format (GL_RGBA8). + // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml + gl.TexImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + int32(pixelBuffer.Width), + int32(pixelBuffer.Height), + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + gl.Ptr(pixelBuffer.Pix)) + + return true, &embedder.FlutterOpenGLTexture{ + Target: gl.TEXTURE_2D, + Name: registration.texture, + Format: gl.RGBA8, + } + +} diff --git a/texture.go b/texture.go index a8e57590..a0e929bb 100644 --- a/texture.go +++ b/texture.go @@ -1,127 +1,43 @@ package flutter import ( + "errors" "fmt" - "sync" - - "github.com/go-gl/gl/v4.6-core/gl" - "github.com/go-gl/glfw/v3.2/glfw" - "github.com/pkg/errors" "github.com/go-flutter-desktop/go-flutter/embedder" ) -// TextureRegistry is a registry entry for a managed SurfaceTexture. -type TextureRegistry struct { - window *glfw.Window - engine *embedder.FlutterEngine - channels map[int64]*externalTextureHanlder - channelsLock sync.RWMutex -} - -func newRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry { - return &TextureRegistry{ - window: window, - engine: engine, - channels: make(map[int64]*externalTextureHanlder), - } +// Texture is an identifier for texture declaration +type Texture struct { + ID int64 + registry *TextureRegistry } -func (t *TextureRegistry) init() error { - t.window.MakeContextCurrent() - // Important! Call gl.Init only under the presence of an active OpenGL context, - // i.e., after MakeContextCurrent. - if err := gl.Init(); err != nil { - return errors.Wrap(err, "TextureRegistry gl init") +// Register registers a textureID +func (t *Texture) Register(handler ExternalTextureHanlderFunc) error { + t.registry.setTextureHandler(t.ID, handler) + result := t.registry.engine.RegisterExternalTexture(t.ID) + if result != embedder.ResultSuccess { + return errors.New("'go-flutter' couldn't register texture with id: " + fmt.Sprint(t.ID)) } return nil } -// SetTextureHandler registers a handler to be invoked when the Flutter -// application want to get a PixelBuffer to draw into the scene. -// -// Registration overwrites any previous registration for the same textureID -// name. Use nil as handler to deregister. -func (t *TextureRegistry) SetTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) { - t.channelsLock.Lock() - if handler == nil { - delete(t.channels, textureID) - } else { - t.channels[textureID] = &externalTextureHanlder{ - handle: handler, - } +// FrameAvailable mark a texture buffer is ready to be draw in the flutter scene +func (t *Texture) FrameAvailable() error { + result := t.registry.engine.MarkExternalTextureFrameAvailable(t.ID) + if result != embedder.ResultSuccess { + return errors.New("'go-flutter' couldn't mark frame available of texture with id: " + fmt.Sprint(t.ID)) } - t.channelsLock.Unlock() -} - -// ExternalTextureHanlderFunc describes the function that handles external -// Texture on a given ID. -type ExternalTextureHanlderFunc func(width int, height int) (bool, *PixelBuffer) - -type externalTextureHanlder struct { - // handle is called when flutter needs the PixelBuffer - handle ExternalTextureHanlderFunc - // gl texture to refer to for this handler - texture uint32 -} - -// PixelBuffer is an in-memory (RGBA) image. -type PixelBuffer struct { - // Pix holds the image's pixels, in R, G, B, A order. - Pix []uint8 - // Width and Height of the image's bounds - Width, Height int + return nil } -func (t *TextureRegistry) handleExternalTexture(textureID int64, - width int, height int) (bool, *embedder.FlutterOpenGLTexture) { - - t.channelsLock.RLock() - registration, registrationExists := t.channels[textureID] - t.channelsLock.RUnlock() - - if !registrationExists { - fmt.Printf("go-flutter: no texture handler found for Texture ID: %v\n", textureID) - return false, nil +// UnRegister mark a texture buffer is ready to be draw in the flutter scene +func (t *Texture) UnRegister() error { + t.registry.setTextureHandler(t.ID, nil) + result := t.registry.engine.UnregisterExternalTexture(t.ID) + if result != embedder.ResultSuccess { + return errors.New("'go-flutter' couldn't unregisters texture with id: " + fmt.Sprint(t.ID)) } - res, pixelBuffer := registration.handle(width, height) - if !res || pixelBuffer == nil { - return false, nil - } - - if len(pixelBuffer.Pix) == 0 { - return false, nil - } - - t.window.MakeContextCurrent() - - if registration.texture == 0 { - gl.GenTextures(1, ®istration.texture) - gl.BindTexture(gl.TEXTURE_2D, registration.texture) - // set the texture wrapping parameters - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER) - // set texture filtering parameters - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) - gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) - } - - gl.BindTexture(gl.TEXTURE_2D, registration.texture) - gl.TexImage2D( - gl.TEXTURE_2D, - 0, - gl.RGBA, - int32(pixelBuffer.Width), - int32(pixelBuffer.Height), - 0, - gl.RGBA, - gl.UNSIGNED_BYTE, - gl.Ptr(pixelBuffer.Pix)) - - return true, &embedder.FlutterOpenGLTexture{ - Target: gl.TEXTURE_2D, - Name: registration.texture, - Format: gl.RGBA8, - } - + return nil } From 3f8aa3a95ad7fa4eeaf3294fd230ad92028ce6c3 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Wed, 24 Jul 2019 13:48:25 +0200 Subject: [PATCH 10/14] checkpoint: Manual collect of pixelBuffer.Pix --- embedder/embedder.go | 10 ++++++---- embedder/embedder_proxy.go | 24 +++++++++++++++++++++--- texture-registry.go | 28 ++++++++++++++++------------ texture.go | 2 +- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/embedder/embedder.go b/embedder/embedder.go index d7f1727f..67a11f08 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -55,12 +55,14 @@ const ( // FlutterOpenGLTexture corresponds to the C.FlutterOpenGLTexture struct. type FlutterOpenGLTexture struct { - // Target texture of the active texture unit (example GL_TEXTURE_2D). + // Target texture of the active texture unit (example GL_TEXTURE_2D) Target uint32 - // The name of the texture. + // The name of the texture Name uint32 - // The texture format (example GL_RGBA8). + // The texture format (example GL_RGBA8) Format uint32 + // Callback invoked to collect the texture + Collect func() } // FlutterEngine corresponds to the C.FlutterEngine with his associated callback's method. @@ -81,7 +83,7 @@ type FlutterEngine struct { GLFboCallback func() int32 GLMakeResourceCurrent func() bool GLProcResolver func(procName string) unsafe.Pointer - GLExternalTextureFrameCallback func(textureID int64, width int, height int) (bool, *FlutterOpenGLTexture) + GLExternalTextureFrameCallback func(textureID int64, width int, height int) *FlutterOpenGLTexture // platform message callback function PlatfromMessage func(message *PlatformMessage) diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index 67d81c43..bf921cbc 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -1,8 +1,10 @@ package embedder // #include "embedder.h" +// void proxy_texture_destruction_callback(void* user_data); import "C" import ( + "runtime" "unsafe" ) @@ -68,12 +70,28 @@ func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, texture *C.FlutterOpenGLTexture) C.bool { flutterEnginePointer := *(*uintptr)(userData) flutterEngine := (*FlutterEngine)(unsafe.Pointer(flutterEnginePointer)) - res, embedderGLTexture := flutterEngine.GLExternalTextureFrameCallback(textureID, int(width), int(height)) + embedderGLTexture := flutterEngine.GLExternalTextureFrameCallback(textureID, int(width), int(height)) if embedderGLTexture == nil { - return C.bool(res) + return C.bool(false) } texture.target = C.uint32_t(embedderGLTexture.Target) texture.name = C.uint32_t(embedderGLTexture.Name) texture.format = C.uint32_t(embedderGLTexture.Format) - return C.bool(res) + collectPointer := (unsafe.Pointer(&embedderGLTexture.Collect)) + texture.user_data = collectPointer + texture.destruction_callback = (C.VoidCallback)(C.proxy_texture_destruction_callback) + defer func() { + runtime.KeepAlive(collectPointer) + }() + return C.bool(true) +} + +//export proxy_texture_destruction_callback +func proxy_texture_destruction_callback(userData unsafe.Pointer) { + defer recover() + destroyCB := (*func())(userData) + if destroyCB != nil { + destroyCB := *destroyCB + destroyCB() + } } diff --git a/texture-registry.go b/texture-registry.go index 61b2d74f..6972c482 100644 --- a/texture-registry.go +++ b/texture-registry.go @@ -21,6 +21,13 @@ type TextureRegistry struct { texturesLock sync.Mutex } +type externalTextureHanlder struct { + // handle is called when flutter needs the PixelBuffer + handle ExternalTextureHanlderFunc + // gl texture to refer to for this handler + texture uint32 +} + func newRegistry(engine *embedder.FlutterEngine, window *glfw.Window) *TextureRegistry { return &TextureRegistry{ window: window, @@ -59,13 +66,6 @@ type PixelBuffer struct { Width, Height int } -type externalTextureHanlder struct { - // handle is called when flutter needs the PixelBuffer - handle ExternalTextureHanlderFunc - // gl texture to refer to for this handler - texture uint32 -} - // setTextureHandler registers a handler to be invoked when the Flutter // application want to get a PixelBuffer to draw into the scene. // @@ -84,7 +84,7 @@ func (t *TextureRegistry) setTextureHandler(textureID int64, handler ExternalTex } func (t *TextureRegistry) handleExternalTexture(textureID int64, - width int, height int) (bool, *embedder.FlutterOpenGLTexture) { + width int, height int) *embedder.FlutterOpenGLTexture { t.channelsLock.RLock() registration, registrationExists := t.channels[textureID] @@ -92,15 +92,15 @@ func (t *TextureRegistry) handleExternalTexture(textureID int64, if !registrationExists { fmt.Printf("go-flutter: no texture handler found for Texture ID: %v\n", textureID) - return false, nil + return nil } res, pixelBuffer := registration.handle(width, height) if !res || pixelBuffer == nil { - return false, nil + return nil } if len(pixelBuffer.Pix) == 0 { - return false, nil + return nil } t.window.MakeContextCurrent() @@ -131,10 +131,14 @@ func (t *TextureRegistry) handleExternalTexture(textureID int64, gl.UNSIGNED_BYTE, gl.Ptr(pixelBuffer.Pix)) - return true, &embedder.FlutterOpenGLTexture{ + return &embedder.FlutterOpenGLTexture{ Target: gl.TEXTURE_2D, Name: registration.texture, Format: gl.RGBA8, + Collect: func() { + // runtime delete the pixelBuffer.Pix, (should be done by the GC) + // gl.DeleteTextures(1, ®istration.texture) // not this, this is for destroy not collect!! + }, } } diff --git a/texture.go b/texture.go index a0e929bb..008b5dd4 100644 --- a/texture.go +++ b/texture.go @@ -13,7 +13,7 @@ type Texture struct { registry *TextureRegistry } -// Register registers a textureID +// Register registers a textureID with his associated handler func (t *Texture) Register(handler ExternalTextureHanlderFunc) error { t.registry.setTextureHandler(t.ID, handler) result := t.registry.engine.RegisterExternalTexture(t.ID) From 3965df74e776fe029403183840ad7e054357ff51 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Wed, 24 Jul 2019 13:50:43 +0200 Subject: [PATCH 11/14] rollback: collect is handled by the golang GC --- embedder/embedder.go | 2 -- embedder/embedder_proxy.go | 18 ------------------ texture-registry.go | 4 ---- 3 files changed, 24 deletions(-) diff --git a/embedder/embedder.go b/embedder/embedder.go index 67a11f08..b63c0bfd 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -61,8 +61,6 @@ type FlutterOpenGLTexture struct { Name uint32 // The texture format (example GL_RGBA8) Format uint32 - // Callback invoked to collect the texture - Collect func() } // FlutterEngine corresponds to the C.FlutterEngine with his associated callback's method. diff --git a/embedder/embedder_proxy.go b/embedder/embedder_proxy.go index bf921cbc..53dd8c9b 100644 --- a/embedder/embedder_proxy.go +++ b/embedder/embedder_proxy.go @@ -1,10 +1,8 @@ package embedder // #include "embedder.h" -// void proxy_texture_destruction_callback(void* user_data); import "C" import ( - "runtime" "unsafe" ) @@ -77,21 +75,5 @@ func proxy_gl_external_texture_frame_callback(userData unsafe.Pointer, texture.target = C.uint32_t(embedderGLTexture.Target) texture.name = C.uint32_t(embedderGLTexture.Name) texture.format = C.uint32_t(embedderGLTexture.Format) - collectPointer := (unsafe.Pointer(&embedderGLTexture.Collect)) - texture.user_data = collectPointer - texture.destruction_callback = (C.VoidCallback)(C.proxy_texture_destruction_callback) - defer func() { - runtime.KeepAlive(collectPointer) - }() return C.bool(true) } - -//export proxy_texture_destruction_callback -func proxy_texture_destruction_callback(userData unsafe.Pointer) { - defer recover() - destroyCB := (*func())(userData) - if destroyCB != nil { - destroyCB := *destroyCB - destroyCB() - } -} diff --git a/texture-registry.go b/texture-registry.go index 6972c482..2dd50025 100644 --- a/texture-registry.go +++ b/texture-registry.go @@ -135,10 +135,6 @@ func (t *TextureRegistry) handleExternalTexture(textureID int64, Target: gl.TEXTURE_2D, Name: registration.texture, Format: gl.RGBA8, - Collect: func() { - // runtime delete the pixelBuffer.Pix, (should be done by the GC) - // gl.DeleteTextures(1, ®istration.texture) // not this, this is for destroy not collect!! - }, } } From fd8bf32f38f67d5e0e1c43d4de1890f4bace7363 Mon Sep 17 00:00:00 2001 From: Drakirus Date: Wed, 24 Jul 2019 14:15:11 +0200 Subject: [PATCH 12/14] RFC --- embedder/embedder.go | 15 +++++++++++++++ texture-registry.go | 6 +++++- texture.go | 1 + 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/embedder/embedder.go b/embedder/embedder.go index b63c0bfd..c4e15fec 100644 --- a/embedder/embedder.go +++ b/embedder/embedder.go @@ -312,12 +312,22 @@ func (flu *FlutterEngine) SendPlatformMessageResponse( // RegisterExternalTexture registers an external texture with a unique identifier. func (flu *FlutterEngine) RegisterExternalTexture(textureID int64) Result { + flu.sync.Lock() + defer flu.sync.Unlock() + if flu.closed { + return ResultEngineNotRunning + } res := C.FlutterEngineRegisterExternalTexture(flu.Engine, C.int64_t(textureID)) return (Result)(res) } // UnregisterExternalTexture unregisters a previous texture registration. func (flu *FlutterEngine) UnregisterExternalTexture(textureID int64) Result { + flu.sync.Lock() + defer flu.sync.Unlock() + if flu.closed { + return ResultEngineNotRunning + } res := C.FlutterEngineUnregisterExternalTexture(flu.Engine, C.int64_t(textureID)) return (Result)(res) } @@ -325,6 +335,11 @@ func (flu *FlutterEngine) UnregisterExternalTexture(textureID int64) Result { // MarkExternalTextureFrameAvailable marks that a new texture frame is // available for a given texture identifier. func (flu *FlutterEngine) MarkExternalTextureFrameAvailable(textureID int64) Result { + flu.sync.Lock() + defer flu.sync.Unlock() + if flu.closed { + return ResultEngineNotRunning + } res := C.FlutterEngineMarkExternalTextureFrameAvailable(flu.Engine, C.int64_t(textureID)) return (Result)(res) } diff --git a/texture-registry.go b/texture-registry.go index 2dd50025..ea496254 100644 --- a/texture-registry.go +++ b/texture-registry.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" ) -// TextureRegistry is a registry entry for a managed SurfaceTexture. +// TextureRegistry is a registry entry for a managed Texture. type TextureRegistry struct { window *glfw.Window engine *embedder.FlutterEngine @@ -74,6 +74,10 @@ type PixelBuffer struct { func (t *TextureRegistry) setTextureHandler(textureID int64, handler ExternalTextureHanlderFunc) { t.channelsLock.Lock() if handler == nil { + texture := t.channels[textureID] + if texture != nil { + gl.DeleteTextures(1, &texture.texture) + } delete(t.channels, textureID) } else { t.channels[textureID] = &externalTextureHanlder{ diff --git a/texture.go b/texture.go index 008b5dd4..376d49aa 100644 --- a/texture.go +++ b/texture.go @@ -18,6 +18,7 @@ func (t *Texture) Register(handler ExternalTextureHanlderFunc) error { t.registry.setTextureHandler(t.ID, handler) result := t.registry.engine.RegisterExternalTexture(t.ID) if result != embedder.ResultSuccess { + t.registry.setTextureHandler(t.ID, nil) return errors.New("'go-flutter' couldn't register texture with id: " + fmt.Sprint(t.ID)) } return nil From 801b7af4cef6181b00ca4ca200922f771214cf09 Mon Sep 17 00:00:00 2001 From: Pierre Champion Date: Wed, 31 Jul 2019 10:32:45 +0200 Subject: [PATCH 13/14] Update texture-registry.go --- texture-registry.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/texture-registry.go b/texture-registry.go index ea496254..d0027cd9 100644 --- a/texture-registry.go +++ b/texture-registry.go @@ -121,9 +121,7 @@ func (t *TextureRegistry) handleExternalTexture(textureID int64, } gl.BindTexture(gl.TEXTURE_2D, registration.texture) - // TODO(Drakirus) handle multiple format of the pixel data (RGB, Gray) and - // Texture format (GL_RGBA8). - // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml + // It seems that current flutter/engine can only support RGBA texture. gl.TexImage2D( gl.TEXTURE_2D, 0, From 2defa22c50c094be63f965cc47105e2ba348534d Mon Sep 17 00:00:00 2001 From: Pierre Champion Date: Wed, 31 Jul 2019 12:00:40 +0200 Subject: [PATCH 14/14] Update texture.go --- texture.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/texture.go b/texture.go index 376d49aa..333e7e8e 100644 --- a/texture.go +++ b/texture.go @@ -33,12 +33,12 @@ func (t *Texture) FrameAvailable() error { return nil } -// UnRegister mark a texture buffer is ready to be draw in the flutter scene +// UnRegister unregisters a textureID with his associated handler func (t *Texture) UnRegister() error { - t.registry.setTextureHandler(t.ID, nil) result := t.registry.engine.UnregisterExternalTexture(t.ID) if result != embedder.ResultSuccess { return errors.New("'go-flutter' couldn't unregisters texture with id: " + fmt.Sprint(t.ID)) } + t.registry.setTextureHandler(t.ID, nil) return nil }