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/texture_image_transport_surface.h" | 5 #include "content/common/gpu/texture_image_transport_surface.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
11 #include "content/common/gpu/gpu_channel.h" | 11 #include "content/common/gpu/gpu_channel.h" |
12 #include "content/common/gpu/gpu_channel_manager.h" | 12 #include "content/common/gpu/gpu_channel_manager.h" |
13 #include "content/common/gpu/gpu_messages.h" | 13 #include "content/common/gpu/gpu_messages.h" |
14 #include "content/common/gpu/sync_point_manager.h" | 14 #include "content/common/gpu/sync_point_manager.h" |
15 #include "content/public/common/content_switches.h" | 15 #include "content/public/common/content_switches.h" |
16 #include "gpu/command_buffer/service/context_group.h" | 16 #include "gpu/command_buffer/service/context_group.h" |
17 #include "gpu/command_buffer/service/gpu_scheduler.h" | 17 #include "gpu/command_buffer/service/gpu_scheduler.h" |
18 #include "ui/gl/scoped_binders.h" | 18 #include "ui/gl/scoped_binders.h" |
19 | 19 |
20 using gpu::gles2::ContextGroup; | 20 using gpu::gles2::ContextGroup; |
| 21 using gpu::gles2::GLES2Decoder; |
21 using gpu::gles2::MailboxManager; | 22 using gpu::gles2::MailboxManager; |
22 using gpu::gles2::MailboxName; | 23 using gpu::gles2::MailboxName; |
23 using gpu::gles2::TextureDefinition; | 24 using gpu::gles2::Texture; |
24 using gpu::gles2::TextureManager; | 25 using gpu::gles2::TextureManager; |
| 26 using gpu::gles2::TextureRef; |
25 | 27 |
26 namespace content { | 28 namespace content { |
27 | 29 |
28 TextureImageTransportSurface::TextureImageTransportSurface( | 30 TextureImageTransportSurface::TextureImageTransportSurface( |
29 GpuChannelManager* manager, | 31 GpuChannelManager* manager, |
30 GpuCommandBufferStub* stub, | 32 GpuCommandBufferStub* stub, |
31 const gfx::GLSurfaceHandle& handle) | 33 const gfx::GLSurfaceHandle& handle) |
32 : fbo_id_(0), | 34 : fbo_id_(0), |
33 backbuffer_(CreateTextureDefinition(gfx::Size(), 0)), | 35 current_size_(1, 1), |
34 scale_factor_(1.f), | 36 scale_factor_(1.f), |
35 stub_destroyed_(false), | 37 stub_destroyed_(false), |
36 backbuffer_suggested_allocation_(true), | 38 backbuffer_suggested_allocation_(true), |
37 frontbuffer_suggested_allocation_(true), | 39 frontbuffer_suggested_allocation_(true), |
38 handle_(handle), | 40 handle_(handle), |
39 is_swap_buffers_pending_(false), | 41 is_swap_buffers_pending_(false), |
40 did_unschedule_(false) { | 42 did_unschedule_(false) { |
41 helper_.reset(new ImageTransportHelper(this, | 43 helper_.reset(new ImageTransportHelper(this, |
42 manager, | 44 manager, |
43 stub, | 45 stub, |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 // Ack arrives. | 87 // Ack arrives. |
86 DCHECK(!did_unschedule_); | 88 DCHECK(!did_unschedule_); |
87 if (is_swap_buffers_pending_) { | 89 if (is_swap_buffers_pending_) { |
88 did_unschedule_ = true; | 90 did_unschedule_ = true; |
89 helper_->SetScheduled(false); | 91 helper_->SetScheduled(false); |
90 return true; | 92 return true; |
91 } | 93 } |
92 return false; | 94 return false; |
93 } | 95 } |
94 | 96 |
95 bool TextureImageTransportSurface::Resize(const gfx::Size&) { | |
96 return true; | |
97 } | |
98 | |
99 bool TextureImageTransportSurface::IsOffscreen() { | 97 bool TextureImageTransportSurface::IsOffscreen() { |
100 return true; | 98 return true; |
101 } | 99 } |
102 | 100 |
103 bool TextureImageTransportSurface::OnMakeCurrent(gfx::GLContext* context) { | 101 unsigned int TextureImageTransportSurface::GetBackingFrameBufferObject() { |
104 if (stub_destroyed_) { | 102 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
105 // Early-exit so that we don't recreate the fbo. We still want to return | |
106 // true, so that the context is made current and the GLES2DecoderImpl can | |
107 // release its own resources. | |
108 return true; | |
109 } | |
110 | |
111 context_ = context; | |
112 | |
113 if (!fbo_id_) { | 103 if (!fbo_id_) { |
114 glGenFramebuffersEXT(1, &fbo_id_); | 104 glGenFramebuffersEXT(1, &fbo_id_); |
115 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_id_); | 105 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_id_); |
116 current_size_ = gfx::Size(1, 1); | |
117 helper_->stub()->AddDestructionObserver(this); | 106 helper_->stub()->AddDestructionObserver(this); |
| 107 CreateBackTexture(); |
118 } | 108 } |
119 | 109 |
120 // We could be receiving non-deferred GL commands, that is anything that does | |
121 // not need a framebuffer. | |
122 if (!backbuffer_->service_id() && !is_swap_buffers_pending_ && | |
123 backbuffer_suggested_allocation_) { | |
124 CreateBackTexture(); | |
125 } | |
126 return true; | |
127 } | |
128 | |
129 unsigned int TextureImageTransportSurface::GetBackingFrameBufferObject() { | |
130 return fbo_id_; | 110 return fbo_id_; |
131 } | 111 } |
132 | 112 |
133 bool TextureImageTransportSurface::SetBackbufferAllocation(bool allocation) { | 113 bool TextureImageTransportSurface::SetBackbufferAllocation(bool allocation) { |
134 DCHECK(!is_swap_buffers_pending_); | 114 DCHECK(!is_swap_buffers_pending_); |
135 if (backbuffer_suggested_allocation_ == allocation) | 115 if (backbuffer_suggested_allocation_ == allocation) |
136 return true; | 116 return true; |
137 backbuffer_suggested_allocation_ = allocation; | 117 backbuffer_suggested_allocation_ = allocation; |
138 | 118 |
139 if (backbuffer_suggested_allocation_) { | 119 if (backbuffer_suggested_allocation_) { |
140 DCHECK(!backbuffer_->service_id()); | 120 DCHECK(!backbuffer_); |
141 CreateBackTexture(); | 121 CreateBackTexture(); |
142 } else { | 122 } else { |
143 ReleaseBackTexture(); | 123 ReleaseBackTexture(); |
144 } | 124 } |
145 | 125 |
146 return true; | 126 return true; |
147 } | 127 } |
148 | 128 |
149 void TextureImageTransportSurface::SetFrontbufferAllocation(bool allocation) { | 129 void TextureImageTransportSurface::SetFrontbufferAllocation(bool allocation) { |
150 if (frontbuffer_suggested_allocation_ == allocation) | 130 if (frontbuffer_suggested_allocation_ == allocation) |
151 return; | 131 return; |
152 frontbuffer_suggested_allocation_ = allocation; | 132 frontbuffer_suggested_allocation_ = allocation; |
153 | 133 |
154 if (!frontbuffer_suggested_allocation_) { | 134 // If a swapbuffers is in flight, wait for the ack before releasing the front |
155 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | 135 // buffer: |
156 helper_->SendAcceleratedSurfaceRelease(params); | 136 // - we don't know yet which texture the browser will want to keep |
| 137 // - we want to ensure we don't destroy a texture that is in flight before the |
| 138 // browser got a reference on it. |
| 139 if (!frontbuffer_suggested_allocation_ && |
| 140 !is_swap_buffers_pending_ && |
| 141 helper_->MakeCurrent()) { |
| 142 ReleaseFrontTexture(); |
157 } | 143 } |
158 } | 144 } |
159 | 145 |
160 void* TextureImageTransportSurface::GetShareHandle() { | 146 void* TextureImageTransportSurface::GetShareHandle() { |
161 return GetHandle(); | 147 return GetHandle(); |
162 } | 148 } |
163 | 149 |
164 void* TextureImageTransportSurface::GetDisplay() { | 150 void* TextureImageTransportSurface::GetDisplay() { |
165 return surface_.get() ? surface_->GetDisplay() : NULL; | 151 return surface_.get() ? surface_->GetDisplay() : NULL; |
166 } | 152 } |
167 | 153 |
168 void* TextureImageTransportSurface::GetConfig() { | 154 void* TextureImageTransportSurface::GetConfig() { |
169 return surface_.get() ? surface_->GetConfig() : NULL; | 155 return surface_.get() ? surface_->GetConfig() : NULL; |
170 } | 156 } |
171 | 157 |
172 void TextureImageTransportSurface::OnResize(gfx::Size size, | 158 void TextureImageTransportSurface::OnResize(gfx::Size size, |
173 float scale_factor) { | 159 float scale_factor) { |
| 160 DCHECK_GE(size.width(), 1); |
| 161 DCHECK_GE(size.height(), 1); |
174 current_size_ = size; | 162 current_size_ = size; |
175 scale_factor_ = scale_factor; | 163 scale_factor_ = scale_factor; |
176 CreateBackTexture(); | 164 CreateBackTexture(); |
177 } | 165 } |
178 | 166 |
179 void TextureImageTransportSurface::OnWillDestroyStub() { | 167 void TextureImageTransportSurface::OnWillDestroyStub() { |
| 168 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
180 helper_->stub()->RemoveDestructionObserver(this); | 169 helper_->stub()->RemoveDestructionObserver(this); |
181 | 170 |
182 GpuHostMsg_AcceleratedSurfaceRelease_Params params; | |
183 helper_->SendAcceleratedSurfaceRelease(params); | |
184 | |
185 ReleaseBackTexture(); | |
186 | |
187 // We are losing the stub owning us, this is our last chance to clean up the | 171 // We are losing the stub owning us, this is our last chance to clean up the |
188 // resources we allocated in the stub's context. | 172 // resources we allocated in the stub's context. |
| 173 ReleaseBackTexture(); |
| 174 ReleaseFrontTexture(); |
| 175 |
189 if (fbo_id_) { | 176 if (fbo_id_) { |
190 glDeleteFramebuffersEXT(1, &fbo_id_); | 177 glDeleteFramebuffersEXT(1, &fbo_id_); |
191 CHECK_GL_ERROR(); | 178 CHECK_GL_ERROR(); |
192 fbo_id_ = 0; | 179 fbo_id_ = 0; |
193 } | 180 } |
194 | 181 |
195 stub_destroyed_ = true; | 182 stub_destroyed_ = true; |
196 } | 183 } |
197 | 184 |
198 void TextureImageTransportSurface::SetLatencyInfo( | 185 void TextureImageTransportSurface::SetLatencyInfo( |
199 const ui::LatencyInfo& latency_info) { | 186 const ui::LatencyInfo& latency_info) { |
200 latency_info_ = latency_info; | 187 latency_info_ = latency_info; |
201 } | 188 } |
202 | 189 |
203 bool TextureImageTransportSurface::SwapBuffers() { | 190 bool TextureImageTransportSurface::SwapBuffers() { |
| 191 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
204 DCHECK(backbuffer_suggested_allocation_); | 192 DCHECK(backbuffer_suggested_allocation_); |
205 | 193 |
206 if (!frontbuffer_suggested_allocation_) | 194 if (!frontbuffer_suggested_allocation_) |
207 return true; | 195 return true; |
208 | 196 |
209 if (!backbuffer_->service_id()) { | 197 if (!backbuffer_) { |
210 LOG(ERROR) << "Swap without valid backing."; | 198 LOG(ERROR) << "Swap without valid backing."; |
211 return true; | 199 return true; |
212 } | 200 } |
213 | 201 |
214 DCHECK(backbuffer_size() == current_size_); | 202 DCHECK(backbuffer_size() == current_size_); |
215 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; | 203 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; |
216 params.size = backbuffer_size(); | 204 params.size = backbuffer_size(); |
217 params.scale_factor = scale_factor_; | 205 params.scale_factor = scale_factor_; |
218 params.mailbox_name.assign( | 206 params.mailbox_name.assign( |
219 reinterpret_cast<const char*>(&mailbox_name_), sizeof(mailbox_name_)); | 207 reinterpret_cast<const char*>(&back_mailbox_name_), |
| 208 sizeof(back_mailbox_name_)); |
220 | 209 |
221 glFlush(); | 210 glFlush(); |
222 ProduceTexture(); | |
223 | |
224 // Do not allow destruction while we are still waiting for a swap ACK, | |
225 // so we do not leak a texture in the mailbox. | |
226 AddRef(); | |
227 | 211 |
228 params.latency_info = latency_info_; | 212 params.latency_info = latency_info_; |
229 helper_->SendAcceleratedSurfaceBuffersSwapped(params); | 213 helper_->SendAcceleratedSurfaceBuffersSwapped(params); |
230 | 214 |
231 DCHECK(!is_swap_buffers_pending_); | 215 DCHECK(!is_swap_buffers_pending_); |
232 is_swap_buffers_pending_ = true; | 216 is_swap_buffers_pending_ = true; |
233 return true; | 217 return true; |
234 } | 218 } |
235 | 219 |
236 bool TextureImageTransportSurface::PostSubBuffer( | 220 bool TextureImageTransportSurface::PostSubBuffer( |
237 int x, int y, int width, int height) { | 221 int x, int y, int width, int height) { |
| 222 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
238 DCHECK(backbuffer_suggested_allocation_); | 223 DCHECK(backbuffer_suggested_allocation_); |
239 if (!frontbuffer_suggested_allocation_) | 224 if (!frontbuffer_suggested_allocation_) |
240 return true; | 225 return true; |
241 const gfx::Rect new_damage_rect(x, y, width, height); | 226 const gfx::Rect new_damage_rect(x, y, width, height); |
242 DCHECK(gfx::Rect(gfx::Point(), current_size_).Contains(new_damage_rect)); | 227 DCHECK(gfx::Rect(gfx::Point(), current_size_).Contains(new_damage_rect)); |
243 | 228 |
244 // An empty damage rect is a successful no-op. | 229 // An empty damage rect is a successful no-op. |
245 if (new_damage_rect.IsEmpty()) | 230 if (new_damage_rect.IsEmpty()) |
246 return true; | 231 return true; |
247 | 232 |
248 if (!backbuffer_->service_id()) { | 233 if (!backbuffer_) { |
249 LOG(ERROR) << "Swap without valid backing."; | 234 LOG(ERROR) << "Swap without valid backing."; |
250 return true; | 235 return true; |
251 } | 236 } |
252 | 237 |
253 DCHECK(current_size_ == backbuffer_size()); | 238 DCHECK(current_size_ == backbuffer_size()); |
254 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; | 239 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params; |
255 params.surface_size = backbuffer_size(); | 240 params.surface_size = backbuffer_size(); |
256 params.surface_scale_factor = scale_factor_; | 241 params.surface_scale_factor = scale_factor_; |
257 params.x = x; | 242 params.x = x; |
258 params.y = y; | 243 params.y = y; |
259 params.width = width; | 244 params.width = width; |
260 params.height = height; | 245 params.height = height; |
261 params.mailbox_name.assign( | 246 params.mailbox_name.assign( |
262 reinterpret_cast<const char*>(&mailbox_name_), sizeof(mailbox_name_)); | 247 reinterpret_cast<const char*>(&back_mailbox_name_), |
| 248 sizeof(back_mailbox_name_)); |
263 | 249 |
264 glFlush(); | 250 glFlush(); |
265 ProduceTexture(); | |
266 | |
267 // Do not allow destruction while we are still waiting for a swap ACK, | |
268 // so we do not leak a texture in the mailbox. | |
269 AddRef(); | |
270 | 251 |
271 params.latency_info = latency_info_; | 252 params.latency_info = latency_info_; |
272 helper_->SendAcceleratedSurfacePostSubBuffer(params); | 253 helper_->SendAcceleratedSurfacePostSubBuffer(params); |
273 | 254 |
274 DCHECK(!is_swap_buffers_pending_); | 255 DCHECK(!is_swap_buffers_pending_); |
275 is_swap_buffers_pending_ = true; | 256 is_swap_buffers_pending_ = true; |
276 return true; | 257 return true; |
277 } | 258 } |
278 | 259 |
279 std::string TextureImageTransportSurface::GetExtensions() { | 260 std::string TextureImageTransportSurface::GetExtensions() { |
280 std::string extensions = gfx::GLSurface::GetExtensions(); | 261 std::string extensions = gfx::GLSurface::GetExtensions(); |
281 extensions += extensions.empty() ? "" : " "; | 262 extensions += extensions.empty() ? "" : " "; |
282 extensions += "GL_CHROMIUM_front_buffer_cached "; | 263 extensions += "GL_CHROMIUM_front_buffer_cached "; |
283 extensions += "GL_CHROMIUM_post_sub_buffer"; | 264 extensions += "GL_CHROMIUM_post_sub_buffer"; |
284 return extensions; | 265 return extensions; |
285 } | 266 } |
286 | 267 |
287 gfx::Size TextureImageTransportSurface::GetSize() { | 268 gfx::Size TextureImageTransportSurface::GetSize() { |
288 gfx::Size size = current_size_; | 269 return current_size_; |
289 | |
290 // OSMesa expects a non-zero size. | |
291 return gfx::Size(size.width() == 0 ? 1 : size.width(), | |
292 size.height() == 0 ? 1 : size.height()); | |
293 } | 270 } |
294 | 271 |
295 void* TextureImageTransportSurface::GetHandle() { | 272 void* TextureImageTransportSurface::GetHandle() { |
296 return surface_.get() ? surface_->GetHandle() : NULL; | 273 return surface_.get() ? surface_->GetHandle() : NULL; |
297 } | 274 } |
298 | 275 |
299 unsigned TextureImageTransportSurface::GetFormat() { | 276 unsigned TextureImageTransportSurface::GetFormat() { |
300 return surface_.get() ? surface_->GetFormat() : 0; | 277 return surface_.get() ? surface_->GetFormat() : 0; |
301 } | 278 } |
302 | 279 |
303 void TextureImageTransportSurface::OnBufferPresented( | 280 void TextureImageTransportSurface::OnBufferPresented( |
304 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { | 281 const AcceleratedSurfaceMsg_BufferPresented_Params& params) { |
305 if (params.sync_point == 0) { | 282 if (params.sync_point == 0) { |
306 BufferPresentedImpl(params.mailbox_name); | 283 BufferPresentedImpl(params.mailbox_name); |
307 } else { | 284 } else { |
308 helper_->manager()->sync_point_manager()->AddSyncPointCallback( | 285 helper_->manager()->sync_point_manager()->AddSyncPointCallback( |
309 params.sync_point, | 286 params.sync_point, |
310 base::Bind(&TextureImageTransportSurface::BufferPresentedImpl, | 287 base::Bind(&TextureImageTransportSurface::BufferPresentedImpl, |
311 this, | 288 this, |
312 params.mailbox_name)); | 289 params.mailbox_name)); |
313 } | 290 } |
314 | |
315 // Careful, we might get deleted now if we were only waiting for | |
316 // a final swap ACK. | |
317 Release(); | |
318 } | 291 } |
319 | 292 |
320 void TextureImageTransportSurface::BufferPresentedImpl( | 293 void TextureImageTransportSurface::BufferPresentedImpl( |
321 const std::string& mailbox_name) { | 294 const std::string& mailbox_name) { |
322 DCHECK(!backbuffer_->service_id()); | |
323 if (!mailbox_name.empty()) { | |
324 DCHECK(mailbox_name.length() == GL_MAILBOX_SIZE_CHROMIUM); | |
325 mailbox_name.copy(reinterpret_cast<char *>(&mailbox_name_), | |
326 sizeof(MailboxName)); | |
327 ConsumeTexture(); | |
328 } | |
329 | |
330 if (stub_destroyed_ && backbuffer_->service_id()) { | |
331 // TODO(sievers): Remove this after changes to the mailbox to take ownership | |
332 // of the service ids. | |
333 DCHECK(context_.get() && surface_.get()); | |
334 uint32 service_id = backbuffer_->ReleaseServiceId(); | |
335 if (context_->MakeCurrent(surface_)) | |
336 glDeleteTextures(1, &service_id); | |
337 | |
338 return; | |
339 } | |
340 | |
341 DCHECK(is_swap_buffers_pending_); | 295 DCHECK(is_swap_buffers_pending_); |
342 is_swap_buffers_pending_ = false; | 296 is_swap_buffers_pending_ = false; |
343 | |
344 // We should not have allowed the backbuffer to be discarded while the ack | 297 // We should not have allowed the backbuffer to be discarded while the ack |
345 // was pending. | 298 // was pending. |
346 DCHECK(backbuffer_suggested_allocation_); | 299 DCHECK(backbuffer_suggested_allocation_); |
| 300 DCHECK(backbuffer_); |
| 301 |
| 302 bool swap = true; |
| 303 if (!mailbox_name.empty()) { |
| 304 DCHECK(mailbox_name.length() == GL_MAILBOX_SIZE_CHROMIUM); |
| 305 if (!memcmp(mailbox_name.data(), |
| 306 &back_mailbox_name_, |
| 307 mailbox_name.length())) { |
| 308 // The browser has skipped the frame to unblock the GPU process, waiting |
| 309 // for one of the right size, and returned the back buffer, so don't swap. |
| 310 swap = false; |
| 311 } |
| 312 } |
| 313 if (swap) { |
| 314 std::swap(backbuffer_, frontbuffer_); |
| 315 std::swap(back_mailbox_name_, front_mailbox_name_); |
| 316 } |
347 | 317 |
348 // We're relying on the fact that the parent context is | 318 // We're relying on the fact that the parent context is |
349 // finished with it's context when it inserts the sync point that | 319 // finished with its context when it inserts the sync point that |
350 // triggers this callback. | 320 // triggers this callback. |
351 if (helper_->MakeCurrent()) { | 321 if (helper_->MakeCurrent()) { |
352 if (backbuffer_size() != current_size_ || !backbuffer_->service_id()) | 322 if (frontbuffer_ && !frontbuffer_suggested_allocation_) |
| 323 ReleaseFrontTexture(); |
| 324 if (!backbuffer_ || backbuffer_size() != current_size_) |
353 CreateBackTexture(); | 325 CreateBackTexture(); |
354 else | 326 else |
355 AttachBackTextureToFBO(); | 327 AttachBackTextureToFBO(); |
356 } | 328 } |
357 | 329 |
358 // Even if MakeCurrent fails, schedule anyway, to trigger the lost context | 330 // Even if MakeCurrent fails, schedule anyway, to trigger the lost context |
359 // logic. | 331 // logic. |
360 if (did_unschedule_) { | 332 if (did_unschedule_) { |
361 did_unschedule_ = false; | 333 did_unschedule_ = false; |
362 helper_->SetScheduled(true); | 334 helper_->SetScheduled(true); |
363 } | 335 } |
364 } | 336 } |
365 | 337 |
366 void TextureImageTransportSurface::OnResizeViewACK() { | 338 void TextureImageTransportSurface::OnResizeViewACK() { |
367 NOTREACHED(); | 339 NOTREACHED(); |
368 } | 340 } |
369 | 341 |
370 void TextureImageTransportSurface::ReleaseBackTexture() { | 342 void TextureImageTransportSurface::ReleaseBackTexture() { |
371 if (!backbuffer_->service_id()) | 343 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
372 return; | 344 backbuffer_ = NULL; |
373 | 345 back_mailbox_name_ = MailboxName(); |
374 uint32 service_id = backbuffer_->ReleaseServiceId(); | |
375 glDeleteTextures(1, &service_id); | |
376 backbuffer_.reset(CreateTextureDefinition(gfx::Size(), 0)); | |
377 mailbox_name_ = MailboxName(); | |
378 glFlush(); | 346 glFlush(); |
379 CHECK_GL_ERROR(); | 347 CHECK_GL_ERROR(); |
380 } | 348 } |
381 | 349 |
| 350 void TextureImageTransportSurface::ReleaseFrontTexture() { |
| 351 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
| 352 frontbuffer_ = NULL; |
| 353 front_mailbox_name_ = MailboxName(); |
| 354 glFlush(); |
| 355 CHECK_GL_ERROR(); |
| 356 GpuHostMsg_AcceleratedSurfaceRelease_Params params; |
| 357 helper_->SendAcceleratedSurfaceRelease(params); |
| 358 } |
| 359 |
382 void TextureImageTransportSurface::CreateBackTexture() { | 360 void TextureImageTransportSurface::CreateBackTexture() { |
| 361 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
383 // If |is_swap_buffers_pending| we are waiting for our backbuffer | 362 // If |is_swap_buffers_pending| we are waiting for our backbuffer |
384 // in the mailbox, so we shouldn't be reallocating it now. | 363 // in the mailbox, so we shouldn't be reallocating it now. |
385 DCHECK(!is_swap_buffers_pending_); | 364 DCHECK(!is_swap_buffers_pending_); |
386 | 365 |
387 if (backbuffer_->service_id() && backbuffer_size() == current_size_) | 366 if (backbuffer_ && backbuffer_size() == current_size_) |
388 return; | 367 return; |
389 | 368 |
390 uint32 service_id = backbuffer_->ReleaseServiceId(); | |
391 | |
392 VLOG(1) << "Allocating new backbuffer texture"; | 369 VLOG(1) << "Allocating new backbuffer texture"; |
393 | 370 |
394 // On Qualcomm we couldn't resize an FBO texture past a certain | 371 // On Qualcomm we couldn't resize an FBO texture past a certain |
395 // size, after we allocated it as 1x1. So here we simply delete | 372 // size, after we allocated it as 1x1. So here we simply delete |
396 // the previous texture on resize, to insure we don't 'run out of | 373 // the previous texture on resize, to insure we don't 'run out of |
397 // memory'. | 374 // memory'. |
398 if (service_id && | 375 if (backbuffer_ && |
399 helper_->stub() | 376 helper_->stub() |
400 ->decoder() | 377 ->decoder() |
401 ->GetContextGroup() | 378 ->GetContextGroup() |
402 ->feature_info() | 379 ->feature_info() |
403 ->workarounds() | 380 ->workarounds() |
404 .delete_instead_of_resize_fbo) { | 381 .delete_instead_of_resize_fbo) { |
405 glDeleteTextures(1, &service_id); | 382 ReleaseBackTexture(); |
406 service_id = 0; | 383 } |
407 mailbox_name_ = MailboxName(); | 384 GLES2Decoder* decoder = helper_->stub()->decoder(); |
| 385 TextureManager* texture_manager = |
| 386 decoder->GetContextGroup()->texture_manager(); |
| 387 if (!backbuffer_) { |
| 388 mailbox_manager_->GenerateMailboxName(&back_mailbox_name_); |
| 389 GLuint service_id; |
| 390 glGenTextures(1, &service_id); |
| 391 backbuffer_ = TextureRef::Create(texture_manager, 0, service_id); |
| 392 texture_manager->SetTarget(backbuffer_, GL_TEXTURE_2D); |
| 393 Texture* texture = texture_manager->Produce(backbuffer_); |
| 394 bool success = mailbox_manager_->ProduceTexture( |
| 395 GL_TEXTURE_2D, back_mailbox_name_, texture); |
| 396 DCHECK(success); |
408 } | 397 } |
409 | 398 |
410 if (!service_id) { | |
411 MailboxName new_mailbox_name; | |
412 MailboxName& name = mailbox_name_; | |
413 // This slot should be uninitialized. | |
414 DCHECK(!memcmp(&name, &new_mailbox_name, sizeof(MailboxName))); | |
415 mailbox_manager_->GenerateMailboxName(&new_mailbox_name); | |
416 name = new_mailbox_name; | |
417 glGenTextures(1, &service_id); | |
418 } | |
419 | |
420 backbuffer_.reset( | |
421 CreateTextureDefinition(current_size_, service_id)); | |
422 | |
423 { | 399 { |
424 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, service_id); | 400 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, |
425 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 401 backbuffer_->service_id()); |
426 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
429 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | 402 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, |
430 current_size_.width(), current_size_.height(), 0, | 403 current_size_.width(), current_size_.height(), 0, |
431 GL_RGBA, GL_UNSIGNED_BYTE, NULL); | 404 GL_RGBA, GL_UNSIGNED_BYTE, NULL); |
| 405 gpu::gles2::ErrorState* error_state = decoder->GetErrorState(); |
| 406 texture_manager->SetParameter("Backbuffer", error_state, backbuffer_, |
| 407 GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 408 texture_manager->SetParameter("Backbuffer", error_state, backbuffer_, |
| 409 GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 410 texture_manager->SetParameter("Backbuffer", error_state, backbuffer_, |
| 411 GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 412 texture_manager->SetParameter("Backbuffer", error_state, backbuffer_, |
| 413 GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 414 texture_manager->SetLevelInfo( |
| 415 backbuffer_, |
| 416 GL_TEXTURE_2D, |
| 417 0, |
| 418 GL_RGBA, |
| 419 current_size_.width(), |
| 420 current_size_.height(), |
| 421 1, |
| 422 0, |
| 423 GL_RGBA, |
| 424 GL_UNSIGNED_BYTE, |
| 425 true); |
| 426 DCHECK(texture_manager->CanRender(backbuffer_)); |
432 CHECK_GL_ERROR(); | 427 CHECK_GL_ERROR(); |
433 } | 428 } |
434 | 429 |
435 AttachBackTextureToFBO(); | 430 AttachBackTextureToFBO(); |
436 } | 431 } |
437 | 432 |
438 void TextureImageTransportSurface::AttachBackTextureToFBO() { | 433 void TextureImageTransportSurface::AttachBackTextureToFBO() { |
439 DCHECK(backbuffer_->service_id()); | 434 DCHECK(helper_->stub()->decoder()->GetGLContext()->IsCurrent(NULL)); |
| 435 DCHECK(backbuffer_); |
440 gfx::ScopedFrameBufferBinder fbo_binder(fbo_id_); | 436 gfx::ScopedFrameBufferBinder fbo_binder(fbo_id_); |
441 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, | 437 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, |
442 GL_COLOR_ATTACHMENT0, | 438 GL_COLOR_ATTACHMENT0, |
443 GL_TEXTURE_2D, | 439 GL_TEXTURE_2D, |
444 backbuffer_->service_id(), | 440 backbuffer_->service_id(), |
445 0); | 441 0); |
446 CHECK_GL_ERROR(); | 442 CHECK_GL_ERROR(); |
447 | 443 |
448 #ifndef NDEBUG | 444 #ifndef NDEBUG |
449 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); | 445 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); |
450 if (status != GL_FRAMEBUFFER_COMPLETE) { | 446 if (status != GL_FRAMEBUFFER_COMPLETE) { |
451 DLOG(FATAL) << "Framebuffer incomplete: " << status; | 447 DLOG(FATAL) << "Framebuffer incomplete: " << status; |
452 } | 448 } |
453 #endif | 449 #endif |
454 } | 450 } |
455 | 451 |
456 TextureDefinition* TextureImageTransportSurface::CreateTextureDefinition( | |
457 gfx::Size size, int service_id) { | |
458 TextureDefinition::LevelInfo info( | |
459 GL_TEXTURE_2D, GL_RGBA, size.width(), size.height(), 1, | |
460 0, GL_RGBA, GL_UNSIGNED_BYTE, true); | |
461 | |
462 TextureDefinition::LevelInfos level_infos; | |
463 level_infos.resize(1); | |
464 level_infos[0].resize(1); | |
465 level_infos[0][0] = info; | |
466 return new TextureDefinition( | |
467 GL_TEXTURE_2D, | |
468 service_id, | |
469 GL_LINEAR, | |
470 GL_LINEAR, | |
471 GL_CLAMP_TO_EDGE, | |
472 GL_CLAMP_TO_EDGE, | |
473 GL_NONE, | |
474 true, | |
475 false, | |
476 level_infos); | |
477 } | |
478 | |
479 void TextureImageTransportSurface::ConsumeTexture() { | |
480 DCHECK(!backbuffer_->service_id()); | |
481 | |
482 backbuffer_.reset(mailbox_manager_->ConsumeTexture( | |
483 GL_TEXTURE_2D, mailbox_name_)); | |
484 if (!backbuffer_) { | |
485 mailbox_name_ = MailboxName(); | |
486 backbuffer_.reset(CreateTextureDefinition(gfx::Size(), 0)); | |
487 } | |
488 } | |
489 | |
490 void TextureImageTransportSurface::ProduceTexture() { | |
491 DCHECK(backbuffer_->service_id()); | |
492 DCHECK(!backbuffer_size().IsEmpty()); | |
493 | |
494 // Pass NULL as |owner| here to avoid errors from glConsumeTextureCHROMIUM() | |
495 // when the renderer context group goes away before the RWHV handles a pending | |
496 // ACK. We avoid leaking a texture in the mailbox by waiting for the final ACK | |
497 // at which point we consume the correct texture back. | |
498 bool success = mailbox_manager_->ProduceTexture( | |
499 GL_TEXTURE_2D, | |
500 mailbox_name_, | |
501 backbuffer_.release(), | |
502 NULL); | |
503 DCHECK(success); | |
504 mailbox_name_ = MailboxName(); | |
505 backbuffer_.reset(CreateTextureDefinition(gfx::Size(), 0)); | |
506 } | |
507 | |
508 } // namespace content | 452 } // namespace content |
OLD | NEW |