+ experimental skia backend (work-in-progress)

This commit is contained in:
artemp 2013-07-15 13:32:06 +01:00
parent 43723d3f81
commit 97039e83a1
11 changed files with 424 additions and 4 deletions

View file

@ -344,6 +344,12 @@ opts.AddVariables(
BoolVariable('CAIRO', 'Attempt to build with Cairo rendering support', 'True'),
PathVariable('CAIRO_INCLUDES', 'Search path for cairo include files', '',PathVariable.PathAccept),
PathVariable('CAIRO_LIBS', 'Search path for cairo library files','',PathVariable.PathAccept),
# Skia backend
BoolVariable('SKIA', 'Attempt to build with Skia rendering support', 'False'),
PathVariable('SKIA_INCLUDES', 'Search path for skia include files', '',PathVariable.PathAccept),
PathVariable('SKIA_LIBS', 'Search path for skia library files','',PathVariable.PathAccept),
('GDAL_CONFIG', 'The path to the gdal-config executable for finding gdal and ogr details.', 'gdal-config'),
('PG_CONFIG', 'The path to the pg_config executable.', 'pg_config'),
PathVariable('OCCI_INCLUDES', 'Search path for OCCI include files', '/usr/lib/oracle/10.2.0.3/client/include', PathVariable.PathAccept),
@ -423,6 +429,7 @@ pickle_store = [# Scons internal variables
'HAS_CAIRO',
'HAS_PYCAIRO',
'HAS_LIBXML2',
'HAS_SKIA',
'PYTHON_IS_64BIT',
'SAMPLE_INPUT_PLUGINS',
'PKG_CONFIG_PATH',
@ -1046,6 +1053,7 @@ if not preconfigured:
env['CAIRO_LIBPATHS'] = []
env['CAIRO_ALL_LIBS'] = []
env['CAIRO_CPPPATHS'] = []
env['HAS_SKIA'] = False
env['HAS_PYCAIRO'] = False
env['HAS_LIBXML2'] = False
env['LIBMAPNIK_LIBS'] = []
@ -1480,6 +1488,17 @@ if not preconfigured:
env['SKIPPED_DEPS'].append('cairo')
env['HAS_CAIRO'] = False
if env['SKIA']:
if env['SKIA_LIBS'] or env['SKIA_INCLUDES']:
env.AppendUnique(CPPPATH = os.path.realpath(env['SKIA_INCLUDES'] + '/config'))
env.AppendUnique(CPPPATH = os.path.realpath(env['SKIA_INCLUDES'] + '/core'))
env.AppendUnique(CPPPATH = os.path.realpath(env['SKIA_INCLUDES'] + '/effects'))
env.AppendUnique(LIBPATH = os.path.realpath(env['SKIA_LIBS']))
env['HAS_SKIA'] = True
else:
color_print(4,'Not building with Skia support, pass SKIA=True to enable')
if 'python' in env['BINDINGS'] or 'python' in env['REQUESTED_PLUGINS']:
if not os.access(env['PYTHON'], os.X_OK):
color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON'])

View file

@ -386,6 +386,9 @@ void MainWindow::createToolBars()
renderer_selector_->addItem("AGG");
#ifdef HAVE_CAIRO
renderer_selector_->addItem("Cairo");
#endif
#ifdef HAVE_SKIA
renderer_selector_->addItem("Skia");
#endif
renderer_selector_->addItem("Grid");
fileToolBar->addWidget(renderer_selector_);

View file

@ -40,6 +40,13 @@
#include <mapnik/cairo_renderer.hpp>
#endif
#ifdef HAVE_SKIA
// skia
#include <mapnik/skia/skia_renderer.hpp>
#include <SkCanvas.h>
#include <SkBitmap.h>
#endif
#include "mapwidget.hpp"
#include "info_dialog.hpp"
@ -525,6 +532,44 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
}
void render_skia(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
{
unsigned width=map.width();
unsigned height=map.height();
mapnik::image_32 buf(width,height);
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.setPixels(buf.raw_data());
SkCanvas canvas(bitmap);
mapnik::skia_renderer ren(map,canvas,scaling_factor);
try
{
{
boost::timer::auto_cpu_timer t;
ren.apply();
}
QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32);
pix = QPixmap::fromImage(image.rgbSwapped());
}
catch (mapnik::config_error & ex)
{
std::cerr << "Skia:" << ex.what() << std::endl;
}
catch (const std::exception & ex)
{
std::cerr << "Skia:exception: " << ex.what() << std::endl;
}
catch (...)
{
std::cerr << "Skia:Unknown exception caught!\n";
}
}
void render_grid(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
{
std::cerr << "Not supported" << std::endl;
@ -535,6 +580,7 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
{
#ifdef HAVE_CAIRO
boost::timer::auto_cpu_timer t;
mapnik::cairo_surface_ptr image_surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,map.width(),map.height()),
mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> renderer(map, image_surface, scaling_factor);
@ -550,6 +596,7 @@ void MapWidget::updateRenderer(QString const& txt)
if (txt == "AGG") cur_renderer_ = AGG;
else if (txt == "Cairo") cur_renderer_ = Cairo;
else if (txt == "Grid") cur_renderer_ = Grid;
else if (txt == "Skia") cur_renderer_ = Skia;
std::cerr << "Update renderer called" << std::endl;
updateMap();
}
@ -576,6 +623,10 @@ void MapWidget::updateMap()
{
render_grid(*map_, scaling_factor_, pix_);
}
else if (cur_renderer_ == Skia)
{
render_skia(*map_, scaling_factor_, pix_);
}
else
{
std::cerr << "Unknown renderer..." << std::endl;

View file

@ -51,6 +51,7 @@ public:
{
AGG,
Cairo,
Skia,
Grid
};

View file

@ -3,12 +3,19 @@
######################################################################
TEMPLATE = app
QT += core gui widgets
QMAKE_CXX = clang++
QMAKE_CXXFLAGS += $$system(mapnik-config --cxxflags)
QMAKE_CXX = /opt/llvm/bin/clang++
QMAKE_LINK = /opt/llvm/bin/clang++
QMAKE_CXXFLAGS += $$system(mapnik-config --cxxflags --defines)
QMAKE_CXXFLAGS += $$system(mapnik-config --includes --dep-includes)
QMAKE_CXXFLAGS += "-I/Users/artem/Projects/skia/trunk/include/core"
QMAKE_CXXFLAGS += "-I/Users/artem/Projects/skia/trunk/include/config"
QMAKE_LFLAGS += $$system(mapnik-config --libs)
QMAKE_LFLAGS += $$system(mapnik-config --ldflags --dep-libs)
QMAKE_LFLAGS += -lboost_timer
QMAKE_LFLAGS += -L/opt/X11/lib
QMAKE_LFLAGS += "-framework Cocoa"
# Input
CONFIG += qt debug_and_release

View file

@ -4,7 +4,7 @@ from glob import glob
Import('env')
base = './mapnik/'
subdirs = ['','svg','wkt','grid','json','util','text_placements','formatting']
subdirs = ['','svg','wkt','grid','json','util','text_placements','formatting','skia']
if env['SVG_RENDERER']:
subdirs.append('svg/output')

View file

@ -121,7 +121,10 @@
namespace mapnik { namespace filter { namespace detail {
static const float blur_matrix[] = {0.1111f,0.1111f,0.1111f,0.1111f,0.1111f,0.1111f,0.1111f,0.1111f,0.1111f};
static const float blur_matrix[] = {1/16.0f,2/16.0f,1/16.0f,
2/16.0f,4/16.0f,2/16.0f,
1/16.0f,2/16.0f,1/16.0f};
static const float emboss_matrix[] = {-2,-1,0,-1,1,1,0,1,2};
static const float sharpen_matrix[] = {0,-1,0,-1,5,-1,0,-1,0 };
static const float edge_detect_matrix[] = {0,1,0,1,-4,1,0,1,0 };

View file

@ -0,0 +1,94 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#if defined(HAVE_SKIA)
#ifndef MAPNIK_SKIA_RENDERER_HPP
#define MAPNIK_SKIA_RENDERER_HPP
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/map.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/rule.hpp>
#include <mapnik/feature_style_processor.hpp>
// skia fwd decl
class SkCanvas;
namespace mapnik
{
class MAPNIK_DECL skia_renderer : public feature_style_processor<skia_renderer>,
private mapnik::noncopyable
{
public:
typedef skia_renderer processor_impl_type;
skia_renderer(Map const& map, SkCanvas & canvas, double scale_factor = 1.0);
~skia_renderer();
void start_map_processing(Map const& map);
void end_map_processing(Map const& map);
void start_layer_processing(layer const& lay, box2d<double> const& query_extent);
void end_layer_processing(layer const& lay);
void start_style_processing(feature_type_style const& st);
void end_style_processing(feature_type_style const& st);
void process(line_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(polygon_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void painted(bool painted) {};
inline bool process(rule::symbolizers const& /*syms*/,
mapnik::feature_impl & /*feature*/,
proj_transform const& /*prj_trans*/)
{
return false;
}
inline eAttributeCollectionPolicy attribute_collection_policy() const
{
return DEFAULT;
}
private:
SkCanvas & canvas_;
unsigned width_;
unsigned height_;
CoordTransform t_;
double scale_factor_;
box2d<double> query_extent_;
};
}
#endif //MAPNIK_SKIA_RENDERER_HPP
#endif // HAVE_SKIA

View file

@ -251,6 +251,16 @@ if env['HAS_CAIRO']:
source.insert(0,'cairo_renderer.cpp')
source.insert(0,'cairo_context.cpp')
if env['HAS_SKIA']:
lib_env.AppendUnique(LIBPATH=env['SKIA_LIBS'])
lib_env.Append(LIBS=['skia_core','skia_ports','skia_utils','skia_images',
'skia_effects','skia_sfnt','skia_opts','skia_opts_ssse3','skia_skgpu'])
lib_env.Append(FRAMEWORKS = ['Cocoa'])
lib_env.Append(CPPDEFINES = '-DHAVE_SKIA')
libmapnik_defines.append('-DHAVE_SKIA')
source.insert(0,'skia/skia_renderer.cpp')
if env['JPEG']:
source += Split(
"""

View file

@ -36,6 +36,10 @@
#include <mapnik/svg/output/svg_renderer.hpp>
#endif
#if defined(HAVE_SKIA)
#include <mapnik/skia/skia_renderer.hpp>
#endif
namespace mapnik
{
@ -44,6 +48,10 @@ template class feature_style_processor<cairo_renderer<cairo_ptr> >;
template class feature_style_processor<cairo_renderer<cairo_surface_ptr> >;
#endif
#if defined(HAVE_SKIA)
template class feature_style_processor<skia_renderer>;
#endif
#if defined(SVG_RENDERER)
template class feature_style_processor<svg_renderer<std::ostream_iterator<char> > >;
#endif

224
src/skia/skia_renderer.cpp Normal file
View file

@ -0,0 +1,224 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2013 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#if defined(HAVE_SKIA)
#include <mapnik/skia/skia_renderer.hpp>
#include <mapnik/vertex_converters.hpp>
// skia
#include <SkCanvas.h>
#include <SkPath.h>
#include <SkPaint.h>
#include <SkDashPathEffect.h>
// agg
//#include "agg_conv_clip_polyline.h"
//#include "agg_conv_clip_polygon.h"
//#include "agg_conv_smooth_poly1.h"
//#include "agg_rendering_buffer.h"
//#include "agg_pixfmt_rgba.h"
#include "agg_trans_affine.h"
namespace mapnik {
struct skia_path_adapter : private mapnik::noncopyable
{
skia_path_adapter(SkPath & path)
: sk_path_(path) {}
template <typename T>
void add_path(T & path)
{
vertex2d vtx(vertex2d::no_init);
path.rewind(0);
while ((vtx.cmd = path.vertex(&vtx.x, &vtx.y)) != SEG_END)
{
//std::cerr << vtx.x << "," << vtx.y << " cmd=" << vtx.cmd << std::endl;
switch (vtx.cmd)
{
case SEG_MOVETO:
sk_path_.moveTo(vtx.x, vtx.y);
case SEG_LINETO:
sk_path_.lineTo(vtx.x, vtx.y);
//case SEG_CLOSE:
//sk_path_.close();
}
}
}
SkPath & sk_path_;
};
skia_renderer::skia_renderer(Map const& map, SkCanvas & canvas, double scale_factor)
: feature_style_processor<skia_renderer>(map,scale_factor),
canvas_(canvas),
width_(map.width()),
height_(map.height()),
t_(map.width(), map.height(), map.get_current_extent()),
scale_factor_(scale_factor) {}
skia_renderer::~skia_renderer() {}
void skia_renderer::start_map_processing(Map const& map)
{
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer_base: Start map processing bbox=" << map.get_current_extent();
boost::optional<color> bg = map.background();
if (bg)
{
canvas_.drawARGB((*bg).alpha(), (*bg).red(), (*bg).green(), (*bg).blue());
}
}
void skia_renderer::end_map_processing(Map const& map)
{
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer_base: End map processing";
}
void skia_renderer::start_layer_processing(layer const& lay, box2d<double> const& query_extent)
{
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer_base: Start processing layer=" << lay.name() ;
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer_base: -- datasource=" << lay.datasource().get();
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer_base: -- query_extent=" << query_extent;
query_extent_ = query_extent;
}
void skia_renderer::end_layer_processing(layer const& lay)
{
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer_base: End layer processing";
}
void skia_renderer::start_style_processing(feature_type_style const& st)
{
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer:start style processing";
}
void skia_renderer::end_style_processing(feature_type_style const& st)
{
MAPNIK_LOG_DEBUG(skia_renderer) << "skia_renderer:end style processing";
}
void skia_renderer::process(line_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
box2d<double> clipping_extent = query_extent_;
if (sym.clip())
{
//double padding = (double)(query_extent_.width()/width_);
//padding *= 4;
//if (fabs(sym.offset()) > 0)
// padding *= fabs(sym.offset()) * 1.2;
//double x0 = query_extent_.minx();
//double y0 = query_extent_.miny();
//double x1 = query_extent_.maxx();
//double y1 = query_extent_.maxy();
//clipping_extent.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
}
SkPath path;
skia_path_adapter adapter(path);
typedef boost::mpl::vector<clip_line_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, skia_path_adapter, line_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clipping_extent,adapter,sym,t_,prj_trans,tr,scale_factor_);
if (prj_trans.equal() && sym.clip()) converter.template set<clip_line_tag>(); //optional clip (default: true)
converter.template set<transform_tag>(); //always transform
converter.template set<affine_transform_tag>();
if (sym.simplify_tolerance() > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
{
if (geom.size() > 1)
{
converter.apply(geom);
}
}
stroke const& stroke_ = sym.get_stroke();
color const& col = stroke_.get_color();
SkPaint paint;
paint.setStyle(SkPaint::kStroke_Style);
paint.setAntiAlias(true);
paint.setARGB(col.alpha(), col.red(), col.green(), col.blue());
paint.setStrokeWidth(stroke_.get_width() * scale_factor_);
if (stroke_.has_dash())
{
std::vector<SkScalar> dash;
for (auto p : stroke_.get_dash_array())
{
dash.push_back(p.first * scale_factor_);
dash.push_back(p.second * scale_factor_);
}
SkDashPathEffect dash_effect(&dash[0], dash.size(), stroke_.dash_offset(), true);
paint.setPathEffect(&dash_effect);
canvas_.drawPath(path, paint);
}
else
{
canvas_.drawPath(path, paint);
}
}
void skia_renderer::process(polygon_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
SkPath path;
skia_path_adapter adapter(path);
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, skia_path_adapter, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_, adapter ,sym,t_,prj_trans,tr,scale_factor_);
if (prj_trans.equal() && sym.clip()) converter.template set<clip_poly_tag>(); //optional clip (default: true)
converter.template set<transform_tag>(); //always transform
converter.template set<affine_transform_tag>();
if (sym.simplify_tolerance() > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
{
if (geom.size() > 2)
{
converter.apply(geom);
}
}
color const& fill = sym.get_fill();
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setAntiAlias(true);
paint.setARGB(fill.alpha(), fill.red(), fill.green(), fill.blue());
canvas_.drawPath(path, paint);
}
}
#endif // HAVE_SKIA