-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Use a host interface for CustomLayer instead of function pointers #11553
Changes from 5 commits
30ecd0c
1137378
efb241f
6bca0f0
46383bb
c3cafe7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,18 +2,11 @@ | |
|
||
#include <mbgl/style/layer.hpp> | ||
|
||
#include <functional> | ||
|
||
namespace mbgl { | ||
namespace style { | ||
|
||
/** | ||
* Initialize any GL state needed by the custom layer. This method is called once, from the | ||
* 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. | ||
*/ | ||
using CustomLayerInitializeFunction = void (*)(void* context); | ||
|
||
/** | ||
* Parameters that define the current camera position for a CustomLayerRenderFunction. | ||
*/ | ||
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. Nit: indentation. |
||
/** | ||
* Initialize any GL state needed by the custom layer. This method is called once, from the | ||
* 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 commentThe reason will be displayed to describe this comment to others. Learn more. "in the UninitializeFunction" → "in |
||
*/ | ||
virtual void initialize() = 0; | ||
|
||
/** | ||
* Render the layer. This method is called once per frame. The implementation should not make | ||
* any assumptions about the GL state (other than that the correct context is active). It may | ||
|
@@ -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 commentThe reason will be displayed to describe this comment to others. Learn more. Update docs. |
||
* `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 commentThe reason will be displayed to describe this comment to others. Learn more. Update docs. |
||
*/ | ||
using CustomLayerDeinitializeFunction = void (*)(void* context); | ||
virtual void deinitialize() = 0; | ||
}; | ||
|
||
class CustomLayer : public Layer { | ||
public: | ||
CustomLayer(const std::string& id, | ||
CustomLayerInitializeFunction, | ||
CustomLayerRenderFunction, | ||
CustomLayerContextLostFunction, | ||
CustomLayerDeinitializeFunction, | ||
void* context); | ||
|
||
CustomLayer(const std::string& id, | ||
CustomLayerInitializeFunction, | ||
CustomLayerRenderFunction, | ||
CustomLayerDeinitializeFunction, | ||
void* context); | ||
std::unique_ptr<CustomLayerHost> host); | ||
|
||
~CustomLayer() final; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,7 +112,7 @@ void checkCompileStatus(GLuint shader) { | |
static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }"; | ||
static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }"; | ||
|
||
class ExampleCustomLayer { | ||
class ExampleCustomLayer: mbgl::style::CustomLayerHost { | ||
public: | ||
~ExampleCustomLayer() { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "~ExampleCustomLayer"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code below needs to move to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For Android, it looks like |
||
|
@@ -158,8 +158,15 @@ class ExampleCustomLayer { | |
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW)); | ||
} | ||
|
||
void render() { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "Render"); | ||
void render(const mbgl::style::CustomLayerRenderParameters&) { | ||
mbgl::Log::Info(mbgl::Event::General, "Render"); | ||
glUseProgram(program); | ||
glBindBuffer(GL_ARRAY_BUFFER, buffer); | ||
glEnableVertexAttribArray(a_pos); | ||
glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL); | ||
glDisable(GL_STENCIL_TEST); | ||
glDisable(GL_DEPTH_TEST); | ||
glUniform4fv(fill_color, 1, color); | ||
|
||
GL_CHECK_ERROR(glUseProgram(program)); | ||
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer)); | ||
|
@@ -172,6 +179,13 @@ class ExampleCustomLayer { | |
|
||
} | ||
|
||
void contextLost() { | ||
} | ||
|
||
void deinitialize() { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit additional return vs contextLost() |
||
} | ||
|
||
GLuint program = 0; | ||
GLuint vertexShader = 0; | ||
GLuint fragmentShader = 0; | ||
|
@@ -186,7 +200,8 @@ GLfloat ExampleCustomLayer::color[] = { 0.0f, 1.0f, 0.0f, 1.0f }; | |
|
||
jlong JNICALL nativeCreateContext(JNIEnv*, jobject) { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeCreateContext"); | ||
return reinterpret_cast<jlong>(new ExampleCustomLayer()); | ||
auto exampleCustomLayer = std::make_unique<ExampleCustomLayer>(); | ||
return reinterpret_cast<jlong>(exampleCustomLayer.release()); | ||
} | ||
|
||
void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat blue, jfloat alpha) { | ||
|
@@ -197,25 +212,6 @@ void JNICALL nativeSetColor(JNIEnv*, jobject, jfloat red, jfloat green, jfloat b | |
ExampleCustomLayer::color[3] = alpha; | ||
} | ||
|
||
void nativeInitialize(void *context) { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeInitialize"); | ||
reinterpret_cast<ExampleCustomLayer*>(context)->initialize(); | ||
} | ||
|
||
void nativeRender(void *context, const mbgl::style::CustomLayerRenderParameters& /*parameters*/) { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeRender"); | ||
reinterpret_cast<ExampleCustomLayer*>(context)->render(); | ||
} | ||
|
||
void nativeContextLost(void */*context*/) { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeContextLost"); | ||
} | ||
|
||
void nativeDeinitialize(void *context) { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "nativeDeinitialize"); | ||
delete reinterpret_cast<ExampleCustomLayer*>(context); | ||
} | ||
|
||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { | ||
__android_log_write(ANDROID_LOG_INFO, LOG_TAG, "OnLoad"); | ||
|
||
|
@@ -234,22 +230,6 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { | |
return JNI_ERR; | ||
} | ||
|
||
env->SetStaticLongField(customLayerClass, | ||
env->GetStaticFieldID(customLayerClass, "InitializeFunction", "J"), | ||
reinterpret_cast<jlong>(nativeInitialize)); | ||
|
||
env->SetStaticLongField(customLayerClass, | ||
env->GetStaticFieldID(customLayerClass, "RenderFunction", "J"), | ||
reinterpret_cast<jlong>(nativeRender)); | ||
|
||
env->SetStaticLongField(customLayerClass, | ||
env->GetStaticFieldID(customLayerClass, "ContextLostFunction", "J"), | ||
reinterpret_cast<jlong>(nativeContextLost)); | ||
|
||
env->SetStaticLongField(customLayerClass, | ||
env->GetStaticFieldID(customLayerClass, "DeinitializeFunction", "J"), | ||
reinterpret_cast<jlong>(nativeDeinitialize)); | ||
|
||
return JNI_VERSION_1_6; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
#import "MGLOpenGLStyleLayer.h" | ||
#import "MGLOpenGLStyleLayer.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: whitespace. |
||
|
||
#import "MGLMapView_Private.h" | ||
#import "MGLStyle_Private.h" | ||
|
@@ -7,49 +7,50 @@ | |
#include <mbgl/style/layers/custom_layer.hpp> | ||
#include <mbgl/math/wrap.hpp> | ||
|
||
/** | ||
Runs the preparation handler block contained in the given context, which is | ||
implicitly an instance of `MGLOpenGLStyleLayer`. | ||
class MGLOpenGLLayerHost : public mbgl::style::CustomLayerHost { | ||
public: | ||
MGLOpenGLLayerHost(MGLOpenGLStyleLayer *styleLayer) { | ||
layerRef = styleLayer; | ||
layer = nil; | ||
} | ||
~MGLOpenGLLayerHost () { | ||
layer = nil; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not necessary to nil member pointers in a destructor. |
||
} | ||
|
||
@param context An `MGLOpenGLStyleLayer` instance that was provided as context | ||
when creating an OpenGL style layer. | ||
*/ | ||
void MGLPrepareCustomStyleLayer(void *context) { | ||
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; | ||
[layer didMoveToMapView:layer.style.mapView]; | ||
} | ||
void initialize() { | ||
if (layerRef == nil) return; | ||
else if (layer == nil) layer = layerRef; | ||
|
||
/** | ||
Runs the drawing handler block contained in the given context, which is | ||
implicitly an instance of `MGLOpenGLStyleLayer`. | ||
[layer didMoveToMapView:layer.style.mapView]; | ||
} | ||
|
||
@param context An `MGLOpenGLStyleLayer` instance that was provided as context | ||
when creating an OpenGL style layer. | ||
*/ | ||
void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRenderParameters ¶ms) { | ||
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context; | ||
MGLStyleLayerDrawingContext drawingContext = { | ||
.size = CGSizeMake(params.width, params.height), | ||
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude), | ||
.zoomLevel = params.zoom, | ||
.direction = mbgl::util::wrap(params.bearing, 0., 360.), | ||
.pitch = static_cast<CGFloat>(params.pitch), | ||
.fieldOfView = static_cast<CGFloat>(params.fieldOfView), | ||
}; | ||
[layer drawInMapView:layer.style.mapView withContext:drawingContext]; | ||
} | ||
void render(const mbgl::style::CustomLayerRenderParameters ¶ms) { | ||
assert(layerRef); | ||
|
||
MGLStyleLayerDrawingContext drawingContext = { | ||
.size = CGSizeMake(params.width, params.height), | ||
.centerCoordinate = CLLocationCoordinate2DMake(params.latitude, params.longitude), | ||
.zoomLevel = params.zoom, | ||
.direction = mbgl::util::wrap(params.bearing, 0., 360.), | ||
.pitch = static_cast<CGFloat>(params.pitch), | ||
.fieldOfView = static_cast<CGFloat>(params.fieldOfView), | ||
}; | ||
[layer drawInMapView:layer.style.mapView withContext:drawingContext]; | ||
} | ||
|
||
/** | ||
Runs the completion handler block contained in the given context, which is | ||
implicitly an instance of `MGLOpenGLStyleLayer`. | ||
void contextLost() {} | ||
|
||
@param context An `MGLOpenGLStyleLayer` instance that was provided as context | ||
when creating an OpenGL style layer. | ||
*/ | ||
void MGLFinishCustomStyleLayer(void *context) { | ||
MGLOpenGLStyleLayer *layer = (__bridge_transfer MGLOpenGLStyleLayer *)context; | ||
[layer willMoveFromMapView:layer.style.mapView]; | ||
} | ||
void deinitialize() { | ||
if (layer == nil) return; | ||
|
||
[layer willMoveFromMapView:layer.style.mapView]; | ||
layerRef = layer; | ||
layer = nil; | ||
} | ||
private: | ||
__weak MGLOpenGLStyleLayer * layerRef; | ||
MGLOpenGLStyleLayer * layer = nil; | ||
}; | ||
|
||
/** | ||
An `MGLOpenGLStyleLayer` is a style layer that is rendered by OpenGL code that | ||
|
@@ -98,10 +99,7 @@ @implementation MGLOpenGLStyleLayer | |
*/ | ||
- (instancetype)initWithIdentifier:(NSString *)identifier { | ||
auto layer = std::make_unique<mbgl::style::CustomLayer>(identifier.UTF8String, | ||
MGLPrepareCustomStyleLayer, | ||
MGLDrawCustomStyleLayer, | ||
MGLFinishCustomStyleLayer, | ||
(__bridge_retained void *)self); | ||
std::make_unique<MGLOpenGLLayerHost>(self)); | ||
return self = [super initWithPendingLayer:std::move(layer)]; | ||
} | ||
|
||
|
@@ -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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Clears the entry from the previous style when calling |
||
_style = style; | ||
_style.openGLLayers[self.identifier] = self; | ||
} | ||
|
||
- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer { | ||
|
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?