OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chromecast/ui/gfx/surface_directfb.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "chromecast/ui/gfx/gfx_plane_directfb.h" |
| 9 #include "ui/gfx/point.h" |
| 10 #include "ui/gfx/rect.h" |
| 11 #include "ui/gfx/size.h" |
| 12 |
| 13 namespace gfx { |
| 14 namespace chromecast { |
| 15 |
| 16 SurfaceDirectFb::SurfaceDirectFb(GfxPlaneDirectFb* arg_plane, |
| 17 const Size& arg_size, bool arg_primary) |
| 18 : Surface(arg_plane, arg_size), |
| 19 primary_(arg_primary) { |
| 20 DFBSurfaceDescription dsc; |
| 21 |
| 22 if (primary_) { |
| 23 // fix directfb's abuse of an enum as a bitfield, allowed in C, not C++ |
| 24 dsc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_CAPS | |
| 25 DSDESC_PIXELFORMAT); |
| 26 #if defined(DOUBLE_BUFFER) |
| 27 dsc.caps = static_cast<DFBSurfaceCapabilities>(DSCAPS_PRIMARY | |
| 28 DSCAPS_DOUBLE); |
| 29 #else |
| 30 dsc.caps = DSCAPS_PRIMARY; |
| 31 // Add DSCAPS_DOUBLE to double-buffer, and if so, we'll need to disable |
| 32 // autoflip-window, and explictly call Flip. |
| 33 // |
| 34 #endif |
| 35 } else { |
| 36 // fix directfb's abuse of an enum as a bitfield, allowed in C, not C++ |
| 37 dsc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_CAPS | |
| 38 DSDESC_WIDTH | |
| 39 DSDESC_HEIGHT | |
| 40 DSDESC_PIXELFORMAT); |
| 41 dsc.caps = DSCAPS_NONE; // not sure this is necessary |
| 42 dsc.width = arg_size.width(); |
| 43 dsc.height = arg_size.height(); |
| 44 } |
| 45 |
| 46 // Default (on Linux) seems to be RGB32, force it to ARGB so as to be |
| 47 // compatible with chrome |
| 48 // and we won't have to convert pixels. |
| 49 dsc.pixelformat = DSPF_ARGB; |
| 50 |
| 51 DFBResult err = arg_plane->dfb()->CreateSurface(arg_plane->dfb(), &dsc, |
| 52 &internal_surface_); |
| 53 if (err != DFB_OK) { |
| 54 LOG(FATAL) << "Create surface failed, err = " << DirectFBErrorString(err); |
| 55 } |
| 56 |
| 57 if (primary_) { |
| 58 // Do some sanity non-fatal sanity checks for primary surface. |
| 59 // These shouldn't fail and it isn't clear how we can recover. |
| 60 DFBSurfacePixelFormat pixelformat; |
| 61 err = internal_surface_->GetPixelFormat(internal_surface_, &pixelformat); |
| 62 if (err != DFB_OK) { |
| 63 LOG(FATAL) << "GetPixelFormat failed, err = " |
| 64 << DirectFBErrorString(err); |
| 65 } else if (pixelformat != DSPF_ARGB) { |
| 66 LOG(FATAL) << "Pixel format not DSPF_ARGB, err = " |
| 67 << DirectFBErrorString(err); |
| 68 } |
| 69 |
| 70 // Reset size. |
| 71 int width = 0; |
| 72 int height = 0; |
| 73 err = internal_surface_->GetSize(internal_surface_, &width, &height); |
| 74 if (err != DFB_OK) { |
| 75 LOG(FATAL) << "GetSize failed, err = " << DirectFBErrorString(err); |
| 76 } else if (width <= 0 || height <= 0) { |
| 77 LOG(FATAL) << "GetSize didn't return a positive screen size, err = " |
| 78 << DirectFBErrorString(err); |
| 79 } |
| 80 set_size(Size(width, height)); |
| 81 } |
| 82 } |
| 83 |
| 84 SurfaceDirectFb::~SurfaceDirectFb() { |
| 85 internal_surface_->Release(internal_surface_); |
| 86 } |
| 87 |
| 88 void SurfaceDirectFb::Blit(Surface* e_src_surface, |
| 89 const Rect& src_rect, |
| 90 const Point& dst_point) { |
| 91 SurfaceDirectFb* src_surface = static_cast<SurfaceDirectFb*>(e_src_surface); |
| 92 |
| 93 DFBRectangle dfb_src_rect; |
| 94 dfb_src_rect.x = src_rect.x(); |
| 95 dfb_src_rect.y = src_rect.y(); |
| 96 dfb_src_rect.w = src_rect.width(); |
| 97 dfb_src_rect.h = src_rect.height(); |
| 98 |
| 99 DFBResult err = internal_surface_->Blit( |
| 100 internal_surface_, src_surface->internal_surface_, &dfb_src_rect, |
| 101 dst_point.x(), dst_point.y()); |
| 102 if (err != DFB_OK) { |
| 103 LOG(FATAL) << "Blit failed, err = " << DirectFBErrorString(err); |
| 104 } |
| 105 } |
| 106 |
| 107 void SurfaceDirectFb::Composite(Surface* e_src_surface, |
| 108 const Rect& src_rect, |
| 109 const Point& dst_point) { |
| 110 // TODO(byungchul): To be perfect, surface for OSD should set this flag |
| 111 // permanently. Considering this implementation is for testing on x86, |
| 112 // setting flag here is just to keep consistency with marvell implementation. |
| 113 internal_surface_->SetBlittingFlags(internal_surface_, |
| 114 DSBLIT_BLEND_ALPHACHANNEL); |
| 115 Blit(e_src_surface, src_rect, dst_point); |
| 116 internal_surface_->SetBlittingFlags(internal_surface_, DSBLIT_NOFX); |
| 117 } |
| 118 |
| 119 void SurfaceDirectFb::CopyBitmap(char* src_bitmap, |
| 120 const Rect& src_rect, |
| 121 const Rect& damage_rect, |
| 122 const Point& dst_point) { |
| 123 std::vector<Rect> damage_rect_vector; |
| 124 damage_rect_vector.push_back(damage_rect); |
| 125 |
| 126 std::vector<Point> dst_point_vector; |
| 127 dst_point_vector.push_back(dst_point); |
| 128 |
| 129 BatchCopyBitmap(src_bitmap, src_rect, damage_rect_vector, dst_point_vector); |
| 130 } |
| 131 |
| 132 void SurfaceDirectFb::BatchCopyBitmap( |
| 133 char* src_bitmap, |
| 134 const Rect& src_rect, |
| 135 const std::vector<Rect>& damage_rect_vector, |
| 136 const std::vector<Point>& dst_point_vector) { |
| 137 DCHECK_EQ(damage_rect_vector.size(), dst_point_vector.size()); |
| 138 |
| 139 // Note: use dynamic arrays (gcc extension) so we don't |
| 140 // have to malloc / free space. |
| 141 DFBRectangle src_rects[damage_rect_vector.size()]; |
| 142 DFBPoint dst_points[damage_rect_vector.size()]; |
| 143 int max_height = 0; |
| 144 for (size_t i = 0; i < damage_rect_vector.size(); ++i) { |
| 145 src_rects[i].x = damage_rect_vector[i].x(); |
| 146 src_rects[i].y = damage_rect_vector[i].y(); |
| 147 src_rects[i].w = damage_rect_vector[i].width(); |
| 148 src_rects[i].h = damage_rect_vector[i].height(); |
| 149 dst_points[i].x = dst_point_vector[i].x(); |
| 150 dst_points[i].y = dst_point_vector[i].y(); |
| 151 if (max_height < damage_rect_vector[i].height()) { |
| 152 max_height = damage_rect_vector[i].height(); |
| 153 } |
| 154 }; |
| 155 |
| 156 DCHECK_LE(max_height, src_rect.height()); |
| 157 |
| 158 // Creates a tempory surface for source bitmap. |
| 159 DFBSurfaceDescription dsc; |
| 160 // fix directfb's abuse of an enum as a bitfield, allowed in C, not C++ |
| 161 dsc.flags = static_cast<DFBSurfaceDescriptionFlags>(DSDESC_CAPS | |
| 162 DSDESC_WIDTH | |
| 163 DSDESC_HEIGHT | |
| 164 DSDESC_PIXELFORMAT | |
| 165 DSDESC_PREALLOCATED); |
| 166 dsc.caps = DSCAPS_NONE; // not sure this is necessary |
| 167 dsc.width = src_rect.width(); |
| 168 dsc.height = src_rect.height(); |
| 169 dsc.pixelformat = DSPF_ARGB; // Assume 32-bit ARGB pixels |
| 170 dsc.preallocated[0].data = src_bitmap; |
| 171 dsc.preallocated[0].pitch = src_rect.width() * kBytesPerPixelOfARGB; |
| 172 dsc.preallocated[1].data = NULL; // back buffer, not provided |
| 173 dsc.preallocated[1].pitch = 0; |
| 174 |
| 175 IDirectFB* dfb = static_cast<GfxPlaneDirectFb*>(plane())->dfb(); |
| 176 IDirectFBSurface* src_surface = NULL; |
| 177 DFBResult err = dfb->CreateSurface(dfb, &dsc, &src_surface); |
| 178 if (err != DFB_OK) { |
| 179 LOG(FATAL) << "Create surface failed, err = " << DirectFBErrorString(err); |
| 180 } |
| 181 |
| 182 err = internal_surface_->BatchBlit(internal_surface_, src_surface, src_rects, |
| 183 dst_points, damage_rect_vector.size()); |
| 184 if (err != DFB_OK) { |
| 185 LOG(FATAL) << "BatchBlit failed, err = " << DirectFBErrorString(err); |
| 186 // falling through to release the surface and it does no harm to flip. |
| 187 } |
| 188 |
| 189 src_surface->Release(src_surface); |
| 190 } |
| 191 |
| 192 void SurfaceDirectFb::Fill(const Rect& rect, int argb) { |
| 193 NOTIMPLEMENTED(); |
| 194 } |
| 195 |
| 196 void SurfaceDirectFb::Display(const Rect& rect, |
| 197 const Point& frame_buffer_point) { |
| 198 plane()->Display(this, rect, frame_buffer_point); |
| 199 |
| 200 // Double buffering shouldn't be necessary when running under X11 |
| 201 // (we should do it anyway for consistency and debugging). |
| 202 // |
| 203 // If running directfb under X11 and we are single-buffered, |
| 204 // a flip is still needed. When running on the target and |
| 205 // single-buffered, no flip is needed (but shouldn't hurt). |
| 206 // |
| 207 // An alternative to flipping here when single buffered is |
| 208 // to allow directfb to create a flipping thread. |
| 209 IDirectFBSurface* primary = |
| 210 static_cast<SurfaceDirectFb*>(plane()->frame_buffer())->internal_surface_; |
| 211 DFBResult err = primary->Flip(primary, NULL, |
| 212 #if defined(DOUBLE_BUFFER) |
| 213 DSFLIP_WAITFORSYNC |
| 214 #else |
| 215 DSFLIP_NONE |
| 216 #endif |
| 217 ); |
| 218 if (err != DFB_OK) { |
| 219 LOG(FATAL) << "Flip failed, err = " << DirectFBErrorString(err); |
| 220 return; |
| 221 } |
| 222 |
| 223 #if defined(DOUBLE_BUFFER) |
| 224 // After a flip, we need to write the data again to the now stale back |
| 225 // buffer (this makes it identical to the currently displayed front buffer. |
| 226 plane()->Display(this, rect, frame_buffer_point); |
| 227 #endif |
| 228 } |
| 229 |
| 230 } // namespace chromecast |
| 231 } // namespace gfx |
OLD | NEW |