-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Use a host interface for CustomLayer instead of function pointers #11553
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this idea, but doesn't the shared_ptr< CustomLayerHost>
need to be used throughout the whole stack -- CustomLayer
, CustomLayer::Impl
-- not just RenderCustomLayer
?
The |
Constructing a |
f198d30
to
b0f68d3
Compare
Unfortunately a brief spin of the run loop is required for the layer reuse test. I've tried to tune this down for my machine; YMMV
… pointers Co-authored-by: Julian Rex <julian.rex@mapbox.com>
…style layer, and upgrade to a strong layer when initialized by the renderer Co-authored-by: Julian Rex <julian.rex@mapbox.com>
b0f68d3
to
46383bb
Compare
} | ||
|
||
void deinitialize() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit additional return vs contextLost()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested on Android device and code is looking 👍
@@ -2,18 +2,11 @@ | |||
|
|||
#include <mbgl/style/layer.hpp> | |||
|
|||
#include <functional> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary?
@@ -28,6 +21,18 @@ struct CustomLayerRenderParameters { | |||
double fieldOfView; | |||
}; | |||
|
|||
class CustomLayerHost { | |||
public: | |||
virtual ~CustomLayerHost() = default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: indentation.
* main thread, at a point when the GL context is active but before rendering for the first | ||
* time. | ||
* | ||
* Resources that are acquired in this method must be released in the UninitializeFunction. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"in the UninitializeFunction" → "in deinitialize
"
@@ -36,38 +41,29 @@ struct CustomLayerRenderParameters { | |||
* Make sure that you are drawing your fragments with a z value of 1 to take advantage of the | |||
* opaque fragment culling in case there are opaque layers above your custom layer. | |||
*/ | |||
using CustomLayerRenderFunction = void (*)(void* context, const CustomLayerRenderParameters&); | |||
virtual void render(const CustomLayerRenderParameters&) = 0; | |||
|
|||
/** | |||
* Called when the system has destroyed the underlying GL context. The | |||
* `CustomLayerDeinitializeFunction` will not be called in this case, however |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update docs.
|
||
/** | ||
* Called when the system has destroyed the underlying GL context. The | ||
* `CustomLayerDeinitializeFunction` will not be called in this case, however | ||
* `CustomLayerInitializeFunction` will be called instead to prepare for a new render. | ||
* | ||
*/ | ||
using CustomLayerContextLostFunction = void (*)(void* context); | ||
virtual void contextLost() = 0; | ||
|
||
/** | ||
* Destroy any GL state needed by the custom layer, and deallocate context, if necessary. This | ||
* method is called once, from the main thread, at a point when the GL context is active. | ||
* | ||
* Note that it may be called even when the InitializeFunction has not been called. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update docs.
@@ -116,7 +114,9 @@ - (void)setStyle:(MGLStyle *)style { | |||
[NSException raise:@"MGLLayerReuseException" | |||
format:@"%@ cannot be added to more than one MGLStyle at a time.", self]; | |||
} | |||
_style.openGLLayers[self.identifier] = nil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clears the entry from the previous style when calling [styleLayer removeFromStyle:]
. I had removed this in #10765, but I think it needs to be returned. In the Obj-C SDK, the style and the CustomLayerHost
-implementation share ownership of the peer layer.
@@ -12,17 +12,16 @@ namespace mbgl { | |||
using namespace style; | |||
|
|||
RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl) | |||
: RenderLayer(LayerType::Custom, _impl) { | |||
: RenderLayer(LayerType::Custom, _impl), host(_impl->host) { | |||
host->initialize(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason you're changing the timing of when the custom layer is initialized? Are you sure the GL context is guaranteed to be active at this point? If so, add assert(BackendScope::exists());
like in the destructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved this to the constructor in an attempt to initialize
and retain the Obj-C peer layer sooner. This was to address a race condition where a custom layer is added to a style, but before the next frame renders, the style is swapped. In this case, the peer layer was released too soon.
This fix didn't address that issue, but I decided to keep it in, since the render layers are created in Renderer::Impl
and rendered in the same render pass. Adding the assert
for protection.
@@ -38,7 +26,6 @@ std::unique_ptr<Layer> CustomLayer::cloneRef(const std::string&) const { | |||
} | |||
|
|||
// Visibility | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: revert whitespace change.
test/api/custom_layer.test.cpp
Outdated
@@ -34,7 +34,7 @@ void main() { | |||
// layer implementation because it is intended to reflect how someone using custom layers | |||
// might actually write their own implementation. | |||
|
|||
class TestLayer { | |||
class TestLayer : public mbgl::style::CustomLayerHost { | |||
public: | |||
~TestLayer() { | |||
if (program) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to move to deinitialize
.
} | ||
if (contextDestroyed) { | ||
host->contextLost(); | ||
} else if (!contextDestroyed) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditional is redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested the changes on macOS. Besides adding the blurb to the changelogs (iOS, macOS & Android) and some nits LGTM.
adac588
to
b2e7d7e
Compare
@@ -172,6 +170,23 @@ class ExampleCustomLayer { | |||
|
|||
} | |||
|
|||
void contextLost() { | |||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "ContextLost"); | |||
if (program) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the context lost case, the system has already destroyed all the GL resources, and glDeleteBuffers
etc should not be called (IIRC, they'll actually produce errors). So all this should do is clear program
.
b2e7d7e
to
c08c88c
Compare
c08c88c
to
c3cafe7
Compare
Fixes #11143.
Fixes #10771.
CustomLayer
s are a special class of style layer where the core API delegates rendering of the layer to external code.With the change to asynchronous rendering, the
RenderCustomLayer
may call out to the external code to initialize, render, or clean-up outside of theCustomLayer
's lifecycle. For example, a custom layer added to the current map style, followed by a different style being set on the map.In addition to #11143, a number of other issues related to custom layers have been opened/addressed recently: #10771, #10755, #10765, #11343.
The existing API using a
void *
context object and function pointers, doesn't provide any lifecycle information. The context object needs to exist for the lifetime of theCustomLayer
(CustomLayer::Impl
to be more specific), and theRenderCustomLayer
. This PR proposes using ashared_ptr<>
to ensure that the context object has the required lifetime.Since a
shared_ptr<>
cannot be used withvoid *
, a host interfaceCustomLayerHost
with the former function pointers converted to equivalent events.On iOS/macOS, the SDK uses the peer style layer
MGLOpenGLStyleLayer
as the context object, creating a tenuous chain of ownership. The implementation ofCustomLayerHost
addresses the retain/release issue described in this comment.RenderCustomLayer
callsCustomLayerHost::initialize()
in its constructor to ensure that the peer style layer is retained, even if the style (andCustomLayer::Impl
) are changed prematurely.TODO
cc @julianrex @lilykaiser @jfirebaugh @akitchen @1ec5