1 #include <mbgl/gl/context.hpp>
2 #include <mbgl/gl/gl.hpp>
3 #include <mbgl/gl/debugging_extension.hpp>
4 #include <mbgl/gl/vertex_array_extension.hpp>
5 #include <mbgl/gl/program_binary_extension.hpp>
6 #include <mbgl/util/traits.hpp>
7 #include <mbgl/util/std.hpp>
8 #include <mbgl/util/logging.hpp>
9 
10 #include <cstring>
11 
12 namespace mbgl {
13 namespace gl {
14 
15 static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch");
16 static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch");
17 
18 static_assert(underlying_type(DataType::Byte) == GL_BYTE, "OpenGL type mismatch");
19 static_assert(underlying_type(DataType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch");
20 static_assert(underlying_type(DataType::Short) == GL_SHORT, "OpenGL type mismatch");
21 static_assert(underlying_type(DataType::UnsignedShort) == GL_UNSIGNED_SHORT, "OpenGL type mismatch");
22 static_assert(underlying_type(DataType::Integer) == GL_INT, "OpenGL type mismatch");
23 static_assert(underlying_type(DataType::UnsignedInteger) == GL_UNSIGNED_INT, "OpenGL type mismatch");
24 static_assert(underlying_type(DataType::Float) == GL_FLOAT, "OpenGL type mismatch");
25 
26 #if not MBGL_USE_GLES2
27 static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8, "OpenGL type mismatch");
28 #else
29 static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8_OES, "OpenGL type mismatch");
30 #endif // MBGL_USE_GLES2
31 #if not MBGL_USE_GLES2
32 static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8, "OpenGL type mismatch");
33 #else
34 static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8_OES, "OpenGL type mismatch");
35 #endif // MBGL_USE_GLES2
36 #if not MBGL_USE_GLES2
37 static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT, "OpenGL type mismatch");
38 #else
39 static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT16, "OpenGL type mismatch");
40 #endif // MBGL_USE_GLES2
41 
42 
43 static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch");
44 static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch");
45 static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch");
46 static_assert(underlying_type(PrimitiveType::LineStrip) == GL_LINE_STRIP, "OpenGL type mismatch");
47 static_assert(underlying_type(PrimitiveType::Triangles) == GL_TRIANGLES, "OpenGL type mismatch");
48 static_assert(underlying_type(PrimitiveType::TriangleStrip) == GL_TRIANGLE_STRIP, "OpenGL type mismatch");
49 static_assert(underlying_type(PrimitiveType::TriangleFan) == GL_TRIANGLE_FAN, "OpenGL type mismatch");
50 
51 static_assert(std::is_same<ProgramID, GLuint>::value, "OpenGL type mismatch");
52 static_assert(std::is_same<ShaderID, GLuint>::value, "OpenGL type mismatch");
53 static_assert(std::is_same<BufferID, GLuint>::value, "OpenGL type mismatch");
54 static_assert(std::is_same<TextureID, GLuint>::value, "OpenGL type mismatch");
55 static_assert(std::is_same<VertexArrayID, GLuint>::value, "OpenGL type mismatch");
56 static_assert(std::is_same<FramebufferID, GLuint>::value, "OpenGL type mismatch");
57 static_assert(std::is_same<RenderbufferID, GLuint>::value, "OpenGL type mismatch");
58 
59 static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value, "OpenGL type mismatch");
60 static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch");
61 static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch");
62 
63 static_assert(std::is_same<std::underlying_type_t<TextureType>, GLenum>::value, "OpenGL type mismatch");
64 static_assert(underlying_type(TextureType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch");
65 
66 #if MBGL_USE_GLES2 && GL_HALF_FLOAT_OES
67 static_assert(underlying_type(TextureType::HalfFloat) == GL_HALF_FLOAT_OES, "OpenGL type mismatch");
68 #endif
69 #if !MBGL_USE_GLES2 && GL_HALF_FLOAT_ARB
70 static_assert(underlying_type(TextureType::HalfFloat) == GL_HALF_FLOAT_ARB, "OpenGL type mismatch");
71 #endif
72 
73 static_assert(underlying_type(UniformDataType::Float) == GL_FLOAT, "OpenGL type mismatch");
74 static_assert(underlying_type(UniformDataType::FloatVec2) == GL_FLOAT_VEC2, "OpenGL type mismatch");
75 static_assert(underlying_type(UniformDataType::FloatVec3) == GL_FLOAT_VEC3, "OpenGL type mismatch");
76 static_assert(underlying_type(UniformDataType::FloatVec4) == GL_FLOAT_VEC4, "OpenGL type mismatch");
77 static_assert(underlying_type(UniformDataType::Int) == GL_INT, "OpenGL type mismatch");
78 static_assert(underlying_type(UniformDataType::IntVec2) == GL_INT_VEC2, "OpenGL type mismatch");
79 static_assert(underlying_type(UniformDataType::IntVec3) == GL_INT_VEC3, "OpenGL type mismatch");
80 static_assert(underlying_type(UniformDataType::IntVec4) == GL_INT_VEC4, "OpenGL type mismatch");
81 static_assert(underlying_type(UniformDataType::Bool) == GL_BOOL, "OpenGL type mismatch");
82 static_assert(underlying_type(UniformDataType::BoolVec2) == GL_BOOL_VEC2, "OpenGL type mismatch");
83 static_assert(underlying_type(UniformDataType::BoolVec3) == GL_BOOL_VEC3, "OpenGL type mismatch");
84 static_assert(underlying_type(UniformDataType::BoolVec4) == GL_BOOL_VEC4, "OpenGL type mismatch");
85 static_assert(underlying_type(UniformDataType::FloatMat2) == GL_FLOAT_MAT2, "OpenGL type mismatch");
86 static_assert(underlying_type(UniformDataType::FloatMat3) == GL_FLOAT_MAT3, "OpenGL type mismatch");
87 static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "OpenGL type mismatch");
88 static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch");
89 static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch");
90 
91 static_assert(underlying_type(BufferUsage::StreamDraw) == GL_STREAM_DRAW, "OpenGL type mismatch");
92 static_assert(underlying_type(BufferUsage::StaticDraw) == GL_STATIC_DRAW, "OpenGL type mismatch");
93 static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "OpenGL type mismatch");
94 
95 static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch");
96 
Context()97 Context::Context()
98     : maximumVertexBindingCount([] {
99           GLint value;
100           MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value));
101           return value;
102       }()) {
103 }
104 
~Context()105 Context::~Context() {
106     if (cleanupOnDestruction) {
107         reset();
108     }
109 }
110 
initializeExtensions(const std::function<gl::ProcAddress (const char *)> & getProcAddress)111 void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) {
112     if (const auto* extensions =
113             reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) {
114 
115         auto fn = [&](
116             std::initializer_list<std::pair<const char*, const char*>> probes) -> ProcAddress {
117             for (auto probe : probes) {
118                 if (strstr(extensions, probe.first) != nullptr) {
119                     if (ProcAddress ptr = getProcAddress(probe.second)) {
120                         return ptr;
121                     }
122                 }
123             }
124             return nullptr;
125         };
126 
127         debugging = std::make_unique<extension::Debugging>(fn);
128         if (!disableVAOExtension) {
129             vertexArray = std::make_unique<extension::VertexArray>(fn);
130         }
131 #if MBGL_HAS_BINARY_PROGRAMS
132         programBinary = std::make_unique<extension::ProgramBinary>(fn);
133 #endif
134 
135 #if MBGL_USE_GLES2
136         constexpr const char* halfFloatExtensionName = "OES_texture_half_float";
137         constexpr const char* halfFloatColorBufferExtensionName = "EXT_color_buffer_half_float";
138 #else
139         constexpr const char* halfFloatExtensionName = "ARB_half_float_pixel";
140         constexpr const char* halfFloatColorBufferExtensionName = "ARB_color_buffer_float";
141 #endif
142         if (strstr(extensions, halfFloatExtensionName) != nullptr &&
143             strstr(extensions, halfFloatColorBufferExtensionName) != nullptr) {
144 
145             supportsHalfFloatTextures = true;
146         }
147 
148         if (!supportsVertexArrays()) {
149             Log::Warning(Event::OpenGL, "Not using Vertex Array Objects");
150         }
151     }
152 }
153 
enableDebugging()154 void Context::enableDebugging() {
155     if (!debugging || !debugging->debugMessageControl || !debugging->debugMessageCallback) {
156         return;
157     }
158 
159     // This will enable all messages including performance hints
160     // MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE));
161 
162     // This will only enable high and medium severity messages
163     MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE));
164     MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE));
165     MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE));
166 
167     MBGL_CHECK_ERROR(debugging->debugMessageCallback(extension::Debugging::DebugCallback, nullptr));
168 }
169 
createShader(ShaderType type,const std::string & source)170 UniqueShader Context::createShader(ShaderType type, const std::string& source) {
171     UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } };
172 
173     const GLchar* sources = source.data();
174     const auto lengths = static_cast<GLsizei>(source.length());
175     MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths));
176     MBGL_CHECK_ERROR(glCompileShader(result));
177 
178     GLint status = 0;
179     MBGL_CHECK_ERROR(glGetShaderiv(result, GL_COMPILE_STATUS, &status));
180     if (status != 0) {
181         return result;
182     }
183 
184     GLint logLength;
185     MBGL_CHECK_ERROR(glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength));
186     if (logLength > 0) {
187         const auto log = std::make_unique<GLchar[]>(logLength);
188         MBGL_CHECK_ERROR(glGetShaderInfoLog(result, logLength, &logLength, log.get()));
189         Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
190     }
191 
192     throw std::runtime_error("shader failed to compile");
193 }
194 
createProgram(ShaderID vertexShader,ShaderID fragmentShader)195 UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentShader) {
196     UniqueProgram result { MBGL_CHECK_ERROR(glCreateProgram()), { this } };
197 
198     MBGL_CHECK_ERROR(glAttachShader(result, vertexShader));
199     MBGL_CHECK_ERROR(glAttachShader(result, fragmentShader));
200 
201     return result;
202 }
203 
204 #if MBGL_HAS_BINARY_PROGRAMS
createProgram(BinaryProgramFormat binaryFormat,const std::string & binaryProgram)205 UniqueProgram Context::createProgram(BinaryProgramFormat binaryFormat,
206                                      const std::string& binaryProgram) {
207     assert(supportsProgramBinaries());
208     UniqueProgram result{ MBGL_CHECK_ERROR(glCreateProgram()), { this } };
209     MBGL_CHECK_ERROR(programBinary->programBinary(result, static_cast<GLenum>(binaryFormat),
210                                                   binaryProgram.data(),
211                                                   static_cast<GLint>(binaryProgram.size())));
212     verifyProgramLinkage(result);
213     return result;
214 }
215 #else
createProgram(BinaryProgramFormat,const std::string &)216 UniqueProgram Context::createProgram(BinaryProgramFormat, const std::string&) {
217     throw std::runtime_error("binary programs are not supported");
218 }
219 #endif
220 
linkProgram(ProgramID program_)221 void Context::linkProgram(ProgramID program_) {
222     MBGL_CHECK_ERROR(glLinkProgram(program_));
223     verifyProgramLinkage(program_);
224 }
225 
verifyProgramLinkage(ProgramID program_)226 void Context::verifyProgramLinkage(ProgramID program_) {
227     GLint status;
228     MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status));
229     if (status == GL_TRUE) {
230         return;
231     }
232 
233     GLint logLength;
234     MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &logLength));
235     const auto log = std::make_unique<GLchar[]>(logLength);
236     if (logLength > 0) {
237         MBGL_CHECK_ERROR(glGetProgramInfoLog(program_, logLength, &logLength, log.get()));
238         Log::Error(Event::Shader, "Program failed to link: %s", log.get());
239     }
240 
241     throw std::runtime_error("program failed to link");
242 }
243 
createVertexBuffer(const void * data,std::size_t size,const BufferUsage usage)244 UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage) {
245     BufferID id = 0;
246     MBGL_CHECK_ERROR(glGenBuffers(1, &id));
247     UniqueBuffer result { std::move(id), { this } };
248     vertexBuffer = result;
249     MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, static_cast<GLenum>(usage)));
250     return result;
251 }
252 
updateVertexBuffer(UniqueBuffer & buffer,const void * data,std::size_t size)253 void Context::updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size) {
254     vertexBuffer = buffer;
255     MBGL_CHECK_ERROR(glBufferSubData(GL_ARRAY_BUFFER, 0, size, data));
256 }
257 
createIndexBuffer(const void * data,std::size_t size,const BufferUsage usage)258 UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size, const BufferUsage usage) {
259     BufferID id = 0;
260     MBGL_CHECK_ERROR(glGenBuffers(1, &id));
261     UniqueBuffer result { std::move(id), { this } };
262     bindVertexArray = 0;
263     globalVertexArrayState.indexBuffer = result;
264     MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, static_cast<GLenum>(usage)));
265     return result;
266 }
267 
updateIndexBuffer(UniqueBuffer & buffer,const void * data,std::size_t size)268 void Context::updateIndexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size) {
269     // Be sure to unbind any existing vertex array object before binding the index buffer
270     // so that we don't mess up another VAO
271     bindVertexArray = 0;
272     globalVertexArrayState.indexBuffer = buffer;
273     MBGL_CHECK_ERROR(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, size, data));
274 }
275 
276 
createTexture()277 UniqueTexture Context::createTexture() {
278     if (pooledTextures.empty()) {
279         pooledTextures.resize(TextureMax);
280         MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data()));
281     }
282 
283     TextureID id = pooledTextures.back();
284     pooledTextures.pop_back();
285     return UniqueTexture{ std::move(id), { this } };
286 }
287 
supportsVertexArrays() const288 bool Context::supportsVertexArrays() const {
289     static bool blacklisted = []() {
290         const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER)));
291 
292         Log::Info(Event::General, "GPU Identifier: %s", renderer.c_str());
293 
294         // Blacklist Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data
295         // Blacklist ARM Mali-T720 (in some MT8163 chipsets) as it crashes on glBindVertexArray
296         return renderer.find("Adreno (TM) 2") != std::string::npos
297             || renderer.find("Adreno (TM) 3") != std::string::npos
298             || renderer.find("Mali-T720") != std::string::npos
299             || renderer.find("Sapphire 650") != std::string::npos;
300 
301     }();
302 
303     return !blacklisted &&
304            vertexArray &&
305            vertexArray->genVertexArrays &&
306            vertexArray->bindVertexArray &&
307            vertexArray->deleteVertexArrays;
308 }
309 
310 #if MBGL_HAS_BINARY_PROGRAMS
supportsProgramBinaries() const311 bool Context::supportsProgramBinaries() const {
312     if (!programBinary || !programBinary->programBinary || !programBinary->getProgramBinary) {
313         return false;
314     }
315 
316     // Blacklist Adreno 3xx, 4xx, and 5xx GPUs due to known bugs:
317     // https://bugs.chromium.org/p/chromium/issues/detail?id=510637
318     // https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_driver_bug_list.json#2316
319     // Blacklist Vivante GC4000 due to bugs when linking loaded programs:
320     // https://github.com/mapbox/mapbox-gl-native/issues/10704
321     const std::string renderer = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER)));
322     if (renderer.find("Adreno (TM) 3") != std::string::npos
323      || renderer.find("Adreno (TM) 4") != std::string::npos
324      || renderer.find("Adreno (TM) 5") != std::string::npos
325      || renderer.find("Vivante GC4000") != std::string::npos) {
326         return false;
327     }
328 
329     return true;
330 }
331 
332 optional<std::pair<BinaryProgramFormat, std::string>>
getBinaryProgram(ProgramID program_) const333 Context::getBinaryProgram(ProgramID program_) const {
334     if (!supportsProgramBinaries()) {
335         return {};
336     }
337     GLint binaryLength;
338     MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &binaryLength));
339     std::string binary;
340     binary.resize(binaryLength);
341     GLenum binaryFormat;
342     MBGL_CHECK_ERROR(programBinary->getProgramBinary(
343         program_, binaryLength, &binaryLength, &binaryFormat, const_cast<char*>(binary.data())));
344     if (size_t(binaryLength) != binary.size()) {
345         return {};
346     }
347     return { { binaryFormat, std::move(binary) } };
348 }
349 #else
getBinaryProgram(ProgramID) const350 optional<std::pair<BinaryProgramFormat, std::string>> Context::getBinaryProgram(ProgramID) const {
351     return {};
352 }
353 #endif
354 
createVertexArray()355 VertexArray Context::createVertexArray() {
356     if (supportsVertexArrays()) {
357         VertexArrayID id = 0;
358         MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id));
359         UniqueVertexArray vao(std::move(id), { this });
360         return { UniqueVertexArrayState(new VertexArrayState(std::move(vao)), VertexArrayStateDeleter { true })};
361     } else {
362         // On GL implementations which do not support vertex arrays, attribute bindings are global state.
363         // So return a VertexArray which shares our global state tracking and whose deleter is a no-op.
364         return { UniqueVertexArrayState(&globalVertexArrayState, VertexArrayStateDeleter { false }) };
365     }
366 }
367 
createFramebuffer()368 UniqueFramebuffer Context::createFramebuffer() {
369     FramebufferID id = 0;
370     MBGL_CHECK_ERROR(glGenFramebuffers(1, &id));
371     return UniqueFramebuffer{ std::move(id), { this } };
372 }
373 
createRenderbuffer(const RenderbufferType type,const Size size)374 UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, const Size size) {
375     RenderbufferID id = 0;
376     MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id));
377     UniqueRenderbuffer renderbuffer{ std::move(id), { this } };
378 
379     bindRenderbuffer = renderbuffer;
380     MBGL_CHECK_ERROR(
381         glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height));
382     bindRenderbuffer = 0;
383     return renderbuffer;
384 }
385 
readFramebuffer(const Size size,const TextureFormat format,const bool flip)386 std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const TextureFormat format, const bool flip) {
387     const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1);
388     auto data = std::make_unique<uint8_t[]>(stride * size.height);
389 
390     // When reading data from the framebuffer, make sure that we are storing the values
391     // tightly packed into the buffer to avoid buffer overruns.
392     pixelStorePack = { 1 };
393 
394     MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast<GLenum>(format),
395                                   GL_UNSIGNED_BYTE, data.get()));
396 
397     if (flip) {
398         auto tmp = std::make_unique<uint8_t[]>(stride);
399         uint8_t* rgba = data.get();
400         for (int i = 0, j = size.height - 1; i < j; i++, j--) {
401             std::memcpy(tmp.get(), rgba + i * stride, stride);
402             std::memcpy(rgba + i * stride, rgba + j * stride, stride);
403             std::memcpy(rgba + j * stride, tmp.get(), stride);
404         }
405     }
406 
407     return data;
408 }
409 
410 #if not MBGL_USE_GLES2
drawPixels(const Size size,const void * data,TextureFormat format)411 void Context::drawPixels(const Size size, const void* data, TextureFormat format) {
412     pixelStoreUnpack = { 1 };
413     if (format != TextureFormat::RGBA) {
414         format = static_cast<TextureFormat>(GL_LUMINANCE);
415     }
416     MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(format),
417                                   GL_UNSIGNED_BYTE, data));
418 }
419 #endif // MBGL_USE_GLES2
420 
421 namespace {
422 
checkFramebuffer()423 void checkFramebuffer() {
424     GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
425     if (status != GL_FRAMEBUFFER_COMPLETE) {
426         switch (status) {
427         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
428             throw std::runtime_error("Couldn't create framebuffer: incomplete attachment");
429         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
430             throw std::runtime_error("Couldn't create framebuffer: incomplete missing attachment");
431 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
432         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
433             throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer");
434 #endif
435 #ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
436         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
437             throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer");
438 #endif
439 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
440         case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
441             throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions");
442 #endif
443 
444         case GL_FRAMEBUFFER_UNSUPPORTED:
445             throw std::runtime_error("Couldn't create framebuffer: unsupported");
446         default:
447             throw std::runtime_error("Couldn't create framebuffer: other");
448         }
449     }
450 }
451 
bindDepthStencilRenderbuffer(const Renderbuffer<RenderbufferType::DepthStencil> & depthStencil)452 void bindDepthStencilRenderbuffer(
453     const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
454 #ifdef GL_DEPTH_STENCIL_ATTACHMENT
455     MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
456                                                GL_RENDERBUFFER, depthStencil.renderbuffer));
457 #else
458     MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
459                                                depthStencil.renderbuffer));
460     MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
461                                                GL_RENDERBUFFER, depthStencil.renderbuffer));
462 #endif
463 }
464 
465 } // namespace
466 
467 Framebuffer
createFramebuffer(const Renderbuffer<RenderbufferType::RGBA> & color,const Renderbuffer<RenderbufferType::DepthStencil> & depthStencil)468 Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color,
469                            const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
470     if (color.size != depthStencil.size) {
471         throw std::runtime_error("Renderbuffer size mismatch");
472     }
473     auto fbo = createFramebuffer();
474     bindFramebuffer = fbo;
475     MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
476                                                GL_RENDERBUFFER, color.renderbuffer));
477     bindDepthStencilRenderbuffer(depthStencil);
478     checkFramebuffer();
479     return { color.size, std::move(fbo) };
480 }
481 
createFramebuffer(const Renderbuffer<RenderbufferType::RGBA> & color)482 Framebuffer Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color) {
483     auto fbo = createFramebuffer();
484     bindFramebuffer = fbo;
485     MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
486                                                GL_RENDERBUFFER, color.renderbuffer));
487     checkFramebuffer();
488     return { color.size, std::move(fbo) };
489 }
490 
491 Framebuffer
createFramebuffer(const Texture & color,const Renderbuffer<RenderbufferType::DepthStencil> & depthStencil)492 Context::createFramebuffer(const Texture& color,
493                            const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
494     if (color.size != depthStencil.size) {
495         throw std::runtime_error("Renderbuffer size mismatch");
496     }
497     auto fbo = createFramebuffer();
498     bindFramebuffer = fbo;
499     MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
500                                             color.texture, 0));
501     bindDepthStencilRenderbuffer(depthStencil);
502     checkFramebuffer();
503     return { color.size, std::move(fbo) };
504 }
505 
createFramebuffer(const Texture & color)506 Framebuffer Context::createFramebuffer(const Texture& color) {
507     auto fbo = createFramebuffer();
508     bindFramebuffer = fbo;
509     MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
510                                             color.texture, 0));
511     checkFramebuffer();
512     return { color.size, std::move(fbo) };
513 }
514 
515 Framebuffer
createFramebuffer(const Texture & color,const Renderbuffer<RenderbufferType::DepthComponent> & depthTarget)516 Context::createFramebuffer(const Texture& color,
517                            const Renderbuffer<RenderbufferType::DepthComponent>& depthTarget) {
518     if (color.size != depthTarget.size) {
519         throw std::runtime_error("Renderbuffer size mismatch");
520     }
521     auto fbo = createFramebuffer();
522     bindFramebuffer = fbo;
523     MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color.texture, 0));
524     MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthTarget.renderbuffer));
525     checkFramebuffer();
526     return { depthTarget.size, std::move(fbo) };
527 }
528 
529 UniqueTexture
createTexture(const Size size,const void * data,TextureFormat format,TextureUnit unit,TextureType type)530 Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit, TextureType type) {
531     auto obj = createTexture();
532     pixelStoreUnpack = { 1 };
533     updateTexture(obj, size, data, format, unit, type);
534     // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures.
535     // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus.
536     MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
537     MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
538     MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
539     MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
540     return obj;
541 }
542 
updateTexture(TextureID id,const Size size,const void * data,TextureFormat format,TextureUnit unit,TextureType type)543 void Context::updateTexture(
544     TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit, TextureType type) {
545     activeTextureUnit = unit;
546     texture[unit] = id;
547     MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width,
548                                   size.height, 0, static_cast<GLenum>(format), static_cast<GLenum>(type),
549                                   data));
550 }
551 
bindTexture(Texture & obj,TextureUnit unit,TextureFilter filter,TextureMipMap mipmap,TextureWrap wrapX,TextureWrap wrapY)552 void Context::bindTexture(Texture& obj,
553                           TextureUnit unit,
554                           TextureFilter filter,
555                           TextureMipMap mipmap,
556                           TextureWrap wrapX,
557                           TextureWrap wrapY) {
558     if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) {
559         activeTextureUnit = unit;
560         texture[unit] = obj.texture;
561 
562         if (filter != obj.filter || mipmap != obj.mipmap) {
563             MBGL_CHECK_ERROR(glTexParameteri(
564                 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
565                 filter == TextureFilter::Linear
566                     ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
567                     : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
568             MBGL_CHECK_ERROR(
569                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
570                                 filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
571             obj.filter = filter;
572             obj.mipmap = mipmap;
573         }
574         if (wrapX != obj.wrapX) {
575 
576             MBGL_CHECK_ERROR(
577                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
578                                 wrapX == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
579             obj.wrapX = wrapX;
580         }
581         if (wrapY != obj.wrapY) {
582             MBGL_CHECK_ERROR(
583                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
584                                 wrapY == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
585             obj.wrapY = wrapY;
586         }
587     } else if (texture[unit] != obj.texture) {
588         // We are checking first to avoid setting the active texture without a subsequent
589         // texture bind.
590         activeTextureUnit = unit;
591         texture[unit] = obj.texture;
592     }
593 }
594 
reset()595 void Context::reset() {
596     std::copy(pooledTextures.begin(), pooledTextures.end(), std::back_inserter(abandonedTextures));
597     pooledTextures.resize(0);
598     performCleanup();
599 }
600 
setDirtyState()601 void Context::setDirtyState() {
602     // Note: does not set viewport/scissorTest/bindFramebuffer to dirty
603     // since they are handled separately in the view object.
604     stencilFunc.setDirty();
605     stencilMask.setDirty();
606     stencilTest.setDirty();
607     stencilOp.setDirty();
608     depthRange.setDirty();
609     depthMask.setDirty();
610     depthTest.setDirty();
611     depthFunc.setDirty();
612     blend.setDirty();
613     blendEquation.setDirty();
614     blendFunc.setDirty();
615     blendColor.setDirty();
616     colorMask.setDirty();
617     clearDepth.setDirty();
618     clearColor.setDirty();
619     clearStencil.setDirty();
620     program.setDirty();
621     lineWidth.setDirty();
622     activeTextureUnit.setDirty();
623     pixelStorePack.setDirty();
624     pixelStoreUnpack.setDirty();
625 #if not MBGL_USE_GLES2
626     pointSize.setDirty();
627     pixelZoom.setDirty();
628     rasterPos.setDirty();
629     pixelTransferDepth.setDirty();
630     pixelTransferStencil.setDirty();
631 #endif // MBGL_USE_GLES2
632     for (auto& tex : texture) {
633        tex.setDirty();
634     }
635     vertexBuffer.setDirty();
636     bindVertexArray.setDirty();
637     globalVertexArrayState.setDirty();
638 }
639 
clear(optional<mbgl::Color> color,optional<float> depth,optional<int32_t> stencil)640 void Context::clear(optional<mbgl::Color> color,
641                     optional<float> depth,
642                     optional<int32_t> stencil) {
643     GLbitfield mask = 0;
644 
645     if (color) {
646         mask |= GL_COLOR_BUFFER_BIT;
647         clearColor = *color;
648         colorMask = value::ColorMask::Default;
649     }
650 
651     if (depth) {
652         mask |= GL_DEPTH_BUFFER_BIT;
653         clearDepth = *depth;
654         depthMask = value::DepthMask::Default;
655     }
656 
657     if (stencil) {
658         mask |= GL_STENCIL_BUFFER_BIT;
659         clearStencil = *stencil;
660         stencilMask = value::StencilMask::Default;
661     }
662 
663     MBGL_CHECK_ERROR(glClear(mask));
664 }
665 
666 #if not MBGL_USE_GLES2
setDrawMode(const Points & points)667 void Context::setDrawMode(const Points& points) {
668     pointSize = points.pointSize;
669 }
670 #else
setDrawMode(const Points &)671 void Context::setDrawMode(const Points&) {
672 }
673 #endif // MBGL_USE_GLES2
674 
setDrawMode(const Lines & lines)675 void Context::setDrawMode(const Lines& lines) {
676     lineWidth = lines.lineWidth;
677 }
678 
setDrawMode(const LineStrip & lineStrip)679 void Context::setDrawMode(const LineStrip& lineStrip) {
680     lineWidth = lineStrip.lineWidth;
681 }
682 
setDrawMode(const Triangles &)683 void Context::setDrawMode(const Triangles&) {
684 }
685 
setDrawMode(const TriangleStrip &)686 void Context::setDrawMode(const TriangleStrip&) {
687 }
688 
setDepthMode(const DepthMode & depth)689 void Context::setDepthMode(const DepthMode& depth) {
690     if (depth.func == DepthMode::Always && !depth.mask) {
691         depthTest = false;
692 
693         // Workaround for rendering errors on Adreno 2xx GPUs. Depth-related state should
694         // not matter when the depth test is disabled, but on these GPUs it apparently does.
695         // https://github.com/mapbox/mapbox-gl-native/issues/9164
696         depthFunc = depth.func;
697         depthMask = depth.mask;
698         depthRange = depth.range;
699     } else {
700         depthTest = true;
701         depthFunc = depth.func;
702         depthMask = depth.mask;
703         depthRange = depth.range;
704     }
705 }
706 
setStencilMode(const StencilMode & stencil)707 void Context::setStencilMode(const StencilMode& stencil) {
708     if (stencil.test.is<StencilMode::Always>() && !stencil.mask) {
709         stencilTest = false;
710     } else {
711         stencilTest = true;
712         stencilMask = stencil.mask;
713         stencilOp = { stencil.fail, stencil.depthFail, stencil.pass };
714         apply_visitor([&] (const auto& test) {
715             stencilFunc = { test.func, stencil.ref, test.mask };
716         }, stencil.test);
717     }
718 }
719 
setColorMode(const ColorMode & color)720 void Context::setColorMode(const ColorMode& color) {
721     if (color.blendFunction.is<ColorMode::Replace>()) {
722         blend = false;
723     } else {
724         blend = true;
725         blendColor = color.blendColor;
726         apply_visitor([&] (const auto& blendFunction) {
727             blendEquation = ColorMode::BlendEquation(blendFunction.equation);
728             blendFunc = { blendFunction.srcFactor, blendFunction.dstFactor };
729         }, color.blendFunction);
730     }
731 
732     colorMask = color.mask;
733 }
734 
draw(PrimitiveType primitiveType,std::size_t indexOffset,std::size_t indexLength)735 void Context::draw(PrimitiveType primitiveType,
736                    std::size_t indexOffset,
737                    std::size_t indexLength) {
738     MBGL_CHECK_ERROR(glDrawElements(
739         static_cast<GLenum>(primitiveType),
740         static_cast<GLsizei>(indexLength),
741         GL_UNSIGNED_SHORT,
742         reinterpret_cast<GLvoid*>(sizeof(uint16_t) * indexOffset)));
743 }
744 
performCleanup()745 void Context::performCleanup() {
746     for (auto id : abandonedPrograms) {
747         if (program == id) {
748             program.setDirty();
749         }
750         MBGL_CHECK_ERROR(glDeleteProgram(id));
751     }
752     abandonedPrograms.clear();
753 
754     for (auto id : abandonedShaders) {
755         MBGL_CHECK_ERROR(glDeleteShader(id));
756     }
757     abandonedShaders.clear();
758 
759     if (!abandonedBuffers.empty()) {
760         for (const auto id : abandonedBuffers) {
761             if (vertexBuffer == id) {
762                 vertexBuffer.setDirty();
763             } else if (globalVertexArrayState.indexBuffer == id) {
764                 globalVertexArrayState.indexBuffer.setDirty();
765             }
766         }
767         MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data()));
768         abandonedBuffers.clear();
769     }
770 
771     if (!abandonedTextures.empty()) {
772         for (const auto id : abandonedTextures) {
773             for (auto& binding : texture) {
774                 if (binding == id) {
775                     binding.setDirty();
776                 }
777             }
778         }
779         MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data()));
780         abandonedTextures.clear();
781     }
782 
783     if (!abandonedVertexArrays.empty()) {
784         assert(supportsVertexArrays());
785         for (const auto id : abandonedVertexArrays) {
786             if (bindVertexArray == id) {
787                 bindVertexArray.setDirty();
788             }
789         }
790         MBGL_CHECK_ERROR(vertexArray->deleteVertexArrays(int(abandonedVertexArrays.size()),
791                                                          abandonedVertexArrays.data()));
792         abandonedVertexArrays.clear();
793     }
794 
795     if (!abandonedFramebuffers.empty()) {
796         for (const auto id : abandonedFramebuffers) {
797             if (bindFramebuffer == id) {
798                 bindFramebuffer.setDirty();
799             }
800         }
801         MBGL_CHECK_ERROR(
802             glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data()));
803         abandonedFramebuffers.clear();
804     }
805 
806     if (!abandonedRenderbuffers.empty()) {
807         MBGL_CHECK_ERROR(glDeleteRenderbuffers(int(abandonedRenderbuffers.size()),
808                                                abandonedRenderbuffers.data()));
809         abandonedRenderbuffers.clear();
810     }
811 }
812 
813 } // namespace gl
814 } // namespace mbgl
815