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); | |
| 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 surface->damage.Union(damage); |
| 78 it != in_flight_surfaces_.end(); | |
| 79 ++it) | |
| 80 it->damage.Union(damage); | |
| 81 } | 79 } |
| 82 | 80 |
| 83 void BufferQueue::SwapBuffers(const gfx::Rect& damage) { | 81 void BufferQueue::SwapBuffers(const gfx::Rect& damage) { |
| 82 DCHECK(current_surface_); | |
| 83 | |
| 84 if (!damage.IsEmpty() && damage != gfx::Rect(size_)) { | 84 if (!damage.IsEmpty() && damage != gfx::Rect(size_)) { |
| 85 // We must have a frame available to copy from. | 85 // We must have a frame available to copy from. |
| 86 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture); | 86 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_); |
| 87 unsigned int texture_id = !in_flight_surfaces_.empty() | 87 unsigned int texture_id = !in_flight_surfaces_.empty() |
| 88 ? in_flight_surfaces_.back().texture | 88 ? in_flight_surfaces_.back()->texture |
| 89 : displayed_surface_.texture; | 89 : displayed_surface_->texture; |
| 90 | 90 CopyBufferDamage(current_surface_->texture, texture_id, damage, |
| 91 CopyBufferDamage(current_surface_.texture, texture_id, damage, | 91 current_surface_->damage); |
| 92 current_surface_.damage); | |
| 93 } | 92 } |
| 94 UpdateBufferDamage(damage); | 93 UpdateBufferDamage(damage); |
| 95 current_surface_.damage = gfx::Rect(); | 94 current_surface_->damage = gfx::Rect(); |
| 96 in_flight_surfaces_.push_back(current_surface_); | 95 in_flight_surfaces_.push_back(current_surface_.Pass()); |
|
danakj
2015/12/09 23:25:16
std::move()
ccameron
2015/12/10 00:19:28
Done.
| |
| 97 current_surface_.texture = 0; | |
| 98 current_surface_.image = 0; | |
| 99 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer | 96 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer |
| 100 // paths), so ensure we restore it here. | 97 // paths), so ensure we restore it here. |
| 101 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 98 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 102 } | 99 } |
| 103 | 100 |
| 104 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { | 101 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { |
| 105 if (size == size_) | 102 if (size == size_) |
| 106 return; | 103 return; |
| 107 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that | 104 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that |
| 108 // is cause for concern or if it is benign. | 105 // is cause for concern or if it is benign. |
| 109 // http://crbug.com/524624 | 106 // http://crbug.com/524624 |
| 110 #if !defined(OS_MACOSX) | 107 #if !defined(OS_MACOSX) |
| 111 DCHECK(!current_surface_.texture); | 108 DCHECK(!current_surface_); |
| 112 #endif | 109 #endif |
| 113 size_ = size; | 110 size_ = size; |
| 114 | 111 |
| 115 // TODO: add stencil buffer when needed. | 112 // TODO: add stencil buffer when needed. |
| 116 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 113 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 117 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 114 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 118 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 115 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 119 texture_target_, 0, 0); | 116 texture_target_, 0, 0); |
| 120 | 117 |
| 121 FreeAllSurfaces(); | 118 FreeAllSurfaces(); |
| 122 } | 119 } |
| 123 | 120 |
| 124 void BufferQueue::RecreateBuffers() { | 121 void BufferQueue::RecreateBuffers() { |
| 125 // We need to recreate the buffers, for whatever reason the old ones are not | 122 // We need to recreate the buffers, for whatever reason the old ones are not |
| 126 // presentable on the device anymore. | 123 // presentable on the device anymore. |
| 127 // Unused buffers can be freed directly, they will be re-allocated as needed. | 124 // Unused buffers can be freed directly, they will be re-allocated as needed. |
| 128 // Any in flight, current or displayed surface must be replaced. | 125 // 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(); | 126 available_surfaces_.clear(); |
| 132 | 127 |
| 128 // Recreate all in-flight surfaces and put the recreated copies in the queue. | |
| 133 for (auto& surface : in_flight_surfaces_) | 129 for (auto& surface : in_flight_surfaces_) |
| 134 surface = RecreateBuffer(&surface); | 130 surface = RecreateBuffer(surface.Pass()); |
|
danakj
2015/12/09 23:25:15
std::move() for all passing
ccameron
2015/12/10 00:19:28
Done.
| |
| 135 | 131 |
| 136 current_surface_ = RecreateBuffer(¤t_surface_); | 132 current_surface_ = RecreateBuffer(current_surface_.Pass()); |
| 137 displayed_surface_ = RecreateBuffer(&displayed_surface_); | 133 displayed_surface_ = RecreateBuffer(displayed_surface_.Pass()); |
| 138 | 134 |
| 139 if (current_surface_.texture) { | 135 if (current_surface_ && current_surface_->texture) { |
|
danakj
2015/12/09 23:25:15
you could just make RecreateBuffer return null if
ccameron
2015/12/10 00:19:28
This is the "remnant" mentioned below.
| |
| 140 // If we have a texture bound, we will need to re-bind it. | 136 // If we have a texture bound, we will need to re-bind it. |
| 141 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 137 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 142 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 138 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 143 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 139 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 144 texture_target_, current_surface_.texture, 0); | 140 texture_target_, current_surface_->texture, 0); |
| 145 } | 141 } |
| 146 } | 142 } |
| 147 | 143 |
| 148 BufferQueue::AllocatedSurface BufferQueue::RecreateBuffer( | 144 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::RecreateBuffer( |
| 149 AllocatedSurface* surface) { | 145 scoped_ptr<AllocatedSurface> surface) { |
| 150 if (!surface->texture) | 146 if (!surface) |
| 151 return *surface; | 147 return scoped_ptr<AllocatedSurface>(); |
|
danakj
2015/12/09 23:25:15
return nullptr
ccameron
2015/12/10 00:19:28
Done.
| |
| 152 AllocatedSurface new_surface = GetNextSurface(); | 148 |
| 153 new_surface.damage = surface->damage; | 149 scoped_ptr<AllocatedSurface> new_surface(GetNextSurface()); |
| 150 new_surface->damage = surface->damage; | |
| 154 | 151 |
| 155 // Copy the entire texture. | 152 // Copy the entire texture. |
| 156 CopyBufferDamage(new_surface.texture, surface->texture, gfx::Rect(), | 153 CopyBufferDamage(new_surface->texture, surface->texture, gfx::Rect(), |
| 157 gfx::Rect(size_)); | 154 gfx::Rect(size_)); |
| 158 | 155 return new_surface.Pass(); |
|
danakj
2015/12/09 23:25:15
don't std::move() on return unless you're upcastin
ccameron
2015/12/10 00:19:28
It does :)
| |
| 159 FreeSurface(surface); | |
| 160 return new_surface; | |
| 161 } | 156 } |
| 162 | 157 |
| 163 void BufferQueue::PageFlipComplete() { | 158 void BufferQueue::PageFlipComplete() { |
| 164 DCHECK(!in_flight_surfaces_.empty()); | 159 DCHECK(!in_flight_surfaces_.empty()); |
| 165 | 160 if (displayed_surface_ && displayed_surface_->texture) |
|
danakj
2015/12/09 23:25:15
can you be non-null but 0 texture?
ccameron
2015/12/10 00:19:28
Yes (... see discussion later).
| |
| 166 if (displayed_surface_.texture) | 161 available_surfaces_.push_back(displayed_surface_.Pass()); |
| 167 available_surfaces_.push_back(displayed_surface_); | 162 displayed_surface_ = in_flight_surfaces_.front().Pass(); |
| 168 | |
| 169 displayed_surface_ = in_flight_surfaces_.front(); | |
| 170 in_flight_surfaces_.pop_front(); | 163 in_flight_surfaces_.pop_front(); |
| 171 } | 164 } |
| 172 | 165 |
| 173 void BufferQueue::FreeAllSurfaces() { | 166 void BufferQueue::FreeAllSurfaces() { |
| 174 FreeSurface(&displayed_surface_); | 167 displayed_surface_.reset(); |
| 175 FreeSurface(¤t_surface_); | 168 current_surface_.reset(); |
| 176 // This is intentionally not emptied since the swap buffers acks are still | 169 // This is intentionally not emptied since the swap buffers acks are still |
| 177 // expected to arrive. | 170 // expected to arrive. |
| 178 for (auto& surface : in_flight_surfaces_) | 171 for (auto& surface : in_flight_surfaces_) |
| 179 FreeSurface(&surface); | 172 FreeSurfaceResources(surface.get()); |
| 180 | |
| 181 for (size_t i = 0; i < available_surfaces_.size(); i++) | |
| 182 FreeSurface(&available_surfaces_[i]); | |
| 183 | |
| 184 available_surfaces_.clear(); | 173 available_surfaces_.clear(); |
| 185 } | 174 } |
| 186 | 175 |
| 187 void BufferQueue::FreeSurface(AllocatedSurface* surface) { | 176 void BufferQueue::FreeSurfaceResources(AllocatedSurface* surface) { |
| 188 if (surface->texture) { | 177 if (!surface->texture) |
| 189 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 178 return; |
| 190 gl->BindTexture(texture_target_, surface->texture); | 179 |
| 191 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); | 180 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 192 gl->DeleteTextures(1, &surface->texture); | 181 gl->BindTexture(texture_target_, surface->texture); |
| 193 gl->DestroyImageCHROMIUM(surface->image); | 182 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); |
| 194 surface->image = 0; | 183 gl->DeleteTextures(1, &surface->texture); |
| 195 surface->texture = 0; | 184 gl->DestroyImageCHROMIUM(surface->image); |
| 196 allocated_count_--; | 185 surface->image = 0; |
| 197 } | 186 surface->texture = 0; |
| 187 surface->buffer.reset(); | |
| 188 surface->buffer_queue = nullptr; | |
| 189 allocated_count_--; | |
| 198 } | 190 } |
| 199 | 191 |
| 200 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() { | 192 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() { |
| 201 if (!available_surfaces_.empty()) { | 193 if (!available_surfaces_.empty()) { |
| 202 AllocatedSurface surface = available_surfaces_.back(); | 194 scoped_ptr<AllocatedSurface> surface = available_surfaces_.back().Pass(); |
| 203 available_surfaces_.pop_back(); | 195 available_surfaces_.pop_back(); |
| 204 return surface; | 196 return surface.Pass(); |
|
danakj
2015/12/09 23:25:15
should be move() but on return shouldn't be anythi
ccameron
2015/12/10 00:19:28
Done.
| |
| 205 } | 197 } |
| 206 | 198 |
| 207 unsigned int texture = 0; | 199 unsigned int texture = 0; |
| 208 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 200 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 209 gl->GenTextures(1, &texture); | 201 gl->GenTextures(1, &texture); |
| 210 if (!texture) | 202 if (!texture) |
| 211 return AllocatedSurface(); | 203 return scoped_ptr<AllocatedSurface>(new AllocatedSurface); |
|
danakj
2015/12/09 23:25:15
make_scoped_ptr(new All...)
but why not return nu
ccameron
2015/12/10 00:19:28
Myself as of a few hours agreed with you (actually
| |
| 212 | 204 |
| 213 // We don't want to allow anything more than triple buffering. | 205 // We don't want to allow anything more than triple buffering. |
| 214 DCHECK_LT(allocated_count_, 4U); | 206 DCHECK_LT(allocated_count_, 4U); |
| 215 | 207 |
| 216 scoped_ptr<gfx::GpuMemoryBuffer> buffer( | 208 scoped_ptr<gfx::GpuMemoryBuffer> buffer( |
| 217 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( | 209 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( |
| 218 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( | 210 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( |
| 219 internal_format_), | 211 internal_format_), |
| 220 surface_id_)); | 212 surface_id_)); |
| 221 if (!buffer.get()) { | 213 if (!buffer.get()) { |
| 222 gl->DeleteTextures(1, &texture); | 214 gl->DeleteTextures(1, &texture); |
| 223 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; | 215 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; |
| 224 return AllocatedSurface(); | 216 return scoped_ptr<AllocatedSurface>(new AllocatedSurface); |
|
danakj
2015/12/09 23:25:15
make_scoped_ptr
ccameron
2015/12/10 00:19:27
Done.
| |
| 225 } | 217 } |
| 226 | 218 |
| 227 unsigned int id = gl->CreateImageCHROMIUM( | 219 unsigned int id = gl->CreateImageCHROMIUM( |
| 228 buffer->AsClientBuffer(), size_.width(), size_.height(), | 220 buffer->AsClientBuffer(), size_.width(), size_.height(), |
| 229 internal_format_); | 221 internal_format_); |
| 230 | 222 |
| 231 if (!id) { | 223 if (!id) { |
| 232 LOG(ERROR) << "Failed to allocate backing image surface"; | 224 LOG(ERROR) << "Failed to allocate backing image surface"; |
| 233 gl->DeleteTextures(1, &texture); | 225 gl->DeleteTextures(1, &texture); |
| 234 return AllocatedSurface(); | 226 return scoped_ptr<AllocatedSurface>(new AllocatedSurface); |
|
danakj
2015/12/09 23:25:15
make_scoped_ptr
ccameron
2015/12/10 00:19:28
Done.
| |
| 235 } | 227 } |
| 236 allocated_count_++; | 228 allocated_count_++; |
| 237 gl->BindTexture(texture_target_, texture); | 229 gl->BindTexture(texture_target_, texture); |
| 238 gl->BindTexImage2DCHROMIUM(texture_target_, id); | 230 gl->BindTexImage2DCHROMIUM(texture_target_, id); |
| 239 return AllocatedSurface(buffer.Pass(), texture, id, gfx::Rect(size_)); | 231 return scoped_ptr<AllocatedSurface>(new AllocatedSurface(this, buffer.Pass(), |
| 232 texture, id, | |
| 233 gfx::Rect(size_))) | |
| 234 .Pass(); | |
| 240 } | 235 } |
| 241 | 236 |
| 242 BufferQueue::AllocatedSurface::AllocatedSurface() : texture(0), image(0) {} | 237 BufferQueue::AllocatedSurface::AllocatedSurface() |
| 238 : buffer_queue(nullptr), texture(0), image(0) {} | |
| 243 | 239 |
| 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/09 23:25:15
it can be null?
ccameron
2015/12/10 00:19:28
Yeah, if the default ctor was used.
| |
| 254 buffer_queue->FreeSurfaceResources(this); | |
| 255 } | |
| 252 | 256 |
| 253 } // namespace content | 257 } // namespace content |
| OLD | NEW |