Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Custom layer fixes #11239

Merged
merged 5 commits into from
Feb 23, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 143 additions & 29 deletions platform/android/src/example_custom_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,114 @@
#include <GLES2/gl2.h>

#include <mbgl/util/logging.hpp>

#include <mbgl/util/string.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably remove the logging.hpp and string.hpp dependencies. I don't think we should encourage custom layer implementations to depend on anything other than custom_layer.hpp.

#include <mbgl/style/layers/custom_layer.hpp>
#include <vector>

// DEBUGGING

const char* stringFromError(GLenum err) {
switch (err) {
case GL_INVALID_ENUM:
return "GL_INVALID_ENUM";

case GL_INVALID_VALUE:
return "GL_INVALID_VALUE";

case GL_INVALID_OPERATION:
return "GL_INVALID_OPERATION";

case GL_INVALID_FRAMEBUFFER_OPERATION:
return "GL_INVALID_FRAMEBUFFER_OPERATION";

case GL_OUT_OF_MEMORY:
return "GL_OUT_OF_MEMORY";

#ifdef GL_TABLE_TOO_LARGE
case GL_TABLE_TOO_LARGE:
return "GL_TABLE_TOO_LARGE";
#endif

#ifdef GL_STACK_OVERFLOW
case GL_STACK_OVERFLOW:
return "GL_STACK_OVERFLOW";
#endif

#ifdef GL_STACK_UNDERFLOW
case GL_STACK_UNDERFLOW:
return "GL_STACK_UNDERFLOW";
#endif

#ifdef GL_CONTEXT_LOST
case GL_CONTEXT_LOST:
return "GL_CONTEXT_LOST";
#endif

default:
return "GL_UNKNOWN";
}
}

struct Error : std::runtime_error {
using std::runtime_error::runtime_error;
};

void checkError(const char *cmd, const char *file, int line) {

GLenum err = GL_NO_ERROR;
if ((err = glGetError()) != GL_NO_ERROR) {
std::string message = std::string(cmd) + ": Error " + stringFromError(err);

// Check for further errors
while ((err = glGetError()) != GL_NO_ERROR) {
message += ", ";
message += stringFromError(err);
}

mbgl::Log::Error(mbgl::Event::General, message + " at " + file + ":" + mbgl::util::toString(line));
throw Error(message + " at " + file + ":" + mbgl::util::toString(line));
}
}

#ifndef NDEBUG
#define GL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_C_E { ~__MBGL_C_E() noexcept(false) { checkError(#cmd, __FILE__, __LINE__); } } __MBGL_C_E; return cmd; }())
#else
#define GL_CHECK_ERROR(cmd) (cmd)
#endif

void checkLinkStatus(GLuint program) {
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE) {
GLint maxLength = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
GLchar infoLog[maxLength];
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
mbgl::Log::Info(mbgl::Event::General, &infoLog[0]);
throw Error(infoLog);
}

}

void checkCompileStatus(GLuint shader) {
GLint isCompiled = 0;
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE) {
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);

// The maxLength includes the NULL character
GLchar errorLog[maxLength];
glGetShaderInfoLog(shader, maxLength, &maxLength, &errorLog[0]);
mbgl::Log::Error(mbgl::Event::General, &errorLog[0]);
throw Error(errorLog);
}
}

// /DEBUGGING

static const GLchar * vertexShaderSource = "attribute vec2 a_pos; void main() { gl_Position = vec4(a_pos, 0, 1); }";
static const GLchar * fragmentShaderSource = "uniform vec4 fill_color; void main() { gl_FragColor = fill_color; }";
static const GLchar * fragmentShaderSource = "uniform highp vec4 fill_color; void main() { gl_FragColor = fill_color; }";

class ExampleCustomLayer {
public:
Expand All @@ -24,37 +127,48 @@ class ExampleCustomLayer {

void initialize() {
mbgl::Log::Info(mbgl::Event::General, "Initialize");
program = glCreateProgram();
vertexShader = glCreateShader(GL_VERTEX_SHADER);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr);
glCompileShader(vertexShader);
glAttachShader(program, vertexShader);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
glCompileShader(fragmentShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
a_pos = glGetAttribLocation(program, "a_pos");
fill_color = glGetUniformLocation(program, "fill_color");

GLfloat background[] = { -1,-1, 1,-1, -1,1, 1,1 };
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW);

// Debug info
int maxAttrib;
GL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttrib));
mbgl::Log::Info(mbgl::Event::General, "Max vertex attributes: %i", maxAttrib);

program = GL_CHECK_ERROR(glCreateProgram());
vertexShader = GL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER));
fragmentShader = GL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER));

GL_CHECK_ERROR(glShaderSource(vertexShader, 1, &vertexShaderSource, nullptr));
GL_CHECK_ERROR(glCompileShader(vertexShader));
checkCompileStatus(vertexShader);
GL_CHECK_ERROR(glAttachShader(program, vertexShader));
GL_CHECK_ERROR(glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr));
GL_CHECK_ERROR(glCompileShader(fragmentShader));
checkCompileStatus(fragmentShader);
GL_CHECK_ERROR(glAttachShader(program, fragmentShader));
GL_CHECK_ERROR(glLinkProgram(program));
checkLinkStatus(program);

a_pos = GL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
fill_color = GL_CHECK_ERROR(glGetUniformLocation(program, "fill_color"));

GLfloat background[] = { -1, -1, 1, -1, -1, 1, 1, 1 };
GL_CHECK_ERROR(glGenBuffers(1, &buffer));
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), background, GL_STATIC_DRAW));
}

void render() {
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);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

GL_CHECK_ERROR(glUseProgram(program));
GL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, buffer));
GL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
GL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_FLOAT, GL_FALSE, 0, NULL));
GL_CHECK_ERROR(glDisable(GL_STENCIL_TEST));
GL_CHECK_ERROR(glDisable(GL_DEPTH_TEST));
GL_CHECK_ERROR(glUniform4fv(fill_color, 1, color));
GL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 4));

}

GLuint program = 0;
Expand Down
11 changes: 9 additions & 2 deletions src/mbgl/gl/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,17 @@ UniqueTexture Context::createTexture() {

bool Context::supportsVertexArrays() const {
static bool blacklisted = []() {
// Blacklist Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data
const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));

Log::Info(Event::General, "GPU Identifier: %s", renderer.c_str());

// Blacklist Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data
// Blacklist ARM Mali-T720 (in some MT8163 chipsets) as it crashes on glBindVertexArray
return renderer.find("Adreno (TM) 2") != std::string::npos
|| renderer.find("Adreno (TM) 3") != std::string::npos;
|| renderer.find("Adreno (TM) 3") != std::string::npos
|| renderer.find("Mali-T720") != std::string::npos
|| renderer.find("Sapphire 650") != std::string::npos;

}();

return !blacklisted &&
Expand Down
7 changes: 4 additions & 3 deletions src/mbgl/renderer/layers/render_custom_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/style/layers/custom_layer_impl.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/gl/gl.hpp>

namespace mbgl {

Expand Down Expand Up @@ -46,11 +47,11 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*)
if (context != impl().context || !initialized) {
//If the context changed, deinitialize the previous one before initializing the new one.
if (context && !contextDestroyed && impl().deinitializeFn) {
impl().deinitializeFn(context);
MBGL_CHECK_ERROR(impl().deinitializeFn(context));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to break on Qt due to the special use of MBGL_CHECK_ERROR there? (#11106)

cc @kkaefer @tmpsantos

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, Qt is not using MBGL_CHECK_ERROR as described by #11106

}
context = impl().context;
assert(impl().initializeFn);
impl().initializeFn(impl().context);
MBGL_CHECK_ERROR(impl().initializeFn(impl().context));
initialized = true;
}

Expand All @@ -75,7 +76,7 @@ void RenderCustomLayer::render(PaintParameters& paintParameters, RenderSource*)
parameters.fieldOfView = state.getFieldOfView();

assert(impl().renderFn);
impl().renderFn(context, parameters);
MBGL_CHECK_ERROR(impl().renderFn(context, parameters));

// Reset the view back to our original one, just in case the CustomLayer changed
// the viewport or Framebuffer.
Expand Down