[core] add getResource template to gfx::*Resource classes

This commit is contained in:
Konstantin Käfer
2019-04-02 22:47:24 +02:00
parent c02010ab6c
commit ebd8508032
20 changed files with 117 additions and 74 deletions

View File

@@ -138,7 +138,7 @@ void LineAtlas::upload(gfx::Context& context) {
gfx::TextureBinding LineAtlas::textureBinding(gfx::Context& context) {
upload(context);
return { *texture->resource, gfx::TextureFilterType::Linear, gfx::TextureMipMapType::No,
return { texture->getResource(), gfx::TextureFilterType::Linear, gfx::TextureMipMapType::No,
gfx::TextureWrapType::Repeat, gfx::TextureWrapType::Clamp };
}

View File

@@ -250,7 +250,7 @@ AttributeBinding attributeBinding(const VertexBuffer<detail::VertexType<As...>>&
return {
Descriptor::data.attributes[I],
Descriptor::data.stride,
buffer.resource.get(),
&buffer.getResource(),
0,
};
}

View File

@@ -51,7 +51,7 @@ public:
template <class Vertex>
void updateVertexBuffer(VertexBuffer<Vertex>& buffer, VertexVector<Vertex>&& v) {
assert(v.elements() == buffer.elements);
updateVertexBufferResource(*buffer.resource, v.data(), v.bytes());
updateVertexBufferResource(buffer.getResource(), v.data(), v.bytes());
}
template <class DrawMode>
@@ -63,19 +63,19 @@ public:
template <class DrawMode>
void updateIndexBuffer(IndexBuffer& buffer, IndexVector<DrawMode>&& v) {
assert(v.elements() == buffer.elements);
updateIndexBufferResource(*buffer.resource, v.data(), v.bytes());
updateIndexBufferResource(buffer.getResource(), v.data(), v.bytes());
}
protected:
virtual std::unique_ptr<const VertexBufferResource>
virtual std::unique_ptr<VertexBufferResource>
createVertexBufferResource(const void* data, std::size_t size, const BufferUsageType) = 0;
virtual void
updateVertexBufferResource(const VertexBufferResource&, const void* data, std::size_t size) = 0;
updateVertexBufferResource(VertexBufferResource&, const void* data, std::size_t size) = 0;
virtual std::unique_ptr<const IndexBufferResource>
virtual std::unique_ptr<IndexBufferResource>
createIndexBufferResource(const void* data, std::size_t size, const BufferUsageType) = 0;
virtual void
updateIndexBufferResource(const IndexBufferResource&, const void* data, std::size_t size) = 0;
updateIndexBufferResource(IndexBufferResource&, const void* data, std::size_t size) = 0;
public:
// Create a texture from an image with data.
@@ -99,28 +99,28 @@ public:
const Image& image,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTextureResource(*texture.resource, image.size, image.data.get(), format, type);
updateTextureResource(texture.getResource(), image.size, image.data.get(), format, type);
texture.size = image.size;
}
template <typename Image>
void updateTextureSub(Texture& texture,
const Image& image,
const uint16_t offsetX,
const uint16_t offsetY,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
const Image& image,
const uint16_t offsetX,
const uint16_t offsetY,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
assert(image.size.width + offsetX <= texture.size.width);
assert(image.size.height + offsetY <= texture.size.height);
auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTextureResourceSub(*texture.resource, offsetX, offsetY, image.size, image.data.get(), format, type);
updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type);
}
protected:
virtual std::unique_ptr<TextureResource> createTextureResource(
Size, const void* data, TexturePixelType, TextureChannelDataType) = 0;
virtual void updateTextureResource(const TextureResource&, Size, const void* data,
virtual void updateTextureResource(TextureResource&, Size, const void* data,
TexturePixelType, TextureChannelDataType) = 0;
virtual void updateTextureResourceSub(const TextureResource&, uint16_t xOffset, uint16_t yOffset, Size, const void* data,
virtual void updateTextureResourceSub(TextureResource&, uint16_t xOffset, uint16_t yOffset, Size, const void* data,
TexturePixelType, TextureChannelDataType) = 0;
public:
@@ -136,7 +136,7 @@ protected:
public:
DrawScope createDrawScope() {
return { createDrawScopeResource() };
return DrawScope{ createDrawScopeResource() };
}
protected:

View File

@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <cassert>
namespace mbgl {
namespace gfx {
@@ -14,6 +15,16 @@ public:
class DrawScope {
public:
explicit DrawScope(std::unique_ptr<DrawScopeResource> resource_) : resource(std::move(resource_)) {
}
template <typename T = DrawScopeResource>
T& getResource() const {
assert(resource);
return static_cast<T&>(*resource);
}
protected:
std::unique_ptr<DrawScopeResource> resource;
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <cassert>
namespace mbgl {
namespace gfx {
@@ -14,8 +15,20 @@ public:
class IndexBuffer {
public:
IndexBuffer(const std::size_t elements_, std::unique_ptr<IndexBufferResource>&& resource_)
: elements(elements_), resource(std::move(resource_)) {
}
std::size_t elements;
std::unique_ptr<const IndexBufferResource> resource;
template <typename T = IndexBufferResource>
T& getResource() const {
assert(resource);
return static_cast<T&>(*resource);
}
protected:
std::unique_ptr<IndexBufferResource> resource;
};
} // namespace gfx

View File

@@ -6,6 +6,7 @@
#include <mbgl/util/indexed_tuple.hpp>
#include <memory>
#include <cassert>
#define MBGL_DEFINE_TEXTURE(name_) \
struct name_ { \
@@ -27,11 +28,19 @@ public:
class Texture {
public:
Texture(Size size_, std::unique_ptr<TextureResource>&& resource_)
: size(std::move(size_)), resource(std::move(resource_)) {
Texture(const Size size_, std::unique_ptr<TextureResource>&& resource_)
: size(size_), resource(std::move(resource_)) {
}
template <typename T = TextureResource>
T& getResource() const {
assert(resource);
return static_cast<T&>(*resource);
}
Size size;
protected:
std::unique_ptr<TextureResource> resource;
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <cassert>
namespace mbgl {
namespace gfx {
@@ -17,8 +18,20 @@ public:
template <class>
class VertexBuffer {
public:
VertexBuffer(const std::size_t elements_, std::unique_ptr<VertexBufferResource>&& resource_)
: elements(elements_), resource(std::move(resource_)) {
}
std::size_t elements;
std::unique_ptr<const VertexBufferResource> resource;
template <typename T = VertexBufferResource>
T& getResource() const {
assert(resource);
return static_cast<T&>(*resource);
}
protected:
std::unique_ptr<VertexBufferResource> resource;
};
} // namespace gfx

View File

@@ -220,7 +220,7 @@ void Context::verifyProgramLinkage(ProgramID program_) {
throw std::runtime_error("program failed to link");
}
std::unique_ptr<const gfx::VertexBufferResource>
std::unique_ptr<gfx::VertexBufferResource>
Context::createVertexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType usage) {
BufferID id = 0;
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
@@ -230,12 +230,12 @@ Context::createVertexBufferResource(const void* data, std::size_t size, const gf
return std::make_unique<gl::VertexBufferResource>(std::move(result));
}
void Context::updateVertexBufferResource(const gfx::VertexBufferResource& resource, const void* data, std::size_t size) {
vertexBuffer = reinterpret_cast<const gl::VertexBufferResource&>(resource).buffer;
void Context::updateVertexBufferResource(gfx::VertexBufferResource& resource, const void* data, std::size_t size) {
vertexBuffer = static_cast<gl::VertexBufferResource&>(resource).buffer;
MBGL_CHECK_ERROR(glBufferSubData(GL_ARRAY_BUFFER, 0, size, data));
}
std::unique_ptr<const gfx::IndexBufferResource>
std::unique_ptr<gfx::IndexBufferResource>
Context::createIndexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType usage) {
BufferID id = 0;
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
@@ -246,11 +246,11 @@ Context::createIndexBufferResource(const void* data, std::size_t size, const gfx
return std::make_unique<gl::IndexBufferResource>(std::move(result));
}
void Context::updateIndexBufferResource(const gfx::IndexBufferResource& resource, const void* data, std::size_t size) {
void Context::updateIndexBufferResource(gfx::IndexBufferResource& resource, const void* data, std::size_t size) {
// Be sure to unbind any existing vertex array object before binding the index buffer
// so that we don't mess up another VAO
bindVertexArray = 0;
globalVertexArrayState.indexBuffer = reinterpret_cast<const gl::IndexBufferResource&>(resource).buffer;
globalVertexArrayState.indexBuffer = static_cast<gl::IndexBufferResource&>(resource).buffer;
MBGL_CHECK_ERROR(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, size, data));
}
@@ -470,9 +470,8 @@ Context::createFramebuffer(const gfx::Texture& color,
}
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
MBGL_CHECK_ERROR(glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
reinterpret_cast<const gl::TextureResource&>(*color.resource).texture, 0));
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
color.getResource<gl::TextureResource>().texture, 0));
bindDepthStencilRenderbuffer(depthStencil);
checkFramebuffer();
return { color.size, std::move(fbo) };
@@ -481,9 +480,8 @@ Context::createFramebuffer(const gfx::Texture& color,
Framebuffer Context::createFramebuffer(const gfx::Texture& color) {
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
MBGL_CHECK_ERROR(glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
reinterpret_cast<const gl::TextureResource&>(*color.resource).texture, 0));
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
color.getResource<gl::TextureResource>().texture, 0));
checkFramebuffer();
return { color.size, std::move(fbo) };
}
@@ -496,9 +494,8 @@ Context::createFramebuffer(const gfx::Texture& color,
}
auto fbo = createFramebuffer();
bindFramebuffer = fbo;
MBGL_CHECK_ERROR(glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
reinterpret_cast<const gl::TextureResource&>(*color.resource).texture, 0));
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
color.getResource<gl::TextureResource>().texture, 0));
auto& depthResource = depth.getResource<gl::RenderbufferResource>();
MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
@@ -525,27 +522,27 @@ Context::createTextureResource(const Size size,
return resource;
}
void Context::updateTextureResource(const gfx::TextureResource& resource,
void Context::updateTextureResource(gfx::TextureResource& resource,
const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
// Always use texture unit 0 for manipulating it.
activeTextureUnit = 0;
texture[0] = reinterpret_cast<const gl::TextureResource&>(resource).texture;
texture[0] = static_cast<gl::TextureResource&>(resource).texture;
MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, Enum<gfx::TexturePixelType>::to(format),
size.width, size.height, 0,
Enum<gfx::TexturePixelType>::to(format),
Enum<gfx::TextureChannelDataType>::to(type), data));
}
void Context::updateTextureResourceSub(const gfx::TextureResource& resource,
const uint16_t xOffset,
const uint16_t yOffset,
const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
void Context::updateTextureResourceSub(gfx::TextureResource& resource,
const uint16_t xOffset,
const uint16_t yOffset,
const Size size,
const void* data,
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
// Always use texture unit 0 for manipulating it.
activeTextureUnit = 0;
texture[0] = static_cast<const gl::TextureResource&>(resource).texture;

View File

@@ -192,14 +192,14 @@ private:
State<value::PointSize> pointSize;
#endif // MBGL_USE_GLES2
std::unique_ptr<const gfx::VertexBufferResource> createVertexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType) override;
void updateVertexBufferResource(const gfx::VertexBufferResource&, const void* data, std::size_t size) override;
std::unique_ptr<const gfx::IndexBufferResource> createIndexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType) override;
void updateIndexBufferResource(const gfx::IndexBufferResource&, const void* data, std::size_t size) override;
std::unique_ptr<gfx::VertexBufferResource> createVertexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType) override;
void updateVertexBufferResource(gfx::VertexBufferResource&, const void* data, std::size_t size) override;
std::unique_ptr<gfx::IndexBufferResource> createIndexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType) override;
void updateIndexBufferResource(gfx::IndexBufferResource&, const void* data, std::size_t size) override;
std::unique_ptr<gfx::TextureResource> createTextureResource(Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResource(const gfx::TextureResource&, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResourceSub(const gfx::TextureResource&, const uint16_t xOffset, const uint16_t yOffset, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResource(gfx::TextureResource&, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResourceSub(gfx::TextureResource&, const uint16_t xOffset, const uint16_t yOffset, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
std::unique_ptr<gfx::RenderbufferResource> createRenderbufferResource(gfx::RenderbufferPixelType, Size size) override;

View File

@@ -194,7 +194,7 @@ public:
instance.textureStates.bind(context, textureBindings);
auto& vertexArray = static_cast<gl::DrawScopeResource&>(*drawScope.resource).vertexArray;
auto& vertexArray = drawScope.getResource<gl::DrawScopeResource>().vertexArray;
vertexArray.bind(context,
indexBuffer,
instance.attributeLocations.toBindingArray(attributeBindings));

View File

@@ -9,7 +9,7 @@ void VertexArray::bind(Context& context,
const gfx::IndexBuffer& indexBuffer,
const AttributeBindingArray& bindings) {
context.bindVertexArray = state->vertexArray;
state->indexBuffer = reinterpret_cast<const gl::IndexBufferResource&>(*indexBuffer.resource).buffer;
state->indexBuffer = indexBuffer.getResource<gl::IndexBufferResource>().buffer;
state->bindings.reserve(bindings.size());
for (AttributeLocation location = 0; location < bindings.size(); ++location) {

View File

@@ -259,7 +259,7 @@ void ImageManager::upload(gfx::Context& context) {
gfx::TextureBinding ImageManager::textureBinding(gfx::Context& context) {
upload(context);
return { *atlasTexture->resource, gfx::TextureFilterType::Linear };
return { atlasTexture->getResource(), gfx::TextureFilterType::Linear };
}
} // namespace mbgl

View File

@@ -162,7 +162,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
patternPosA,
patternPosB,
FillExtrusionPatternProgram::TextureBindings{
textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ geometryTile.iconAtlasTexture->getResource(), gfx::TextureFilterType::Linear },
}
);
}
@@ -209,7 +209,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters, RenderSource*
allUniformValues,
allAttributeBindings,
ExtrusionTextureProgram::TextureBindings{
textures::image::Value{ *renderTexture->getTexture().resource },
textures::image::Value{ renderTexture->getTexture().getResource() },
},
getID());
}

View File

@@ -215,7 +215,7 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
*bucket.triangleIndexBuffer,
bucket.triangleSegments,
FillPatternProgram::TextureBindings{
textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ geometryTile.iconAtlasTexture->getResource(), gfx::TextureFilterType::Linear },
});
if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) {
@@ -225,7 +225,7 @@ void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) {
*bucket.lineIndexBuffer,
bucket.lineSegments,
FillOutlinePatternProgram::TextureBindings{
textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ geometryTile.iconAtlasTexture->getResource(), gfx::TextureFilterType::Linear },
});
}
}

View File

@@ -177,8 +177,8 @@ void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) {
allUniformValues,
allAttributeBindings,
HeatmapTextureProgram::TextureBindings{
textures::image::Value{ *renderTexture->getTexture().resource, gfx::TextureFilterType::Linear },
textures::color_ramp::Value{ *colorRampTexture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ renderTexture->getTexture().getResource(), gfx::TextureFilterType::Linear },
textures::color_ramp::Value{ colorRampTexture->getResource(), gfx::TextureFilterType::Linear },
},
getID()
);

View File

@@ -169,7 +169,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
allUniformValues,
allAttributeBindings,
HillshadePrepareProgram::TextureBindings{
textures::image::Value{ *bucket.dem->resource },
textures::image::Value{ bucket.dem->getResource() },
},
getID()
);
@@ -186,7 +186,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
bucket.segments,
tile.id,
HillshadeProgram::TextureBindings{
textures::image::Value{ *bucket.texture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ bucket.texture->getResource(), gfx::TextureFilterType::Linear },
});
} else {
// Draw the full tile.
@@ -196,7 +196,7 @@ void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src
parameters.staticData.rasterSegments,
tile.id,
HillshadeProgram::TextureBindings{
textures::image::Value{ *bucket.texture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ bucket.texture->getResource(), gfx::TextureFilterType::Linear },
});
}
}

View File

@@ -143,7 +143,7 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) {
posA,
posB,
LinePatternProgram::TextureBindings{
textures::image::Value{ *geometryTile.iconAtlasTexture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ geometryTile.iconAtlasTexture->getResource(), gfx::TextureFilterType::Linear },
});
} else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
if (!colorRampTexture) {
@@ -159,7 +159,7 @@ void RenderLineLayer::render(PaintParameters& parameters, RenderSource*) {
{},
{},
LineGradientProgram::TextureBindings{
textures::image::Value{ *colorRampTexture->resource, gfx::TextureFilterType::Linear },
textures::image::Value{ colorRampTexture->getResource(), gfx::TextureFilterType::Linear },
});
} else {
draw(parameters.programs.getLineLayerPrograms().line,

View File

@@ -137,8 +137,8 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source
*bucket.indexBuffer,
bucket.segments,
RasterProgram::TextureBindings{
textures::image0::Value{ *bucket.texture->resource, filter },
textures::image1::Value{ *bucket.texture->resource, filter },
textures::image0::Value{ bucket.texture->getResource(), filter },
textures::image1::Value{ bucket.texture->getResource(), filter },
});
}
}
@@ -161,8 +161,8 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source
*bucket.indexBuffer,
bucket.segments,
RasterProgram::TextureBindings{
textures::image0::Value{ *bucket.texture->resource, filter },
textures::image1::Value{ *bucket.texture->resource, filter },
textures::image0::Value{ bucket.texture->getResource(), filter },
textures::image1::Value{ bucket.texture->getResource(), filter },
});
} else {
// Draw the full tile.
@@ -171,8 +171,8 @@ void RenderRasterLayer::render(PaintParameters& parameters, RenderSource* source
parameters.staticData.quadTriangleIndexBuffer,
parameters.staticData.rasterSegments,
RasterProgram::TextureBindings{
textures::image0::Value{ *bucket.texture->resource, filter },
textures::image1::Value{ *bucket.texture->resource, filter },
textures::image0::Value{ bucket.texture->getResource(), filter },
textures::image1::Value{ bucket.texture->getResource(), filter },
});
}
}

View File

@@ -171,7 +171,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0;
const gfx::TextureBinding textureBinding{ *geometryTile.iconAtlasTexture->resource,
const gfx::TextureBinding textureBinding{ geometryTile.iconAtlasTexture->getResource(),
bucket.sdfIcons ||
parameters.state.isChanging() ||
iconScaled || iconTransformed
@@ -221,7 +221,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
}
if (bucket.hasTextData()) {
const gfx::TextureBinding textureBinding{ *geometryTile.glyphAtlasTexture->resource,
const gfx::TextureBinding textureBinding{ geometryTile.glyphAtlasTexture->getResource(),
gfx::TextureFilterType::Linear };
auto values = textPropertyValues(evaluated_, layout);

View File

@@ -159,7 +159,7 @@ void main() {
test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0);
// Now, composite the Framebuffer texture we've rendered to onto the main FBO.
gl::bindTexture(context, 0, { *texture.getTexture().resource, gfx::TextureFilterType::Linear });
gl::bindTexture(context, 0, { texture.getTexture().getResource(), gfx::TextureFilterType::Linear });
MBGL_CHECK_ERROR(glUseProgram(compositeShader.program));
MBGL_CHECK_ERROR(glUniform1i(u_texture, 0));
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer));