1 #pragma once
2 
3 #include <mbgl/gl/features.hpp>
4 #include <mbgl/gl/object.hpp>
5 #include <mbgl/gl/state.hpp>
6 #include <mbgl/gl/value.hpp>
7 #include <mbgl/gl/texture.hpp>
8 #include <mbgl/gl/renderbuffer.hpp>
9 #include <mbgl/gl/framebuffer.hpp>
10 #include <mbgl/gl/vertex_buffer.hpp>
11 #include <mbgl/gl/index_buffer.hpp>
12 #include <mbgl/gl/vertex_array.hpp>
13 #include <mbgl/gl/types.hpp>
14 #include <mbgl/gl/draw_mode.hpp>
15 #include <mbgl/gl/depth_mode.hpp>
16 #include <mbgl/gl/stencil_mode.hpp>
17 #include <mbgl/gl/color_mode.hpp>
18 #include <mbgl/util/noncopyable.hpp>
19 
20 
21 #include <functional>
22 #include <memory>
23 #include <vector>
24 #include <array>
25 #include <string>
26 
27 namespace mbgl {
28 namespace gl {
29 
30 constexpr size_t TextureMax = 64;
31 using ProcAddress = void (*)();
32 
33 namespace extension {
34 class VertexArray;
35 class Debugging;
36 class ProgramBinary;
37 } // namespace extension
38 
39 class Context {
40 public:
41     Context();
42     ~Context();
43     Context(const Context&) = delete;
44     Context& operator=(const Context& other) = delete;
45 
46     void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&);
47 
48     void enableDebugging();
49 
50     UniqueShader createShader(ShaderType type, const std::string& source);
51     UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader);
52     UniqueProgram createProgram(BinaryProgramFormat binaryFormat, const std::string& binaryProgram);
53     void verifyProgramLinkage(ProgramID);
54     void linkProgram(ProgramID);
55     UniqueTexture createTexture();
56     VertexArray createVertexArray();
57 
58 #if MBGL_HAS_BINARY_PROGRAMS
59     bool supportsProgramBinaries() const;
60 #else
supportsProgramBinaries() const61     constexpr bool supportsProgramBinaries() const { return false; }
62 #endif
63     optional<std::pair<BinaryProgramFormat, std::string>> getBinaryProgram(ProgramID) const;
64 
65     template <class Vertex, class DrawMode>
createVertexBuffer(VertexVector<Vertex,DrawMode> && v,const BufferUsage usage=BufferUsage::StaticDraw)66     VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v, const BufferUsage usage = BufferUsage::StaticDraw) {
67         return VertexBuffer<Vertex, DrawMode> {
68             v.vertexSize(),
69             createVertexBuffer(v.data(), v.byteSize(), usage)
70         };
71     }
72 
73     template <class Vertex, class DrawMode>
updateVertexBuffer(VertexBuffer<Vertex,DrawMode> & buffer,VertexVector<Vertex,DrawMode> && v)74     void updateVertexBuffer(VertexBuffer<Vertex, DrawMode>& buffer, VertexVector<Vertex, DrawMode>&& v) {
75         assert(v.vertexSize() == buffer.vertexCount);
76         updateVertexBuffer(buffer.buffer, v.data(), v.byteSize());
77     }
78 
79     template <class DrawMode>
createIndexBuffer(IndexVector<DrawMode> && v,const BufferUsage usage=BufferUsage::StaticDraw)80     IndexBuffer<DrawMode> createIndexBuffer(IndexVector<DrawMode>&& v, const BufferUsage usage = BufferUsage::StaticDraw) {
81         return IndexBuffer<DrawMode> {
82             v.indexSize(),
83             createIndexBuffer(v.data(), v.byteSize(), usage)
84         };
85     }
86 
87     template <class DrawMode>
updateIndexBuffer(IndexBuffer<DrawMode> & buffer,IndexVector<DrawMode> && v)88     void updateIndexBuffer(IndexBuffer<DrawMode>& buffer, IndexVector<DrawMode>&& v) {
89         assert(v.indexSize() == buffer.indexCount);
90         updateIndexBuffer(buffer.buffer, v.data(), v.byteSize());
91     }
92 
93     template <RenderbufferType type>
createRenderbuffer(const Size size)94     Renderbuffer<type> createRenderbuffer(const Size size) {
95         static_assert(type == RenderbufferType::RGBA ||
96                       type == RenderbufferType::DepthStencil ||
97                       type == RenderbufferType::DepthComponent,
98                       "invalid renderbuffer type");
99         return { size, createRenderbuffer(type, size) };
100     }
101 
102     Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&,
103                                   const Renderbuffer<RenderbufferType::DepthStencil>&);
104     Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&);
105     Framebuffer createFramebuffer(const Texture&,
106                                   const Renderbuffer<RenderbufferType::DepthStencil>&);
107     Framebuffer createFramebuffer(const Texture&);
108     Framebuffer createFramebuffer(const Texture&,
109                                   const Renderbuffer<RenderbufferType::DepthComponent>&);
110 
111     template <typename Image,
112               TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA
113                                                           : TextureFormat::Alpha>
readFramebuffer(const Size size,bool flip=true)114     Image readFramebuffer(const Size size, bool flip = true) {
115         static_assert(Image::channels == (format == TextureFormat::RGBA ? 4 : 1),
116                       "image format mismatch");
117         return { size, readFramebuffer(size, format, flip) };
118     }
119 
120 #if not MBGL_USE_GLES2
121     template <typename Image>
drawPixels(const Image & image)122     void drawPixels(const Image& image) {
123         auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
124         drawPixels(image.size, image.data.get(), format);
125     }
126 #endif // MBGL_USE_GLES2
127 
128     // Create a texture from an image with data.
129     template <typename Image>
createTexture(const Image & image,TextureUnit unit=0,TextureType type=TextureType::UnsignedByte)130     Texture createTexture(const Image& image,
131                           TextureUnit unit = 0,
132                           TextureType type = TextureType::UnsignedByte) {
133         auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
134         return { image.size, createTexture(image.size, image.data.get(), format, unit, type) };
135     }
136 
137     template <typename Image>
updateTexture(Texture & obj,const Image & image,TextureUnit unit=0,TextureType type=TextureType::UnsignedByte)138     void updateTexture(Texture& obj,
139                        const Image& image,
140                        TextureUnit unit = 0,
141                        TextureType type = TextureType::UnsignedByte) {
142         auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha;
143         updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit, type);
144         obj.size = image.size;
145     }
146 
147     // Creates an empty texture with the specified dimensions.
createTexture(const Size size,TextureFormat format=TextureFormat::RGBA,TextureUnit unit=0,TextureType type=TextureType::UnsignedByte)148     Texture createTexture(const Size size,
149                           TextureFormat format = TextureFormat::RGBA,
150                           TextureUnit unit = 0,
151                           TextureType type = TextureType::UnsignedByte) {
152         return { size, createTexture(size, nullptr, format, unit, type) };
153     }
154 
155     void bindTexture(Texture&,
156                      TextureUnit = 0,
157                      TextureFilter = TextureFilter::Nearest,
158                      TextureMipMap = TextureMipMap::No,
159                      TextureWrap wrapX = TextureWrap::Clamp,
160                      TextureWrap wrapY = TextureWrap::Clamp);
161 
162     void clear(optional<mbgl::Color> color,
163                optional<float> depth,
164                optional<int32_t> stencil);
165 
166     void setDrawMode(const Points&);
167     void setDrawMode(const Lines&);
168     void setDrawMode(const LineStrip&);
169     void setDrawMode(const Triangles&);
170     void setDrawMode(const TriangleStrip&);
171 
172     void setDepthMode(const DepthMode&);
173     void setStencilMode(const StencilMode&);
174     void setColorMode(const ColorMode&);
175 
176     void draw(PrimitiveType,
177               std::size_t indexOffset,
178               std::size_t indexLength);
179 
180     // Actually remove the objects we marked as abandoned with the above methods.
181     // Only call this while the OpenGL context is exclusive to this thread.
182     void performCleanup();
183 
184     // Drain pools and remove abandoned objects, in preparation for destroying the store.
185     // Only call this while the OpenGL context is exclusive to this thread.
186     void reset();
187 
empty() const188     bool empty() const {
189         return pooledTextures.empty()
190             && abandonedPrograms.empty()
191             && abandonedShaders.empty()
192             && abandonedBuffers.empty()
193             && abandonedTextures.empty()
194             && abandonedVertexArrays.empty()
195             && abandonedFramebuffers.empty();
196     }
197 
198     void setDirtyState();
199 
getDebuggingExtension() const200     extension::Debugging* getDebuggingExtension() const {
201         return debugging.get();
202     }
203 
getVertexArrayExtension() const204     extension::VertexArray* getVertexArrayExtension() const {
205         return vertexArray.get();
206     }
207 
setCleanupOnDestruction(bool cleanup)208     void setCleanupOnDestruction(bool cleanup) {
209         cleanupOnDestruction = cleanup;
210     }
211 
212 private:
213     bool cleanupOnDestruction = true;
214 
215     std::unique_ptr<extension::Debugging> debugging;
216     std::unique_ptr<extension::VertexArray> vertexArray;
217 #if MBGL_HAS_BINARY_PROGRAMS
218     std::unique_ptr<extension::ProgramBinary> programBinary;
219 #endif
220 
221 public:
222     State<value::ActiveTextureUnit> activeTextureUnit;
223     State<value::BindFramebuffer> bindFramebuffer;
224     State<value::Viewport> viewport;
225     State<value::ScissorTest> scissorTest;
226     std::array<State<value::BindTexture>, 2> texture;
227     State<value::Program> program;
228     State<value::BindVertexBuffer> vertexBuffer;
229 
230     State<value::BindVertexArray, const Context&> bindVertexArray { *this };
231     VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }) };
232 
233     State<value::PixelStorePack> pixelStorePack;
234     State<value::PixelStoreUnpack> pixelStoreUnpack;
235 
236 #if not MBGL_USE_GLES2
237     State<value::PixelZoom> pixelZoom;
238     State<value::RasterPos> rasterPos;
239     State<value::PixelTransferDepth> pixelTransferDepth;
240     State<value::PixelTransferStencil> pixelTransferStencil;
241 #endif // MBGL_USE_GLES2
242 
243     bool supportsHalfFloatTextures = false;
244     const uint32_t maximumVertexBindingCount;
245     static constexpr const uint32_t minimumRequiredVertexBindingCount = 8;
246 
247 private:
248     State<value::StencilFunc> stencilFunc;
249     State<value::StencilMask> stencilMask;
250     State<value::StencilTest> stencilTest;
251     State<value::StencilOp> stencilOp;
252     State<value::DepthRange> depthRange;
253     State<value::DepthMask> depthMask;
254     State<value::DepthTest> depthTest;
255     State<value::DepthFunc> depthFunc;
256     State<value::Blend> blend;
257     State<value::BlendEquation> blendEquation;
258     State<value::BlendFunc> blendFunc;
259     State<value::BlendColor> blendColor;
260     State<value::ColorMask> colorMask;
261     State<value::ClearDepth> clearDepth;
262     State<value::ClearColor> clearColor;
263     State<value::ClearStencil> clearStencil;
264     State<value::LineWidth> lineWidth;
265     State<value::BindRenderbuffer> bindRenderbuffer;
266 #if not MBGL_USE_GLES2
267     State<value::PointSize> pointSize;
268 #endif // MBGL_USE_GLES2
269 
270     UniqueBuffer createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage);
271     void updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size);
272     UniqueBuffer createIndexBuffer(const void* data, std::size_t size, const BufferUsage usage);
273     void updateIndexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size);
274     UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit, TextureType);
275     void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit, TextureType);
276     UniqueFramebuffer createFramebuffer();
277     UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size);
278     std::unique_ptr<uint8_t[]> readFramebuffer(Size, TextureFormat, bool flip);
279 #if not MBGL_USE_GLES2
280     void drawPixels(Size size, const void* data, TextureFormat);
281 #endif // MBGL_USE_GLES2
282 
283     bool supportsVertexArrays() const;
284 
285     friend detail::ProgramDeleter;
286     friend detail::ShaderDeleter;
287     friend detail::BufferDeleter;
288     friend detail::TextureDeleter;
289     friend detail::VertexArrayDeleter;
290     friend detail::FramebufferDeleter;
291     friend detail::RenderbufferDeleter;
292 
293     std::vector<TextureID> pooledTextures;
294 
295     std::vector<ProgramID> abandonedPrograms;
296     std::vector<ShaderID> abandonedShaders;
297     std::vector<BufferID> abandonedBuffers;
298     std::vector<TextureID> abandonedTextures;
299     std::vector<VertexArrayID> abandonedVertexArrays;
300     std::vector<FramebufferID> abandonedFramebuffers;
301     std::vector<RenderbufferID> abandonedRenderbuffers;
302 
303 public:
304     // For testing and Windows because Qt + ANGLE
305     // crashes with VAO enabled.
306 #if defined(_WINDOWS)
307     bool disableVAOExtension = true;
308 #else
309     bool disableVAOExtension = false;
310 #endif
311 };
312 
313 } // namespace gl
314 } // namespace mbgl
315