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