| Index: chromecast/ui/gfx/surface_directfb.cc
|
| diff --git a/chromecast/ui/gfx/surface_directfb.cc b/chromecast/ui/gfx/surface_directfb.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2b4e16374c2c27f8ede6b25c5e27b3fdc5210427
|
| --- /dev/null
|
| +++ b/chromecast/ui/gfx/surface_directfb.cc
|
| @@ -0,0 +1,231 @@
|
| +// Copyright (c) 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chromecast/ui/gfx/surface_directfb.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "chromecast/ui/gfx/gfx_plane_directfb.h"
|
| +#include "ui/gfx/point.h"
|
| +#include "ui/gfx/rect.h"
|
| +#include "ui/gfx/size.h"
|
| +
|
| +namespace gfx {
|
| +namespace chromecast {
|
| +
|
| +SurfaceDirectFb::SurfaceDirectFb(GfxPlaneDirectFb* arg_plane,
|
| + const Size& arg_size, bool arg_primary)
|
| + : Surface(arg_plane, arg_size),
|
| + primary_(arg_primary) {
|
| + DFBSurfaceDescription dsc;
|
| +
|
| + if (primary_) {
|
| + // fix directfb's abuse of an enum as a bitfield, allowed in C, not C++
|
| + dsc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_CAPS |
|
| + DSDESC_PIXELFORMAT);
|
| +#if defined(DOUBLE_BUFFER)
|
| + dsc.caps = static_cast<DFBSurfaceCapabilities>(DSCAPS_PRIMARY |
|
| + DSCAPS_DOUBLE);
|
| +#else
|
| + dsc.caps = DSCAPS_PRIMARY;
|
| + // Add DSCAPS_DOUBLE to double-buffer, and if so, we'll need to disable
|
| + // autoflip-window, and explictly call Flip.
|
| + //
|
| +#endif
|
| + } else {
|
| + // fix directfb's abuse of an enum as a bitfield, allowed in C, not C++
|
| + dsc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_CAPS |
|
| + DSDESC_WIDTH |
|
| + DSDESC_HEIGHT |
|
| + DSDESC_PIXELFORMAT);
|
| + dsc.caps = DSCAPS_NONE; // not sure this is necessary
|
| + dsc.width = arg_size.width();
|
| + dsc.height = arg_size.height();
|
| + }
|
| +
|
| + // Default (on Linux) seems to be RGB32, force it to ARGB so as to be
|
| + // compatible with chrome
|
| + // and we won't have to convert pixels.
|
| + dsc.pixelformat = DSPF_ARGB;
|
| +
|
| + DFBResult err = arg_plane->dfb()->CreateSurface(arg_plane->dfb(), &dsc,
|
| + &internal_surface_);
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "Create surface failed, err = " << DirectFBErrorString(err);
|
| + }
|
| +
|
| + if (primary_) {
|
| + // Do some sanity non-fatal sanity checks for primary surface.
|
| + // These shouldn't fail and it isn't clear how we can recover.
|
| + DFBSurfacePixelFormat pixelformat;
|
| + err = internal_surface_->GetPixelFormat(internal_surface_, &pixelformat);
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "GetPixelFormat failed, err = "
|
| + << DirectFBErrorString(err);
|
| + } else if (pixelformat != DSPF_ARGB) {
|
| + LOG(FATAL) << "Pixel format not DSPF_ARGB, err = "
|
| + << DirectFBErrorString(err);
|
| + }
|
| +
|
| + // Reset size.
|
| + int width = 0;
|
| + int height = 0;
|
| + err = internal_surface_->GetSize(internal_surface_, &width, &height);
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "GetSize failed, err = " << DirectFBErrorString(err);
|
| + } else if (width <= 0 || height <= 0) {
|
| + LOG(FATAL) << "GetSize didn't return a positive screen size, err = "
|
| + << DirectFBErrorString(err);
|
| + }
|
| + set_size(Size(width, height));
|
| + }
|
| +}
|
| +
|
| +SurfaceDirectFb::~SurfaceDirectFb() {
|
| + internal_surface_->Release(internal_surface_);
|
| +}
|
| +
|
| +void SurfaceDirectFb::Blit(Surface* e_src_surface,
|
| + const Rect& src_rect,
|
| + const Point& dst_point) {
|
| + SurfaceDirectFb* src_surface = static_cast<SurfaceDirectFb*>(e_src_surface);
|
| +
|
| + DFBRectangle dfb_src_rect;
|
| + dfb_src_rect.x = src_rect.x();
|
| + dfb_src_rect.y = src_rect.y();
|
| + dfb_src_rect.w = src_rect.width();
|
| + dfb_src_rect.h = src_rect.height();
|
| +
|
| + DFBResult err = internal_surface_->Blit(
|
| + internal_surface_, src_surface->internal_surface_, &dfb_src_rect,
|
| + dst_point.x(), dst_point.y());
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "Blit failed, err = " << DirectFBErrorString(err);
|
| + }
|
| +}
|
| +
|
| +void SurfaceDirectFb::Composite(Surface* e_src_surface,
|
| + const Rect& src_rect,
|
| + const Point& dst_point) {
|
| + // TODO(byungchul): To be perfect, surface for OSD should set this flag
|
| + // permanently. Considering this implementation is for testing on x86,
|
| + // setting flag here is just to keep consistency with marvell implementation.
|
| + internal_surface_->SetBlittingFlags(internal_surface_,
|
| + DSBLIT_BLEND_ALPHACHANNEL);
|
| + Blit(e_src_surface, src_rect, dst_point);
|
| + internal_surface_->SetBlittingFlags(internal_surface_, DSBLIT_NOFX);
|
| +}
|
| +
|
| +void SurfaceDirectFb::CopyBitmap(char* src_bitmap,
|
| + const Rect& src_rect,
|
| + const Rect& damage_rect,
|
| + const Point& dst_point) {
|
| + std::vector<Rect> damage_rect_vector;
|
| + damage_rect_vector.push_back(damage_rect);
|
| +
|
| + std::vector<Point> dst_point_vector;
|
| + dst_point_vector.push_back(dst_point);
|
| +
|
| + BatchCopyBitmap(src_bitmap, src_rect, damage_rect_vector, dst_point_vector);
|
| +}
|
| +
|
| +void SurfaceDirectFb::BatchCopyBitmap(
|
| + char* src_bitmap,
|
| + const Rect& src_rect,
|
| + const std::vector<Rect>& damage_rect_vector,
|
| + const std::vector<Point>& dst_point_vector) {
|
| + DCHECK_EQ(damage_rect_vector.size(), dst_point_vector.size());
|
| +
|
| + // Note: use dynamic arrays (gcc extension) so we don't
|
| + // have to malloc / free space.
|
| + DFBRectangle src_rects[damage_rect_vector.size()];
|
| + DFBPoint dst_points[damage_rect_vector.size()];
|
| + int max_height = 0;
|
| + for (size_t i = 0; i < damage_rect_vector.size(); ++i) {
|
| + src_rects[i].x = damage_rect_vector[i].x();
|
| + src_rects[i].y = damage_rect_vector[i].y();
|
| + src_rects[i].w = damage_rect_vector[i].width();
|
| + src_rects[i].h = damage_rect_vector[i].height();
|
| + dst_points[i].x = dst_point_vector[i].x();
|
| + dst_points[i].y = dst_point_vector[i].y();
|
| + if (max_height < damage_rect_vector[i].height()) {
|
| + max_height = damage_rect_vector[i].height();
|
| + }
|
| + };
|
| +
|
| + DCHECK_LE(max_height, src_rect.height());
|
| +
|
| + // Creates a tempory surface for source bitmap.
|
| + DFBSurfaceDescription dsc;
|
| + // fix directfb's abuse of an enum as a bitfield, allowed in C, not C++
|
| + dsc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_CAPS |
|
| + DSDESC_WIDTH |
|
| + DSDESC_HEIGHT |
|
| + DSDESC_PIXELFORMAT |
|
| + DSDESC_PREALLOCATED);
|
| + dsc.caps = DSCAPS_NONE; // not sure this is necessary
|
| + dsc.width = src_rect.width();
|
| + dsc.height = src_rect.height();
|
| + dsc.pixelformat = DSPF_ARGB; // Assume 32-bit ARGB pixels
|
| + dsc.preallocated[0].data = src_bitmap;
|
| + dsc.preallocated[0].pitch = src_rect.width() * kBytesPerPixelOfARGB;
|
| + dsc.preallocated[1].data = NULL; // back buffer, not provided
|
| + dsc.preallocated[1].pitch = 0;
|
| +
|
| + IDirectFB* dfb = static_cast<GfxPlaneDirectFb*>(plane())->dfb();
|
| + IDirectFBSurface* src_surface = NULL;
|
| + DFBResult err = dfb->CreateSurface(dfb, &dsc, &src_surface);
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "Create surface failed, err = " << DirectFBErrorString(err);
|
| + }
|
| +
|
| + err = internal_surface_->BatchBlit(internal_surface_, src_surface, src_rects,
|
| + dst_points, damage_rect_vector.size());
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "BatchBlit failed, err = " << DirectFBErrorString(err);
|
| + // falling through to release the surface and it does no harm to flip.
|
| + }
|
| +
|
| + src_surface->Release(src_surface);
|
| +}
|
| +
|
| +void SurfaceDirectFb::Fill(const Rect& rect, int argb) {
|
| + NOTIMPLEMENTED();
|
| +}
|
| +
|
| +void SurfaceDirectFb::Display(const Rect& rect,
|
| + const Point& frame_buffer_point) {
|
| + plane()->Display(this, rect, frame_buffer_point);
|
| +
|
| + // Double buffering shouldn't be necessary when running under X11
|
| + // (we should do it anyway for consistency and debugging).
|
| + //
|
| + // If running directfb under X11 and we are single-buffered,
|
| + // a flip is still needed. When running on the target and
|
| + // single-buffered, no flip is needed (but shouldn't hurt).
|
| + //
|
| + // An alternative to flipping here when single buffered is
|
| + // to allow directfb to create a flipping thread.
|
| + IDirectFBSurface* primary =
|
| + static_cast<SurfaceDirectFb*>(plane()->frame_buffer())->internal_surface_;
|
| + DFBResult err = primary->Flip(primary, NULL,
|
| +#if defined(DOUBLE_BUFFER)
|
| + DSFLIP_WAITFORSYNC
|
| +#else
|
| + DSFLIP_NONE
|
| +#endif
|
| + );
|
| + if (err != DFB_OK) {
|
| + LOG(FATAL) << "Flip failed, err = " << DirectFBErrorString(err);
|
| + return;
|
| + }
|
| +
|
| +#if defined(DOUBLE_BUFFER)
|
| + // After a flip, we need to write the data again to the now stale back
|
| + // buffer (this makes it identical to the currently displayed front buffer.
|
| + plane()->Display(this, rect, frame_buffer_point);
|
| +#endif
|
| +}
|
| +
|
| +} // namespace chromecast
|
| +} // namespace gfx
|
|
|