OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/common/gpu/image_transport_surface.h" | 5 #include "content/common/gpu/image_transport_surface_fbo_mac.h" |
6 | 6 |
7 #include "base/mac/scoped_cftyperef.h" | |
8 #include "base/memory/scoped_ptr.h" | |
9 #include "content/common/gpu/gpu_command_buffer_stub.h" | |
10 #include "content/common/gpu/gpu_messages.h" | 7 #include "content/common/gpu/gpu_messages.h" |
| 8 #include "content/common/gpu/image_transport_surface_iosurface_mac.h" |
11 #include "ui/gfx/native_widget_types.h" | 9 #include "ui/gfx/native_widget_types.h" |
12 #include "ui/gl/gl_bindings.h" | |
13 #include "ui/gl/gl_context.h" | 10 #include "ui/gl/gl_context.h" |
14 #include "ui/gl/gl_implementation.h" | 11 #include "ui/gl/gl_implementation.h" |
15 #include "ui/gl/gl_surface_cgl.h" | |
16 #include "ui/gl/gl_surface_osmesa.h" | 12 #include "ui/gl/gl_surface_osmesa.h" |
17 | 13 |
18 // Note that this must be included after gl_bindings.h to avoid conflicts. | 14 namespace content { |
19 #include <OpenGL/CGLIOSurface.h> | |
20 | 15 |
21 namespace content { | 16 ImageTransportSurfaceFBO::ImageTransportSurfaceFBO( |
22 namespace { | 17 StorageProvider* storage_provider, |
23 | |
24 // IOSurface dimensions will be rounded up to a multiple of this value in order | |
25 // to reduce memory thrashing during resize. This must be a power of 2. | |
26 const uint32 kIOSurfaceDimensionRoundup = 64; | |
27 | |
28 int RoundUpSurfaceDimension(int number) { | |
29 DCHECK(number >= 0); | |
30 // Cast into unsigned space for portable bitwise ops. | |
31 uint32 unsigned_number = static_cast<uint32>(number); | |
32 uint32 roundup_sub_1 = kIOSurfaceDimensionRoundup - 1; | |
33 unsigned_number = (unsigned_number + roundup_sub_1) & ~roundup_sub_1; | |
34 return static_cast<int>(unsigned_number); | |
35 } | |
36 | |
37 // We are backed by an offscreen surface for the purposes of creating | |
38 // a context, but use FBOs to render to texture backed IOSurface | |
39 class IOSurfaceImageTransportSurface | |
40 : public gfx::NoOpGLSurfaceCGL, | |
41 public ImageTransportSurface, | |
42 public GpuCommandBufferStub::DestructionObserver { | |
43 public: | |
44 IOSurfaceImageTransportSurface(GpuChannelManager* manager, | |
45 GpuCommandBufferStub* stub, | |
46 gfx::PluginWindowHandle handle); | |
47 | |
48 // GLSurface implementation | |
49 virtual bool Initialize() OVERRIDE; | |
50 virtual void Destroy() OVERRIDE; | |
51 virtual bool DeferDraws() OVERRIDE; | |
52 virtual bool IsOffscreen() OVERRIDE; | |
53 virtual bool SwapBuffers() OVERRIDE; | |
54 virtual bool PostSubBuffer(int x, int y, int width, int height) OVERRIDE; | |
55 virtual bool SupportsPostSubBuffer() OVERRIDE; | |
56 virtual gfx::Size GetSize() OVERRIDE; | |
57 virtual bool OnMakeCurrent(gfx::GLContext* context) OVERRIDE; | |
58 virtual unsigned int GetBackingFrameBufferObject() OVERRIDE; | |
59 virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE; | |
60 virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE; | |
61 | |
62 protected: | |
63 // ImageTransportSurface implementation | |
64 virtual void OnBufferPresented( | |
65 const AcceleratedSurfaceMsg_BufferPresented_Params& params) OVERRIDE; | |
66 virtual void OnResize(gfx::Size size, float scale_factor) OVERRIDE; | |
67 virtual void SetLatencyInfo( | |
68 const std::vector<ui::LatencyInfo>&) OVERRIDE; | |
69 virtual void WakeUpGpu() OVERRIDE; | |
70 | |
71 // GpuCommandBufferStub::DestructionObserver implementation. | |
72 virtual void OnWillDestroyStub() OVERRIDE; | |
73 | |
74 private: | |
75 virtual ~IOSurfaceImageTransportSurface() OVERRIDE; | |
76 | |
77 void AdjustBufferAllocation(); | |
78 void UnrefIOSurface(); | |
79 void CreateIOSurface(); | |
80 | |
81 // Tracks the current buffer allocation state. | |
82 bool backbuffer_suggested_allocation_; | |
83 bool frontbuffer_suggested_allocation_; | |
84 | |
85 uint32 fbo_id_; | |
86 GLuint texture_id_; | |
87 GLuint depth_stencil_renderbuffer_id_; | |
88 | |
89 base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; | |
90 | |
91 // The id of |io_surface_| or 0 if that's NULL. | |
92 uint64 io_surface_handle_; | |
93 | |
94 // Weak pointer to the context that this was last made current to. | |
95 gfx::GLContext* context_; | |
96 | |
97 gfx::Size size_; | |
98 gfx::Size rounded_size_; | |
99 float scale_factor_; | |
100 | |
101 // Whether or not we've successfully made the surface current once. | |
102 bool made_current_; | |
103 | |
104 // Whether a SwapBuffers is pending. | |
105 bool is_swap_buffers_pending_; | |
106 | |
107 // Whether we unscheduled command buffer because of pending SwapBuffers. | |
108 bool did_unschedule_; | |
109 | |
110 std::vector<ui::LatencyInfo> latency_info_; | |
111 | |
112 scoped_ptr<ImageTransportHelper> helper_; | |
113 | |
114 DISALLOW_COPY_AND_ASSIGN(IOSurfaceImageTransportSurface); | |
115 }; | |
116 | |
117 void AddBooleanValue(CFMutableDictionaryRef dictionary, | |
118 const CFStringRef key, | |
119 bool value) { | |
120 CFDictionaryAddValue(dictionary, key, | |
121 (value ? kCFBooleanTrue : kCFBooleanFalse)); | |
122 } | |
123 | |
124 void AddIntegerValue(CFMutableDictionaryRef dictionary, | |
125 const CFStringRef key, | |
126 int32 value) { | |
127 base::ScopedCFTypeRef<CFNumberRef> number( | |
128 CFNumberCreate(NULL, kCFNumberSInt32Type, &value)); | |
129 CFDictionaryAddValue(dictionary, key, number.get()); | |
130 } | |
131 | |
132 IOSurfaceImageTransportSurface::IOSurfaceImageTransportSurface( | |
133 GpuChannelManager* manager, | 18 GpuChannelManager* manager, |
134 GpuCommandBufferStub* stub, | 19 GpuCommandBufferStub* stub, |
135 gfx::PluginWindowHandle handle) | 20 gfx::PluginWindowHandle handle) |
136 : gfx::NoOpGLSurfaceCGL(gfx::Size(1, 1)), | 21 : storage_provider_(storage_provider), |
137 backbuffer_suggested_allocation_(true), | 22 backbuffer_suggested_allocation_(true), |
138 frontbuffer_suggested_allocation_(true), | 23 frontbuffer_suggested_allocation_(true), |
139 fbo_id_(0), | 24 fbo_id_(0), |
140 texture_id_(0), | 25 texture_id_(0), |
141 depth_stencil_renderbuffer_id_(0), | 26 depth_stencil_renderbuffer_id_(0), |
142 io_surface_handle_(0), | 27 has_complete_framebuffer_(false), |
143 context_(NULL), | 28 context_(NULL), |
144 scale_factor_(1.f), | 29 scale_factor_(1.f), |
145 made_current_(false), | 30 made_current_(false), |
146 is_swap_buffers_pending_(false), | 31 is_swap_buffers_pending_(false), |
147 did_unschedule_(false) { | 32 did_unschedule_(false) { |
148 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); | 33 helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); |
149 } | 34 } |
150 | 35 |
151 IOSurfaceImageTransportSurface::~IOSurfaceImageTransportSurface() { | 36 ImageTransportSurfaceFBO::~ImageTransportSurfaceFBO() { |
152 } | 37 } |
153 | 38 |
154 bool IOSurfaceImageTransportSurface::Initialize() { | 39 bool ImageTransportSurfaceFBO::Initialize() { |
155 // Only support IOSurfaces if the GL implementation is the native desktop GL. | 40 // Only support IOSurfaces if the GL implementation is the native desktop GL. |
156 // IO surfaces will not work with, for example, OSMesa software renderer | 41 // IO surfaces will not work with, for example, OSMesa software renderer |
157 // GL contexts. | 42 // GL contexts. |
158 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL && | 43 if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL && |
159 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL) | 44 gfx::GetGLImplementation() != gfx::kGLImplementationAppleGL) |
160 return false; | 45 return false; |
161 | 46 |
162 if (!helper_->Initialize()) | 47 if (!helper_->Initialize()) |
163 return false; | 48 return false; |
164 | 49 |
165 if (!NoOpGLSurfaceCGL::Initialize()) { | |
166 helper_->Destroy(); | |
167 return false; | |
168 } | |
169 | |
170 helper_->stub()->AddDestructionObserver(this); | 50 helper_->stub()->AddDestructionObserver(this); |
171 return true; | 51 return true; |
172 } | 52 } |
173 | 53 |
174 void IOSurfaceImageTransportSurface::Destroy() { | 54 void ImageTransportSurfaceFBO::Destroy() { |
175 UnrefIOSurface(); | 55 DestroyFramebuffer(); |
176 | 56 |
177 helper_->Destroy(); | 57 helper_->Destroy(); |
178 NoOpGLSurfaceCGL::Destroy(); | |
179 } | 58 } |
180 | 59 |
181 bool IOSurfaceImageTransportSurface::DeferDraws() { | 60 bool ImageTransportSurfaceFBO::DeferDraws() { |
182 // The command buffer hit a draw/clear command that could clobber the | 61 // The command buffer hit a draw/clear command that could clobber the |
183 // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort | 62 // IOSurface in use by an earlier SwapBuffers. If a Swap is pending, abort |
184 // processing of the command by returning true and unschedule until the Swap | 63 // processing of the command by returning true and unschedule until the Swap |
185 // Ack arrives. | 64 // Ack arrives. |
186 if(did_unschedule_) | 65 if(did_unschedule_) |
187 return true; // Still unscheduled, so just return true. | 66 return true; // Still unscheduled, so just return true. |
188 if (is_swap_buffers_pending_) { | 67 if (is_swap_buffers_pending_) { |
189 did_unschedule_ = true; | 68 did_unschedule_ = true; |
190 helper_->SetScheduled(false); | 69 helper_->SetScheduled(false); |
191 return true; | 70 return true; |
192 } | 71 } |
193 return false; | 72 return false; |
194 } | 73 } |
195 | 74 |
196 bool IOSurfaceImageTransportSurface::IsOffscreen() { | 75 bool ImageTransportSurfaceFBO::IsOffscreen() { |
197 return false; | 76 return false; |
198 } | 77 } |
199 | 78 |
200 bool IOSurfaceImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { | 79 bool ImageTransportSurfaceFBO::OnMakeCurrent(gfx::GLContext* context) { |
201 context_ = context; | 80 context_ = context; |
202 | 81 |
203 if (made_current_) | 82 if (made_current_) |
204 return true; | 83 return true; |
205 | 84 |
206 OnResize(gfx::Size(1, 1), 1.f); | 85 OnResize(gfx::Size(1, 1), 1.f); |
207 | 86 |
208 made_current_ = true; | 87 made_current_ = true; |
209 return true; | 88 return true; |
210 } | 89 } |
211 | 90 |
212 unsigned int IOSurfaceImageTransportSurface::GetBackingFrameBufferObject() { | 91 unsigned int ImageTransportSurfaceFBO::GetBackingFrameBufferObject() { |
213 return fbo_id_; | 92 return fbo_id_; |
214 } | 93 } |
215 | 94 |
216 bool IOSurfaceImageTransportSurface::SetBackbufferAllocation(bool allocation) { | 95 bool ImageTransportSurfaceFBO::SetBackbufferAllocation(bool allocation) { |
217 if (backbuffer_suggested_allocation_ == allocation) | 96 if (backbuffer_suggested_allocation_ == allocation) |
218 return true; | 97 return true; |
219 backbuffer_suggested_allocation_ = allocation; | 98 backbuffer_suggested_allocation_ = allocation; |
220 AdjustBufferAllocation(); | 99 AdjustBufferAllocation(); |
221 return true; | 100 return true; |
222 } | 101 } |
223 | 102 |
224 void IOSurfaceImageTransportSurface::SetFrontbufferAllocation(bool allocation) { | 103 void ImageTransportSurfaceFBO::SetFrontbufferAllocation(bool allocation) { |
225 if (frontbuffer_suggested_allocation_ == allocation) | 104 if (frontbuffer_suggested_allocation_ == allocation) |
226 return; | 105 return; |
227 frontbuffer_suggested_allocation_ = allocation; | 106 frontbuffer_suggested_allocation_ = allocation; |
228 AdjustBufferAllocation(); | 107 AdjustBufferAllocation(); |
229 } | 108 } |
230 | 109 |
231 void IOSurfaceImageTransportSurface::AdjustBufferAllocation() { | 110 void ImageTransportSurfaceFBO::AdjustBufferAllocation() { |
232 // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is | 111 // On mac, the frontbuffer and backbuffer are the same buffer. The buffer is |
233 // free'd when both the browser and gpu processes have Unref'd the IOSurface. | 112 // free'd when both the browser and gpu processes have Unref'd the IOSurface. |
234 if (!backbuffer_suggested_allocation_ && | 113 if (!backbuffer_suggested_allocation_ && |
235 !frontbuffer_suggested_allocation_ && | 114 !frontbuffer_suggested_allocation_ && |
236 io_surface_.get()) { | 115 has_complete_framebuffer_) { |
237 UnrefIOSurface(); | 116 DestroyFramebuffer(); |
238 helper_->Suspend(); | 117 helper_->Suspend(); |
239 } else if (backbuffer_suggested_allocation_ && !io_surface_) { | 118 } else if (backbuffer_suggested_allocation_ && !has_complete_framebuffer_) { |
240 CreateIOSurface(); | 119 CreateFramebuffer(); |
241 } | 120 } |
242 } | 121 } |
243 | 122 |
244 bool IOSurfaceImageTransportSurface::SwapBuffers() { | 123 bool ImageTransportSurfaceFBO::SwapBuffers() { |
245 DCHECK(backbuffer_suggested_allocation_); | 124 DCHECK(backbuffer_suggested_allocation_); |
246 if (!frontbuffer_suggested_allocation_) | 125 if (!frontbuffer_suggested_allocation_) |
247 return true; | 126 return true; |
248 glFlush(); | 127 glFlush(); |
249 | 128 |
250 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | 129 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; |
251 params.surface_handle = io_surface_handle_; | 130 params.surface_handle = storage_provider_->GetSurfaceHandle(); |
252 params.size = GetSize(); | 131 params.size = GetSize(); |
253 params.scale_factor = scale_factor_; | 132 params.scale_factor = scale_factor_; |
254 params.latency_info.swap(latency_info_); | 133 params.latency_info.swap(latency_info_); |
255 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | 134 helper_->SendAcceleratedSurfaceBuffersSwapped(params); |
256 | 135 |
257 DCHECK(!is_swap_buffers_pending_); | 136 DCHECK(!is_swap_buffers_pending_); |
258 is_swap_buffers_pending_ = true; | 137 is_swap_buffers_pending_ = true; |
259 return true; | 138 return true; |
260 } | 139 } |
261 | 140 |
262 bool IOSurfaceImageTransportSurface::PostSubBuffer( | 141 bool ImageTransportSurfaceFBO::PostSubBuffer( |
263 int x, int y, int width, int height) { | 142 int x, int y, int width, int height) { |
264 DCHECK(backbuffer_suggested_allocation_); | 143 DCHECK(backbuffer_suggested_allocation_); |
265 if (!frontbuffer_suggested_allocation_) | 144 if (!frontbuffer_suggested_allocation_) |
266 return true; | 145 return true; |
267 glFlush(); | 146 glFlush(); |
268 | 147 |
269 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | 148 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; |
270 params.surface_handle = io_surface_handle_; | 149 params.surface_handle = storage_provider_->GetSurfaceHandle(); |
271 params.x = x; | 150 params.x = x; |
272 params.y = y; | 151 params.y = y; |
273 params.width = width; | 152 params.width = width; |
274 params.height = height; | 153 params.height = height; |
275 params.surface_size = GetSize(); | 154 params.surface_size = GetSize(); |
276 params.surface_scale_factor = scale_factor_; | 155 params.surface_scale_factor = scale_factor_; |
277 params.latency_info.swap(latency_info_); | 156 params.latency_info.swap(latency_info_); |
278 helper_->SendAcceleratedSurfacePostSubBuffer(params); | 157 helper_->SendAcceleratedSurfacePostSubBuffer(params); |
279 | 158 |
280 DCHECK(!is_swap_buffers_pending_); | 159 DCHECK(!is_swap_buffers_pending_); |
281 is_swap_buffers_pending_ = true; | 160 is_swap_buffers_pending_ = true; |
282 return true; | 161 return true; |
283 } | 162 } |
284 | 163 |
285 bool IOSurfaceImageTransportSurface::SupportsPostSubBuffer() { | 164 bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() { |
286 return true; | 165 return true; |
287 } | 166 } |
288 | 167 |
289 gfx::Size IOSurfaceImageTransportSurface::GetSize() { | 168 gfx::Size ImageTransportSurfaceFBO::GetSize() { |
290 return size_; | 169 return size_; |
291 } | 170 } |
292 | 171 |
293 void IOSurfaceImageTransportSurface::OnBufferPresented( | 172 void* ImageTransportSurfaceFBO::GetHandle() { |
| 173 return NULL; |
| 174 } |
| 175 |
| 176 void* ImageTransportSurfaceFBO::GetDisplay() { |
| 177 return NULL; |
| 178 } |
| 179 |
| 180 void ImageTransportSurfaceFBO::OnBufferPresented( |
294 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { | 181 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { |
295 DCHECK(is_swap_buffers_pending_); | 182 DCHECK(is_swap_buffers_pending_); |
296 | 183 |
297 context_->share_group()->SetRendererID(params.renderer_id); | 184 context_->share_group()->SetRendererID(params.renderer_id); |
298 is_swap_buffers_pending_ = false; | 185 is_swap_buffers_pending_ = false; |
299 if (did_unschedule_) { | 186 if (did_unschedule_) { |
300 did_unschedule_ = false; | 187 did_unschedule_ = false; |
301 helper_->SetScheduled(true); | 188 helper_->SetScheduled(true); |
302 } | 189 } |
303 } | 190 } |
304 | 191 |
305 void IOSurfaceImageTransportSurface::OnResize(gfx::Size size, | 192 void ImageTransportSurfaceFBO::OnResize(gfx::Size size, |
306 float scale_factor) { | 193 float scale_factor) { |
307 // This trace event is used in gpu_feature_browsertest.cc - the test will need | 194 // This trace event is used in gpu_feature_browsertest.cc - the test will need |
308 // to be updated if this event is changed or moved. | 195 // to be updated if this event is changed or moved. |
309 TRACE_EVENT2("gpu", "IOSurfaceImageTransportSurface::OnResize", | 196 TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::OnResize", |
310 "old_width", size_.width(), "new_width", size.width()); | 197 "old_width", size_.width(), "new_width", size.width()); |
311 // Caching |context_| from OnMakeCurrent. It should still be current. | 198 // Caching |context_| from OnMakeCurrent. It should still be current. |
312 DCHECK(context_->IsCurrent(this)); | 199 DCHECK(context_->IsCurrent(this)); |
313 | 200 |
314 size_ = size; | 201 size_ = size; |
315 scale_factor_ = scale_factor; | 202 scale_factor_ = scale_factor; |
316 | 203 |
317 CreateIOSurface(); | 204 CreateFramebuffer(); |
318 } | 205 } |
319 | 206 |
320 void IOSurfaceImageTransportSurface::SetLatencyInfo( | 207 void ImageTransportSurfaceFBO::SetLatencyInfo( |
321 const std::vector<ui::LatencyInfo>& latency_info) { | 208 const std::vector<ui::LatencyInfo>& latency_info) { |
322 for (size_t i = 0; i < latency_info.size(); i++) | 209 for (size_t i = 0; i < latency_info.size(); i++) |
323 latency_info_.push_back(latency_info[i]); | 210 latency_info_.push_back(latency_info[i]); |
324 } | 211 } |
325 | 212 |
326 void IOSurfaceImageTransportSurface::WakeUpGpu() { | 213 void ImageTransportSurfaceFBO::WakeUpGpu() { |
327 NOTIMPLEMENTED(); | 214 NOTIMPLEMENTED(); |
328 } | 215 } |
329 | 216 |
330 void IOSurfaceImageTransportSurface::OnWillDestroyStub() { | 217 void ImageTransportSurfaceFBO::OnWillDestroyStub() { |
331 helper_->stub()->RemoveDestructionObserver(this); | 218 helper_->stub()->RemoveDestructionObserver(this); |
332 Destroy(); | 219 Destroy(); |
333 } | 220 } |
334 | 221 |
335 void IOSurfaceImageTransportSurface::UnrefIOSurface() { | 222 void ImageTransportSurfaceFBO::DestroyFramebuffer() { |
336 // If we have resources to destroy, then make sure that we have a current | 223 // If we have resources to destroy, then make sure that we have a current |
337 // context which we can use to delete the resources. | 224 // context which we can use to delete the resources. |
338 if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) { | 225 if (context_ || fbo_id_ || texture_id_ || depth_stencil_renderbuffer_id_) { |
339 DCHECK(gfx::GLContext::GetCurrent() == context_); | 226 DCHECK(gfx::GLContext::GetCurrent() == context_); |
340 DCHECK(context_->IsCurrent(this)); | 227 DCHECK(context_->IsCurrent(this)); |
341 DCHECK(CGLGetCurrentContext()); | 228 DCHECK(CGLGetCurrentContext()); |
342 } | 229 } |
343 | 230 |
344 if (fbo_id_) { | 231 if (fbo_id_) { |
345 glDeleteFramebuffersEXT(1, &fbo_id_); | 232 glDeleteFramebuffersEXT(1, &fbo_id_); |
346 fbo_id_ = 0; | 233 fbo_id_ = 0; |
347 } | 234 } |
348 | 235 |
349 if (texture_id_) { | 236 if (texture_id_) { |
350 glDeleteTextures(1, &texture_id_); | 237 glDeleteTextures(1, &texture_id_); |
351 texture_id_ = 0; | 238 texture_id_ = 0; |
352 } | 239 } |
353 | 240 |
354 if (depth_stencil_renderbuffer_id_) { | 241 if (depth_stencil_renderbuffer_id_) { |
355 glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_); | 242 glDeleteRenderbuffersEXT(1, &depth_stencil_renderbuffer_id_); |
356 depth_stencil_renderbuffer_id_ = 0; | 243 depth_stencil_renderbuffer_id_ = 0; |
357 } | 244 } |
358 | 245 |
359 io_surface_.reset(); | 246 storage_provider_->FreeColorBufferStorage(); |
360 io_surface_handle_ = 0; | 247 |
| 248 has_complete_framebuffer_ = false; |
361 } | 249 } |
362 | 250 |
363 void IOSurfaceImageTransportSurface::CreateIOSurface() { | 251 void ImageTransportSurfaceFBO::CreateFramebuffer() { |
364 gfx::Size new_rounded_size(RoundUpSurfaceDimension(size_.width()), | 252 gfx::Size new_rounded_size = storage_provider_->GetRoundedSize(size_); |
365 RoundUpSurfaceDimension(size_.height())); | |
366 | 253 |
367 // Only recreate surface when the rounded up size has changed. | 254 // Only recreate surface when the rounded up size has changed. |
368 if (io_surface_.get() && new_rounded_size == rounded_size_) | 255 if (has_complete_framebuffer_ && new_rounded_size == rounded_size_) |
369 return; | 256 return; |
370 | 257 |
371 // This trace event is used in gpu_feature_browsertest.cc - the test will need | 258 // This trace event is used in gpu_feature_browsertest.cc - the test will need |
372 // to be updated if this event is changed or moved. | 259 // to be updated if this event is changed or moved. |
373 TRACE_EVENT2("gpu", "IOSurfaceImageTransportSurface::CreateIOSurface", | 260 TRACE_EVENT2("gpu", "ImageTransportSurfaceFBO::CreateFramebuffer", |
374 "width", new_rounded_size.width(), | 261 "width", new_rounded_size.width(), |
375 "height", new_rounded_size.height()); | 262 "height", new_rounded_size.height()); |
376 | 263 |
377 rounded_size_ = new_rounded_size; | 264 rounded_size_ = new_rounded_size; |
378 | 265 |
| 266 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on |
| 267 // Mac OS X and is required for IOSurface interoperability. |
379 GLint previous_texture_id = 0; | 268 GLint previous_texture_id = 0; |
380 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id); | 269 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &previous_texture_id); |
381 | 270 |
382 // Free the old IO Surface first to reduce memory fragmentation. | 271 // Free the old IO Surface first to reduce memory fragmentation. |
383 UnrefIOSurface(); | 272 DestroyFramebuffer(); |
384 | 273 |
385 glGenFramebuffersEXT(1, &fbo_id_); | 274 glGenFramebuffersEXT(1, &fbo_id_); |
386 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_); | 275 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id_); |
387 | 276 |
388 glGenTextures(1, &texture_id_); | 277 glGenTextures(1, &texture_id_); |
389 | 278 |
390 // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on | 279 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_id_); |
391 // Mac OS X and is required for IOSurface interoperability. | 280 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
392 GLenum target = GL_TEXTURE_RECTANGLE_ARB; | 281 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
393 glBindTexture(target, texture_id_); | 282 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
394 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 283 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
395 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 284 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, |
396 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 285 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
397 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
398 | 286 |
399 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, | 287 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, |
400 GL_COLOR_ATTACHMENT0_EXT, | 288 GL_COLOR_ATTACHMENT0_EXT, |
401 target, | 289 GL_TEXTURE_RECTANGLE_ARB, |
402 texture_id_, | 290 texture_id_, |
403 0); | 291 0); |
404 | 292 |
405 | |
406 // Search through the provided attributes; if the caller has | 293 // Search through the provided attributes; if the caller has |
407 // requested a stencil buffer, try to get one. | 294 // requested a stencil buffer, try to get one. |
408 | 295 |
409 int32 stencil_bits = | 296 int32 stencil_bits = |
410 helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE); | 297 helper_->stub()->GetRequestedAttribute(EGL_STENCIL_SIZE); |
411 if (stencil_bits > 0) { | 298 if (stencil_bits > 0) { |
412 // Create and bind the stencil buffer | 299 // Create and bind the stencil buffer |
413 bool has_packed_depth_stencil = | 300 bool has_packed_depth_stencil = |
414 GLSurface::ExtensionsContain( | 301 GLSurface::ExtensionsContain( |
415 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)), | 302 reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS)), |
(...skipping 10 matching lines...) Expand all Loading... |
426 GL_RENDERBUFFER_EXT, | 313 GL_RENDERBUFFER_EXT, |
427 depth_stencil_renderbuffer_id_); | 314 depth_stencil_renderbuffer_id_); |
428 } | 315 } |
429 | 316 |
430 // If we asked for stencil but the extension isn't present, | 317 // If we asked for stencil but the extension isn't present, |
431 // it's OK to silently fail; subsequent code will/must check | 318 // it's OK to silently fail; subsequent code will/must check |
432 // for the presence of a stencil buffer before attempting to | 319 // for the presence of a stencil buffer before attempting to |
433 // do stencil-based operations. | 320 // do stencil-based operations. |
434 } | 321 } |
435 | 322 |
436 // Allocate a new IOSurface, which is the GPU resource that can be | 323 bool allocated_color_buffer = storage_provider_->AllocateColorBufferStorage( |
437 // shared across processes. | 324 static_cast<CGLContextObj>(context_->GetHandle()), |
438 base::ScopedCFTypeRef<CFMutableDictionaryRef> properties; | 325 rounded_size_); |
439 properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault, | 326 if (!allocated_color_buffer) { |
440 0, | 327 DLOG(ERROR) << "Failed to allocate color buffer storage."; |
441 &kCFTypeDictionaryKeyCallBacks, | 328 DestroyFramebuffer(); |
442 &kCFTypeDictionaryValueCallBacks)); | |
443 AddIntegerValue(properties, | |
444 kIOSurfaceWidth, | |
445 rounded_size_.width()); | |
446 AddIntegerValue(properties, | |
447 kIOSurfaceHeight, | |
448 rounded_size_.height()); | |
449 AddIntegerValue(properties, | |
450 kIOSurfaceBytesPerElement, 4); | |
451 AddBooleanValue(properties, | |
452 kIOSurfaceIsGlobal, true); | |
453 // I believe we should be able to unreference the IOSurfaces without | |
454 // synchronizing with the browser process because they are | |
455 // ultimately reference counted by the operating system. | |
456 io_surface_.reset(IOSurfaceCreate(properties)); | |
457 io_surface_handle_ = IOSurfaceGetID(io_surface_); | |
458 | |
459 // Don't think we need to identify a plane. | |
460 GLuint plane = 0; | |
461 CGLError cglerror = | |
462 CGLTexImageIOSurface2D( | |
463 static_cast<CGLContextObj>(context_->GetHandle()), | |
464 target, | |
465 GL_RGBA, | |
466 rounded_size_.width(), | |
467 rounded_size_.height(), | |
468 GL_BGRA, | |
469 GL_UNSIGNED_INT_8_8_8_8_REV, | |
470 io_surface_.get(), | |
471 plane); | |
472 if (cglerror != kCGLNoError) { | |
473 UnrefIOSurface(); | |
474 return; | 329 return; |
475 } | 330 } |
476 | 331 |
477 glFlush(); | |
478 | |
479 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); | 332 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); |
480 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { | 333 if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
481 DLOG(ERROR) << "Framebuffer was incomplete: " << status; | 334 DLOG(ERROR) << "Framebuffer was incomplete: " << status; |
482 UnrefIOSurface(); | 335 DestroyFramebuffer(); |
483 return; | 336 return; |
484 } | 337 } |
485 | 338 |
486 glBindTexture(target, previous_texture_id); | 339 has_complete_framebuffer_ = true; |
| 340 |
| 341 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, previous_texture_id); |
487 // The FBO remains bound for this GL context. | 342 // The FBO remains bound for this GL context. |
488 } | 343 } |
489 | 344 |
490 // A subclass of GLSurfaceOSMesa that doesn't print an error message when | |
491 // SwapBuffers() is called. | |
492 class DRTSurfaceOSMesa : public gfx::GLSurfaceOSMesa { | |
493 public: | |
494 // Size doesn't matter, the surface is resized to the right size later. | |
495 DRTSurfaceOSMesa() : GLSurfaceOSMesa(GL_RGBA, gfx::Size(1, 1)) {} | |
496 | |
497 // Implement a subset of GLSurface. | |
498 virtual bool SwapBuffers() OVERRIDE; | |
499 | |
500 private: | |
501 virtual ~DRTSurfaceOSMesa() {} | |
502 DISALLOW_COPY_AND_ASSIGN(DRTSurfaceOSMesa); | |
503 }; | |
504 | |
505 bool DRTSurfaceOSMesa::SwapBuffers() { | |
506 return true; | |
507 } | |
508 | |
509 bool g_allow_os_mesa = false; | |
510 | |
511 } // namespace | |
512 | |
513 // static | |
514 scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( | |
515 GpuChannelManager* manager, | |
516 GpuCommandBufferStub* stub, | |
517 const gfx::GLSurfaceHandle& surface_handle) { | |
518 DCHECK(surface_handle.transport_type == gfx::NATIVE_DIRECT || | |
519 surface_handle.transport_type == gfx::NATIVE_TRANSPORT); | |
520 | |
521 switch (gfx::GetGLImplementation()) { | |
522 case gfx::kGLImplementationDesktopGL: | |
523 case gfx::kGLImplementationAppleGL: | |
524 return scoped_refptr<gfx::GLSurface>(new IOSurfaceImageTransportSurface( | |
525 manager, stub, surface_handle.handle)); | |
526 | |
527 default: | |
528 // Content shell in DRT mode spins up a gpu process which needs an | |
529 // image transport surface, but that surface isn't used to read pixel | |
530 // baselines. So this is mostly a dummy surface. | |
531 if (!g_allow_os_mesa) { | |
532 NOTREACHED(); | |
533 return scoped_refptr<gfx::GLSurface>(); | |
534 } | |
535 scoped_refptr<gfx::GLSurface> surface(new DRTSurfaceOSMesa()); | |
536 if (!surface.get() || !surface->Initialize()) | |
537 return surface; | |
538 return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface( | |
539 manager, stub, surface.get())); | |
540 } | |
541 } | |
542 | |
543 // static | |
544 void ImageTransportSurface::SetAllowOSMesaForTesting(bool allow) { | |
545 g_allow_os_mesa = allow; | |
546 } | |
547 | |
548 } // namespace content | 345 } // namespace content |
OLD | NEW |