| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/browser/compositor/buffer_queue.h" | 5 #include "content/browser/compositor/buffer_queue.h" |
| 6 | 6 |
| 7 #include "base/containers/adapters.h" |
| 7 #include "content/browser/compositor/image_transport_factory.h" | 8 #include "content/browser/compositor/image_transport_factory.h" |
| 8 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" | 9 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h" |
| 9 #include "content/common/gpu/client/context_provider_command_buffer.h" | 10 #include "content/common/gpu/client/context_provider_command_buffer.h" |
| 10 #include "content/common/gpu/client/gl_helper.h" | 11 #include "content/common/gpu/client/gl_helper.h" |
| 11 #include "gpu/GLES2/gl2extchromium.h" | 12 #include "gpu/GLES2/gl2extchromium.h" |
| 12 #include "gpu/command_buffer/client/gles2_interface.h" | 13 #include "gpu/command_buffer/client/gles2_interface.h" |
| 13 #include "gpu/command_buffer/service/image_factory.h" | 14 #include "gpu/command_buffer/service/image_factory.h" |
| 14 #include "third_party/skia/include/core/SkRect.h" | 15 #include "third_party/skia/include/core/SkRect.h" |
| 15 #include "third_party/skia/include/core/SkRegion.h" | 16 #include "third_party/skia/include/core/SkRegion.h" |
| 16 #include "ui/gfx/gpu_memory_buffer.h" | 17 #include "ui/gfx/gpu_memory_buffer.h" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 44 | 45 |
| 45 void BufferQueue::Initialize() { | 46 void BufferQueue::Initialize() { |
| 46 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 47 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 47 gl->GenFramebuffers(1, &fbo_); | 48 gl->GenFramebuffers(1, &fbo_); |
| 48 } | 49 } |
| 49 | 50 |
| 50 void BufferQueue::BindFramebuffer() { | 51 void BufferQueue::BindFramebuffer() { |
| 51 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 52 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 52 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 53 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 53 | 54 |
| 54 if (!current_surface_.texture) { | 55 if (!current_surface_) |
| 55 current_surface_ = GetNextSurface(); | 56 current_surface_ = GetNextSurface(); |
| 57 |
| 58 if (current_surface_) { |
| 56 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 59 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 57 texture_target_, current_surface_.texture, 0); | 60 texture_target_, current_surface_->texture, 0); |
| 58 } | 61 } |
| 59 } | 62 } |
| 60 | 63 |
| 61 void BufferQueue::CopyBufferDamage(int texture, | 64 void BufferQueue::CopyBufferDamage(int texture, |
| 62 int source_texture, | 65 int source_texture, |
| 63 const gfx::Rect& new_damage, | 66 const gfx::Rect& new_damage, |
| 64 const gfx::Rect& old_damage) { | 67 const gfx::Rect& old_damage) { |
| 65 gl_helper_->CopySubBufferDamage( | 68 gl_helper_->CopySubBufferDamage( |
| 66 texture_target_, texture, source_texture, | 69 texture_target_, texture, source_texture, |
| 67 SkRegion(gfx::RectToSkIRect(new_damage)), | 70 SkRegion(gfx::RectToSkIRect(new_damage)), |
| 68 SkRegion(gfx::RectToSkIRect(old_damage))); | 71 SkRegion(gfx::RectToSkIRect(old_damage))); |
| 69 } | 72 } |
| 70 | 73 |
| 71 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) { | 74 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) { |
| 72 displayed_surface_.damage.Union(damage); | 75 if (displayed_surface_) |
| 73 for (size_t i = 0; i < available_surfaces_.size(); i++) | 76 displayed_surface_->damage.Union(damage); |
| 74 available_surfaces_[i].damage.Union(damage); | 77 for (auto& surface : available_surfaces_) |
| 75 | 78 surface->damage.Union(damage); |
| 76 for (std::deque<AllocatedSurface>::iterator it = | 79 for (auto& surface : in_flight_surfaces_) { |
| 77 in_flight_surfaces_.begin(); | 80 if (surface) |
| 78 it != in_flight_surfaces_.end(); | 81 surface->damage.Union(damage); |
| 79 ++it) | 82 } |
| 80 it->damage.Union(damage); | |
| 81 } | 83 } |
| 82 | 84 |
| 83 void BufferQueue::SwapBuffers(const gfx::Rect& damage) { | 85 void BufferQueue::SwapBuffers(const gfx::Rect& damage) { |
| 84 if (!damage.IsEmpty() && damage != gfx::Rect(size_)) { | 86 if (current_surface_) { |
| 85 // We must have a frame available to copy from. | 87 if (!damage.IsEmpty() && damage != gfx::Rect(size_)) { |
| 86 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture); | 88 // Copy damage from the most recently swapped buffer. In the event that |
| 87 unsigned int texture_id = !in_flight_surfaces_.empty() | 89 // the buffer was destroyed and failed to recreate, pick from the most |
| 88 ? in_flight_surfaces_.back().texture | 90 // recently available buffer. |
| 89 : displayed_surface_.texture; | 91 unsigned int texture_id = 0; |
| 92 for (auto& surface : base::Reversed(in_flight_surfaces_)) { |
| 93 if (surface) { |
| 94 texture_id = surface->texture; |
| 95 break; |
| 96 } |
| 97 } |
| 98 if (!texture_id && displayed_surface_) |
| 99 texture_id = displayed_surface_->texture; |
| 90 | 100 |
| 91 CopyBufferDamage(current_surface_.texture, texture_id, damage, | 101 if (texture_id) { |
| 92 current_surface_.damage); | 102 CopyBufferDamage(current_surface_->texture, texture_id, damage, |
| 103 current_surface_->damage); |
| 104 } |
| 105 } |
| 106 current_surface_->damage = gfx::Rect(); |
| 93 } | 107 } |
| 94 UpdateBufferDamage(damage); | 108 UpdateBufferDamage(damage); |
| 95 current_surface_.damage = gfx::Rect(); | 109 in_flight_surfaces_.push_back(std::move(current_surface_)); |
| 96 in_flight_surfaces_.push_back(current_surface_); | |
| 97 current_surface_.texture = 0; | |
| 98 current_surface_.image = 0; | |
| 99 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer | 110 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer |
| 100 // paths), so ensure we restore it here. | 111 // paths), so ensure we restore it here. |
| 101 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 112 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 102 } | 113 } |
| 103 | 114 |
| 104 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { | 115 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { |
| 105 if (size == size_) | 116 if (size == size_) |
| 106 return; | 117 return; |
| 107 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that | 118 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that |
| 108 // is cause for concern or if it is benign. | 119 // is cause for concern or if it is benign. |
| 109 // http://crbug.com/524624 | 120 // http://crbug.com/524624 |
| 110 #if !defined(OS_MACOSX) | 121 #if !defined(OS_MACOSX) |
| 111 DCHECK(!current_surface_.texture); | 122 DCHECK(!current_surface_); |
| 112 #endif | 123 #endif |
| 113 size_ = size; | 124 size_ = size; |
| 114 | 125 |
| 115 // TODO: add stencil buffer when needed. | 126 // TODO: add stencil buffer when needed. |
| 116 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 127 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 117 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 128 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 118 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 129 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 119 texture_target_, 0, 0); | 130 texture_target_, 0, 0); |
| 120 | 131 |
| 121 FreeAllSurfaces(); | 132 FreeAllSurfaces(); |
| 122 } | 133 } |
| 123 | 134 |
| 124 void BufferQueue::RecreateBuffers() { | 135 void BufferQueue::RecreateBuffers() { |
| 125 // We need to recreate the buffers, for whatever reason the old ones are not | 136 // We need to recreate the buffers, for whatever reason the old ones are not |
| 126 // presentable on the device anymore. | 137 // presentable on the device anymore. |
| 127 // Unused buffers can be freed directly, they will be re-allocated as needed. | 138 // Unused buffers can be freed directly, they will be re-allocated as needed. |
| 128 // Any in flight, current or displayed surface must be replaced. | 139 // Any in flight, current or displayed surface must be replaced. |
| 129 for (size_t i = 0; i < available_surfaces_.size(); i++) | |
| 130 FreeSurface(&available_surfaces_[i]); | |
| 131 available_surfaces_.clear(); | 140 available_surfaces_.clear(); |
| 132 | 141 |
| 142 // Recreate all in-flight surfaces and put the recreated copies in the queue. |
| 133 for (auto& surface : in_flight_surfaces_) | 143 for (auto& surface : in_flight_surfaces_) |
| 134 surface = RecreateBuffer(&surface); | 144 surface = RecreateBuffer(std::move(surface)); |
| 135 | 145 |
| 136 current_surface_ = RecreateBuffer(¤t_surface_); | 146 current_surface_ = RecreateBuffer(std::move(current_surface_)); |
| 137 displayed_surface_ = RecreateBuffer(&displayed_surface_); | 147 displayed_surface_ = RecreateBuffer(std::move(displayed_surface_)); |
| 138 | 148 |
| 139 if (current_surface_.texture) { | 149 if (current_surface_) { |
| 140 // If we have a texture bound, we will need to re-bind it. | 150 // If we have a texture bound, we will need to re-bind it. |
| 141 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 151 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 142 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 152 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 143 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 153 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 144 texture_target_, current_surface_.texture, 0); | 154 texture_target_, current_surface_->texture, 0); |
| 145 } | 155 } |
| 146 } | 156 } |
| 147 | 157 |
| 148 BufferQueue::AllocatedSurface BufferQueue::RecreateBuffer( | 158 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::RecreateBuffer( |
| 149 AllocatedSurface* surface) { | 159 scoped_ptr<AllocatedSurface> surface) { |
| 150 if (!surface->texture) | 160 if (!surface) |
| 151 return *surface; | 161 return nullptr; |
| 152 AllocatedSurface new_surface = GetNextSurface(); | 162 |
| 153 new_surface.damage = surface->damage; | 163 scoped_ptr<AllocatedSurface> new_surface(GetNextSurface()); |
| 164 if (!new_surface) |
| 165 return nullptr; |
| 166 |
| 167 new_surface->damage = surface->damage; |
| 154 | 168 |
| 155 // Copy the entire texture. | 169 // Copy the entire texture. |
| 156 CopyBufferDamage(new_surface.texture, surface->texture, gfx::Rect(), | 170 CopyBufferDamage(new_surface->texture, surface->texture, gfx::Rect(), |
| 157 gfx::Rect(size_)); | 171 gfx::Rect(size_)); |
| 158 | |
| 159 FreeSurface(surface); | |
| 160 return new_surface; | 172 return new_surface; |
| 161 } | 173 } |
| 162 | 174 |
| 163 void BufferQueue::PageFlipComplete() { | 175 void BufferQueue::PageFlipComplete() { |
| 164 DCHECK(!in_flight_surfaces_.empty()); | 176 DCHECK(!in_flight_surfaces_.empty()); |
| 165 | 177 if (displayed_surface_) |
| 166 if (displayed_surface_.texture) | 178 available_surfaces_.push_back(std::move(displayed_surface_)); |
| 167 available_surfaces_.push_back(displayed_surface_); | 179 displayed_surface_ = std::move(in_flight_surfaces_.front()); |
| 168 | |
| 169 displayed_surface_ = in_flight_surfaces_.front(); | |
| 170 in_flight_surfaces_.pop_front(); | 180 in_flight_surfaces_.pop_front(); |
| 171 } | 181 } |
| 172 | 182 |
| 173 void BufferQueue::FreeAllSurfaces() { | 183 void BufferQueue::FreeAllSurfaces() { |
| 174 FreeSurface(&displayed_surface_); | 184 displayed_surface_.reset(); |
| 175 FreeSurface(¤t_surface_); | 185 current_surface_.reset(); |
| 176 // This is intentionally not emptied since the swap buffers acks are still | 186 // This is intentionally not emptied since the swap buffers acks are still |
| 177 // expected to arrive. | 187 // expected to arrive. |
| 178 for (auto& surface : in_flight_surfaces_) | 188 for (auto& surface : in_flight_surfaces_) |
| 179 FreeSurface(&surface); | 189 surface = nullptr; |
| 180 | |
| 181 for (size_t i = 0; i < available_surfaces_.size(); i++) | |
| 182 FreeSurface(&available_surfaces_[i]); | |
| 183 | |
| 184 available_surfaces_.clear(); | 190 available_surfaces_.clear(); |
| 185 } | 191 } |
| 186 | 192 |
| 187 void BufferQueue::FreeSurface(AllocatedSurface* surface) { | 193 void BufferQueue::FreeSurfaceResources(AllocatedSurface* surface) { |
| 188 if (surface->texture) { | 194 if (!surface->texture) |
| 189 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 195 return; |
| 190 gl->BindTexture(texture_target_, surface->texture); | 196 |
| 191 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); | 197 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 192 gl->DeleteTextures(1, &surface->texture); | 198 gl->BindTexture(texture_target_, surface->texture); |
| 193 gl->DestroyImageCHROMIUM(surface->image); | 199 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); |
| 194 surface->image = 0; | 200 gl->DeleteTextures(1, &surface->texture); |
| 195 surface->texture = 0; | 201 gl->DestroyImageCHROMIUM(surface->image); |
| 196 allocated_count_--; | 202 surface->buffer.reset(); |
| 197 } | 203 allocated_count_--; |
| 198 } | 204 } |
| 199 | 205 |
| 200 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() { | 206 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() { |
| 201 if (!available_surfaces_.empty()) { | 207 if (!available_surfaces_.empty()) { |
| 202 AllocatedSurface surface = available_surfaces_.back(); | 208 scoped_ptr<AllocatedSurface> surface = |
| 209 std::move(available_surfaces_.back()); |
| 203 available_surfaces_.pop_back(); | 210 available_surfaces_.pop_back(); |
| 204 return surface; | 211 return surface; |
| 205 } | 212 } |
| 206 | 213 |
| 207 unsigned int texture = 0; | 214 unsigned int texture = 0; |
| 208 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 215 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 209 gl->GenTextures(1, &texture); | 216 gl->GenTextures(1, &texture); |
| 210 if (!texture) | 217 if (!texture) |
| 211 return AllocatedSurface(); | 218 return nullptr; |
| 212 | 219 |
| 213 // We don't want to allow anything more than triple buffering. | 220 // We don't want to allow anything more than triple buffering. |
| 214 DCHECK_LT(allocated_count_, 4U); | 221 DCHECK_LT(allocated_count_, 4U); |
| 215 | 222 |
| 216 scoped_ptr<gfx::GpuMemoryBuffer> buffer( | 223 scoped_ptr<gfx::GpuMemoryBuffer> buffer( |
| 217 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( | 224 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( |
| 218 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( | 225 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( |
| 219 internal_format_), | 226 internal_format_), |
| 220 surface_id_)); | 227 surface_id_)); |
| 221 if (!buffer.get()) { | 228 if (!buffer.get()) { |
| 222 gl->DeleteTextures(1, &texture); | 229 gl->DeleteTextures(1, &texture); |
| 223 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; | 230 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; |
| 224 return AllocatedSurface(); | 231 return nullptr; |
| 225 } | 232 } |
| 226 | 233 |
| 227 unsigned int id = gl->CreateImageCHROMIUM( | 234 unsigned int id = gl->CreateImageCHROMIUM( |
| 228 buffer->AsClientBuffer(), size_.width(), size_.height(), | 235 buffer->AsClientBuffer(), size_.width(), size_.height(), |
| 229 internal_format_); | 236 internal_format_); |
| 230 | |
| 231 if (!id) { | 237 if (!id) { |
| 232 LOG(ERROR) << "Failed to allocate backing image surface"; | 238 LOG(ERROR) << "Failed to allocate backing image surface"; |
| 233 gl->DeleteTextures(1, &texture); | 239 gl->DeleteTextures(1, &texture); |
| 234 return AllocatedSurface(); | 240 return nullptr; |
| 235 } | 241 } |
| 242 |
| 236 allocated_count_++; | 243 allocated_count_++; |
| 237 gl->BindTexture(texture_target_, texture); | 244 gl->BindTexture(texture_target_, texture); |
| 238 gl->BindTexImage2DCHROMIUM(texture_target_, id); | 245 gl->BindTexImage2DCHROMIUM(texture_target_, id); |
| 239 return AllocatedSurface(buffer.Pass(), texture, id, gfx::Rect(size_)); | 246 return make_scoped_ptr(new AllocatedSurface(this, std::move(buffer), texture, |
| 247 id, gfx::Rect(size_))); |
| 240 } | 248 } |
| 241 | 249 |
| 242 BufferQueue::AllocatedSurface::AllocatedSurface() : texture(0), image(0) {} | |
| 243 | |
| 244 BufferQueue::AllocatedSurface::AllocatedSurface( | 250 BufferQueue::AllocatedSurface::AllocatedSurface( |
| 251 BufferQueue* buffer_queue, |
| 245 scoped_ptr<gfx::GpuMemoryBuffer> buffer, | 252 scoped_ptr<gfx::GpuMemoryBuffer> buffer, |
| 246 unsigned int texture, | 253 unsigned int texture, |
| 247 unsigned int image, | 254 unsigned int image, |
| 248 const gfx::Rect& rect) | 255 const gfx::Rect& rect) |
| 249 : buffer(buffer.release()), texture(texture), image(image), damage(rect) {} | 256 : buffer_queue(buffer_queue), |
| 257 buffer(buffer.release()), |
| 258 texture(texture), |
| 259 image(image), |
| 260 damage(rect) {} |
| 250 | 261 |
| 251 BufferQueue::AllocatedSurface::~AllocatedSurface() {} | 262 BufferQueue::AllocatedSurface::~AllocatedSurface() { |
| 263 buffer_queue->FreeSurfaceResources(this); |
| 264 } |
| 252 | 265 |
| 253 } // namespace content | 266 } // namespace content |
| OLD | NEW |