[core] convert LineAtlas to use managed texture handling

This commit is contained in:
Konstantin Käfer
2016-10-26 18:06:36 -07:00
parent 7b50cac49f
commit ed155460d3
9 changed files with 70 additions and 82 deletions

View File

@@ -11,10 +11,8 @@
namespace mbgl {
LineAtlas::LineAtlas(uint16_t w, uint16_t h)
: width(w),
height(h),
data(std::make_unique<char[]>(w * h)),
LineAtlas::LineAtlas(const Size size)
: image(size),
dirty(true) {
}
@@ -40,11 +38,11 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray,
}
LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatternCap patternCap) {
int n = patternCap == LinePatternCap::Round ? 7 : 0;
int dashheight = 2 * n + 1;
const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0;
const uint8_t dashheight = 2 * n + 1;
const uint8_t offset = 128;
if (nextRow + dashheight > height) {
if (nextRow + dashheight > image.size.height) {
Log::Warning(Event::OpenGL, "line atlas bitmap overflow");
return LinePatternPos();
}
@@ -54,7 +52,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
length += part;
}
float stretch = width / length;
float stretch = image.size.width / length;
float halfWidth = stretch * 0.5;
// If dasharray has an odd length, both the first and last parts
// are dashes and should be joined seamlessly.
@@ -62,7 +60,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
for (int y = -n; y <= n; y++) {
int row = nextRow + n + y;
int index = width * row;
int index = image.size.width * row;
float left = 0;
float right = dasharray[0];
@@ -72,7 +70,7 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
left -= dasharray.back();
}
for (int x = 0; x < width; x++) {
for (uint32_t x = 0; x < image.size.width; x++) {
while (right < x / stretch) {
left = right;
@@ -104,13 +102,13 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
signedDistance = int((inside ? 1 : -1) * dist);
}
data[index + x] = fmax(0, fmin(255, signedDistance + offset));
image.data[index + x] = fmax(0, fmin(255, signedDistance + offset));
}
}
LinePatternPos position;
position.y = (0.5 + nextRow + n) / height;
position.height = (2.0 * n) / height;
position.y = (0.5 + nextRow + n) / image.size.height;
position.height = (2.0 * n) / image.size.height;
position.width = length;
nextRow += dashheight;
@@ -120,59 +118,24 @@ LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, LinePatte
return position;
}
Size LineAtlas::getSize() const {
return image.size;
}
void LineAtlas::upload(gl::Context& context, gl::TextureUnit unit) {
if (dirty) {
bind(context, unit);
if (!texture) {
texture = context.createTexture(image, unit);
} else if (dirty) {
context.updateTexture(*texture, image, unit);
}
dirty = false;
}
void LineAtlas::bind(gl::Context& context, gl::TextureUnit unit) {
bool first = false;
if (!texture) {
texture = context.createTexture();
context.activeTexture = unit;
context.texture[unit] = *texture;
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
first = true;
} else if (context.texture[unit] != *texture) {
context.activeTexture = unit;
context.texture[unit] = *texture;
}
if (dirty) {
context.activeTexture = unit;
if (first) {
MBGL_CHECK_ERROR(glTexImage2D(
GL_TEXTURE_2D, // GLenum target
0, // GLint level
GL_ALPHA, // GLint internalformat
width, // GLsizei width
height, // GLsizei height
0, // GLint border
GL_ALPHA, // GLenum format
GL_UNSIGNED_BYTE, // GLenum type
data.get() // const GLvoid * data
));
} else {
MBGL_CHECK_ERROR(glTexSubImage2D(
GL_TEXTURE_2D, // GLenum target
0, // GLint level
0, // GLint xoffset
0, // GLint yoffset
width, // GLsizei width
height, // GLsizei height
GL_ALPHA, // GLenum format
GL_UNSIGNED_BYTE, // GLenum type
data.get() // const GLvoid *pixels
));
}
dirty = false;
}
upload(context, unit);
context.bindTexture(*texture, unit, gl::TextureFilter::Linear, gl::TextureMipMap::No,
gl::TextureWrap::Repeat, gl::TextureWrap::Clamp);
}
} // namespace mbgl

View File

@@ -1,6 +1,8 @@
#pragma once
#include <mbgl/gl/texture.hpp>
#include <mbgl/gl/object.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/optional.hpp>
#include <vector>
@@ -27,7 +29,7 @@ enum class LinePatternCap : bool {
class LineAtlas {
public:
LineAtlas(uint16_t width, uint16_t height);
LineAtlas(Size);
~LineAtlas();
// Binds the atlas texture to the GPU, and uploads data if it is out of date.
@@ -40,14 +42,13 @@ public:
LinePatternPos getDashPosition(const std::vector<float>&, LinePatternCap);
LinePatternPos addDash(const std::vector<float>& dasharray, LinePatternCap);
const uint16_t width;
const uint16_t height;
Size getSize() const;
private:
const std::unique_ptr<char[]> data;
const AlphaImage image;
bool dirty;
mbgl::optional<gl::UniqueTexture> texture;
int nextRow = 0;
mbgl::optional<gl::Texture> texture;
uint32_t nextRow = 0;
std::unordered_map<size_t, LinePatternPos> positions;
};

View File

@@ -211,19 +211,38 @@ void Context::updateTexture(
void Context::bindTexture(Texture& obj,
TextureUnit unit,
TextureFilter filter,
TextureMipMap mipmap) {
if (filter != obj.filter || mipmap != obj.mipmap) {
TextureMipMap mipmap,
TextureWrap wrapX,
TextureWrap wrapY) {
if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) {
activeTexture = unit;
texture[unit] = obj.texture;
MBGL_CHECK_ERROR(glTexParameteri(
GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
filter == TextureFilter::Linear
? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
: (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
obj.filter = filter;
obj.mipmap = mipmap;
if (filter != obj.filter || mipmap != obj.mipmap) {
MBGL_CHECK_ERROR(glTexParameteri(
GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
filter == TextureFilter::Linear
? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
: (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST));
obj.filter = filter;
obj.mipmap = mipmap;
}
if (wrapX != obj.wrapX) {
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
wrapX == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
obj.wrapX = wrapX;
}
if (wrapY != obj.wrapY) {
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
wrapY == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
obj.wrapY = wrapY;
}
} else if (texture[unit] != obj.texture) {
// We are checking first to avoid setting the active texture without a subsequent
// texture bind.

View File

@@ -86,7 +86,9 @@ public:
void bindTexture(Texture&,
TextureUnit = 0,
TextureFilter = TextureFilter::Nearest,
TextureMipMap = TextureMipMap::No);
TextureMipMap = TextureMipMap::No,
TextureWrap wrapX = TextureWrap::Clamp,
TextureWrap wrapY = TextureWrap::Clamp);
void clear(optional<mbgl::Color> color,
optional<float> depth,

View File

@@ -12,6 +12,8 @@ public:
UniqueTexture texture;
TextureFilter filter = TextureFilter::Nearest;
TextureMipMap mipmap = TextureMipMap::No;
TextureWrap wrapX = TextureWrap::Clamp;
TextureWrap wrapY = TextureWrap::Clamp;
};
} // namespace gl

View File

@@ -46,6 +46,7 @@ enum class RenderbufferType : uint32_t {
enum class TextureMipMap : bool { No = false, Yes = true };
enum class TextureFilter : bool { Nearest = false, Linear = true };
enum class TextureWrap : bool { Clamp, Repeat };
enum class TextureFormat : uint32_t {
RGBA = 0x1908,
Alpha = 0x1906,

View File

@@ -55,7 +55,7 @@ void Painter::renderLine(PaintParameters& parameters,
posA,
posB,
layer.impl->dashLineWidth,
lineAtlas->width));
lineAtlas->getSize().width));
} else if (!properties.linePattern.value.from.empty()) {
optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition(

View File

@@ -101,7 +101,7 @@ void Painter::renderSymbol(PaintParameters& parameters,
auto values = layer.impl->textPropertyValues(layout);
const Size texsize = glyphAtlas->getSize()x§;
const Size texsize = glyphAtlas->getSize();
if (values.hasHalo()) {
draw(parameters.shaders.symbolGlyph,

View File

@@ -40,7 +40,7 @@ Style::Style(FileSource& fileSource_, float pixelRatio)
: fileSource(fileSource_),
glyphAtlas(std::make_unique<GlyphAtlas>(Size{ 2048, 2048 }, fileSource)),
spriteAtlas(std::make_unique<SpriteAtlas>(Size{ 1024, 1024 }, pixelRatio)),
lineAtlas(std::make_unique<LineAtlas>(256, 512)),
lineAtlas(std::make_unique<LineAtlas>(Size{ 256, 512 })),
observer(&nullObserver) {
glyphAtlas->setObserver(this);
spriteAtlas->setObserver(this);