[core] remove Raster object in favor of a more low-level Texture object
This commit is contained in:
committed by
John Firebaugh
parent
e103d92b18
commit
07315711d6
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
19
src/mbgl/gl/texture.hpp
Normal 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
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user