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> | |
79 data(new XRenderPictureData(this->xconn_)); | |
Daniel Erat
2011/04/05 22:45:19
nit: variable name should come on same line as typ
marcheu
2011/04/06 00:26:12
Done.
| |
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 |