OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 The Chromium OS 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 "window_manager/compositor/xrender/xrender_visitor.h" |
| 6 |
| 7 #include <X11/extensions/Xrender.h> |
| 8 |
| 9 #include "base/basictypes.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/scoped_ptr.h" |
| 12 #include "window_manager/image_container.h" |
| 13 #include "window_manager/image_enums.h" |
| 14 #include "window_manager/util.h" |
| 15 #include "window_manager/x11/x_connection.h" |
| 16 |
| 17 |
| 18 #ifndef COMPOSITOR_XRENDER |
| 19 #error Need COMPOSITOR_XRENDER defined to compile this file |
| 20 #endif |
| 21 |
| 22 namespace window_manager { |
| 23 |
| 24 const int kRGBPictureBitDepth = 24; |
| 25 const int kRGBAPictureBitDepth = 32; |
| 26 |
| 27 class XRenderPictureData : public TextureData { |
| 28 public: |
| 29 XRenderPictureData(XConnection* xconn) |
| 30 : pixmap_(0), |
| 31 xconn_(xconn) { |
| 32 } |
| 33 virtual ~XRenderPictureData() { |
| 34 xconn_->RenderFreePicture(texture()); |
| 35 } |
| 36 |
| 37 // Initialize our texture and make it contain the current contents of the |
| 38 // passed-in pixmap. False is returned if the process fails (in |
| 39 // which case this object should be thrown away). |
| 40 bool Init(XPixmap pixmap, int bpp) { |
| 41 XPicture picture = xconn_->RenderCreatePicture(pixmap, bpp); |
| 42 set_texture(picture); |
| 43 return (picture != None); |
| 44 } |
| 45 |
| 46 private: |
| 47 // The actor's X pixmap. Ownership of the pixmap remains with the caller. |
| 48 XPixmap pixmap_; |
| 49 |
| 50 XConnection* xconn_; // Not owned. |
| 51 }; |
| 52 |
| 53 XRenderDrawVisitor::XRenderDrawVisitor(RealCompositor* compositor, |
| 54 Compositor::StageActor* stage) |
| 55 : root_window_(None), |
| 56 back_picture_(None), |
| 57 back_pixmap_(None), |
| 58 stage_picture_(None), |
| 59 compositor_(NULL), |
| 60 xconn_(compositor->x_conn()), |
| 61 stage_(NULL), |
| 62 ancestor_opacity_(1.0), |
| 63 has_fullscreen_actor_(false) { |
| 64 // Check for the XRender extension. |
| 65 CHECK(xconn_->RenderQueryExtension()); |
| 66 |
| 67 CHECK(AllocateXResources(stage)); |
| 68 } |
| 69 |
| 70 XRenderDrawVisitor::~XRenderDrawVisitor() { |
| 71 CHECK(FreeXResources()); |
| 72 } |
| 73 |
| 74 void XRenderDrawVisitor::BindImage(const ImageContainer& container, |
| 75 RealCompositor::ImageActor* actor) { |
| 76 XPixmap pixmap = xconn_->CreatePixmapFromContainer(container); |
| 77 |
| 78 scoped_ptr<window_manager::XRenderPictureData> data( |
| 79 new XRenderPictureData(this->xconn_)); |
| 80 data->Init(pixmap, kRGBAPictureBitDepth); |
| 81 actor->set_texture_data(data.release()); |
| 82 } |
| 83 |
| 84 void XRenderDrawVisitor::VisitStage(RealCompositor::StageActor* actor) { |
| 85 if (!actor->IsVisible()) |
| 86 return; |
| 87 |
| 88 stage_ = actor; |
| 89 |
| 90 if (actor->was_resized()) { |
| 91 CHECK(FreeXResources()); |
| 92 CHECK(AllocateXResources(actor)); |
| 93 actor->unset_was_resized(); |
| 94 } |
| 95 |
| 96 // If we don't have a full screen actor we do a fill with the stage color. |
| 97 if (!has_fullscreen_actor_) { |
| 98 const Compositor::Color& color = actor->stage_color(); |
| 99 xconn_->RenderFillRectangle(back_picture_, |
| 100 color.red, |
| 101 color.green, |
| 102 color.blue, |
| 103 Point(0, 0), |
| 104 root_geometry_.bounds.size()); |
| 105 } |
| 106 |
| 107 #ifdef EXTRA_LOGGING |
| 108 DLOG(INFO) << "Starting Render pass."; |
| 109 #endif |
| 110 |
| 111 ancestor_opacity_ = actor->opacity(); |
| 112 |
| 113 // Walk the actors and render them |
| 114 VisitContainer(actor); |
| 115 |
| 116 #ifdef EXTRA_LOGGING |
| 117 DLOG(INFO) << "Ending Render pass."; |
| 118 #endif |
| 119 |
| 120 if (!damaged_region_.empty()) { |
| 121 Matrix4 identity = Matrix4::identity(); |
| 122 identity[0][0] = damaged_region_.width; |
| 123 identity[1][1] = damaged_region_.height; |
| 124 identity[3][0] = damaged_region_.x; |
| 125 identity[3][1] = root_geometry_.bounds.height - |
| 126 damaged_region_.y - damaged_region_.height; |
| 127 |
| 128 xconn_->RenderComposite(false, |
| 129 back_picture_, |
| 130 None, |
| 131 stage_picture_, |
| 132 Point(damaged_region_.x, |
| 133 root_geometry_.bounds.height - |
| 134 damaged_region_.y - |
| 135 damaged_region_.height), |
| 136 Point(0, 0), |
| 137 identity, |
| 138 damaged_region_.size()); |
| 139 } else { |
| 140 Matrix4 identity = Vectormath::Aos::Matrix4::identity(); |
| 141 identity[0][0] = root_geometry_.bounds.width; |
| 142 identity[1][1] = root_geometry_.bounds.height; |
| 143 xconn_->RenderComposite(false, |
| 144 back_picture_, |
| 145 None, |
| 146 stage_picture_, |
| 147 Point(0, 0), |
| 148 Point(0, 0), |
| 149 identity, |
| 150 root_geometry_.bounds.size()); |
| 151 } |
| 152 |
| 153 stage_ = NULL; |
| 154 } |
| 155 |
| 156 void XRenderDrawVisitor::VisitContainer(RealCompositor::ContainerActor* actor) { |
| 157 if (!actor->IsVisible()) |
| 158 return; |
| 159 |
| 160 #ifdef EXTRA_LOGGING |
| 161 DLOG(INFO) << "Drawing container " << actor->name() << "."; |
| 162 DLOG(INFO) << " at: (" << actor->x() << ", " << actor->y() |
| 163 << ", " << actor->z() << ") with scale: (" |
| 164 << actor->scale_x() << ", " << actor->scale_y() << ") at size (" |
| 165 << actor->width() << "x" << actor->height() << ")"; |
| 166 #endif |
| 167 RealCompositor::ActorVector children = actor->GetChildren(); |
| 168 |
| 169 float original_opacity = ancestor_opacity_; |
| 170 ancestor_opacity_ *= actor->opacity(); |
| 171 |
| 172 // Walk backwards so we go back to front. |
| 173 RealCompositor::ActorVector::const_reverse_iterator iterator; |
| 174 for (iterator = children.rbegin(); iterator != children.rend(); |
| 175 ++iterator) { |
| 176 RealCompositor::Actor* child = *iterator; |
| 177 |
| 178 if (child->IsVisible()) { |
| 179 #ifdef EXTRA_LOGGING |
| 180 DLOG(INFO) << "Drawing child " << child->name() |
| 181 << " (visible: " << child->IsVisible() |
| 182 << ", has_children: " << child->has_children() |
| 183 << ", opacity: " << child->opacity() |
| 184 << ", ancestor_opacity: " << ancestor_opacity_ |
| 185 << ", is_opaque: " << child->is_opaque() << ")"; |
| 186 #endif |
| 187 child->Accept(this); |
| 188 } else { |
| 189 #ifdef EXTRA_LOGGING |
| 190 DLOG(INFO) << "NOT drawing child " << child->name() |
| 191 << " (visible: " << child->IsVisible() |
| 192 << ", has_children: " << child->has_children() |
| 193 << ", opacity: " << child->opacity() |
| 194 << ", ancestor_opacity: " << ancestor_opacity_ |
| 195 << ", is_opaque: " << child->is_opaque() << ")"; |
| 196 #endif |
| 197 } |
| 198 |
| 199 // Reset ancestor opacity. |
| 200 ancestor_opacity_ = original_opacity; |
| 201 } |
| 202 } |
| 203 |
| 204 void XRenderDrawVisitor::VisitImage(RealCompositor::ImageActor* actor) { |
| 205 if (!actor->IsVisible()) |
| 206 return; |
| 207 |
| 208 // All ImageActors are also QuadActors, and so we let the |
| 209 // QuadActor do all the actual drawing. |
| 210 VisitQuad(actor); |
| 211 } |
| 212 |
| 213 void XRenderDrawVisitor::VisitTexturePixmap( |
| 214 RealCompositor::TexturePixmapActor* actor) { |
| 215 if (!actor->IsVisible()) |
| 216 return; |
| 217 |
| 218 // Make sure we have an XRender pic for this pixmap |
| 219 if (!actor->texture_data()) { |
| 220 if (actor->pixmap()) { |
| 221 scoped_ptr<window_manager::XRenderPictureData> |
| 222 data(new XRenderPictureData(this->xconn_)); |
| 223 data->Init(actor->pixmap(), |
| 224 actor->pixmap_is_opaque() ? |
| 225 kRGBPictureBitDepth : kRGBAPictureBitDepth); |
| 226 actor->set_texture_data(data.release()); |
| 227 } |
| 228 } |
| 229 |
| 230 // All texture pixmaps are also QuadActors, and so we let the |
| 231 // QuadActor do all the actual drawing. |
| 232 VisitQuad(actor); |
| 233 } |
| 234 |
| 235 void XRenderDrawVisitor::VisitQuad(RealCompositor::QuadActor* actor) { |
| 236 if (!actor->IsVisible()) |
| 237 return; |
| 238 |
| 239 #ifdef EXTRA_LOGGING |
| 240 DLOG(INFO) << "Drawing quad " << actor->name() << "."; |
| 241 #endif |
| 242 |
| 243 // Calculate the vertex colors, taking into account the actor color, |
| 244 // opacity and the dimming gradient. |
| 245 float actor_opacity = actor->is_opaque() ? |
| 246 1.f : |
| 247 actor->opacity() * ancestor_opacity_; |
| 248 float dimmed_transparency_begin = 1.f - actor->dimmed_opacity_begin(); |
| 249 float dimmed_transparency_end = 1.f - actor->dimmed_opacity_end(); |
| 250 float red = actor->color().red; |
| 251 float green = actor->color().green; |
| 252 float blue = actor->color().blue; |
| 253 DCHECK_LE(actor_opacity, 1.f); |
| 254 DCHECK_GE(actor_opacity, 0.f); |
| 255 DCHECK_LE(dimmed_transparency_begin, 1.f); |
| 256 DCHECK_GE(dimmed_transparency_begin, 0.f); |
| 257 DCHECK_LE(dimmed_transparency_end, 1.f); |
| 258 DCHECK_GE(dimmed_transparency_end, 0.f); |
| 259 DCHECK_LE(red, 1.f); |
| 260 DCHECK_GE(red, 0.f); |
| 261 DCHECK_LE(green, 1.f); |
| 262 DCHECK_GE(green, 0.f); |
| 263 DCHECK_LE(blue, 1.f); |
| 264 DCHECK_GE(blue, 0.f); |
| 265 |
| 266 xconn_->RenderComposite( |
| 267 !actor->is_opaque(), |
| 268 static_cast<XPicture>(actor->texture_data()->texture()), |
| 269 static_cast<XPicture>(None), |
| 270 back_picture_, |
| 271 Point(0, 0), |
| 272 Point(0, 0), |
| 273 actor->model_view(), |
| 274 actor->GetBounds().size()); |
| 275 } |
| 276 |
| 277 bool XRenderDrawVisitor::FreeXResources() { |
| 278 return xconn_->FreePixmap(back_pixmap_) && |
| 279 xconn_->RenderFreePicture(back_picture_) && |
| 280 xconn_->RenderFreePicture(stage_picture_); |
| 281 } |
| 282 |
| 283 bool XRenderDrawVisitor::AllocateXResources(Compositor::StageActor* stage) { |
| 284 // Find root window geometry. |
| 285 root_window_ = stage->GetStageXWindow(); |
| 286 xconn_->GetWindowGeometry(root_window_, &root_geometry_); |
| 287 |
| 288 // Create back pixmap. |
| 289 back_pixmap_ = |
| 290 xconn_->CreatePixmap( |
| 291 root_window_, |
| 292 root_geometry_.bounds.size(), |
| 293 root_geometry_.depth); |
| 294 |
| 295 // Create back picture. |
| 296 back_picture_ = xconn_->RenderCreatePicture(back_pixmap_, |
| 297 kRGBPictureBitDepth); |
| 298 |
| 299 // Create stage picture. |
| 300 stage_picture_ = xconn_->RenderCreatePicture(root_window_, |
| 301 kRGBPictureBitDepth); |
| 302 |
| 303 return (back_pixmap_ != None) && |
| 304 (back_picture_ != None) && |
| 305 (stage_picture_ != None); |
| 306 } |
| 307 |
| 308 |
| 309 } // namespace window_manager |
OLD | NEW |