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