[core] remove Raster object in favor of a more low-level Texture object

This commit is contained in:
Konstantin Käfer
2016-10-04 12:45:11 +02:00
committed by John Firebaugh
parent e103d92b18
commit 07315711d6
13 changed files with 116 additions and 190 deletions

View File

@@ -87,6 +87,7 @@ set(MBGL_CORE_FILES
src/mbgl/gl/object.cpp
src/mbgl/gl/object.hpp
src/mbgl/gl/state.hpp
src/mbgl/gl/texture.hpp
src/mbgl/gl/types.hpp
src/mbgl/gl/value.cpp
src/mbgl/gl/value.hpp
@@ -229,6 +230,7 @@ set(MBGL_CORE_FILES
include/mbgl/storage/response.hpp
src/mbgl/storage/asset_file_source.hpp
src/mbgl/storage/http_file_source.hpp
src/mbgl/storage/local_file_source.hpp
src/mbgl/storage/network_status.cpp
src/mbgl/storage/resource.cpp
src/mbgl/storage/response.cpp
@@ -468,8 +470,6 @@ set(MBGL_CORE_FILES
src/mbgl/util/premultiply.cpp
src/mbgl/util/premultiply.hpp
src/mbgl/util/rapidjson.hpp
src/mbgl/util/raster.cpp
src/mbgl/util/raster.hpp
src/mbgl/util/rect.hpp
src/mbgl/util/std.hpp
src/mbgl/util/stopwatch.cpp

View File

@@ -124,6 +124,44 @@ void Context::uploadBuffer(BufferType type, size_t size, void* data) {
MBGL_CHECK_ERROR(glBufferData(static_cast<GLenum>(type), size, data, GL_STATIC_DRAW));
}
UniqueTexture
Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) {
auto obj = createTexture();
activeTexture = unit;
texture[unit] = obj;
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
MBGL_CHECK_ERROR(
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data));
return obj;
}
void Context::bindTexture(Texture& obj,
TextureUnit unit,
TextureFilter filter,
TextureMipMap mipmap) {
if (filter != obj.filter || mipmap != obj.mipmap) {
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;
} else if (texture[unit] != obj.texture) {
// We are checking first to avoid setting the active texture without a subsequent
// texture bind.
activeTexture = unit;
texture[unit] = obj.texture;
}
}
void Context::reset() {
std::copy(pooledTextures.begin(), pooledTextures.end(), std::back_inserter(abandonedTextures));
pooledTextures.resize(0);

View File

@@ -3,6 +3,7 @@
#include <mbgl/gl/object.hpp>
#include <mbgl/gl/state.hpp>
#include <mbgl/gl/value.hpp>
#include <mbgl/gl/texture.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <memory>
@@ -28,6 +29,23 @@ public:
void uploadBuffer(BufferType, size_t, void*);
// Create a texture from an image with data.
template <typename Image>
Texture createTexture(const Image& image, TextureUnit unit = 0) {
return { {{ image.width, image.height }},
createTexture(image.width, image.height, image.data.get(), unit) };
}
// Creates an empty texture with the specified dimensions.
Texture createTexture(const std::array<uint16_t, 2>& size, TextureUnit unit = 0) {
return { size, createTexture(size[0], size[1], nullptr, unit) };
}
void bindTexture(Texture&,
TextureUnit = 0,
TextureFilter = TextureFilter::Nearest,
TextureMipMap = TextureMipMap::No);
// Actually remove the objects we marked as abandoned with the above methods.
// Only call this while the OpenGL context is exclusive to this thread.
void performCleanup();
@@ -79,6 +97,9 @@ public:
State<value::BindElementBuffer> elementBuffer;
State<value::BindVertexArray> vertexArrayObject;
private:
UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit);
private:
friend detail::ProgramDeleter;
friend detail::ShaderDeleter;

19
src/mbgl/gl/texture.hpp Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <mbgl/gl/object.hpp>
#include <array>
namespace mbgl {
namespace gl {
class Texture {
public:
std::array<uint16_t, 2> size;
UniqueTexture texture;
TextureFilter filter = TextureFilter::Nearest;
TextureMipMap mipmap = TextureMipMap::No;
};
} // namespace gl
} // namespace mbgl

View File

@@ -27,6 +27,9 @@ enum class BufferType : uint32_t {
Element = 0x8893
};
enum class TextureMipMap : bool { No = false, Yes = true };
enum class TextureFilter : bool { Nearest = false, Linear = true };
enum class StencilTestFunction : uint32_t {
Never = 0x0200,
Less = 0x0201,

View File

@@ -9,11 +9,13 @@ namespace mbgl {
using namespace style;
RasterBucket::RasterBucket(PremultipliedImage&& image_) : image(std::move(image_)) {
}
void RasterBucket::upload(gl::Context& context) {
if (hasData()) {
raster.upload(context, 0);
uploaded = true;
}
texture = context.createTexture(image);
image = {};
uploaded = true;
}
void RasterBucket::render(Painter& painter,
@@ -23,22 +25,19 @@ void RasterBucket::render(Painter& painter,
painter.renderRaster(parameters, *this, *layer.as<RasterLayer>(), tile);
}
void RasterBucket::setImage(PremultipliedImage image) {
raster.load(std::move(image));
}
void RasterBucket::drawRaster(RasterShader& shader,
StaticRasterVertexBuffer& vertices,
VertexArrayObject& array,
gl::Context& context) {
raster.bind(context, 0, Raster::Scaling::Linear);
raster.bind(context, 1, Raster::Scaling::Linear);
assert(texture);
context.bindTexture(*texture, 0, gl::TextureFilter::Linear);
context.bindTexture(*texture, 1, gl::TextureFilter::Linear);
array.bind(shader, vertices, BUFFER_OFFSET_0, context);
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)vertices.index()));
}
bool RasterBucket::hasData() const {
return raster.isLoaded();
return true;
}
bool RasterBucket::needsClipping() const {

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/util/raster.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/gl/context.hpp>
namespace mbgl {
@@ -12,16 +12,18 @@ class VertexArrayObject;
class RasterBucket : public Bucket {
public:
RasterBucket(PremultipliedImage&&);
void upload(gl::Context&) override;
void render(Painter&, PaintParameters&, const style::Layer&, const RenderTile&) override;
bool hasData() const override;
bool needsClipping() const override;
void setImage(PremultipliedImage);
void drawRaster(RasterShader&, StaticRasterVertexBuffer&, VertexArrayObject&, gl::Context&);
Raster raster;
private:
PremultipliedImage image;
optional<gl::Texture> texture;
};
} // namespace mbgl

View File

@@ -16,8 +16,7 @@ void RasterTileWorker::parse(std::shared_ptr<const std::string> data) {
}
try {
auto bucket = std::make_unique<RasterBucket>();
bucket->setImage(decodeImage(*data));
auto bucket = std::make_unique<RasterBucket>(decodeImage(*data));
parent.invoke(&RasterTile::onParsed, std::move(bucket));
} catch (...) {
parent.invoke(&RasterTile::setError, std::current_exception());

View File

@@ -10,16 +10,15 @@ void OffscreenTexture::bind(gl::Context& context,
std::array<uint16_t, 2> size) {
assert(size[0] > 0 && size[1] > 0);
if (raster.getSize() != size) {
raster.load(PremultipliedImage(size[0], size[1], nullptr));
raster.upload(context, 0);
if (!texture || texture->size != size) {
texture = context.createTexture(size);
}
if (!framebuffer) {
framebuffer = context.createFramebuffer();
context.bindFramebuffer = *framebuffer;
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
raster.getID(), 0));
texture->texture, 0));
GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -55,12 +54,17 @@ void OffscreenTexture::bind(gl::Context& context,
context.viewport = { 0, 0, size[0], size[1] };
}
Raster& OffscreenTexture::getTexture() {
return raster;
gl::Texture& OffscreenTexture::getTexture() {
return *texture;
}
std::array<uint16_t, 2> OffscreenTexture::getSize() const {
return raster.getSize();
if (texture) {
// Use explicit dereference instead of -> due to clang 3.5 bug
return (*texture).size;
} else {
return {{ 0, 0 }};
}
}
} // namespace mbgl

View File

@@ -1,6 +1,6 @@
#pragma once
#include <mbgl/util/raster.hpp>
#include <mbgl/gl/texture.hpp>
namespace mbgl {
@@ -12,12 +12,12 @@ class OffscreenTexture {
public:
void bind(gl::Context&, std::array<uint16_t, 2> size);
Raster& getTexture();
gl::Texture& getTexture();
std::array<uint16_t, 2> getSize() const;
private:
mbgl::optional<gl::UniqueFramebuffer> framebuffer;
Raster raster;
optional<gl::UniqueFramebuffer> framebuffer;
optional<gl::Texture> texture;
};
} // namespace mbgl

View File

@@ -1,96 +0,0 @@
#include <mbgl/platform/platform.hpp>
#include <mbgl/gl/gl.hpp>
#include <mbgl/gl/context.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/raster.hpp>
#include <cassert>
#include <cstring>
namespace mbgl {
bool Raster::isLoaded() const {
return loaded;
}
gl::TextureID Raster::getID() const {
return texture ? *texture : 0;
}
std::array<uint16_t, 2> Raster::getSize() const {
return size;
}
void Raster::load(PremultipliedImage image, uint32_t mipmapLevel) {
if (images.size() <= mipmapLevel) {
images.resize(mipmapLevel + 1);
}
images.at(mipmapLevel) = std::move(image);
loaded = true;
}
void Raster::bind(gl::Context& context,
uint32_t unit,
Scaling newFilter,
MipMap newMipMap) {
bool filterNeedsUpdate = false;
if (!texture) {
if (images.empty()) {
Log::Error(Event::OpenGL, "trying to bind texture without images");
return;
} else {
upload(context, unit);
filterNeedsUpdate = true;
}
} else {
if (context.texture[unit] != *texture) {
context.activeTexture = unit;
context.texture[unit] = *texture;
}
filterNeedsUpdate = (filter != newFilter || mipmap != newMipMap);
}
if (filterNeedsUpdate) {
filter = newFilter;
mipmap = newMipMap;
updateFilter();
}
}
void Raster::updateFilter() {
MBGL_CHECK_ERROR(glTexParameteri(
GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
filter == Scaling::Linear
? (mipmap == MipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR)
: (mipmap == MipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST)));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
filter == Scaling::Linear ? GL_LINEAR : GL_NEAREST));
}
void Raster::upload(gl::Context& context, uint32_t unit) {
if (!images.empty() && !texture) {
texture = context.createTexture();
context.activeTexture = unit;
context.texture[unit] = *texture;
updateFilter();
#if not MBGL_USE_GLES2
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, images.size()));
#endif // MBGL_USE_GLES2
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GLint level = 0;
for (auto& img : images) {
MBGL_CHECK_ERROR(glTexImage2D(
GL_TEXTURE_2D, level++, GL_RGBA, static_cast<GLsizei>(img.width),
static_cast<GLsizei>(img.height), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data.get()));
}
size = { { images.front().width, images.front().height } };
images.clear();
images.shrink_to_fit();
}
}
} // namespace mbgl

View File

@@ -1,62 +0,0 @@
#pragma once
#include <mbgl/gl/object.hpp>
#include <mbgl/util/image.hpp>
#include <mbgl/util/optional.hpp>
#include <atomic>
#include <array>
#include <vector>
namespace mbgl {
namespace gl {
class Context;
} // namespace gl
class Raster {
public:
enum class MipMap : bool { No = false, Yes = true };
enum class Scaling : bool { Nearest = false, Linear = true };
// load image data
void load(PremultipliedImage, uint32_t mipmapLevel = 0);
// bind current texture
void bind(gl::Context&,
uint32_t unit,
Scaling = Scaling::Nearest,
MipMap = MipMap::No);
// uploads the texture if it hasn't been uploaded yet.
void upload(gl::Context&, uint32_t unit);
// loaded status
bool isLoaded() const;
// returns the OpenGL texture ID
gl::TextureID getID() const;
// size of uploaded image.
std::array<uint16_t, 2> getSize() const;
private:
void updateFilter();
private:
// raw pixels have been loaded
std::atomic<bool> loaded { false };
std::array<uint16_t, 2> size = {{ 0, 0 }};
// filters
Scaling filter = Scaling::Nearest;
MipMap mipmap = MipMap::No;
// the raw pixels
std::vector<PremultipliedImage> images;
// GL buffer object handle.
mbgl::optional<gl::UniqueTexture> texture;
};
} // namespace mbgl

View File

@@ -4,7 +4,6 @@
#include <mbgl/platform/default/headless_view.hpp>
#include <mbgl/util/offscreen_texture.hpp>
#include <mbgl/util/raster.hpp>
using namespace mbgl;
@@ -137,7 +136,7 @@ void main() {
// Now, composite the Framebuffer texture we've rendered to onto the main FBO.
context.program = compositeShader.program;
texture.getTexture().bind(context, 0, Raster::Scaling::Linear);
context.bindTexture(texture.getTexture(), 0, gl::TextureFilter::Linear);
MBGL_CHECK_ERROR(glUniform1i(u_texture, 0));
MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, viewportBuffer.buffer));
MBGL_CHECK_ERROR(glEnableVertexAttribArray(compositeShader.a_pos));