Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: ui/accelerated_widget_mac/io_surface_texture.mm

Issue 1420533005: Mac: Kill lots of AcceleratedWidget code (with fire) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Feedback 2 Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 "ui/accelerated_widget_mac/io_surface_texture.h"
6
7 #include <OpenGL/CGLIOSurface.h>
8 #include <OpenGL/CGLRenderers.h>
9 #include <OpenGL/gl.h>
10 #include <OpenGL/OpenGL.h>
11
12 #include "base/bind.h"
13 #include "base/bind_helpers.h"
14 #include "base/callback_helpers.h"
15 #include "base/command_line.h"
16 #include "base/logging.h"
17 #include "base/mac/bind_objc_block.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/trace_event/trace_event.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/accelerated_widget_mac/io_surface_context.h"
23 #include "ui/base/ui_base_switches.h"
24 #include "ui/gfx/geometry/rect.h"
25 #include "ui/gfx/geometry/size_conversions.h"
26 #include "ui/gl/gl_context.h"
27
28 namespace ui {
29
30 // static
31 scoped_refptr<IOSurfaceTexture> IOSurfaceTexture::Create(
32 bool needs_gl_finish_workaround,
33 bool use_ns_apis) {
34 scoped_refptr<IOSurfaceContext> offscreen_context;
35 if (!use_ns_apis) {
36 offscreen_context = IOSurfaceContext::Get(
37 IOSurfaceContext::kOffscreenContext);
38 if (!offscreen_context.get()) {
39 LOG(ERROR) << "Failed to create context for offscreen operations";
40 return NULL;
41 }
42 }
43 return new IOSurfaceTexture(
44 offscreen_context, use_ns_apis, needs_gl_finish_workaround);
45 }
46
47 IOSurfaceTexture::IOSurfaceTexture(
48 const scoped_refptr<IOSurfaceContext>& offscreen_context,
49 bool use_ns_apis,
50 bool needs_gl_finish_workaround)
51 : offscreen_context_(offscreen_context),
52 texture_(0),
53 gl_error_(GL_NO_ERROR),
54 eviction_queue_iterator_(eviction_queue_.Get().end()),
55 eviction_has_been_drawn_since_updated_(false),
56 needs_gl_finish_workaround_(needs_gl_finish_workaround),
57 using_ns_apis_(use_ns_apis) {
58 }
59
60 IOSurfaceTexture::~IOSurfaceTexture() {
61 ReleaseIOSurfaceAndTexture();
62 offscreen_context_ = NULL;
63 DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end());
64 }
65
66 bool IOSurfaceTexture::DrawIOSurface() {
67 return DrawIOSurfaceWithDamageRect(gfx::Rect(pixel_size_));
68 }
69
70 bool IOSurfaceTexture::DrawIOSurfaceWithDamageRect(gfx::Rect damage_rect) {
71 TRACE_EVENT0("browser", "IOSurfaceTexture::DrawIOSurfaceWithDamageRect");
72 DCHECK(CGLGetCurrentContext());
73
74 // If we have release the IOSurface, clear the screen to light grey and
75 // early-out.
76 if (!io_surface_) {
77 glClearColor(0.9, 0.9, 0.9, 1);
78 glClear(GL_COLOR_BUFFER_BIT);
79 return false;
80 }
81
82 // The viewport is the size of the CALayer, which should always match the
83 // IOSurface pixel size.
84 GLint viewport[4];
85 glGetIntegerv(GL_VIEWPORT, viewport);
86 gfx::Rect viewport_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
87
88 // Set the projection matrix to match 1 unit to 1 pixel.
89 glMatrixMode(GL_PROJECTION);
90 glLoadIdentity();
91 glOrtho(0, viewport_rect.width(),
92 pixel_size_.height() - viewport_rect.height(), pixel_size_.height(),
93 -1, 1);
94 glMatrixMode(GL_MODELVIEW);
95 glLoadIdentity();
96
97 // Draw a quad the size of the IOSurface. This should cover the full viewport.
98 glColor4f(1, 1, 1, 1);
99 glEnable(GL_TEXTURE_RECTANGLE_ARB);
100 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
101 glBegin(GL_QUADS);
102 glTexCoord2f(damage_rect.x(), damage_rect.y());
103 glVertex2f(damage_rect.x(), damage_rect.y());
104 glTexCoord2f(damage_rect.right(), damage_rect.y());
105 glVertex2f(damage_rect.right(), damage_rect.y());
106 glTexCoord2f(damage_rect.right(), damage_rect.bottom());
107 glVertex2f(damage_rect.right(), damage_rect.bottom());
108 glTexCoord2f(damage_rect.x(), damage_rect.bottom());
109 glVertex2f(damage_rect.x(), damage_rect.bottom());
110 glEnd();
111 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
112 glDisable(GL_TEXTURE_RECTANGLE_ARB);
113
114 // Workaround for issue 158469. Issue a dummy draw call with texture_ not
115 // bound to a texture, in order to shake all references to the IOSurface out
116 // of the driver.
117 glBegin(GL_TRIANGLES);
118 glEnd();
119
120 if (needs_gl_finish_workaround_) {
121 TRACE_EVENT0("gpu", "glFinish");
122 glFinish();
123 }
124
125 // Check if any of the drawing calls result in an error.
126 GetAndSaveGLError();
127 bool result = true;
128 if (gl_error_ != GL_NO_ERROR) {
129 LOG(ERROR) << "GL error in DrawIOSurface: " << gl_error_;
130 result = false;
131 // If there was an error, clear the screen to a light grey to avoid
132 // rendering artifacts.
133 glClearColor(0.8, 0.8, 0.8, 1.0);
134 glClear(GL_COLOR_BUFFER_BIT);
135 }
136
137 eviction_has_been_drawn_since_updated_ = true;
138 return result;
139 }
140
141 bool IOSurfaceTexture::IsUpToDate(
142 IOSurfaceID io_surface_id, const gfx::Size& pixel_size) const {
143 return io_surface_ &&
144 io_surface_id == IOSurfaceGetID(io_surface_) &&
145 pixel_size == pixel_size_;
146 }
147
148 bool IOSurfaceTexture::SetIOSurface(
149 IOSurfaceID io_surface_id, const gfx::Size& pixel_size) {
150 TRACE_EVENT0("browser", "IOSurfaceTexture::MapIOSurfaceToTexture");
151
152 // Destroy the old IOSurface and texture if it is no longer needed.
153 bool needs_new_iosurface =
154 !io_surface_ || io_surface_id != IOSurfaceGetID(io_surface_);
155 if (needs_new_iosurface)
156 ReleaseIOSurfaceAndTexture();
157
158 // Note that because IOSurface sizes are rounded, the same IOSurface may have
159 // two different sizes associated with it, so update the sizes before the
160 // early-out.
161 pixel_size_ = pixel_size;
162
163 // Early-out if the IOSurface has not changed.
164 if (!needs_new_iosurface)
165 return true;
166
167 // If we early-out at any point from now on, it's because of an error, and we
168 // should destroy the texture and release the IOSurface.
169 base::ScopedClosureRunner error_runner(base::BindBlock(^{
170 ReleaseIOSurfaceAndTexture();
171 }));
172
173 // Open the IOSurface handle.
174 io_surface_.reset(IOSurfaceLookup(io_surface_id));
175 if (!io_surface_)
176 return false;
177
178 // Actual IOSurface size is rounded up to reduce reallocations during window
179 // resize. Get the actual size to properly map the texture.
180 gfx::Size rounded_size(IOSurfaceGetWidth(io_surface_),
181 IOSurfaceGetHeight(io_surface_));
182
183 // Create the GL texture and set it to be backed by the IOSurface.
184 CGLError cgl_error = kCGLNoError;
185 {
186 scoped_ptr<gfx::ScopedCGLSetCurrentContext> scoped_set_current_context;
187 if (offscreen_context_) {
188 scoped_set_current_context.reset(new gfx::ScopedCGLSetCurrentContext(
189 offscreen_context_->cgl_context()));
190 } else {
191 DCHECK(CGLGetCurrentContext());
192 }
193
194 glGenTextures(1, &texture_);
195 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
196 glTexParameterf(
197 GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
198 glTexParameterf(
199 GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
200 cgl_error = CGLTexImageIOSurface2D(
201 CGLGetCurrentContext(),
202 GL_TEXTURE_RECTANGLE_ARB,
203 GL_RGBA,
204 rounded_size.width(),
205 rounded_size.height(),
206 GL_BGRA,
207 GL_UNSIGNED_INT_8_8_8_8_REV,
208 io_surface_.get(),
209 0 /* plane */);
210 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
211 GetAndSaveGLError();
212 }
213
214 // Return failure if an error was encountered by CGL or GL.
215 if (cgl_error != kCGLNoError) {
216 LOG(ERROR) << "CGLTexImageIOSurface2D failed with CGL error: " << cgl_error;
217 return false;
218 }
219 if (gl_error_ != GL_NO_ERROR) {
220 LOG(ERROR) << "Hit GL error in SetIOSurface: " << gl_error_;
221 return false;
222 }
223
224 ignore_result(error_runner.Release());
225 return true;
226 }
227
228 void IOSurfaceTexture::ReleaseIOSurfaceAndTexture() {
229 scoped_ptr<gfx::ScopedCGLSetCurrentContext> scoped_set_current_context;
230 if (offscreen_context_) {
231 scoped_set_current_context.reset(new gfx::ScopedCGLSetCurrentContext(
232 offscreen_context_->cgl_context()));
233 } else {
234 DCHECK(CGLGetCurrentContext());
235 }
236
237 if (texture_) {
238 glDeleteTextures(1, &texture_);
239 texture_ = 0;
240 }
241 pixel_size_ = gfx::Size();
242 io_surface_.reset();
243
244 EvictionMarkEvicted();
245 }
246
247 bool IOSurfaceTexture::HasBeenPoisoned() const {
248 if (offscreen_context_)
249 return offscreen_context_->HasBeenPoisoned();
250 return false;
251 }
252
253 GLenum IOSurfaceTexture::GetAndSaveGLError() {
254 GLenum gl_error = glGetError();
255 if (gl_error_ == GL_NO_ERROR)
256 gl_error_ = gl_error;
257 return gl_error;
258 }
259
260 void IOSurfaceTexture::EvictionMarkUpdated() {
261 EvictionMarkEvicted();
262 eviction_queue_.Get().push_back(this);
263 eviction_queue_iterator_ = --eviction_queue_.Get().end();
264 eviction_has_been_drawn_since_updated_ = false;
265 EvictionScheduleDoEvict();
266 }
267
268 void IOSurfaceTexture::EvictionMarkEvicted() {
269 if (eviction_queue_iterator_ == eviction_queue_.Get().end())
270 return;
271 eviction_queue_.Get().erase(eviction_queue_iterator_);
272 eviction_queue_iterator_ = eviction_queue_.Get().end();
273 eviction_has_been_drawn_since_updated_ = false;
274 }
275
276 // static
277 void IOSurfaceTexture::EvictionScheduleDoEvict() {
278 if (eviction_scheduled_)
279 return;
280 if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
281 return;
282
283 eviction_scheduled_ = true;
284 base::MessageLoop::current()->PostTask(
285 FROM_HERE,
286 base::Bind(&IOSurfaceTexture::EvictionDoEvict));
287 }
288
289 // static
290 void IOSurfaceTexture::EvictionDoEvict() {
291 eviction_scheduled_ = false;
292 // Walk the list of allocated surfaces from least recently used to most
293 // recently used.
294 for (EvictionQueue::iterator it = eviction_queue_.Get().begin();
295 it != eviction_queue_.Get().end();) {
296 IOSurfaceTexture* surface = *it;
297 ++it;
298
299 // If the number of IOSurfaces allocated is less than the threshold,
300 // stop walking the list of surfaces.
301 if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
302 break;
303
304 // Don't evict anything that has not yet been drawn.
305 if (!surface->eviction_has_been_drawn_since_updated_)
306 continue;
307
308 // Don't evict anything that doesn't have an offscreen context (as we have
309 // context in which to delete the texture).
310 if (!surface->offscreen_context_)
311 continue;
312
313 // Evict the surface.
314 surface->ReleaseIOSurfaceAndTexture();
315 }
316 }
317
318 // static
319 base::LazyInstance<IOSurfaceTexture::EvictionQueue>
320 IOSurfaceTexture::eviction_queue_;
321
322 // static
323 bool IOSurfaceTexture::eviction_scheduled_ = false;
324
325 } // namespace ui
OLDNEW
« no previous file with comments | « ui/accelerated_widget_mac/io_surface_texture.h ('k') | ui/accelerated_widget_mac/software_layer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698