OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "chrome/browser/renderer_host/accelerated_surface_container_mac.h" | |
6 | |
7 #include "app/surface/io_surface_support_mac.h" | |
8 #include "base/logging.h" | |
9 #include "chrome/browser/renderer_host/accelerated_surface_container_manager_mac
.h" | |
10 #include "webkit/plugins/npapi/webplugin.h" | |
11 | |
12 AcceleratedSurfaceContainerMac::AcceleratedSurfaceContainerMac( | |
13 AcceleratedSurfaceContainerManagerMac* manager, | |
14 bool opaque) | |
15 : manager_(manager), | |
16 opaque_(opaque), | |
17 surface_id_(0), | |
18 width_(0), | |
19 height_(0), | |
20 texture_(0), | |
21 texture_needs_upload_(true), | |
22 texture_pending_deletion_(0), | |
23 visible_(false), | |
24 was_painted_to_(false) { | |
25 } | |
26 | |
27 AcceleratedSurfaceContainerMac::~AcceleratedSurfaceContainerMac() { | |
28 } | |
29 | |
30 void AcceleratedSurfaceContainerMac::SetSizeAndIOSurface( | |
31 int32 width, | |
32 int32 height, | |
33 uint64 io_surface_identifier) { | |
34 // Ignore |io_surface_identifier|: The surface hasn't been painted to and | |
35 // only contains garbage data. Update the surface in |set_was_painted_to()| | |
36 // instead. | |
37 width_ = width; | |
38 height_ = height; | |
39 } | |
40 | |
41 void AcceleratedSurfaceContainerMac::SetSizeAndTransportDIB( | |
42 int32 width, | |
43 int32 height, | |
44 TransportDIB::Handle transport_dib) { | |
45 if (TransportDIB::is_valid(transport_dib)) { | |
46 transport_dib_.reset(TransportDIB::Map(transport_dib)); | |
47 EnqueueTextureForDeletion(); | |
48 width_ = width; | |
49 height_ = height; | |
50 } | |
51 } | |
52 | |
53 void AcceleratedSurfaceContainerMac::SetGeometry( | |
54 const webkit::npapi::WebPluginGeometry& geom) { | |
55 visible_ = geom.visible; | |
56 if (geom.rects_valid) | |
57 clip_rect_ = geom.clip_rect; | |
58 } | |
59 | |
60 void AcceleratedSurfaceContainerMac::Draw(CGLContextObj context) { | |
61 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); | |
62 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | |
63 if (texture_pending_deletion_) { | |
64 // Clean up an old texture object. This is essentially a pre-emptive | |
65 // cleanup, as the resources will be released when the OpenGL context | |
66 // associated with our containing NSView is destroyed. However, if we | |
67 // resize a plugin often, we might generate a lot of textures, so we | |
68 // should try to eagerly reclaim their resources. Note also that the | |
69 // OpenGL context must be current when performing the deletion, and it | |
70 // seems risky to make the OpenGL context current at an arbitrary point | |
71 // in time, which is why the deletion does not occur in the container's | |
72 // destructor. | |
73 glDeleteTextures(1, &texture_pending_deletion_); | |
74 texture_pending_deletion_ = 0; | |
75 } | |
76 if (!texture_) { | |
77 if ((io_surface_support && !surface_.get()) || | |
78 (!io_surface_support && !transport_dib_.get())) | |
79 return; | |
80 glGenTextures(1, &texture_); | |
81 glBindTexture(target, texture_); | |
82 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
83 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
84 if (io_surface_support) { | |
85 texture_needs_upload_ = true; | |
86 } else { | |
87 // Reserve space on the card for the actual texture upload, done with the | |
88 // glTexSubImage2D() call, below. | |
89 glTexImage2D(target, | |
90 0, // mipmap level 0 | |
91 GL_RGBA, // internal format | |
92 width_, | |
93 height_, | |
94 0, // no border | |
95 GL_BGRA, // The GPU plugin read BGRA pixels | |
96 GL_UNSIGNED_INT_8_8_8_8_REV, | |
97 NULL); // No data, this call just reserves room. | |
98 } | |
99 } | |
100 | |
101 // When using an IOSurface, the texture does not need to be repeatedly | |
102 // uploaded, just when we've been told we have to. | |
103 if (io_surface_support && texture_needs_upload_) { | |
104 DCHECK(surface_.get()); | |
105 glBindTexture(target, texture_); | |
106 // Don't think we need to identify a plane. | |
107 GLuint plane = 0; | |
108 io_surface_support->CGLTexImageIOSurface2D(context, | |
109 target, | |
110 GL_RGBA, | |
111 surface_width_, | |
112 surface_height_, | |
113 GL_BGRA, | |
114 GL_UNSIGNED_INT_8_8_8_8_REV, | |
115 surface_.get(), | |
116 plane); | |
117 texture_needs_upload_ = false; | |
118 } | |
119 // If using TransportDIBs, the texture needs to be uploaded every frame. | |
120 if (transport_dib_.get() != NULL) { | |
121 void* pixel_memory = transport_dib_->memory(); | |
122 if (pixel_memory) { | |
123 glBindTexture(target, texture_); | |
124 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Needed for NPOT textures. | |
125 glTexSubImage2D(target, | |
126 0, // mipmap level 0 | |
127 0, // x-offset | |
128 0, // y-offset | |
129 width_, | |
130 height_, | |
131 GL_BGRA, // The GPU plugin gave us BGRA pixels | |
132 GL_UNSIGNED_INT_8_8_8_8_REV, | |
133 pixel_memory); | |
134 } | |
135 } | |
136 | |
137 if (texture_) { | |
138 int texture_width = io_surface_support ? surface_width_ : width_; | |
139 int texture_height = io_surface_support ? surface_height_ : height_; | |
140 | |
141 // TODO(kbr): convert this to use only OpenGL ES 2.0 functionality. | |
142 | |
143 // TODO(kbr): may need to pay attention to cutout rects. | |
144 int clipX = clip_rect_.x(); | |
145 int clipY = clip_rect_.y(); | |
146 int clipWidth = clip_rect_.width(); | |
147 int clipHeight = clip_rect_.height(); | |
148 | |
149 if (clipX + clipWidth > texture_width) | |
150 clipWidth = texture_width - clipX; | |
151 if (clipY + clipHeight > texture_height) | |
152 clipHeight = texture_height - clipY; | |
153 | |
154 if (opaque_) { | |
155 // Pepper 3D's output is currently considered opaque even if the | |
156 // program draws pixels with alpha less than 1. In order to have | |
157 // this effect, we need to drop the alpha channel of the input, | |
158 // replacing it with alpha = 1. | |
159 | |
160 // First fill the rectangle with alpha=1. | |
161 glColorMask(false, false, false, true); | |
162 glColor4f(0.0f, 0.0f, 0.0f, 1.0f); | |
163 glBegin(GL_TRIANGLE_STRIP); | |
164 glVertex3f(0, 0, 0); | |
165 glVertex3f(clipWidth, 0, 0); | |
166 glVertex3f(0, clipHeight, 0); | |
167 glVertex3f(clipWidth, clipHeight, 0); | |
168 glEnd(); | |
169 | |
170 // Now draw the color channels from the incoming texture. | |
171 glColorMask(true, true, true, false); | |
172 // This call shouldn't be necessary -- we are using the GL_REPLACE | |
173 // texture environment mode -- but it appears to be. | |
174 glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |
175 } else { | |
176 glColorMask(true, true, true, true); | |
177 } | |
178 | |
179 // Draw the color channels from the incoming texture. | |
180 glBindTexture(target, texture_); | |
181 glEnable(target); | |
182 glBegin(GL_TRIANGLE_STRIP); | |
183 | |
184 glTexCoord2f(clipX, texture_height - clipY); | |
185 glVertex3f(0, 0, 0); | |
186 | |
187 glTexCoord2f(clipX + clipWidth, texture_height - clipY); | |
188 glVertex3f(clipWidth, 0, 0); | |
189 | |
190 glTexCoord2f(clipX, texture_height - clipY - clipHeight); | |
191 glVertex3f(0, clipHeight, 0); | |
192 | |
193 glTexCoord2f(clipX + clipWidth, texture_height - clipY - clipHeight); | |
194 glVertex3f(clipWidth, clipHeight, 0); | |
195 | |
196 glEnd(); | |
197 glDisable(target); | |
198 } | |
199 } | |
200 | |
201 bool AcceleratedSurfaceContainerMac::ShouldBeVisible() const { | |
202 return visible_ && was_painted_to_ && !clip_rect_.IsEmpty(); | |
203 } | |
204 | |
205 void AcceleratedSurfaceContainerMac::set_was_painted_to(uint64 surface_id) { | |
206 if (surface_id && (!surface_ || surface_id != surface_id_)) { | |
207 // Keep the surface that was most recently painted to around. | |
208 if (IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize()) { | |
209 CFTypeRef surface = io_surface_support->IOSurfaceLookup( | |
210 static_cast<uint32>(surface_id)); | |
211 // Can fail if IOSurface with that ID was already released by the | |
212 // gpu process or the plugin process. We will get a |set_was_painted_to()| | |
213 // message with a new surface soon in that case. | |
214 if (surface) { | |
215 surface_.reset(surface); | |
216 surface_id_ = surface_id; | |
217 surface_width_ = io_surface_support->IOSurfaceGetWidth(surface_); | |
218 surface_height_ = io_surface_support->IOSurfaceGetHeight(surface_); | |
219 EnqueueTextureForDeletion(); | |
220 } | |
221 } | |
222 } | |
223 was_painted_to_ = true; | |
224 } | |
225 | |
226 void AcceleratedSurfaceContainerMac::EnqueueTextureForDeletion() { | |
227 if (texture_) { | |
228 DCHECK(texture_pending_deletion_ == 0); | |
229 texture_pending_deletion_ = texture_; | |
230 texture_ = 0; | |
231 } | |
232 } | |
233 | |
OLD | NEW |