Topic/atlas tex 2d (#1194)

Co-authored-by: mwilsnd <mwilsnd@gmail.com>
This commit is contained in:
Tim Sylvester
2023-06-02 08:11:12 -07:00
committed by Bart Louwers
parent e771363d4b
commit 4cac8a8dfb
43 changed files with 552 additions and 190 deletions

View File

@@ -940,6 +940,7 @@ if(MLN_WITH_OPENGL)
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/prelude.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/background.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_background.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_background_pattern.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_circle.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline.hpp

View File

@@ -102,7 +102,7 @@ public:
/// @brief Attach the given texture to this drawable at the given sampler location.
/// @param texture Texture2D instance
/// @param location A sampler location in the shader being used with this drawable.
void setTexture(std::shared_ptr<gfx::Texture2D>& texture, int32_t location);
void setTexture(std::shared_ptr<gfx::Texture2D> texture, int32_t location);
/// not used for anything yet
DrawPriority getDrawPriority() const { return drawPriority; }

View File

@@ -11,6 +11,8 @@ struct Drawable::DrawSegment {
segment(std::move(segment_)) {}
const gfx::DrawMode& getMode() const { return mode; }
Segment<void>& getSegment() { return segment; }
const Segment<void>& getSegment() const { return segment; }
protected:

View File

@@ -50,6 +50,10 @@ public:
/// @return this
virtual Texture2D& setSize(Size size_) noexcept = 0;
/// @brief Get the size of the texture
/// @return Size of the texture
virtual Size getSize() const noexcept = 0;
/// @brief Determine the size of the buffer backing this texture
/// as configured, in bytes.
/// @return Size in bytes
@@ -63,17 +67,31 @@ public:
/// @return Channel count
virtual size_t numChannels() const noexcept = 0;
/// @brief Create the texture using the provided buffer.
/// @param pixelData Buffer of bytes to initialize the texture with
virtual void create(const std::vector<uint8_t>& pixelData, gfx::UploadPass& uploadPass) noexcept = 0;
/// @brief Create the texture with default initialized memory.
virtual void create() noexcept = 0;
/// @brief Upload image data to the texture resource
/// @param image Image data to transfer
/// @param uploadPass Upload pass to orchestrate upload
virtual void upload(const PremultipliedImage& image, gfx::UploadPass& uploadPass) const noexcept = 0;
/// @param pixelData Image data to transfer
virtual void upload(const void* pixelData, const Size& size_) noexcept = 0;
template <typename Image>
void upload(const Image& img) noexcept {
setFormat(Image::channels == 1 ? gfx::TexturePixelType::Alpha : gfx::TexturePixelType::RGBA,
gfx::TextureChannelDataType::UnsignedByte);
upload(&img.data[0], img.size);
}
virtual void uploadSubRegion(const void* pixelData,
const Size& size,
uint16_t xOffset,
uint16_t yOffset) noexcept = 0;
template <typename Image>
void uploadSubRegion(const Image& img, uint16_t xOffset, uint16_t yOffset) noexcept {
assert(Image::channels == numChannels());
assert(Image::channels == getPixelStride());
assert(img.size.width + xOffset <= getSize().width);
assert(img.size.height + yOffset <= getSize().height);
uploadSubRegion(&img.data[0], img.size, xOffset, yOffset);
}
/// @brief Get the underlying GL texture resource
/// @note: Compat with legacy textures, to be refactored

View File

@@ -51,8 +51,7 @@ public:
const std::shared_ptr<UniformBuffer>& get(const std::string& name) const;
/// Add a new uniform buffer element or replace the existing one.
const std::shared_ptr<UniformBuffer>& addOrReplace(std::string name,
const std::shared_ptr<UniformBuffer>& uniformBuffer);
const std::shared_ptr<UniformBuffer>& addOrReplace(std::string name, std::shared_ptr<UniformBuffer> uniformBuffer);
UniformBufferArray& operator=(UniformBufferArray&&);
UniformBufferArray& operator=(const UniformBufferArray&);

View File

@@ -15,7 +15,6 @@ class Segment;
namespace gfx {
class Context;
class IndexBuffer;
class UploadPass;
class VertexBufferResource;
@@ -51,7 +50,7 @@ public:
/// Reset a single color attribute for all vertexes
void resetColor(const Color&) override;
void upload(gfx::Context&, gfx::UploadPass&);
void upload(gfx::UploadPass&);
protected:
class Impl;

View File

@@ -13,7 +13,7 @@ public:
TileLayerGroupGL(int32_t layerIndex, std::size_t initialCapacity);
~TileLayerGroupGL() override {}
void upload(gfx::Context&, gfx::UploadPass&) override;
void upload(gfx::UploadPass&) override;
void render(RenderOrchestrator&, PaintParameters&) override;
protected:

View File

@@ -24,24 +24,31 @@ public: // gfx::Texture2D
Texture2D& setSize(Size size_) noexcept override;
Size getSize() const noexcept override { return size; }
size_t getDataSize() const noexcept override;
size_t getPixelStride() const noexcept override;
size_t numChannels() const noexcept override;
void create(const std::vector<uint8_t>& pixelData, gfx::UploadPass& uploadPass) noexcept override;
void create() noexcept override;
void upload(const PremultipliedImage& image, gfx::UploadPass& uploadPass) const noexcept override;
void upload(const void* pixelData, const Size& size_) noexcept override;
void uploadSubRegion(const void* pixelData, const Size& size, uint16_t xOffset, uint16_t yOffset) noexcept override;
gfx::TextureResource& getResource() override { return *textureResource; }
gfx::TextureResource& getResource() override {
assert(textureResource);
return *textureResource;
}
public:
/// @brief Get the OpenGL handle ID for the underlying resource
/// @return GLuint
platform::GLuint getTextureID() const noexcept;
void updateSamplerConfiguration() noexcept;
/// @brief Bind this texture to the specified texture unit
/// @param location Location index of texture sampler in a shader
/// @param textureUnit Unit to bind to. A maximum of gl::MaxActiveTextureUnits
@@ -60,7 +67,7 @@ private:
gfx::TextureChannelDataType channelType;
Size size{0, 0};
mutable bool samplerStateDirty{false};
bool samplerStateDirty{false};
int32_t boundTextureUnit{-1};
int32_t boundLocation{-1};

View File

@@ -44,7 +44,7 @@ public:
/// Called before starting each frame
virtual void preRender(RenderOrchestrator&, PaintParameters&) {}
/// Called during the upload pass
virtual void upload(gfx::Context&, gfx::UploadPass&) {}
virtual void upload(gfx::UploadPass&) {}
/// Called during each render pass
virtual void render(RenderOrchestrator&, PaintParameters&) {}
/// Called at the end of each frame

View File

@@ -0,0 +1,85 @@
// Generated code, do not modify this file!
#pragma once
#include <mbgl/shaders/shader_source.hpp>
namespace mbgl {
namespace shaders {
template <>
struct ShaderSource<BuiltIn::BackgroundPatternShader, gfx::Backend::Type::OpenGL> {
static constexpr const char* name = "BackgroundPatternShader";
static constexpr const char* vertex = R"(layout (std140) uniform BackgroundDrawableUBO {
highp mat4 u_matrix;
};
layout (std140) uniform BackgroundLayerUBO {
highp vec2 u_pattern_tl_a;
highp vec2 u_pattern_br_a;
highp vec2 u_pattern_tl_b;
highp vec2 u_pattern_br_b;
highp vec2 u_texsize;
highp vec2 u_pattern_size_a;
highp vec2 u_pattern_size_b;
highp vec2 u_pixel_coord_upper;
highp vec2 u_pixel_coord_lower;
highp float u_tile_units_to_pixels;
highp float u_scale_a;
highp float u_scale_b;
highp float u_mix;
highp float u_opacity;
highp float pad;
};
layout (location = 0) in vec2 a_pos;
out mediump vec2 v_pos_a;
out mediump vec2 v_pos_b;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
}
)";
static constexpr const char* fragment = R"(layout (std140) uniform BackgroundLayerUBO {
highp vec2 u_pattern_tl_a;
highp vec2 u_pattern_br_a;
highp vec2 u_pattern_tl_b;
highp vec2 u_pattern_br_b;
highp vec2 u_texsize;
highp vec2 u_pattern_size_a;
highp vec2 u_pattern_size_b;
highp vec2 u_pixel_coord_upper;
highp vec2 u_pixel_coord_lower;
highp float u_tile_units_to_pixels;
highp float u_scale_a;
highp float u_scale_b;
highp float u_mix;
highp float u_opacity;
highp float pad;
};
uniform sampler2D u_image;
in mediump vec2 v_pos_a;
in mediump vec2 v_pos_b;
void main() {
vec2 imagecoord = mod(v_pos_a, 1.0);
vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord);
vec4 color1 = texture(u_image, pos);
vec2 imagecoord_b = mod(v_pos_b, 1.0);
vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b);
vec4 color2 = texture(u_image, pos2);
fragColor = mix(color1, color2, u_mix) * u_opacity;
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
#endif
}
)";
};
} // namespace shaders
} // namespace mbgl

View File

@@ -4,6 +4,7 @@
#ifdef MBGL_RENDER_BACKEND_OPENGL
#include <mbgl/shaders/gl/drawable_background.hpp>
#include <mbgl/shaders/gl/drawable_background_pattern.hpp>
#include <mbgl/shaders/gl/drawable_circle.hpp>
#include <mbgl/shaders/gl/drawable_fill.hpp>
#include <mbgl/shaders/gl/drawable_fill_outline.hpp>

View File

@@ -10,6 +10,7 @@ namespace shaders {
enum class BuiltIn {
None,
BackgroundShader,
BackgroundPatternShader,
CircleShader,
FillShader,
FillOutlineShader,

View File

@@ -0,0 +1,38 @@
layout (std140) uniform BackgroundLayerUBO {
highp vec2 u_pattern_tl_a;
highp vec2 u_pattern_br_a;
highp vec2 u_pattern_tl_b;
highp vec2 u_pattern_br_b;
highp vec2 u_texsize;
highp vec2 u_pattern_size_a;
highp vec2 u_pattern_size_b;
highp vec2 u_pixel_coord_upper;
highp vec2 u_pixel_coord_lower;
highp float u_tile_units_to_pixels;
highp float u_scale_a;
highp float u_scale_b;
highp float u_mix;
highp float u_opacity;
highp float pad;
};
uniform sampler2D u_image;
in mediump vec2 v_pos_a;
in mediump vec2 v_pos_b;
void main() {
vec2 imagecoord = mod(v_pos_a, 1.0);
vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord);
vec4 color1 = texture(u_image, pos);
vec2 imagecoord_b = mod(v_pos_b, 1.0);
vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b);
vec4 color2 = texture(u_image, pos2);
fragColor = mix(color1, color2, u_mix) * u_opacity;
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
#endif
}

View File

@@ -0,0 +1,31 @@
layout (std140) uniform BackgroundDrawableUBO {
highp mat4 u_matrix;
};
layout (std140) uniform BackgroundLayerUBO {
highp vec2 u_pattern_tl_a;
highp vec2 u_pattern_br_a;
highp vec2 u_pattern_tl_b;
highp vec2 u_pattern_br_b;
highp vec2 u_texsize;
highp vec2 u_pattern_size_a;
highp vec2 u_pattern_size_b;
highp vec2 u_pixel_coord_upper;
highp vec2 u_pixel_coord_lower;
highp float u_tile_units_to_pixels;
highp float u_scale_a;
highp float u_scale_b;
highp float u_mix;
highp float u_opacity;
highp float pad;
};
layout (location = 0) in vec2 a_pos;
out mediump vec2 v_pos_a;
out mediump vec2 v_pos_b;
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos);
v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos);
}

View File

@@ -6,6 +6,13 @@
"glsl_frag": "drawable.background.fragment.glsl",
"uses_ubos": true
},
{
"name": "BackgroundPatternShader",
"header": "drawable_background_pattern",
"glsl_vert": "drawable.background_pattern.vertex.glsl",
"glsl_frag": "drawable.background_pattern.fragment.glsl",
"uses_ubos": true
},
{
"name": "CircleShader",
"header": "drawable_circle",

View File

@@ -28,12 +28,14 @@ class DrawableTweaker;
class OffscreenTexture;
class ShaderProgramBase;
class ShaderRegistry;
class Texture2D;
using DrawablePtr = std::shared_ptr<Drawable>;
using UniqueDrawableBuilder = std::unique_ptr<DrawableBuilder>;
using DrawableTweakerPtr = std::shared_ptr<DrawableTweaker>;
using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
using ShaderProgramBasePtr = std::shared_ptr<ShaderProgramBase>;
using Texture2DPtr = std::shared_ptr<Texture2D>;
class Context {
protected:
@@ -115,6 +117,9 @@ public:
/// Create a layer group implementation
virtual TileLayerGroupPtr createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity) = 0;
/// Create a texture
virtual Texture2DPtr createTexture2D() = 0;
};
} // namespace gfx

View File

@@ -27,14 +27,14 @@ void Drawable::setCullFaceMode(const gfx::CullFaceMode& value) {
impl->cullFaceMode = value;
}
void Drawable::setTexture(std::shared_ptr<gfx::Texture2D>& texture, int32_t location) {
void Drawable::setTexture(std::shared_ptr<gfx::Texture2D> texture, int32_t location) {
for (auto& tex : textures) {
if (tex.location == location) {
tex.texture = texture;
tex.texture = std::move(texture);
return;
}
}
textures.emplace_back(texture, location);
textures.emplace_back(std::move(texture), location);
}
void Drawable::removeTexture(int32_t location) {

View File

@@ -120,6 +120,13 @@ void DrawableBuilder::addTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1
if (colorAttrMode == ColorAttrMode::PerVertex) {
impl->colors.insert(impl->colors.end(), 3, impl->currentColor);
}
if (impl->segments.empty()) {
impl->segments.emplace_back(createSegment(gfx::Triangles(), {0, 0}));
}
auto& segment = impl->segments.back();
segment->getSegment().vertexLength += 3;
segment->getSegment().indexLength += 3;
}
void DrawableBuilder::appendTriangle(int16_t x0, int16_t y0) {
@@ -129,6 +136,11 @@ void DrawableBuilder::appendTriangle(int16_t x0, int16_t y0) {
if (colorAttrMode == ColorAttrMode::PerVertex) {
impl->colors.emplace_back(impl->currentColor);
}
assert(!impl->segments.empty());
auto& segment = impl->segments.back();
segment->getSegment().vertexLength += 1;
segment->getSegment().indexLength += 3;
}
void DrawableBuilder::addQuad(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {

View File

@@ -29,8 +29,8 @@ const std::shared_ptr<UniformBuffer>& UniformBufferArray::get(const std::string&
return (result != uniformBufferMap.end()) ? result->second : nullref;
}
const std::shared_ptr<UniformBuffer>& UniformBufferArray::addOrReplace(
std::string name, const std::shared_ptr<UniformBuffer>& uniformBuffer) {
const std::shared_ptr<UniformBuffer>& UniformBufferArray::addOrReplace(std::string name,
std::shared_ptr<UniformBuffer> uniformBuffer) {
const auto result = uniformBufferMap.insert(std::make_pair(std::move(name), std::shared_ptr<UniformBuffer>()));
result.first->second = std::move(uniformBuffer);
return result.first->second;

View File

@@ -7,6 +7,7 @@
#include <mbgl/gfx/index_vector.hpp>
#include <mbgl/gfx/index_buffer.hpp>
#include <mbgl/gfx/texture.hpp>
#include <mbgl/gfx/texture2d.hpp>
#include <mbgl/util/size.hpp>
#include <mbgl/util/image.hpp>
@@ -20,6 +21,7 @@ class Texture2D;
class VertexAttributeArray;
using AttributeBindingArray = std::vector<std::optional<gfx::AttributeBinding>>;
using Texture2DPtr = std::shared_ptr<Texture2D>;
class UploadPass {
protected:
@@ -36,6 +38,9 @@ public:
DebugGroup<UploadPass> createDebugGroup(const char* name) { return {*this, name}; }
virtual Context& getContext() = 0;
virtual const Context& getContext() const = 0;
public:
template <class Vertex>
VertexBuffer<Vertex> createVertexBuffer(VertexVector<Vertex>&& v,
@@ -92,7 +97,7 @@ public:
void updateTexture(Texture& texture,
const Image& image,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTextureResource(texture.getResource(), image.size, image.data.get(), format, type);
texture.size = image.size;
}
@@ -105,7 +110,27 @@ public:
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;
const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type);
}
template <typename Image>
void updateTexture(Texture2D& texture,
const Image& image,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTexture2D(texture, image.size, image.data.get(), format, type);
}
template <typename Image>
void updateTextureSub(Texture2D& texture,
const Image& image,
const uint16_t offsetX,
const uint16_t offsetY,
TextureChannelDataType type = TextureChannelDataType::UnsignedByte) {
assert(image.size.width + offsetX <= texture.getSize().width);
assert(image.size.height + offsetY <= texture.getSize().height);
const auto format = image.channels == 4 ? TexturePixelType::RGBA : TexturePixelType::Alpha;
updateTextureResourceSub(texture.getResource(), offsetX, offsetY, image.size, image.data.get(), format, type);
}
@@ -116,6 +141,7 @@ public:
TextureChannelDataType) = 0;
virtual void updateTextureResource(
TextureResource&, Size, const void* data, TexturePixelType, TextureChannelDataType) = 0;
virtual void updateTextureResourceSub(TextureResource&,
uint16_t xOffset,
uint16_t yOffset,
@@ -123,8 +149,6 @@ public:
const void* data,
TexturePixelType,
TextureChannelDataType) = 0;
virtual std::shared_ptr<gfx::Texture2D> createTexture2D(const PremultipliedImage& image) = 0;
};
} // namespace gfx

View File

@@ -475,6 +475,10 @@ TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t
return std::make_shared<TileLayerGroupGL>(layerIndex, initialCapacity);
}
gfx::Texture2DPtr Context::createTexture2D() {
return std::make_shared<gl::Texture2D>(*this);
}
void Context::clear(std::optional<mbgl::Color> color, std::optional<float> depth, std::optional<int32_t> stencil) {
GLbitfield mask = 0;
@@ -603,10 +607,10 @@ void Context::performCleanup() {
// TODO: Find a better way to unbind VAOs after we're done with them without
// introducing unnecessary bind(0)/bind(N) sequences.
{
activeTextureUnit = 1;
texture[1] = 0;
activeTextureUnit = 0;
texture[0] = 0;
for (auto i = 0; i < gfx::MaxActiveTextureUnits; i++) {
activeTextureUnit = i;
texture[i] = 0;
}
bindVertexArray = 0;
}

View File

@@ -111,6 +111,8 @@ public:
TileLayerGroupPtr createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity) override;
gfx::Texture2DPtr createTexture2D() override;
private:
RendererBackend& backend;
bool cleanupOnDestruction = true;

View File

@@ -126,7 +126,7 @@ void DrawableGL::unbindUniformBuffers() const {
}
}
void DrawableGL::upload(gfx::Context& context, gfx::UploadPass& uploadPass) {
void DrawableGL::upload(gfx::UploadPass& uploadPass) {
if (!shader) {
return;
}
@@ -137,6 +137,7 @@ void DrawableGL::upload(gfx::Context& context, gfx::UploadPass& uploadPass) {
});
if (build) {
auto& context = uploadPass.getContext();
auto& glContext = static_cast<gl::Context&>(context);
constexpr auto usage = gfx::BufferUsageType::StaticDraw;

View File

@@ -15,7 +15,7 @@ namespace gl {
TileLayerGroupGL::TileLayerGroupGL(int32_t layerIndex_, std::size_t initialCapacity)
: TileLayerGroup(layerIndex_, initialCapacity) {}
void TileLayerGroupGL::upload(gfx::Context& context, gfx::UploadPass& uploadPass) {
void TileLayerGroupGL::upload(gfx::UploadPass& uploadPass) {
observeDrawables([&](gfx::Drawable& drawable) {
auto& drawableGL = static_cast<gl::DrawableGL&>(drawable);
@@ -28,7 +28,7 @@ void TileLayerGroupGL::upload(gfx::Context& context, gfx::UploadPass& uploadPass
const auto debugGroup = uploadPass.createDebugGroup(labelPtr);
#endif
drawableGL.upload(context, uploadPass);
drawableGL.upload(uploadPass);
});
}

View File

@@ -94,6 +94,7 @@ void registerTypes(gfx::ShaderRegistry& registry, gl::Context& glContext, const
void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramParameters& programParameters) {
registerTypes<shaders::BuiltIn::BackgroundShader,
shaders::BuiltIn::BackgroundPatternShader,
shaders::BuiltIn::CircleShader,
shaders::BuiltIn::FillShader,
shaders::BuiltIn::FillOutlineShader,

View File

@@ -23,6 +23,11 @@ Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_)
}
Texture2D& Texture2D::setFormat(gfx::TexturePixelType pixelFormat_, gfx::TextureChannelDataType channelType_) noexcept {
if (pixelFormat_ == pixelFormat && channelType_ == channelType) {
return *this;
}
assert(!textureResource);
pixelFormat = pixelFormat_;
channelType = channelType_;
return *this;
@@ -52,56 +57,61 @@ size_t Texture2D::numChannels() const noexcept {
switch (pixelFormat) {
case gfx::TexturePixelType::RGBA:
return 4;
case gfx::TexturePixelType::Alpha:
return 1;
default:
return 0;
}
}
void Texture2D::create(const std::vector<uint8_t>& pixelData, gfx::UploadPass& uploadPass) noexcept {
assert(!textureResource);
textureResource = uploadPass.createTextureResource(size, pixelData.data(), pixelFormat, channelType);
}
void Texture2D::create() noexcept {
assert(!textureResource);
textureResource = context.createTextureResource(size, pixelFormat, channelType);
auto obj = context.createUniqueTexture();
const auto storageSize = gl::TextureResource::getStorageSize(size, pixelFormat, channelType);
context.renderingStats().memTextures += storageSize;
// @TODO: TextureResource is still needed while we have legacy rendering pathways
textureResource = std::make_unique<gl::TextureResource>(std::move(obj), storageSize);
}
platform::GLuint Texture2D::getTextureID() const noexcept {
return static_cast<gl::TextureResource&>(*textureResource).texture;
}
void Texture2D::updateSamplerConfiguration() noexcept {
using namespace platform;
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
samplerState.minification == gfx::TextureFilterType::Nearest ? GL_NEAREST : GL_LINEAR));
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER,
samplerState.magnification == gfx::TextureFilterType::Nearest ? GL_NEAREST : GL_LINEAR));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_S,
samplerState.wrapU == gfx::TextureWrapType::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_T,
samplerState.wrapV == gfx::TextureWrapType::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
}
void Texture2D::bind(int32_t location, int32_t textureUnit) noexcept {
using namespace platform;
assert(gfx::MaxActiveTextureUnits > textureUnit);
if (gfx::MaxActiveTextureUnits > textureUnit) return;
if (gfx::MaxActiveTextureUnits <= textureUnit) return;
// Bind to the texture unit
context.activeTextureUnit = static_cast<uint8_t>(textureUnit);
context.texture[static_cast<size_t>(textureUnit)] = getTextureID();
boundTextureUnit = textureUnit;
// Update the sampler state if it was changed after resource creation
if (samplerStateDirty) {
samplerStateDirty = false;
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER,
samplerState.minification == gfx::TextureFilterType::Nearest ? GL_NEAREST : GL_LINEAR));
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER,
samplerState.magnification == gfx::TextureFilterType::Nearest ? GL_NEAREST : GL_LINEAR));
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_S,
samplerState.wrapU == gfx::TextureWrapType::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
MBGL_CHECK_ERROR(
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_T,
samplerState.wrapV == gfx::TextureWrapType::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT));
updateSamplerConfiguration();
}
// Link the bound texture unit with the requested sampler in the active shader
@@ -126,18 +136,55 @@ void Texture2D::unbind() noexcept {
}
}
void Texture2D::upload(const PremultipliedImage& image, gfx::UploadPass& uploadPass) const noexcept {
void Texture2D::upload(const void* pixelData, const Size& size_) noexcept {
using namespace platform;
if (!textureResource) {
create();
}
assert(textureResource);
assert(image.size == size);
if (image.size != size) {
return;
// Bind to TU 0 and upload
context.activeTextureUnit = 0;
context.texture[0] = getTextureID();
if (samplerStateDirty) {
updateSamplerConfiguration();
}
assert(PremultipliedImage::channels == numChannels());
// note: images are always unsigned bytes
assert(PremultipliedImage::channels == getPixelStride());
if (size_ == Size{0, 0} || size_ != size) {
size = size_;
MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D,
0,
Enum<gfx::TexturePixelType>::to(pixelFormat),
size.width,
size.height,
0,
Enum<gfx::TexturePixelType>::to(pixelFormat),
Enum<gfx::TextureChannelDataType>::to(channelType),
pixelData));
} else {
uploadSubRegion(pixelData, size, 0, 0);
}
}
uploadPass.updateTextureResource(*textureResource, size, &image.data[0], pixelFormat, channelType);
void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16_t xOffset, uint16_t yOffset) noexcept {
using namespace platform;
assert(textureResource);
assert(!samplerStateDirty);
// Bind to TU 0 and upload
context.activeTextureUnit = 0;
context.texture[0] = getTextureID();
MBGL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D,
0,
xOffset,
yOffset,
size_.width,
size_.height,
Enum<gfx::TexturePixelType>::to(pixelFormat),
Enum<gfx::TextureChannelDataType>::to(channelType),
pixelData));
}
} // namespace gl

View File

@@ -68,10 +68,9 @@ std::unique_ptr<gfx::TextureResource> UploadPass::createTextureResource(const Si
gfx::TexturePixelType format,
gfx::TextureChannelDataType type) {
auto obj = commandEncoder.context.createUniqueTexture();
int textureByteSize = gl::TextureResource::getStorageSize(size, format, type);
const int textureByteSize = gl::TextureResource::getStorageSize(size, format, type);
commandEncoder.context.renderingStats().memTextures += textureByteSize;
std::unique_ptr<gfx::TextureResource> resource = std::make_unique<gl::TextureResource>(std::move(obj),
textureByteSize);
auto resource = std::make_unique<gl::TextureResource>(std::move(obj), textureByteSize);
commandEncoder.context.pixelStoreUnpack = {1};
updateTextureResource(*resource, size, data, format, type);
// We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT
@@ -210,13 +209,6 @@ gfx::AttributeBindingArray UploadPass::buildAttributeBindings(
return {};
}
std::shared_ptr<gfx::Texture2D> UploadPass::createTexture2D(const PremultipliedImage& image) {
auto tex = std::make_shared<gl::Texture2D>(commandEncoder.context);
tex->setSize(image.size).setFormat(gfx::TexturePixelType::RGBA, gfx::TextureChannelDataType::UnsignedByte).create();
tex->upload(image, *this);
return tex;
}
void UploadPass::pushDebugGroup(const char* name) {
commandEncoder.pushDebugGroup(name);
}
@@ -225,5 +217,13 @@ void UploadPass::popDebugGroup() {
commandEncoder.popDebugGroup();
}
gfx::Context& UploadPass::getContext() {
return commandEncoder.context;
}
const gfx::Context& UploadPass::getContext() const {
return commandEncoder.context;
}
} // namespace gl
} // namespace mbgl

View File

@@ -26,6 +26,9 @@ private:
void popDebugGroup() override;
public:
gfx::Context& getContext() override;
const gfx::Context& getContext() const override;
std::unique_ptr<gfx::VertexBufferResource> createVertexBufferResource(const void* data,
std::size_t size,
gfx::BufferUsageType) override;
@@ -49,6 +52,7 @@ public:
gfx::TextureChannelDataType) override;
void updateTextureResource(
gfx::TextureResource&, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override;
void updateTextureResourceSub(gfx::TextureResource&,
uint16_t xOffset,
uint16_t yOffset,
@@ -57,8 +61,6 @@ public:
gfx::TexturePixelType,
gfx::TextureChannelDataType) override;
std::shared_ptr<gfx::Texture2D> createTexture2D(const PremultipliedImage& image) override;
private:
gl::CommandEncoder& commandEncoder;
const gfx::DebugGroup<gfx::CommandEncoder> debugGroup;

View File

@@ -1,9 +1,11 @@
#include <mbgl/renderer/layers/background_layer_tweaker.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/style/layers/background_layer_properties.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/pattern_atlas.hpp>
#include <mbgl/style/layers/background_layer_properties.hpp>
#include <mbgl/util/convert.hpp>
namespace mbgl {
@@ -16,53 +18,116 @@ struct alignas(16) BackgroundDrawableUBO {
static_assert(sizeof(BackgroundDrawableUBO) % 16 == 0);
struct alignas(16) BackgroundLayerUBO {
Color color;
float opacity;
float padding[3];
/* 0 */ Color color;
/* 16 */ float opacity;
/* 20 */ std::array<float, 3> pad;
/* 32 */
};
static_assert(sizeof(BackgroundLayerUBO) % 16 == 0);
static_assert(sizeof(BackgroundLayerUBO) == 32);
struct alignas(16) BackgroundPatternLayerUBO {
std::array<float, 2> pattern_tl_a;
std::array<float, 2> pattern_br_a;
std::array<float, 2> pattern_tl_b;
std::array<float, 2> pattern_br_b;
std::array<float, 2> texsize;
std::array<float, 2> pattern_size_a;
std::array<float, 2> pattern_size_b;
std::array<float, 2> pixel_coord_upper;
std::array<float, 2> pixel_coord_lower;
float tile_units_to_pixels;
float scale_a;
float scale_b;
float mix;
float opacity;
/* 0 */ std::array<float, 2> pattern_tl_a;
/* 8 */ std::array<float, 2> pattern_br_a;
/* 16 */ std::array<float, 2> pattern_tl_b;
/* 24 */ std::array<float, 2> pattern_br_b;
/* 32 */ std::array<float, 2> texsize;
/* 40 */ std::array<float, 2> pattern_size_a;
/* 48 */ std::array<float, 2> pattern_size_b;
/* 56 */ std::array<float, 2> pixel_coord_upper;
/* 64 */ std::array<float, 2> pixel_coord_lower;
/* 72 */ float tile_units_to_pixels;
/* 76 */ float scale_a;
/* 80 */ float scale_b;
/* 84 */ float mix;
/* 88 */ float opacity;
/* 92 */ std::array<float, 1> pad;
/* 96 */
};
static_assert(sizeof(BackgroundPatternLayerUBO) % 16 == 0);
static_assert(sizeof(BackgroundPatternLayerUBO) == 96);
void BackgroundLayerTweaker::execute(LayerGroup& layerGroup, const RenderTree&, const PaintParameters& parameters) {
const auto& state = parameters.state;
const auto& evaluated = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).evaluated;
const auto& crossfade = static_cast<const BackgroundLayerProperties&>(*evaluatedProperties).crossfade;
if (!layerUniformBuffer) {
BackgroundLayerUBO layerUBO;
layerUBO.color = evaluated.get<BackgroundColor>();
layerUBO.opacity = evaluated.get<BackgroundOpacity>();
layerUniformBuffer = parameters.context.createUniformBuffer(&layerUBO, sizeof(layerUBO));
const bool hasPattern = !evaluated.get<BackgroundPattern>().to.empty();
const std::optional<ImagePosition> imagePosA = hasPattern ? parameters.patternAtlas.getPattern(
evaluated.get<BackgroundPattern>().from.id())
: std::nullopt;
const std::optional<ImagePosition> imagePosB = hasPattern ? parameters.patternAtlas.getPattern(
evaluated.get<BackgroundPattern>().to.id())
: std::nullopt;
if (hasPattern && (!imagePosA || !imagePosB)) {
return;
}
if (!shader) {
shader = parameters.context.getGenericShader(parameters.shaders, "BackgroundShader");
}
if (!patternShader) {
patternShader = parameters.context.getGenericShader(parameters.shaders, "BackgroundPatternShader");
}
const auto& curShader = hasPattern ? patternShader : shader;
if (!curShader) {
return;
}
layerGroup.observeDrawables([&](gfx::Drawable& drawable) {
drawable.mutableUniformBuffers().addOrReplace("BackgroundLayerUBO", layerUniformBuffer);
if (!drawable.getTileID()) {
return;
}
assert(drawable.getTileID());
const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped();
const auto matrix = parameters.matrixForTile(tileID);
drawable.setShader(curShader);
BackgroundDrawableUBO drawableUBO;
drawableUBO.matrix = util::cast<float>(matrix);
auto drawableUniformBuffer = parameters.context.createUniformBuffer(&drawableUBO, sizeof(drawableUBO));
drawable.mutableUniformBuffers().addOrReplace("BackgroundDrawableUBO", drawableUniformBuffer);
drawable.mutableUniformBuffers().addOrReplace("BackgroundDrawableUBO", std::move(drawableUniformBuffer));
gfx::UniformBufferPtr layerUniformBuffer;
if (hasPattern) {
// TODO: add when raster is merged
// curShader->getSamplerLocation("u_image");
drawable.setTexture(parameters.patternAtlas.texture(), 0);
// from BackgroundPatternProgram::layoutUniformValues
const int32_t tileSizeAtNearestZoom = static_cast<int32_t>(
util::tileSize_D * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z));
const int32_t pixelX = static_cast<int32_t>(
tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z)));
const int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y;
const Size atlasSize = parameters.patternAtlas.getPixelSize();
const auto pixToTile = tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom());
const BackgroundPatternLayerUBO layerUBO = {
/* .pattern_tl_a = */ util::cast<float>(imagePosA->tl()),
/* .pattern_br_a = */ util::cast<float>(imagePosA->br()),
/* .pattern_tl_b = */ util::cast<float>(imagePosB->tl()),
/* .pattern_br_b = */ util::cast<float>(imagePosB->br()),
/* .texsize = */ {static_cast<float>(atlasSize.width), static_cast<float>(atlasSize.height)},
/* .pattern_size_a = */ imagePosA->displaySize(),
/* .pattern_size_b = */ imagePosB->displaySize(),
/* .pixel_coord_upper = */ {static_cast<float>(pixelX >> 16), static_cast<float>(pixelY >> 16)},
/* .pixel_coord_lower = */ {static_cast<float>(pixelX & 0xFFFF), static_cast<float>(pixelY & 0xFFFF)},
/* .tile_units_to_pixels = */ (pixToTile != 0) ? 1.0f / pixToTile : 0.0f,
/* .scale_a = */ crossfade.fromScale,
/* .scale_b = */ crossfade.toScale,
/* .mix = */ crossfade.t,
/* .opacity = */ evaluated.get<BackgroundOpacity>(),
/* .pad = */ {0},
};
// TODO: Update UBOs in-place
layerUniformBuffer = parameters.context.createUniformBuffer(&layerUBO, sizeof(layerUBO));
} else {
const BackgroundLayerUBO layerUBO = {
/* .color = */ evaluated.get<BackgroundColor>(),
/* .opacity = */ evaluated.get<BackgroundOpacity>(),
/* .pad = */ {0, 0, 0},
};
layerUniformBuffer = parameters.context.createUniformBuffer(&layerUBO, sizeof(layerUBO));
}
drawable.mutableUniformBuffers().addOrReplace("BackgroundLayerUBO", std::move(layerUniformBuffer));
});
}

View File

@@ -2,10 +2,15 @@
#include <mbgl/renderer/layer_tweaker.hpp>
#include <memory>
namespace mbgl {
namespace gfx {
class ShaderProgramBase;
class UniformBuffer;
using ShaderProgramBasePtr = std::shared_ptr<ShaderProgramBase>;
using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
} // namespace gfx
@@ -23,7 +28,8 @@ public:
void execute(LayerGroup&, const RenderTree&, const PaintParameters&) override;
protected:
gfx::UniformBufferPtr layerUniformBuffer = nullptr;
gfx::ShaderProgramBasePtr shader;
gfx::ShaderProgramBasePtr patternShader;
};
} // namespace mbgl

View File

@@ -2,7 +2,6 @@
#include <mbgl/renderer/layers/background_layer_tweaker.hpp>
#include <mbgl/gfx/context.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
#include <mbgl/gfx/shader_registry.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/programs/programs.hpp>
@@ -206,17 +205,13 @@ void RenderBackgroundLayer::layerRemoved(UniqueChangeRequestVec& changes) {
}
}
void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
void RenderBackgroundLayer::update(gfx::ShaderRegistry& /*shaders*/,
gfx::Context& context,
const TransformState& state,
[[maybe_unused]] const RenderTree& renderTree,
[[maybe_unused]] UniqueChangeRequestVec& changes) {
std::unique_lock<std::mutex> guard(mutex);
if (!shader) {
shader = context.getGenericShader(shaders, "BackgroundShader");
}
const auto removeAll = [&]() {
if (tileLayerGroup) {
stats.tileDrawablesRemoved += tileLayerGroup->getDrawableCount();
@@ -228,7 +223,6 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
const auto tileCover = util::tileCover(state, zoom);
// renderTiles is always empty, we use tileCover instead
// if (!renderTiles || renderTiles->empty()) {
if (tileCover.empty()) {
removeAll();
return;
@@ -245,9 +239,6 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
: RenderPass::Opaque |
RenderPass::Translucent; // evaluated based on opaquePassCutoff in render()
// unevaluated.hasTransition();
// getCrossfade<BackgroundLayerProperties>(evaluatedProperties).t != 1;
// If the result is transparent or missing, just remove any existing drawables and stop
if (drawPasses == RenderPass::None) {
removeAll();
@@ -284,7 +275,6 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
});
// For each tile in the cover set, add a tile drawable if one doesn't already exist.
// We currently assume only one drawable per tile.
for (const auto& tileID : tileCover) {
// If we already have drawables for this tile, skip.
// If a drawable needs to be updated, that's handled in the layer tweaker.
@@ -296,7 +286,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
if (!builder) {
builder = context.createDrawableBuilder("background");
builder->setRenderPass(drawPasses);
builder->setShader(shader);
// builder->setShader(shader);
builder->setColorAttrMode(gfx::DrawableBuilder::ColorAttrMode::PerDrawable);
builder->setDepthType(gfx::DepthMaskType::ReadWrite);
}
@@ -306,9 +296,7 @@ void RenderBackgroundLayer::update(gfx::ShaderRegistry& shaders,
builder->flush();
auto newDrawables = builder->clearDrawables();
if (!newDrawables.empty()) {
auto& drawable = newDrawables[0];
for (auto& drawable : builder->clearDrawables()) {
drawable->setTileID(tileID);
tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable));
++stats.tileDrawablesAdded;

View File

@@ -48,8 +48,6 @@ private:
// Programs
std::shared_ptr<BackgroundProgram> backgroundProgram;
std::shared_ptr<BackgroundPatternProgram> backgroundPatternProgram;
gfx::ShaderProgramBasePtr shader;
};
} // namespace mbgl

View File

@@ -189,7 +189,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) {
tile.translatedClipMatrix(evaluated.get<FillExtrusionTranslate>(),
evaluated.get<FillExtrusionTranslateAnchor>(),
parameters.state),
tile.getIconAtlasTexture().size,
tile.getIconAtlasTexture()->getSize(),
crossfade,
tile.id,
parameters.state,
@@ -201,8 +201,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) {
patternPosA,
patternPosB,
FillExtrusionPatternProgram::TextureBindings{
textures::image::Value{tile.getIconAtlasTexture().getResource(),
gfx::TextureFilterType::Linear},
textures::image::Value{tile.getIconAtlasTextureBinding(gfx::TextureFilterType::Linear)},
},
name);
}

View File

@@ -195,7 +195,7 @@ void RenderFillLayer::render(PaintParameters& parameters) {
tile.translatedMatrix(
evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state),
parameters.backend.getDefaultRenderable().getSize(),
tile.getIconAtlasTexture().size,
tile.getIconAtlasTexture()->getSize(),
crossfade,
tile.id,
parameters.state,
@@ -230,8 +230,7 @@ void RenderFillLayer::render(PaintParameters& parameters) {
*bucket.triangleIndexBuffer,
bucket.triangleSegments,
FillPatternProgram::TextureBindings{
textures::image::Value{tile.getIconAtlasTexture().getResource(),
gfx::TextureFilterType::Linear},
tile.getIconAtlasTextureBinding(gfx::TextureFilterType::Linear),
});
}
if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) {
@@ -241,8 +240,7 @@ void RenderFillLayer::render(PaintParameters& parameters) {
*bucket.lineIndexBuffer,
bucket.lineSegments,
FillOutlinePatternProgram::TextureBindings{
textures::image::Value{tile.getIconAtlasTexture().getResource(),
gfx::TextureFilterType::Linear},
tile.getIconAtlasTextureBinding(gfx::TextureFilterType::Linear),
});
}
}
@@ -519,6 +517,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
patternBuilder->setDepthType(gfx::DepthMaskType::ReadWrite);
patternBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
patternBuilder->setSubLayerIndex(1);
// patternBuilder->setTexture(tile.getIconAtlasTexture(), 0);
}
if (doOutline && !outlinePatternBuilder && outlinePatternShader) {
outlinePatternBuilder = context.createDrawableBuilder("fill-outline-pattern");
@@ -528,6 +527,7 @@ void RenderFillLayer::update(gfx::ShaderRegistry& shaders,
outlinePatternBuilder->setDepthType(gfx::DepthMaskType::ReadOnly);
outlinePatternBuilder->setCullFaceMode(gfx::CullFaceMode::disabled());
outlinePatternBuilder->setSubLayerIndex(2);
// outlinePatternBuilder->setTexture(tile.getIconAtlasTexture(), 0);
}
// parameters.stencilModeForClipping(tile.id),

View File

@@ -169,7 +169,7 @@ void RenderLineLayer::render(PaintParameters& parameters) {
} else if (!unevaluated.get<LinePattern>().isUndefined()) {
const auto& linePatternValue = evaluated.get<LinePattern>().constantOr(Faded<expression::Image>{"", ""});
const Size& texsize = tile.getIconAtlasTexture().size;
const Size& texsize = tile.getIconAtlasTexture()->getSize();
std::optional<ImagePosition> posA = tile.getPattern(linePatternValue.from.id());
std::optional<ImagePosition> posB = tile.getPattern(linePatternValue.to.id());
@@ -185,7 +185,7 @@ void RenderLineLayer::render(PaintParameters& parameters) {
posA,
posB,
LinePatternProgram::TextureBindings{
textures::image::Value{tile.getIconAtlasTexture().getResource(), gfx::TextureFilterType::Linear},
tile.getIconAtlasTextureBinding(gfx::TextureFilterType::Linear),
});
} else if (!unevaluated.get<LineGradient>().getValue().isUndefined()) {
assert(colorRampTexture);

View File

@@ -120,12 +120,11 @@ void drawIcon(const RenderSymbolLayer::Programs& programs,
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{tile.getIconAtlasTexture().getResource(),
sdfIcons || parameters.state.isChanging() || iconScaled || iconTransformed
? gfx::TextureFilterType::Linear
: gfx::TextureFilterType::Nearest};
const bool linear = sdfIcons || parameters.state.isChanging() || iconScaled || iconTransformed;
const auto filterType = linear ? gfx::TextureFilterType::Linear : gfx::TextureFilterType::Nearest;
const gfx::TextureBinding textureBinding = tile.getIconAtlasTextureBinding(filterType);
const Size& iconSize = tile.getIconAtlasTexture().size;
const Size& iconSize = tile.getIconAtlasTexture()->getSize();
const bool variablePlacedIcon = bucket.hasVariablePlacement && layout.get<IconTextFit>() != IconTextFitType::None;
if (sdfIcons) {
@@ -211,9 +210,8 @@ void drawText(const RenderSymbolLayer::Programs& programs,
const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point &&
layout.get<TextRotationAlignment>() == AlignmentType::Map;
const Size& glyphTexSize = tile.getGlyphAtlasTexture().size;
const gfx::TextureBinding glyphTextureBinding{tile.getGlyphAtlasTexture().getResource(),
gfx::TextureFilterType::Linear};
const Size& glyphTexSize = tile.getGlyphAtlasTexture()->getSize();
const gfx::TextureBinding glyphTextureBinding = tile.getGlyphAtlasTextureBinding(gfx::TextureFilterType::Linear);
const auto drawGlyphs = [&](auto& program, const auto& uniforms, const auto& textures, SymbolSDFPart part) {
draw(program,
@@ -231,12 +229,10 @@ void drawText(const RenderSymbolLayer::Programs& programs,
const ZoomEvaluatedSize partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(
static_cast<float>(parameters.state.getZoom()));
const bool transformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0;
const Size& iconTexSize = tile.getIconAtlasTexture().size;
const gfx::TextureBinding iconTextureBinding{
tile.getIconAtlasTexture().getResource(),
parameters.state.isChanging() || transformed || !partiallyEvaluatedTextSize.isZoomConstant
? gfx::TextureFilterType::Linear
: gfx::TextureFilterType::Nearest};
const Size& iconTexSize = tile.getIconAtlasTexture()->getSize();
const bool linear = parameters.state.isChanging() || transformed || !partiallyEvaluatedTextSize.isZoomConstant;
const auto filterType = linear ? gfx::TextureFilterType::Linear : gfx::TextureFilterType::Nearest;
const gfx::TextureBinding iconTextureBinding = tile.getIconAtlasTextureBinding(filterType);
if (values.hasHalo) {
drawGlyphs(*programs.symbolTextAndIconProgram,
SymbolTextAndIconProgram::layoutUniformValues(bucket.hasVariablePlacement,

View File

@@ -87,16 +87,12 @@ Size PatternAtlas::getPixelSize() const {
return {static_cast<uint32_t>(shelfPack.width()), static_cast<uint32_t>(shelfPack.height())};
}
void PatternAtlas::upload(gfx::UploadPass& uploadPass) {
// @note: This is what we should be doing, but will fail a ton of render tests until we update them all
// if (atlasImage.size.isEmpty()) {
// return;
// }
void PatternAtlas::upload([[maybe_unused]] gfx::UploadPass& uploadPass) {
if (!atlasTexture2D) {
atlasTexture2D = uploadPass.createTexture2D(atlasImage);
atlasTexture2D = uploadPass.getContext().createTexture2D();
atlasTexture2D->upload(atlasImage);
} else if (dirty) {
atlasTexture2D->upload(atlasImage, uploadPass);
atlasTexture2D->upload(atlasImage);
}
dirty = false;

View File

@@ -96,14 +96,32 @@ std::optional<ImagePosition> RenderTile::getPattern(const std::string& pattern)
return renderData->getPattern(pattern);
}
const gfx::Texture& RenderTile::getGlyphAtlasTexture() const {
assert(renderData);
return renderData->getGlyphAtlasTexture();
static const gfx::Texture2DPtr noTexture;
bool RenderTile::hasGlyphAtlasTexture() const {
return renderData && renderData->getGlyphAtlasTexture();
}
const gfx::Texture& RenderTile::getIconAtlasTexture() const {
assert(renderData);
return renderData->getIconAtlasTexture();
const gfx::Texture2DPtr& RenderTile::getGlyphAtlasTexture() const {
return renderData ? renderData->getGlyphAtlasTexture() : noTexture;
}
gfx::TextureBinding RenderTile::getGlyphAtlasTextureBinding(gfx::TextureFilterType filter) const {
assert(renderData && renderData->getGlyphAtlasTexture());
return {getGlyphAtlasTexture()->getResource(), filter};
}
bool RenderTile::hasIconAtlasTexture() const {
return renderData && renderData->getIconAtlasTexture();
}
const gfx::Texture2DPtr& RenderTile::getIconAtlasTexture() const {
return renderData ? renderData->getIconAtlasTexture() : noTexture;
}
gfx::TextureBinding RenderTile::getIconAtlasTextureBinding(gfx::TextureFilterType filter) const {
assert(renderData && renderData->getIconAtlasTexture());
return {getIconAtlasTexture()->getResource(), filter};
}
void RenderTile::upload(gfx::UploadPass& uploadPass) const {

View File

@@ -14,7 +14,9 @@
namespace mbgl {
namespace gfx {
class Texture2D;
class UploadPass;
using Texture2DPtr = std::shared_ptr<Texture2D>;
} // namespace gfx
class Bucket;
@@ -55,8 +57,14 @@ public:
Bucket* getBucket(const style::Layer::Impl&) const;
const LayerRenderData* getLayerRenderData(const style::Layer::Impl&) const;
std::optional<ImagePosition> getPattern(const std::string& pattern) const;
const gfx::Texture& getGlyphAtlasTexture() const;
const gfx::Texture& getIconAtlasTexture() const;
bool hasGlyphAtlasTexture() const;
const gfx::Texture2DPtr& getGlyphAtlasTexture() const;
gfx::TextureBinding getGlyphAtlasTextureBinding(gfx::TextureFilterType) const;
bool hasIconAtlasTexture() const;
const gfx::Texture2DPtr& getIconAtlasTexture() const;
gfx::TextureBinding getIconAtlasTextureBinding(gfx::TextureFilterType) const;
void upload(gfx::UploadPass&) const;
void prepare(const SourcePrepareParameters&);

View File

@@ -130,7 +130,7 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
renderTree.getPatternAtlas().upload(*uploadPass);
// Give the layers a chance to upload
orchestrator.observeLayerGroups([&](LayerGroup& layerGroup) { layerGroup.upload(context, *uploadPass); });
orchestrator.observeLayerGroups([&](LayerGroup& layerGroup) { layerGroup.upload(*uploadPass); });
}
// - 3D PASS

View File

@@ -9,16 +9,14 @@ TileRenderData::TileRenderData(std::shared_ptr<TileAtlasTextures> atlasTextures_
TileRenderData::~TileRenderData() = default;
const gfx::Texture& TileRenderData::getGlyphAtlasTexture() const {
assert(atlasTextures);
assert(atlasTextures->glyph);
return *atlasTextures->glyph;
static gfx::Texture2DPtr noTexture;
const gfx::Texture2DPtr& TileRenderData::getGlyphAtlasTexture() const {
return atlasTextures ? atlasTextures->glyph : noTexture;
}
const gfx::Texture& TileRenderData::getIconAtlasTexture() const {
assert(atlasTextures);
assert(atlasTextures->icon);
return *atlasTextures->icon;
const gfx::Texture2DPtr& TileRenderData::getIconAtlasTexture() const {
return atlasTextures ? atlasTextures->icon : noTexture;
}
std::optional<ImagePosition> TileRenderData::getPattern(const std::string&) const {

View File

@@ -10,7 +10,9 @@
namespace mbgl {
namespace gfx {
class Texture2D;
class UploadPass;
using Texture2DPtr = std::shared_ptr<gfx::Texture2D>;
} // namespace gfx
class Bucket;
@@ -19,15 +21,15 @@ class SourcePrepareParameters;
class TileAtlasTextures {
public:
std::optional<gfx::Texture> glyph;
std::optional<gfx::Texture> icon;
gfx::Texture2DPtr glyph;
gfx::Texture2DPtr icon;
};
class TileRenderData {
public:
virtual ~TileRenderData();
const gfx::Texture& getGlyphAtlasTexture() const;
const gfx::Texture& getIconAtlasTexture() const;
const gfx::Texture2DPtr& getGlyphAtlasTexture() const;
const gfx::Texture2DPtr& getIconAtlasTexture() const;
// To be implemented for concrete tile types.
virtual std::optional<ImagePosition> getPattern(const std::string&) const;
virtual const LayerRenderData* getLayerRenderData(const style::Layer::Impl&) const;

View File

@@ -87,21 +87,22 @@ void GeometryTileRenderData::upload(gfx::UploadPass& uploadPass) {
assert(atlasTextures);
if (layoutResult->glyphAtlasImage) {
atlasTextures->glyph = uploadPass.createTexture(*layoutResult->glyphAtlasImage);
atlasTextures->glyph = uploadPass.getContext().createTexture2D();
atlasTextures->glyph->upload(*layoutResult->glyphAtlasImage);
layoutResult->glyphAtlasImage = {};
}
if (layoutResult->iconAtlas.image.valid()) {
atlasTextures->icon = uploadPass.createTexture(layoutResult->iconAtlas.image);
atlasTextures->icon = uploadPass.getContext().createTexture2D();
atlasTextures->icon->upload(layoutResult->iconAtlas.image);
layoutResult->iconAtlas.image = {};
}
if (atlasTextures->icon && !imagePatches.empty()) {
for (const auto& imagePatch : imagePatches) { // patch updated images.
uploadPass.updateTextureSub(*atlasTextures->icon,
imagePatch.image->image,
imagePatch.paddedRect.x + ImagePosition::padding,
imagePatch.paddedRect.y + ImagePosition::padding);
atlasTextures->icon->uploadSubRegion(imagePatch.image->image,
imagePatch.paddedRect.x + ImagePosition::padding,
imagePatch.paddedRect.y + ImagePosition::padding);
}
imagePatches.clear();
}