add new canvas Image item, with somewhat optimized API for asynchronous, threaded rendering directly into an image buffer suitable for use by cairo as a source surface (currently untested)

This commit is contained in:
Paul Davis 2013-04-15 21:40:15 -04:00
parent 64c861a791
commit fe34485907
3 changed files with 139 additions and 1 deletions

View File

@ -0,0 +1,57 @@
#ifndef __CANVAS_IMAGE__
#define __CANVAS_IMAGE__
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include "canvas/item.h"
namespace ArdourCanvas {
class Image : public Item
{
public:
Image (Group *, Cairo::Format, int width, int height);
struct Data {
Data (boost::shared_array<uint8_t> d, int w, int h, int s, Cairo::Format fmt)
: data (d)
, width (w)
, height (h)
, stride (s)
, format (fmt)
{}
boost::shared_array<uint8_t> data;
int width;
int height;
int stride;
Cairo::Format format;
};
boost::shared_ptr<Data> get_image ();
void put_image (boost::shared_ptr<Data>);
void render (Rect const &, Cairo::RefPtr<Cairo::Context>) const;
void compute_bounding_box () const;
XMLNode* get_state () const;
void set_state (XMLNode const *);
private:
Cairo::Format _format;
int _width;
int _height;
int _data;
mutable boost::shared_ptr<Data> _current;
boost::shared_ptr<Data> _pending;
mutable bool _need_render;
mutable Cairo::RefPtr<Cairo::Surface> _surface;
void accept_data ();
PBD::Signal0<void> DataReady;
PBD::ScopedConnectionList data_connections;
};
}
#endif

80
libs/canvas/image.cc Normal file
View File

@ -0,0 +1,80 @@
#include "canvas/image.h"
#include "gtkmm2ext/gui_thread.h"
#include "pbd/xml++.h"
using namespace ArdourCanvas;
Image::Image (Group* group, Cairo::Format fmt, int width, int height)
: Item (group)
, _format (fmt)
, _width (width)
, _height (height)
, _need_render (false)
{
DataReady.connect (data_connections, MISSING_INVALIDATOR, boost::bind (&Image::accept_data, this), gui_context());
}
void
Image::render (Rect const& area, Cairo::RefPtr<Cairo::Context> context) const
{
if (_current) {
_surface = Cairo::ImageSurface::create (_current->data.get(),
_current->format,
_current->width,
_current->height,
_current->stride);
}
_current.reset ();
context->set_source (_surface, 0, 0);
context->rectangle (area.x0, area.y0, area.width(), area.height());
context->fill ();
}
void
Image::compute_bounding_box () const
{
_bounding_box = boost::optional<Rect> (Rect (0, 0, _width, _height));
_bounding_box_dirty = false;
}
boost::shared_ptr<Image::Data>
Image::get_image ()
{
int stride = Cairo::ImageSurface::format_stride_for_width (_format, _width);
boost::shared_ptr<Data> d (new Data (boost::shared_array<uint8_t> (new uint8_t[stride*_height]), _width, _height, stride, _format));
return d;
}
void
Image::put_image (boost::shared_ptr<Data> d)
{
_pending = d;
DataReady (); /* EMIT SIGNAL */
}
void
Image::accept_data ()
{
/* must be executed in gui thread */
_current = _pending;
_pending.reset ();
_need_render = true;
}
XMLNode *
Image::get_state () const
{
/* XXX */
return new XMLNode ("Image");
}
void
Image::set_state (XMLNode const * /*node*/)
{
/* XXX */
}

View File

@ -36,6 +36,7 @@ canvas_sources = [
'fill.cc',
'flag.cc',
'group.cc',
'image.cc',
'item_factory.cc',
'line.cc',
'line_set.cc',
@ -72,7 +73,7 @@ def build(bld):
obj.export_includes = ['.']
obj.includes = ['.']
obj.uselib = 'SIGCPP CAIROMM GTKMM'
obj.uselib = 'SIGCPP CAIROMM GTKMM BOOST'
obj.use = [ 'libpbd', 'libevoral', 'libardour', 'libgtkmm2ext' ]
obj.name = 'libcanvas'
obj.target = 'canvas'