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 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 56 gl->FramebufferTexture2D( |
| 57 texture_target_, current_surface_.texture, 0); | 57 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target_, |
| 58 current_surface_ ? current_surface_->texture : 0, 0); | |
|
danakj
2015/12/10 01:36:02
is there a point to doing FramebufferTexture2D(...
ccameron
2015/12/10 07:39:27
The spec says that the texture is automatically un
| |
| 58 } | 59 } |
| 59 } | 60 } |
| 60 | 61 |
| 61 void BufferQueue::CopyBufferDamage(int texture, | 62 void BufferQueue::CopyBufferDamage(int texture, |
| 62 int source_texture, | 63 int source_texture, |
| 63 const gfx::Rect& new_damage, | 64 const gfx::Rect& new_damage, |
| 64 const gfx::Rect& old_damage) { | 65 const gfx::Rect& old_damage) { |
| 65 gl_helper_->CopySubBufferDamage( | 66 gl_helper_->CopySubBufferDamage( |
| 66 texture_target_, texture, source_texture, | 67 texture_target_, texture, source_texture, |
| 67 SkRegion(gfx::RectToSkIRect(new_damage)), | 68 SkRegion(gfx::RectToSkIRect(new_damage)), |
| 68 SkRegion(gfx::RectToSkIRect(old_damage))); | 69 SkRegion(gfx::RectToSkIRect(old_damage))); |
| 69 } | 70 } |
| 70 | 71 |
| 71 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) { | 72 void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) { |
| 72 displayed_surface_.damage.Union(damage); | 73 if (displayed_surface_) |
| 73 for (size_t i = 0; i < available_surfaces_.size(); i++) | 74 displayed_surface_->damage.Union(damage); |
| 74 available_surfaces_[i].damage.Union(damage); | 75 for (auto& surface : available_surfaces_) |
| 75 | 76 surface->damage.Union(damage); |
| 76 for (std::deque<AllocatedSurface>::iterator it = | 77 for (auto& surface : in_flight_surfaces_) { |
| 77 in_flight_surfaces_.begin(); | 78 if (surface) |
| 78 it != in_flight_surfaces_.end(); | 79 surface->damage.Union(damage); |
| 79 ++it) | 80 } |
| 80 it->damage.Union(damage); | |
| 81 } | 81 } |
| 82 | 82 |
| 83 void BufferQueue::SwapBuffers(const gfx::Rect& damage) { | 83 void BufferQueue::SwapBuffers(const gfx::Rect& damage) { |
| 84 if (!damage.IsEmpty() && damage != gfx::Rect(size_)) { | 84 if (current_surface_) { |
| 85 // We must have a frame available to copy from. | 85 if (!damage.IsEmpty() && damage != gfx::Rect(size_)) { |
| 86 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture); | 86 unsigned int texture_id = 0; |
|
danakj
2015/12/10 01:36:02
no more dcheck?
ccameron
2015/12/10 07:39:27
That was wrong-by-inspection. It was entirely poss
| |
| 87 unsigned int texture_id = !in_flight_surfaces_.empty() | 87 if (!in_flight_surfaces_.empty() && in_flight_surfaces_.back()) |
|
danakj
2015/12/10 01:36:02
This logic is a bit different.
Before if there wa
ccameron
2015/12/10 07:39:27
Yeah. Actually, to be more thorough, we should do
| |
| 88 ? in_flight_surfaces_.back().texture | 88 texture_id = in_flight_surfaces_.back()->texture; |
| 89 : displayed_surface_.texture; | 89 else if (displayed_surface_) |
| 90 | 90 texture_id = displayed_surface_->texture; |
| 91 CopyBufferDamage(current_surface_.texture, texture_id, damage, | 91 if (texture_id) { |
|
danakj
2015/12/10 01:36:02
nit: can you put a whitespace line above this to s
ccameron
2015/12/10 07:39:27
Done.
| |
| 92 current_surface_.damage); | 92 CopyBufferDamage(current_surface_->texture, texture_id, damage, |
| 93 current_surface_->damage); | |
| 94 } | |
| 95 } | |
| 96 current_surface_->damage = gfx::Rect(); | |
| 93 } | 97 } |
| 94 UpdateBufferDamage(damage); | 98 UpdateBufferDamage(damage); |
| 95 current_surface_.damage = gfx::Rect(); | 99 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 | 100 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer |
| 100 // paths), so ensure we restore it here. | 101 // paths), so ensure we restore it here. |
| 101 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 102 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 102 } | 103 } |
| 103 | 104 |
| 104 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { | 105 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { |
| 105 if (size == size_) | 106 if (size == size_) |
| 106 return; | 107 return; |
| 107 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that | 108 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that |
| 108 // is cause for concern or if it is benign. | 109 // is cause for concern or if it is benign. |
| 109 // http://crbug.com/524624 | 110 // http://crbug.com/524624 |
| 110 #if !defined(OS_MACOSX) | 111 #if !defined(OS_MACOSX) |
| 111 DCHECK(!current_surface_.texture); | 112 DCHECK(!current_surface_); |
| 112 #endif | 113 #endif |
| 113 size_ = size; | 114 size_ = size; |
| 114 | 115 |
| 115 // TODO: add stencil buffer when needed. | 116 // TODO: add stencil buffer when needed. |
| 116 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 117 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 117 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 118 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 118 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 119 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 119 texture_target_, 0, 0); | 120 texture_target_, 0, 0); |
| 120 | 121 |
| 121 FreeAllSurfaces(); | 122 FreeAllSurfaces(); |
| 122 } | 123 } |
| 123 | 124 |
| 124 void BufferQueue::RecreateBuffers() { | 125 void BufferQueue::RecreateBuffers() { |
| 125 // We need to recreate the buffers, for whatever reason the old ones are not | 126 // We need to recreate the buffers, for whatever reason the old ones are not |
| 126 // presentable on the device anymore. | 127 // presentable on the device anymore. |
| 127 // Unused buffers can be freed directly, they will be re-allocated as needed. | 128 // Unused buffers can be freed directly, they will be re-allocated as needed. |
| 128 // Any in flight, current or displayed surface must be replaced. | 129 // 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(); | 130 available_surfaces_.clear(); |
| 132 | 131 |
| 132 // Recreate all in-flight surfaces and put the recreated copies in the queue. | |
| 133 for (auto& surface : in_flight_surfaces_) | 133 for (auto& surface : in_flight_surfaces_) |
| 134 surface = RecreateBuffer(&surface); | 134 surface = RecreateBuffer(std::move(surface)); |
| 135 | 135 |
| 136 current_surface_ = RecreateBuffer(¤t_surface_); | 136 current_surface_ = RecreateBuffer(std::move(current_surface_)); |
| 137 displayed_surface_ = RecreateBuffer(&displayed_surface_); | 137 displayed_surface_ = RecreateBuffer(std::move(displayed_surface_)); |
| 138 | 138 |
| 139 if (current_surface_.texture) { | 139 if (current_surface_) { |
| 140 // If we have a texture bound, we will need to re-bind it. | 140 // If we have a texture bound, we will need to re-bind it. |
| 141 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 141 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 142 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 142 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 143 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 143 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 144 texture_target_, current_surface_.texture, 0); | 144 texture_target_, current_surface_->texture, 0); |
| 145 } | 145 } |
| 146 } | 146 } |
| 147 | 147 |
| 148 BufferQueue::AllocatedSurface BufferQueue::RecreateBuffer( | 148 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::RecreateBuffer( |
| 149 AllocatedSurface* surface) { | 149 scoped_ptr<AllocatedSurface> surface) { |
| 150 if (!surface->texture) | 150 if (!surface) |
| 151 return *surface; | 151 return nullptr; |
| 152 AllocatedSurface new_surface = GetNextSurface(); | 152 |
| 153 new_surface.damage = surface->damage; | 153 scoped_ptr<AllocatedSurface> new_surface(GetNextSurface()); |
| 154 if (!new_surface) | |
| 155 return nullptr; | |
| 156 | |
| 157 new_surface->damage = surface->damage; | |
| 154 | 158 |
| 155 // Copy the entire texture. | 159 // Copy the entire texture. |
| 156 CopyBufferDamage(new_surface.texture, surface->texture, gfx::Rect(), | 160 CopyBufferDamage(new_surface->texture, surface->texture, gfx::Rect(), |
| 157 gfx::Rect(size_)); | 161 gfx::Rect(size_)); |
| 158 | |
| 159 FreeSurface(surface); | |
| 160 return new_surface; | 162 return new_surface; |
| 161 } | 163 } |
| 162 | 164 |
| 163 void BufferQueue::PageFlipComplete() { | 165 void BufferQueue::PageFlipComplete() { |
| 164 DCHECK(!in_flight_surfaces_.empty()); | 166 DCHECK(!in_flight_surfaces_.empty()); |
| 165 | 167 if (displayed_surface_) |
| 166 if (displayed_surface_.texture) | 168 available_surfaces_.push_back(std::move(displayed_surface_)); |
| 167 available_surfaces_.push_back(displayed_surface_); | 169 displayed_surface_ = std::move(in_flight_surfaces_.front()); |
| 168 | |
| 169 displayed_surface_ = in_flight_surfaces_.front(); | |
| 170 in_flight_surfaces_.pop_front(); | 170 in_flight_surfaces_.pop_front(); |
| 171 } | 171 } |
| 172 | 172 |
| 173 void BufferQueue::FreeAllSurfaces() { | 173 void BufferQueue::FreeAllSurfaces() { |
| 174 FreeSurface(&displayed_surface_); | 174 displayed_surface_.reset(); |
| 175 FreeSurface(¤t_surface_); | 175 current_surface_.reset(); |
| 176 // This is intentionally not emptied since the swap buffers acks are still | 176 // This is intentionally not emptied since the swap buffers acks are still |
| 177 // expected to arrive. | 177 // expected to arrive. |
| 178 for (auto& surface : in_flight_surfaces_) | 178 for (auto& surface : in_flight_surfaces_) |
| 179 FreeSurface(&surface); | 179 surface = nullptr; |
| 180 | |
| 181 for (size_t i = 0; i < available_surfaces_.size(); i++) | |
| 182 FreeSurface(&available_surfaces_[i]); | |
| 183 | |
| 184 available_surfaces_.clear(); | 180 available_surfaces_.clear(); |
| 185 } | 181 } |
| 186 | 182 |
| 187 void BufferQueue::FreeSurface(AllocatedSurface* surface) { | 183 void BufferQueue::FreeSurfaceResources(AllocatedSurface* surface) { |
| 188 if (surface->texture) { | 184 if (!surface->texture) |
| 189 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 185 return; |
| 190 gl->BindTexture(texture_target_, surface->texture); | 186 |
| 191 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); | 187 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 192 gl->DeleteTextures(1, &surface->texture); | 188 gl->BindTexture(texture_target_, surface->texture); |
| 193 gl->DestroyImageCHROMIUM(surface->image); | 189 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); |
| 194 surface->image = 0; | 190 gl->DeleteTextures(1, &surface->texture); |
| 195 surface->texture = 0; | 191 gl->DestroyImageCHROMIUM(surface->image); |
| 196 allocated_count_--; | 192 surface->buffer.reset(); |
| 197 } | 193 allocated_count_--; |
| 198 } | 194 } |
| 199 | 195 |
| 200 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() { | 196 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() { |
| 201 if (!available_surfaces_.empty()) { | 197 if (!available_surfaces_.empty()) { |
| 202 AllocatedSurface surface = available_surfaces_.back(); | 198 scoped_ptr<AllocatedSurface> surface = |
| 199 std::move(available_surfaces_.back()); | |
| 203 available_surfaces_.pop_back(); | 200 available_surfaces_.pop_back(); |
| 204 return surface; | 201 return surface; |
| 205 } | 202 } |
| 206 | 203 |
| 207 unsigned int texture = 0; | 204 unsigned int texture = 0; |
| 208 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 205 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 209 gl->GenTextures(1, &texture); | 206 gl->GenTextures(1, &texture); |
| 210 if (!texture) | 207 if (!texture) |
| 211 return AllocatedSurface(); | 208 return nullptr; |
| 212 | 209 |
| 213 // We don't want to allow anything more than triple buffering. | 210 // We don't want to allow anything more than triple buffering. |
| 214 DCHECK_LT(allocated_count_, 4U); | 211 DCHECK_LT(allocated_count_, 4U); |
| 215 | 212 |
| 216 scoped_ptr<gfx::GpuMemoryBuffer> buffer( | 213 scoped_ptr<gfx::GpuMemoryBuffer> buffer( |
| 217 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( | 214 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( |
| 218 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( | 215 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( |
| 219 internal_format_), | 216 internal_format_), |
| 220 surface_id_)); | 217 surface_id_)); |
| 221 if (!buffer.get()) { | 218 if (!buffer.get()) { |
| 222 gl->DeleteTextures(1, &texture); | 219 gl->DeleteTextures(1, &texture); |
| 223 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; | 220 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; |
| 224 return AllocatedSurface(); | 221 return nullptr; |
| 225 } | 222 } |
| 226 | 223 |
| 227 unsigned int id = gl->CreateImageCHROMIUM( | 224 unsigned int id = gl->CreateImageCHROMIUM( |
| 228 buffer->AsClientBuffer(), size_.width(), size_.height(), | 225 buffer->AsClientBuffer(), size_.width(), size_.height(), |
| 229 internal_format_); | 226 internal_format_); |
| 230 | |
| 231 if (!id) { | 227 if (!id) { |
| 232 LOG(ERROR) << "Failed to allocate backing image surface"; | 228 LOG(ERROR) << "Failed to allocate backing image surface"; |
| 233 gl->DeleteTextures(1, &texture); | 229 gl->DeleteTextures(1, &texture); |
| 234 return AllocatedSurface(); | 230 return nullptr; |
| 235 } | 231 } |
| 232 | |
| 236 allocated_count_++; | 233 allocated_count_++; |
| 237 gl->BindTexture(texture_target_, texture); | 234 gl->BindTexture(texture_target_, texture); |
| 238 gl->BindTexImage2DCHROMIUM(texture_target_, id); | 235 gl->BindTexImage2DCHROMIUM(texture_target_, id); |
| 239 return AllocatedSurface(buffer.Pass(), texture, id, gfx::Rect(size_)); | 236 return make_scoped_ptr(new AllocatedSurface(this, std::move(buffer), texture, |
| 237 id, gfx::Rect(size_))); | |
| 240 } | 238 } |
| 241 | 239 |
| 242 BufferQueue::AllocatedSurface::AllocatedSurface() : texture(0), image(0) {} | |
| 243 | |
| 244 BufferQueue::AllocatedSurface::AllocatedSurface( | 240 BufferQueue::AllocatedSurface::AllocatedSurface( |
| 241 BufferQueue* buffer_queue, | |
| 245 scoped_ptr<gfx::GpuMemoryBuffer> buffer, | 242 scoped_ptr<gfx::GpuMemoryBuffer> buffer, |
| 246 unsigned int texture, | 243 unsigned int texture, |
| 247 unsigned int image, | 244 unsigned int image, |
| 248 const gfx::Rect& rect) | 245 const gfx::Rect& rect) |
| 249 : buffer(buffer.release()), texture(texture), image(image), damage(rect) {} | 246 : buffer_queue(buffer_queue), |
| 247 buffer(buffer.release()), | |
| 248 texture(texture), | |
| 249 image(image), | |
| 250 damage(rect) {} | |
| 250 | 251 |
| 251 BufferQueue::AllocatedSurface::~AllocatedSurface() {} | 252 BufferQueue::AllocatedSurface::~AllocatedSurface() { |
| 253 if (buffer_queue) | |
|
danakj
2015/12/10 01:36:02
i don't see calls to default constructor anymore.
ccameron
2015/12/10 07:39:27
Good call -- I removed the default ctor, so this c
| |
| 254 buffer_queue->FreeSurfaceResources(this); | |
| 255 } | |
| 252 | 256 |
| 253 } // namespace content | 257 } // namespace content |
| OLD | NEW |