diff --git a/CMakeLists.txt b/CMakeLists.txt index 930d81932..e0920c886 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/mbgl/gfx/drawable.hpp b/include/mbgl/gfx/drawable.hpp index 50dfd93ab..e0687721b 100644 --- a/include/mbgl/gfx/drawable.hpp +++ b/include/mbgl/gfx/drawable.hpp @@ -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& texture, int32_t location); + void setTexture(std::shared_ptr texture, int32_t location); /// not used for anything yet DrawPriority getDrawPriority() const { return drawPriority; } diff --git a/include/mbgl/gfx/drawable_impl.hpp b/include/mbgl/gfx/drawable_impl.hpp index f03079dee..6ef0ddf60 100644 --- a/include/mbgl/gfx/drawable_impl.hpp +++ b/include/mbgl/gfx/drawable_impl.hpp @@ -11,6 +11,8 @@ struct Drawable::DrawSegment { segment(std::move(segment_)) {} const gfx::DrawMode& getMode() const { return mode; } + + Segment& getSegment() { return segment; } const Segment& getSegment() const { return segment; } protected: diff --git a/include/mbgl/gfx/texture2d.hpp b/include/mbgl/gfx/texture2d.hpp index 9b25386e6..bd2345fcf 100644 --- a/include/mbgl/gfx/texture2d.hpp +++ b/include/mbgl/gfx/texture2d.hpp @@ -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& 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 + 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 + 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 diff --git a/include/mbgl/gfx/uniform_buffer.hpp b/include/mbgl/gfx/uniform_buffer.hpp index 5be936d9d..8e749912c 100644 --- a/include/mbgl/gfx/uniform_buffer.hpp +++ b/include/mbgl/gfx/uniform_buffer.hpp @@ -51,8 +51,7 @@ public: const std::shared_ptr& get(const std::string& name) const; /// Add a new uniform buffer element or replace the existing one. - const std::shared_ptr& addOrReplace(std::string name, - const std::shared_ptr& uniformBuffer); + const std::shared_ptr& addOrReplace(std::string name, std::shared_ptr uniformBuffer); UniformBufferArray& operator=(UniformBufferArray&&); UniformBufferArray& operator=(const UniformBufferArray&); diff --git a/include/mbgl/gl/drawable_gl.hpp b/include/mbgl/gl/drawable_gl.hpp index 69315da80..aa0a610ea 100644 --- a/include/mbgl/gl/drawable_gl.hpp +++ b/include/mbgl/gl/drawable_gl.hpp @@ -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; diff --git a/include/mbgl/gl/layer_group_gl.hpp b/include/mbgl/gl/layer_group_gl.hpp index b26a6babd..fd7a54259 100644 --- a/include/mbgl/gl/layer_group_gl.hpp +++ b/include/mbgl/gl/layer_group_gl.hpp @@ -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: diff --git a/include/mbgl/gl/texture2d.hpp b/include/mbgl/gl/texture2d.hpp index f75921886..306d16e48 100644 --- a/include/mbgl/gl/texture2d.hpp +++ b/include/mbgl/gl/texture2d.hpp @@ -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& 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}; diff --git a/include/mbgl/renderer/layer_group.hpp b/include/mbgl/renderer/layer_group.hpp index ddd91faba..92ddf45b4 100644 --- a/include/mbgl/renderer/layer_group.hpp +++ b/include/mbgl/renderer/layer_group.hpp @@ -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 diff --git a/include/mbgl/shaders/gl/drawable_background_pattern.hpp b/include/mbgl/shaders/gl/drawable_background_pattern.hpp new file mode 100644 index 000000000..52183580b --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_background_pattern.hpp @@ -0,0 +1,85 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + 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 diff --git a/include/mbgl/shaders/shader_manifest.hpp b/include/mbgl/shaders/shader_manifest.hpp index a2bd093b0..4c125fbb5 100644 --- a/include/mbgl/shaders/shader_manifest.hpp +++ b/include/mbgl/shaders/shader_manifest.hpp @@ -4,6 +4,7 @@ #ifdef MBGL_RENDER_BACKEND_OPENGL #include +#include #include #include #include diff --git a/include/mbgl/shaders/shader_source.hpp b/include/mbgl/shaders/shader_source.hpp index 884b5e70f..079ffde18 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -10,6 +10,7 @@ namespace shaders { enum class BuiltIn { None, BackgroundShader, + BackgroundPatternShader, CircleShader, FillShader, FillOutlineShader, diff --git a/shaders/drawable.background_pattern.fragment.glsl b/shaders/drawable.background_pattern.fragment.glsl new file mode 100644 index 000000000..ac49a616c --- /dev/null +++ b/shaders/drawable.background_pattern.fragment.glsl @@ -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 +} diff --git a/shaders/drawable.background_pattern.vertex.glsl b/shaders/drawable.background_pattern.vertex.glsl new file mode 100644 index 000000000..eda93326d --- /dev/null +++ b/shaders/drawable.background_pattern.vertex.glsl @@ -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); +} diff --git a/shaders/manifest.json b/shaders/manifest.json index 9b78bf2ef..bed5d3407 100644 --- a/shaders/manifest.json +++ b/shaders/manifest.json @@ -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", diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index f2c0a42ea..982ed9f2f 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -28,12 +28,14 @@ class DrawableTweaker; class OffscreenTexture; class ShaderProgramBase; class ShaderRegistry; +class Texture2D; using DrawablePtr = std::shared_ptr; using UniqueDrawableBuilder = std::unique_ptr; using DrawableTweakerPtr = std::shared_ptr; using UniformBufferPtr = std::shared_ptr; using ShaderProgramBasePtr = std::shared_ptr; +using Texture2DPtr = std::shared_ptr; 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 diff --git a/src/mbgl/gfx/drawable.cpp b/src/mbgl/gfx/drawable.cpp index c1c8a343c..edb1d3347 100644 --- a/src/mbgl/gfx/drawable.cpp +++ b/src/mbgl/gfx/drawable.cpp @@ -27,14 +27,14 @@ void Drawable::setCullFaceMode(const gfx::CullFaceMode& value) { impl->cullFaceMode = value; } -void Drawable::setTexture(std::shared_ptr& texture, int32_t location) { +void Drawable::setTexture(std::shared_ptr 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) { diff --git a/src/mbgl/gfx/drawable_builder.cpp b/src/mbgl/gfx/drawable_builder.cpp index a99cfb4dd..12cbb232f 100644 --- a/src/mbgl/gfx/drawable_builder.cpp +++ b/src/mbgl/gfx/drawable_builder.cpp @@ -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) { diff --git a/src/mbgl/gfx/uniform_buffer.cpp b/src/mbgl/gfx/uniform_buffer.cpp index c62eb4479..76c1f2cab 100644 --- a/src/mbgl/gfx/uniform_buffer.cpp +++ b/src/mbgl/gfx/uniform_buffer.cpp @@ -29,8 +29,8 @@ const std::shared_ptr& UniformBufferArray::get(const std::string& return (result != uniformBufferMap.end()) ? result->second : nullref; } -const std::shared_ptr& UniformBufferArray::addOrReplace( - std::string name, const std::shared_ptr& uniformBuffer) { +const std::shared_ptr& UniformBufferArray::addOrReplace(std::string name, + std::shared_ptr uniformBuffer) { const auto result = uniformBufferMap.insert(std::make_pair(std::move(name), std::shared_ptr())); result.first->second = std::move(uniformBuffer); return result.first->second; diff --git a/src/mbgl/gfx/upload_pass.hpp b/src/mbgl/gfx/upload_pass.hpp index 1f759f4e7..f712b2ae1 100644 --- a/src/mbgl/gfx/upload_pass.hpp +++ b/src/mbgl/gfx/upload_pass.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ class Texture2D; class VertexAttributeArray; using AttributeBindingArray = std::vector>; +using Texture2DPtr = std::shared_ptr; class UploadPass { protected: @@ -36,6 +38,9 @@ public: DebugGroup createDebugGroup(const char* name) { return {*this, name}; } + virtual Context& getContext() = 0; + virtual const Context& getContext() const = 0; + public: template VertexBuffer createVertexBuffer(VertexVector&& 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 + 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 + 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 createTexture2D(const PremultipliedImage& image) = 0; }; } // namespace gfx diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 09749f051..4c982936f 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -475,6 +475,10 @@ TileLayerGroupPtr Context::createTileLayerGroup(int32_t layerIndex, std::size_t return std::make_shared(layerIndex, initialCapacity); } +gfx::Texture2DPtr Context::createTexture2D() { + return std::make_shared(*this); +} + void Context::clear(std::optional color, std::optional depth, std::optional 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; } diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index fc60a7e5f..87d75a89e 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -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; diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index 315ac41fc..b250969b7 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -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(context); constexpr auto usage = gfx::BufferUsageType::StaticDraw; diff --git a/src/mbgl/gl/layer_group_gl.cpp b/src/mbgl/gl/layer_group_gl.cpp index 43ec8e6e6..3205fe0bf 100644 --- a/src/mbgl/gl/layer_group_gl.cpp +++ b/src/mbgl/gl/layer_group_gl.cpp @@ -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(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); }); } diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index c2ce692a5..1c595f1e1 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -94,6 +94,7 @@ void registerTypes(gfx::ShaderRegistry& registry, gl::Context& glContext, const void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramParameters& programParameters) { registerTypes& 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(std::move(obj), storageSize); } platform::GLuint Texture2D::getTextureID() const noexcept { return static_cast(*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(textureUnit); context.texture[static_cast(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::to(pixelFormat), + size.width, + size.height, + 0, + Enum::to(pixelFormat), + Enum::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::to(pixelFormat), + Enum::to(channelType), + pixelData)); } } // namespace gl diff --git a/src/mbgl/gl/upload_pass.cpp b/src/mbgl/gl/upload_pass.cpp index d3b4b9c03..e66fc7851 100644 --- a/src/mbgl/gl/upload_pass.cpp +++ b/src/mbgl/gl/upload_pass.cpp @@ -68,10 +68,9 @@ std::unique_ptr 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 resource = std::make_unique(std::move(obj), - textureByteSize); + auto resource = std::make_unique(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 UploadPass::createTexture2D(const PremultipliedImage& image) { - auto tex = std::make_shared(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 diff --git a/src/mbgl/gl/upload_pass.hpp b/src/mbgl/gl/upload_pass.hpp index d1395abb3..2ba88fff7 100644 --- a/src/mbgl/gl/upload_pass.hpp +++ b/src/mbgl/gl/upload_pass.hpp @@ -26,6 +26,9 @@ private: void popDebugGroup() override; public: + gfx::Context& getContext() override; + const gfx::Context& getContext() const override; + std::unique_ptr 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 createTexture2D(const PremultipliedImage& image) override; - private: gl::CommandEncoder& commandEncoder; const gfx::DebugGroup debugGroup; diff --git a/src/mbgl/renderer/layers/background_layer_tweaker.cpp b/src/mbgl/renderer/layers/background_layer_tweaker.cpp index 75d6bfb0e..24ef602c1 100644 --- a/src/mbgl/renderer/layers/background_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/background_layer_tweaker.cpp @@ -1,9 +1,11 @@ #include -#include -#include -#include + #include #include +#include +#include +#include +#include #include 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 pad; + /* 32 */ }; -static_assert(sizeof(BackgroundLayerUBO) % 16 == 0); +static_assert(sizeof(BackgroundLayerUBO) == 32); struct alignas(16) BackgroundPatternLayerUBO { - std::array pattern_tl_a; - std::array pattern_br_a; - std::array pattern_tl_b; - std::array pattern_br_b; - std::array texsize; - std::array pattern_size_a; - std::array pattern_size_b; - std::array pixel_coord_upper; - std::array pixel_coord_lower; - float tile_units_to_pixels; - float scale_a; - float scale_b; - float mix; - float opacity; + /* 0 */ std::array pattern_tl_a; + /* 8 */ std::array pattern_br_a; + /* 16 */ std::array pattern_tl_b; + /* 24 */ std::array pattern_br_b; + /* 32 */ std::array texsize; + /* 40 */ std::array pattern_size_a; + /* 48 */ std::array pattern_size_b; + /* 56 */ std::array pixel_coord_upper; + /* 64 */ std::array 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 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(*evaluatedProperties).evaluated; + const auto& crossfade = static_cast(*evaluatedProperties).crossfade; - if (!layerUniformBuffer) { - BackgroundLayerUBO layerUBO; - layerUBO.color = evaluated.get(); - layerUBO.opacity = evaluated.get(); - layerUniformBuffer = parameters.context.createUniformBuffer(&layerUBO, sizeof(layerUBO)); + const bool hasPattern = !evaluated.get().to.empty(); + const std::optional imagePosA = hasPattern ? parameters.patternAtlas.getPattern( + evaluated.get().from.id()) + : std::nullopt; + const std::optional imagePosB = hasPattern ? parameters.patternAtlas.getPattern( + evaluated.get().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(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( + util::tileSize_D * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z)); + const int32_t pixelX = static_cast( + 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(imagePosA->tl()), + /* .pattern_br_a = */ util::cast(imagePosA->br()), + /* .pattern_tl_b = */ util::cast(imagePosB->tl()), + /* .pattern_br_b = */ util::cast(imagePosB->br()), + /* .texsize = */ {static_cast(atlasSize.width), static_cast(atlasSize.height)}, + /* .pattern_size_a = */ imagePosA->displaySize(), + /* .pattern_size_b = */ imagePosB->displaySize(), + /* .pixel_coord_upper = */ {static_cast(pixelX >> 16), static_cast(pixelY >> 16)}, + /* .pixel_coord_lower = */ {static_cast(pixelX & 0xFFFF), static_cast(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(), + /* .pad = */ {0}, + }; + // TODO: Update UBOs in-place + layerUniformBuffer = parameters.context.createUniformBuffer(&layerUBO, sizeof(layerUBO)); + } else { + const BackgroundLayerUBO layerUBO = { + /* .color = */ evaluated.get(), + /* .opacity = */ evaluated.get(), + /* .pad = */ {0, 0, 0}, + }; + layerUniformBuffer = parameters.context.createUniformBuffer(&layerUBO, sizeof(layerUBO)); + } + drawable.mutableUniformBuffers().addOrReplace("BackgroundLayerUBO", std::move(layerUniformBuffer)); }); } diff --git a/src/mbgl/renderer/layers/background_layer_tweaker.hpp b/src/mbgl/renderer/layers/background_layer_tweaker.hpp index 0016ccc7a..aec03f32d 100644 --- a/src/mbgl/renderer/layers/background_layer_tweaker.hpp +++ b/src/mbgl/renderer/layers/background_layer_tweaker.hpp @@ -2,10 +2,15 @@ #include +#include + namespace mbgl { namespace gfx { +class ShaderProgramBase; class UniformBuffer; + +using ShaderProgramBasePtr = std::shared_ptr; using UniformBufferPtr = std::shared_ptr; } // 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 diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp index 13834ad24..0b42acd1f 100644 --- a/src/mbgl/renderer/layers/render_background_layer.cpp +++ b/src/mbgl/renderer/layers/render_background_layer.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include @@ -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 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(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; diff --git a/src/mbgl/renderer/layers/render_background_layer.hpp b/src/mbgl/renderer/layers/render_background_layer.hpp index d1ffc30d8..3069ec6b5 100644 --- a/src/mbgl/renderer/layers/render_background_layer.hpp +++ b/src/mbgl/renderer/layers/render_background_layer.hpp @@ -48,8 +48,6 @@ private: // Programs std::shared_ptr backgroundProgram; std::shared_ptr backgroundPatternProgram; - - gfx::ShaderProgramBasePtr shader; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index ad806523c..0af94e8c6 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -189,7 +189,7 @@ void RenderFillExtrusionLayer::render(PaintParameters& parameters) { tile.translatedClipMatrix(evaluated.get(), evaluated.get(), 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); } diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp index 2f6e595eb..3df3719a5 100644 --- a/src/mbgl/renderer/layers/render_fill_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_layer.cpp @@ -195,7 +195,7 @@ void RenderFillLayer::render(PaintParameters& parameters) { tile.translatedMatrix( evaluated.get(), evaluated.get(), 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() && unevaluated.get().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), diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 13da300f8..727ffed9c 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -169,7 +169,7 @@ void RenderLineLayer::render(PaintParameters& parameters) { } else if (!unevaluated.get().isUndefined()) { const auto& linePatternValue = evaluated.get().constantOr(Faded{"", ""}); - const Size& texsize = tile.getIconAtlasTexture().size; + const Size& texsize = tile.getIconAtlasTexture()->getSize(); std::optional posA = tile.getPattern(linePatternValue.from.id()); std::optional 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().getValue().isUndefined()) { assert(colorRampTexture); diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 807d1b67b..6254f1369 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -120,12 +120,11 @@ void drawIcon(const RenderSymbolLayer::Programs& programs, const bool iconScaled = layout.get().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() != IconTextFitType::None; if (sdfIcons) { @@ -211,9 +210,8 @@ void drawText(const RenderSymbolLayer::Programs& programs, const bool alongLine = layout.get() != SymbolPlacementType::Point && layout.get() == 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(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, diff --git a/src/mbgl/renderer/pattern_atlas.cpp b/src/mbgl/renderer/pattern_atlas.cpp index e5ba696af..dc509c941 100644 --- a/src/mbgl/renderer/pattern_atlas.cpp +++ b/src/mbgl/renderer/pattern_atlas.cpp @@ -87,16 +87,12 @@ Size PatternAtlas::getPixelSize() const { return {static_cast(shelfPack.width()), static_cast(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; diff --git a/src/mbgl/renderer/render_tile.cpp b/src/mbgl/renderer/render_tile.cpp index d5de5280f..ac7e8767a 100644 --- a/src/mbgl/renderer/render_tile.cpp +++ b/src/mbgl/renderer/render_tile.cpp @@ -96,14 +96,32 @@ std::optional 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 { diff --git a/src/mbgl/renderer/render_tile.hpp b/src/mbgl/renderer/render_tile.hpp index c887ad337..6f2219dfe 100644 --- a/src/mbgl/renderer/render_tile.hpp +++ b/src/mbgl/renderer/render_tile.hpp @@ -14,7 +14,9 @@ namespace mbgl { namespace gfx { +class Texture2D; class UploadPass; +using Texture2DPtr = std::shared_ptr; } // 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 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&); diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 5ab61b2e8..6e69c3e85 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -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 diff --git a/src/mbgl/renderer/tile_render_data.cpp b/src/mbgl/renderer/tile_render_data.cpp index f0845381c..0f28afd66 100644 --- a/src/mbgl/renderer/tile_render_data.cpp +++ b/src/mbgl/renderer/tile_render_data.cpp @@ -9,16 +9,14 @@ TileRenderData::TileRenderData(std::shared_ptr 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 TileRenderData::getPattern(const std::string&) const { diff --git a/src/mbgl/renderer/tile_render_data.hpp b/src/mbgl/renderer/tile_render_data.hpp index b4f3de150..a3d3b7215 100644 --- a/src/mbgl/renderer/tile_render_data.hpp +++ b/src/mbgl/renderer/tile_render_data.hpp @@ -10,7 +10,9 @@ namespace mbgl { namespace gfx { +class Texture2D; class UploadPass; +using Texture2DPtr = std::shared_ptr; } // namespace gfx class Bucket; @@ -19,15 +21,15 @@ class SourcePrepareParameters; class TileAtlasTextures { public: - std::optional glyph; - std::optional 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 getPattern(const std::string&) const; virtual const LayerRenderData* getLayerRenderData(const style::Layer::Impl&) const; diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 4e50367b0..588bd4ade 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -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(); }