| 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/renderer/gpu/mailbox_output_surface.h" | 5 #include "content/renderer/gpu/mailbox_output_surface.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "cc/output/compositor_frame.h" | 8 #include "cc/output/compositor_frame.h" |
| 9 #include "cc/output/compositor_frame_ack.h" | 9 #include "cc/output/compositor_frame_ack.h" |
| 10 #include "cc/output/gl_frame_data.h" | 10 #include "cc/output/gl_frame_data.h" |
| 11 #include "cc/output/managed_memory_policy.h" | |
| 12 #include "cc/output/output_surface_client.h" | |
| 13 #include "cc/resources/resource_provider.h" | 11 #include "cc/resources/resource_provider.h" |
| 14 #include "content/renderer/gpu/frame_swap_message_queue.h" | 12 #include "content/renderer/gpu/frame_swap_message_queue.h" |
| 15 #include "gpu/command_buffer/client/context_support.h" | |
| 16 #include "gpu/command_buffer/client/gles2_interface.h" | 13 #include "gpu/command_buffer/client/gles2_interface.h" |
| 17 #include "gpu/command_buffer/common/gpu_memory_allocation.h" | |
| 18 #include "third_party/khronos/GLES2/gl2.h" | 14 #include "third_party/khronos/GLES2/gl2.h" |
| 19 #include "third_party/khronos/GLES2/gl2ext.h" | 15 #include "third_party/khronos/GLES2/gl2ext.h" |
| 20 | 16 |
| 21 using cc::CompositorFrame; | 17 using cc::CompositorFrame; |
| 22 using cc::GLFrameData; | 18 using cc::GLFrameData; |
| 23 using cc::ResourceProvider; | 19 using cc::ResourceProvider; |
| 24 using gpu::Mailbox; | 20 using gpu::Mailbox; |
| 25 using gpu::gles2::GLES2Interface; | 21 using gpu::gles2::GLES2Interface; |
| 26 | 22 |
| 27 namespace content { | 23 namespace content { |
| 28 | 24 |
| 29 MailboxOutputSurface::MailboxOutputSurface( | 25 MailboxOutputSurface::MailboxOutputSurface( |
| 26 int32_t routing_id, |
| 30 uint32_t output_surface_id, | 27 uint32_t output_surface_id, |
| 31 scoped_refptr<cc::ContextProvider> context_provider, | 28 const scoped_refptr<ContextProviderCommandBuffer>& context_provider, |
| 32 scoped_refptr<cc::ContextProvider> worker_context_provider) | 29 const scoped_refptr<ContextProviderCommandBuffer>& worker_context_provider, |
| 33 : cc::OutputSurface(std::move(context_provider), | 30 scoped_refptr<FrameSwapMessageQueue> swap_frame_message_queue, |
| 34 std::move(worker_context_provider), | 31 cc::ResourceFormat format) |
| 35 nullptr), | 32 : CompositorOutputSurface(routing_id, |
| 36 output_surface_id_(output_surface_id), | 33 output_surface_id, |
| 34 context_provider, |
| 35 worker_context_provider, |
| 36 nullptr, |
| 37 nullptr, |
| 38 swap_frame_message_queue, |
| 39 true), |
| 37 fbo_(0), | 40 fbo_(0), |
| 38 is_backbuffer_discarded_(false), | 41 is_backbuffer_discarded_(false), |
| 39 weak_ptrs_(this) { | 42 format_(format) { |
| 40 pending_textures_.push_back(TransferableFrame()); | 43 pending_textures_.push_back(TransferableFrame()); |
| 41 capabilities_.uses_default_gl_framebuffer = false; | 44 capabilities_.uses_default_gl_framebuffer = false; |
| 42 } | 45 } |
| 43 | 46 |
| 44 MailboxOutputSurface::~MailboxOutputSurface() = default; | 47 MailboxOutputSurface::~MailboxOutputSurface() {} |
| 45 | |
| 46 bool MailboxOutputSurface::BindToClient(cc::OutputSurfaceClient* client) { | |
| 47 if (!cc::OutputSurface::BindToClient(client)) | |
| 48 return false; | |
| 49 | |
| 50 if (!context_provider()) { | |
| 51 // Without a GPU context, the memory policy otherwise wouldn't be set. | |
| 52 client->SetMemoryPolicy(cc::ManagedMemoryPolicy( | |
| 53 128 * 1024 * 1024, gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE, | |
| 54 base::SharedMemory::GetHandleLimit() / 3)); | |
| 55 } | |
| 56 | |
| 57 return true; | |
| 58 } | |
| 59 | 48 |
| 60 void MailboxOutputSurface::DetachFromClient() { | 49 void MailboxOutputSurface::DetachFromClient() { |
| 61 DiscardBackbuffer(); | 50 DiscardBackbuffer(); |
| 62 while (!pending_textures_.empty()) { | 51 while (!pending_textures_.empty()) { |
| 63 if (pending_textures_.front().texture_id) { | 52 if (pending_textures_.front().texture_id) { |
| 64 context_provider_->ContextGL()->DeleteTextures( | 53 context_provider_->ContextGL()->DeleteTextures( |
| 65 1, &pending_textures_.front().texture_id); | 54 1, &pending_textures_.front().texture_id); |
| 66 } | 55 } |
| 67 pending_textures_.pop_front(); | 56 pending_textures_.pop_front(); |
| 68 } | 57 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 91 } | 80 } |
| 92 | 81 |
| 93 if (!current_backing_.texture_id) { | 82 if (!current_backing_.texture_id) { |
| 94 gl->GenTextures(1, ¤t_backing_.texture_id); | 83 gl->GenTextures(1, ¤t_backing_.texture_id); |
| 95 current_backing_.size = surface_size_; | 84 current_backing_.size = surface_size_; |
| 96 gl->BindTexture(GL_TEXTURE_2D, current_backing_.texture_id); | 85 gl->BindTexture(GL_TEXTURE_2D, current_backing_.texture_id); |
| 97 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 86 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 98 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 87 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 99 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 88 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 100 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 89 gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 101 gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(cc::RGBA_8888), | 90 gl->TexImage2D(GL_TEXTURE_2D, |
| 102 surface_size_.width(), surface_size_.height(), 0, | 91 0, |
| 103 GLDataFormat(cc::RGBA_8888), GLDataType(cc::RGBA_8888), | 92 GLInternalFormat(format_), |
| 93 surface_size_.width(), |
| 94 surface_size_.height(), |
| 95 0, |
| 96 GLDataFormat(format_), |
| 97 GLDataType(format_), |
| 104 NULL); | 98 NULL); |
| 105 gl->GenMailboxCHROMIUM(current_backing_.mailbox.name); | 99 gl->GenMailboxCHROMIUM(current_backing_.mailbox.name); |
| 106 gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, current_backing_.mailbox.name); | 100 gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, current_backing_.mailbox.name); |
| 107 } | 101 } |
| 108 } | 102 } |
| 109 } | 103 } |
| 110 | 104 |
| 111 void MailboxOutputSurface::DiscardBackbuffer() { | 105 void MailboxOutputSurface::DiscardBackbuffer() { |
| 112 is_backbuffer_discarded_ = true; | 106 is_backbuffer_discarded_ = true; |
| 113 | 107 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 GL_COLOR_ATTACHMENT0, | 150 GL_COLOR_ATTACHMENT0, |
| 157 GL_TEXTURE_2D, | 151 GL_TEXTURE_2D, |
| 158 current_backing_.texture_id, | 152 current_backing_.texture_id, |
| 159 0); | 153 0); |
| 160 } | 154 } |
| 161 | 155 |
| 162 void MailboxOutputSurface::OnSwapAck(uint32_t output_surface_id, | 156 void MailboxOutputSurface::OnSwapAck(uint32_t output_surface_id, |
| 163 const cc::CompositorFrameAck& ack) { | 157 const cc::CompositorFrameAck& ack) { |
| 164 // Ignore message if it's a stale one coming from a different output surface | 158 // Ignore message if it's a stale one coming from a different output surface |
| 165 // (e.g. after a lost context). | 159 // (e.g. after a lost context). |
| 166 if (output_surface_id != output_surface_id_) | 160 if (output_surface_id != output_surface_id_) { |
| 161 CompositorOutputSurface::OnSwapAck(output_surface_id, ack); |
| 167 return; | 162 return; |
| 168 | 163 } |
| 169 if (!ack.gl_frame_data->mailbox.IsZero()) { | 164 if (!ack.gl_frame_data->mailbox.IsZero()) { |
| 170 DCHECK(!ack.gl_frame_data->size.IsEmpty()); | 165 DCHECK(!ack.gl_frame_data->size.IsEmpty()); |
| 171 // The browser could be returning the oldest or any other pending texture | 166 // The browser could be returning the oldest or any other pending texture |
| 172 // if it decided to skip a frame. | 167 // if it decided to skip a frame. |
| 173 std::deque<TransferableFrame>::iterator it; | 168 std::deque<TransferableFrame>::iterator it; |
| 174 for (it = pending_textures_.begin(); it != pending_textures_.end(); it++) { | 169 for (it = pending_textures_.begin(); it != pending_textures_.end(); it++) { |
| 175 DCHECK(!it->mailbox.IsZero()); | 170 DCHECK(!it->mailbox.IsZero()); |
| 176 if (!memcmp(it->mailbox.name, | 171 if (!memcmp(it->mailbox.name, |
| 177 ack.gl_frame_data->mailbox.name, | 172 ack.gl_frame_data->mailbox.name, |
| 178 sizeof(it->mailbox.name))) { | 173 sizeof(it->mailbox.name))) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 193 } else { | 188 } else { |
| 194 DCHECK(!pending_textures_.empty()); | 189 DCHECK(!pending_textures_.empty()); |
| 195 // The browser always keeps one texture as the frontbuffer. | 190 // The browser always keeps one texture as the frontbuffer. |
| 196 // If it does not return a mailbox, it discarded the frontbuffer which is | 191 // If it does not return a mailbox, it discarded the frontbuffer which is |
| 197 // the oldest texture we sent. | 192 // the oldest texture we sent. |
| 198 uint32_t texture_id = pending_textures_.front().texture_id; | 193 uint32_t texture_id = pending_textures_.front().texture_id; |
| 199 if (texture_id) | 194 if (texture_id) |
| 200 context_provider_->ContextGL()->DeleteTextures(1, &texture_id); | 195 context_provider_->ContextGL()->DeleteTextures(1, &texture_id); |
| 201 pending_textures_.pop_front(); | 196 pending_textures_.pop_front(); |
| 202 } | 197 } |
| 203 | 198 CompositorOutputSurface::OnSwapAck(output_surface_id, ack); |
| 204 ReclaimResources(&ack); | |
| 205 client_->DidSwapBuffersComplete(); | |
| 206 } | |
| 207 | |
| 208 void MailboxOutputSurface::ShortcutSwapAck( | |
| 209 uint32_t output_surface_id, | |
| 210 std::unique_ptr<cc::GLFrameData> gl_frame_data) { | |
| 211 if (!previous_frame_ack_) { | |
| 212 previous_frame_ack_.reset(new cc::CompositorFrameAck); | |
| 213 previous_frame_ack_->gl_frame_data.reset(new cc::GLFrameData); | |
| 214 } | |
| 215 | |
| 216 OnSwapAck(output_surface_id, *previous_frame_ack_); | |
| 217 | |
| 218 previous_frame_ack_->gl_frame_data = std::move(gl_frame_data); | |
| 219 } | 199 } |
| 220 | 200 |
| 221 void MailboxOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { | 201 void MailboxOutputSurface::SwapBuffers(cc::CompositorFrame* frame) { |
| 222 // This class is here to support layout tests that are currently | |
| 223 // doing a readback in the renderer instead of the browser. So they | |
| 224 // are using deprecated code paths in the renderer and don't need to | |
| 225 // actually swap anything to the browser. We shortcut the swap to the | |
| 226 // browser here and just ack directly within the renderer process. | |
| 227 // Once crbug.com/311404 is fixed, this can be removed. | |
| 228 | |
| 229 // This would indicate that crbug.com/311404 is being fixed, and this | |
| 230 // block needs to be removed. | |
| 231 DCHECK(!frame->delegated_frame_data); | |
| 232 | |
| 233 DCHECK(frame->gl_frame_data); | 202 DCHECK(frame->gl_frame_data); |
| 234 DCHECK(!surface_size_.IsEmpty()); | 203 DCHECK(!surface_size_.IsEmpty()); |
| 235 DCHECK(surface_size_ == current_backing_.size); | 204 DCHECK(surface_size_ == current_backing_.size); |
| 236 DCHECK(frame->gl_frame_data->size == current_backing_.size); | 205 DCHECK(frame->gl_frame_data->size == current_backing_.size); |
| 237 DCHECK(!current_backing_.mailbox.IsZero() || | 206 DCHECK(!current_backing_.mailbox.IsZero() || |
| 238 context_provider_->ContextGL()->GetGraphicsResetStatusKHR() != | 207 context_provider_->ContextGL()->GetGraphicsResetStatusKHR() != |
| 239 GL_NO_ERROR); | 208 GL_NO_ERROR); |
| 240 | 209 |
| 241 frame->gl_frame_data->mailbox = current_backing_.mailbox; | 210 frame->gl_frame_data->mailbox = current_backing_.mailbox; |
| 242 | 211 |
| 243 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 212 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 244 | 213 |
| 245 const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); | 214 const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); |
| 246 gl->Flush(); | 215 gl->Flush(); |
| 216 |
| 247 gl->GenSyncTokenCHROMIUM(fence_sync, | 217 gl->GenSyncTokenCHROMIUM(fence_sync, |
| 248 frame->gl_frame_data->sync_token.GetData()); | 218 frame->gl_frame_data->sync_token.GetData()); |
| 249 | 219 |
| 250 context_provider()->ContextSupport()->SignalSyncToken( | 220 CompositorOutputSurface::SwapBuffers(frame); |
| 251 frame->gl_frame_data->sync_token, | |
| 252 base::Bind(&MailboxOutputSurface::ShortcutSwapAck, | |
| 253 weak_ptrs_.GetWeakPtr(), output_surface_id_, | |
| 254 base::Passed(&frame->gl_frame_data))); | |
| 255 | 221 |
| 256 pending_textures_.push_back(current_backing_); | 222 pending_textures_.push_back(current_backing_); |
| 257 current_backing_ = TransferableFrame(); | 223 current_backing_ = TransferableFrame(); |
| 224 } |
| 258 | 225 |
| 259 client_->DidSwapBuffers(); | 226 size_t MailboxOutputSurface::GetNumAcksPending() { |
| 227 DCHECK(pending_textures_.size()); |
| 228 return pending_textures_.size() - 1; |
| 260 } | 229 } |
| 261 | 230 |
| 262 MailboxOutputSurface::TransferableFrame::TransferableFrame() : texture_id(0) {} | 231 MailboxOutputSurface::TransferableFrame::TransferableFrame() : texture_id(0) {} |
| 263 | 232 |
| 264 MailboxOutputSurface::TransferableFrame::TransferableFrame( | 233 MailboxOutputSurface::TransferableFrame::TransferableFrame( |
| 265 uint32_t texture_id, | 234 uint32_t texture_id, |
| 266 const gpu::Mailbox& mailbox, | 235 const gpu::Mailbox& mailbox, |
| 267 const gfx::Size size) | 236 const gfx::Size size) |
| 268 : texture_id(texture_id), mailbox(mailbox), size(size) {} | 237 : texture_id(texture_id), mailbox(mailbox), size(size) {} |
| 269 | 238 |
| 270 } // namespace content | 239 } // namespace content |
| OLD | NEW |