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 |