C++ Image API: introduce the SharedPixelBuffer

This commit is contained in:
Olivier Goffart 2023-03-20 13:24:40 +01:00 committed by Olivier Goffart
parent be47c8464c
commit ef7fb6422a
5 changed files with 136 additions and 41 deletions

View file

@ -11,8 +11,61 @@
namespace slint {
using cbindgen_private::types::Rgb8Pixel;
using cbindgen_private::types::Rgba8Pixel;
/// SharedPixelBuffer is a container for storing image data as pixels. It is
/// internally reference counted and cheap to clone.
///
/// You can construct a new empty shared pixel buffer with its default constructor,
/// or you can copy it from an existing contiguous buffer that you might already have, using that
/// constructor
///
/// See the documentation for Image for examples how to use this type to integrate
/// Slint with external rendering functions.
template<typename Pixel>
struct SharedPixelBuffer
{
/// construct an empty SharedPixelBuffer
SharedPixelBuffer() = default;
/// construct a SharedPixelBuffer with the given size
SharedPixelBuffer(uint32_t width, uint32_t height)
: m_width(width), m_height(height), m_data(width * height)
{
}
/// Construct a SharedPixelBuffer by copying the data from the \a data array.
/// The array must be of size \a width * \a height
SharedPixelBuffer(uint32_t width, uint32_t height, const Pixel *data)
: m_width(width), m_height(height), m_data(data, data + (width * height))
{
}
/// Return the width of the buffer in pixels
uint32_t width() const { return m_width; }
/// Return the height of the buffer in pixels
uint32_t height() const { return m_height; }
/// Returns a const pointer to the first pixel of this buffer.
const Pixel *begin() const { return m_data.begin(); }
/// Returns a const pointer past this buffer.
const Pixel *end() const { return m_data.end(); }
/// Returns a pointer to the first pixel of this buffer.
Pixel *begin() { return m_data.begin(); }
/// Returns a pointer past this buffer.
Pixel *end() { return m_data.end(); }
/// Returns a const pointer to the first pixel of this buffer.
const Pixel *cbegin() const { return m_data.begin(); }
/// Returns a const pointer past this buffer.
const Pixel *cend() const { return m_data.end(); }
/// Compare two SharedPixelBuffer. They are considered equal if all their pixels are equal
bool operator==(const SharedPixelBuffer &other) const = default;
private:
friend struct Image;
uint32_t m_width;
uint32_t m_height;
SharedVector<Pixel> m_data;
};
/// An image type that can be displayed by the Image element
struct Image
@ -28,32 +81,28 @@ public:
return img;
}
/// Construct an image from a vector of RGB pixel.
/// The size of the vector \a data should be \a width * \a height
static Image from_raw_data(unsigned int width, unsigned int height,
const SharedVector<Rgb8Pixel> &data)
{
Image img;
img.data = Data::ImageInner_EmbeddedImage(
/// Construct an image from a SharedPixelBuffer of RGB pixel.
Image(SharedPixelBuffer<Rgb8Pixel> buffer)
: data(Data::ImageInner_EmbeddedImage(
cbindgen_private::types::ImageCacheKey::Invalid(),
cbindgen_private::types::SharedImageBuffer::RGB8(
cbindgen_private::types::SharedPixelBuffer<Rgb8Pixel> {
.width = width, .height = height, .data = data }));
return img;
.width = buffer.width(),
.height = buffer.height(),
.data = buffer.m_data })))
{
}
/// Construct an image from a vector of RGBA pixels.
/// The size of the vector \a data should be \a width * \a height
static Image from_raw_data(unsigned int width, unsigned int height,
const SharedVector<Rgba8Pixel> &data)
{
Image img;
img.data = Data::ImageInner_EmbeddedImage(
/// Construct an image from a SharedPixelBuffer of RGB pixel.
Image(SharedPixelBuffer<Rgba8Pixel> buffer)
: data(Data::ImageInner_EmbeddedImage(
cbindgen_private::types::ImageCacheKey::Invalid(),
cbindgen_private::types::SharedImageBuffer::RGBA8(
cbindgen_private::types::SharedPixelBuffer<Rgba8Pixel> {
.width = width, .height = height, .data = data }));
return img;
.width = buffer.width(),
.height = buffer.height(),
.data = buffer.m_data })))
{
}
/// Returns the size of the Image in pixels.

View file

@ -230,8 +230,7 @@ public:
///
/// The stride is the amount of pixels between two lines in the buffer.
/// It is must be at least as large as the width of the window.
void render(std::span<slint::cbindgen_private::Rgb8Pixel> buffer,
std::size_t pixel_stride) const
void render(std::span<slint::Rgb8Pixel> buffer, std::size_t pixel_stride) const
{
cbindgen_private::slint_software_renderer_render_rgb8(inner, buffer.data(), buffer.size(),
pixel_stride);

View file

@ -21,17 +21,48 @@ struct SharedVector
cbindgen_private::slint_shared_vector_empty())))
{
}
/// Creates a new vector that holds all the elements of the given std::initializer_list \a args.
SharedVector(std::initializer_list<T> args) : SharedVector()
SharedVector(std::initializer_list<T> args)
: SharedVector(SharedVector::with_capacity(args.size()))
{
auto new_array = SharedVector::with_capacity(args.size());
auto new_data = reinterpret_cast<T *>(new_array.inner + 1);
auto new_data = reinterpret_cast<T *>(inner + 1);
auto input_it = args.begin();
for (std::size_t i = 0; i < args.size(); ++i, ++input_it) {
new (new_data + i) T(*input_it);
new_array.inner->size++;
inner->size++;
}
}
/// Creates a vector of a given size, with default-constructed data.
explicit SharedVector(size_t size) : SharedVector(SharedVector::with_capacity(size))
{
auto new_data = reinterpret_cast<T *>(inner + 1);
for (std::size_t i = 0; i < size; ++i) {
new (new_data + i) T();
inner->size++;
}
}
/// Creates a vector of a given size, with with copies of the value.
explicit SharedVector(size_t size, const T &value)
: SharedVector(SharedVector::with_capacity(size))
{
auto new_data = reinterpret_cast<T *>(inner + 1);
for (std::size_t i = 0; i < size; ++i) {
new (new_data + i) T(value);
inner->size++;
}
}
/// Constructs the container with the contents of the range `[first, last)`.
template<class InputIt>
SharedVector(InputIt first, InputIt last)
: SharedVector(SharedVector::with_capacity(std::distance(first, last)))
{
for (auto it = first; it != last; ++it) {
push_back(*it);
}
*this = std::move(new_array);
}
/// Creates a new vector that is a copy of \a other.
@ -41,6 +72,7 @@ struct SharedVector
++inner->refcount;
}
}
/// Destroys this vector. The underlying data is destroyed if no other
/// vector references it.
~SharedVector() { drop(); }
@ -139,13 +171,10 @@ struct SharedVector
/// and all the elements also compare equal; false otherwise.
friend bool operator==(const SharedVector &a, const SharedVector &b)
{
if (a.size() != a.size())
if (a.size() != b.size())
return false;
return std::equal(a.cbegin(), a.cend(), b.cbegin());
}
/// Returns false if the vector \a a has the same number of elements as \a b
/// and all the elements also compare equal; true otherwise.
friend bool operator!=(const SharedVector &a, const SharedVector &b) { return !(a == b); }
/// \private
std::size_t capacity() const { return inner->capacity; }