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 12 matching lines...) Expand all Loading... | |
| 23 unsigned int texture_target, | 23 unsigned int texture_target, |
| 24 unsigned int internalformat, | 24 unsigned int internalformat, |
| 25 GLHelper* gl_helper, | 25 GLHelper* gl_helper, |
| 26 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager, | 26 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager, |
| 27 int surface_id) | 27 int surface_id) |
| 28 : context_provider_(context_provider), | 28 : context_provider_(context_provider), |
| 29 fbo_(0), | 29 fbo_(0), |
| 30 allocated_count_(0), | 30 allocated_count_(0), |
| 31 texture_target_(texture_target), | 31 texture_target_(texture_target), |
| 32 internal_format_(internalformat), | 32 internal_format_(internalformat), |
| 33 deleted_in_flight_surface_count_(0), | |
| 33 gl_helper_(gl_helper), | 34 gl_helper_(gl_helper), |
| 34 gpu_memory_buffer_manager_(gpu_memory_buffer_manager), | 35 gpu_memory_buffer_manager_(gpu_memory_buffer_manager), |
| 35 surface_id_(surface_id) {} | 36 surface_id_(surface_id) {} |
| 36 | 37 |
| 37 BufferQueue::~BufferQueue() { | 38 BufferQueue::~BufferQueue() { |
| 38 FreeAllSurfaces(); | 39 FreeAllSurfaces(); |
| 39 | 40 |
| 40 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 41 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 41 if (fbo_) | 42 if (fbo_) |
| 42 gl->DeleteFramebuffers(1, &fbo_); | 43 gl->DeleteFramebuffers(1, &fbo_); |
| 43 } | 44 } |
| 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(); |
| 56 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 57 gl->FramebufferTexture2D( |
| 57 texture_target_, current_surface_.texture, 0); | 58 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target_, |
| 59 current_surface_ ? current_surface_->texture : 0, 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_) |
| 75 displayed_surface_->damage.Union(damage); | |
| 76 | |
| 73 for (size_t i = 0; i < available_surfaces_.size(); i++) | 77 for (size_t i = 0; i < available_surfaces_.size(); i++) |
| 74 available_surfaces_[i].damage.Union(damage); | 78 available_surfaces_[i]->damage.Union(damage); |
| 75 | 79 for (size_t i = 0; i < in_flight_surfaces_.size(); i++) |
| 76 for (std::deque<AllocatedSurface>::iterator it = | 80 in_flight_surfaces_[i]->damage.Union(damage); |
| 77 in_flight_surfaces_.begin(); | |
| 78 it != in_flight_surfaces_.end(); | |
| 79 ++it) | |
| 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 (!current_surface_) | |
| 85 return; | |
| 86 | |
| 84 if (damage != gfx::Rect(size_)) { | 87 if (damage != gfx::Rect(size_)) { |
| 85 // We must have a frame available to copy from. | 88 // If there is damage, then there must have been a previous frame to copy |
| 86 DCHECK(!in_flight_surfaces_.empty() || displayed_surface_.texture); | 89 // from (though it may have been deleted). |
| 87 unsigned int texture_id = !in_flight_surfaces_.empty() | 90 DCHECK(deleted_in_flight_surface_count_ || !in_flight_surfaces_.empty() || |
| 88 ? in_flight_surfaces_.back().texture | 91 displayed_surface_); |
| 89 : displayed_surface_.texture; | 92 unsigned int texture_id = 0; |
| 90 | 93 if (!in_flight_surfaces_.empty()) |
| 91 CopyBufferDamage(current_surface_.texture, texture_id, damage, | 94 texture_id = in_flight_surfaces_.back()->texture; |
| 92 current_surface_.damage); | 95 else if (displayed_surface_) |
| 96 texture_id = displayed_surface_->texture; | |
| 97 if (texture_id) { | |
| 98 CopyBufferDamage(current_surface_->texture, texture_id, damage, | |
| 99 current_surface_->damage); | |
| 100 } | |
| 93 } | 101 } |
| 94 UpdateBufferDamage(damage); | 102 UpdateBufferDamage(damage); |
| 95 current_surface_.damage = gfx::Rect(); | 103 current_surface_->damage = gfx::Rect(); |
| 96 in_flight_surfaces_.push_back(current_surface_); | 104 in_flight_surfaces_.push_back(current_surface_.Pass()); |
| 97 current_surface_.texture = 0; | |
| 98 current_surface_.image = 0; | |
| 99 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer | 105 // Some things reset the framebuffer (CopySubBufferDamage, some GLRenderer |
| 100 // paths), so ensure we restore it here. | 106 // paths), so ensure we restore it here. |
| 101 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 107 context_provider_->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 102 } | 108 } |
| 103 | 109 |
| 104 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { | 110 void BufferQueue::Reshape(const gfx::Size& size, float scale_factor) { |
| 105 if (size == size_) | 111 if (size == size_) |
| 106 return; | 112 return; |
| 107 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that | 113 // TODO(ccameron): This assert is being hit on Mac try jobs. Determine if that |
| 108 // is cause for concern or if it is benign. | 114 // is cause for concern or if it is benign. |
| 109 // http://crbug.com/524624 | 115 // http://crbug.com/524624 |
| 110 #if !defined(OS_MACOSX) | 116 #if !defined(OS_MACOSX) |
| 111 DCHECK(!current_surface_.texture); | 117 DCHECK(!current_surface_); |
| 112 #endif | 118 #endif |
| 113 size_ = size; | 119 size_ = size; |
| 114 | 120 |
| 115 // TODO: add stencil buffer when needed. | 121 // TODO: add stencil buffer when needed. |
| 116 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 122 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 117 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 123 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 118 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 124 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 119 texture_target_, 0, 0); | 125 texture_target_, 0, 0); |
| 120 | 126 |
| 121 FreeAllSurfaces(); | 127 FreeAllSurfaces(); |
| 122 } | 128 } |
| 123 | 129 |
| 124 void BufferQueue::RecreateBuffers() { | 130 void BufferQueue::RecreateBuffers() { |
| 125 // We need to recreate the buffers, for whatever reason the old ones are not | 131 // Available surfaces do not need to be recreated, so they may be destoryed. |
| 126 // presentable on the device anymore. | 132 while (!available_surfaces_.empty()) { |
| 127 // Unused buffers can be freed directly, they will be re-allocated as needed. | 133 FreeSurface(available_surfaces_.take_back().Pass()); |
| 128 // Any in flight, current or displayed surface must be replaced. | 134 available_surfaces_.pop_back(); |
| 129 for (size_t i = 0; i < available_surfaces_.size(); i++) | 135 } |
| 130 FreeSurface(&available_surfaces_[i]); | |
| 131 available_surfaces_.clear(); | |
| 132 | 136 |
| 133 for (auto& surface : in_flight_surfaces_) | 137 // Recreate all in-flight surfaces and put the recreated copies in the queue. |
| 134 surface = RecreateBuffer(&surface); | 138 size_t old_in_flight_surface_size = in_flight_surfaces_.size(); |
| 139 for (size_t i = 0; i < old_in_flight_surface_size; ++i) | |
| 140 // Ensure that all entries in |in_flight_surfaces_| be non-null. If a | |
| 141 // recreation fails, then mark that it wasdeleted, to ensure it is accounted | |
| 142 // for in PageFlipComplete. | |
| 143 scoped_ptr<AllocatedSurface> recreated_buffer = | |
| 144 RecreateBuffer(in_flight_surfaces_.take_front().Pass()); | |
| 145 if (recreated_buffer) | |
| 146 in_flight_surfaces_.push_back(recreated_buffer); | |
| 147 else | |
| 148 deleted_in_flight_surface_count_ += 1; | |
| 149 } | |
| 135 | 150 |
| 136 current_surface_ = RecreateBuffer(¤t_surface_); | 151 current_surface_ = RecreateBuffer(current_surface_.Pass()); |
| 137 displayed_surface_ = RecreateBuffer(&displayed_surface_); | 152 displayed_surface_ = RecreateBuffer(displayed_surface_.Pass()); |
| 138 | 153 |
| 139 if (current_surface_.texture) { | 154 if (current_surface_) { |
| 140 // If we have a texture bound, we will need to re-bind it. | 155 // If we have a texture bound, we will need to re-bind it. |
| 141 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 156 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 142 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); | 157 gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_); |
| 143 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 158 gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 144 texture_target_, current_surface_.texture, 0); | 159 texture_target_, current_surface_->texture, 0); |
| 145 } | 160 } |
| 146 } | 161 } |
| 147 | 162 |
| 148 BufferQueue::AllocatedSurface BufferQueue::RecreateBuffer( | 163 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::RecreateBuffer( |
| 149 AllocatedSurface* surface) { | 164 scoped_ptr<AllocatedSurface> surface) { |
| 150 if (!surface->texture) | 165 if (!surface) |
| 151 return *surface; | 166 return scoped_ptr<AllocatedSurface>(); |
| 152 AllocatedSurface new_surface = GetNextSurface(); | 167 |
| 153 new_surface.damage = surface->damage; | 168 scoped_ptr<AllocatedSurface> new_surface(GetNextSurface()); |
| 169 new_surface->damage = surface->damage; | |
| 154 | 170 |
| 155 // Copy the entire texture. | 171 // Copy the entire texture. |
| 156 CopyBufferDamage(new_surface.texture, surface->texture, gfx::Rect(), | 172 CopyBufferDamage(new_surface->texture, surface->texture, gfx::Rect(), |
| 157 gfx::Rect(size_)); | 173 gfx::Rect(size_)); |
| 158 | 174 |
| 159 FreeSurface(surface); | 175 FreeSurface(surface.Pass()); |
| 160 return new_surface; | 176 return new_surface.Pass(); |
| 161 } | 177 } |
| 162 | 178 |
| 163 void BufferQueue::PageFlipComplete() { | 179 void BufferQueue::PageFlipComplete() { |
| 180 // If the next in-flight surface was destroyed, simply leave the currently | |
| 181 // displaying surface unchanged. | |
| 182 if (deleted_in_flight_surface_count_ > 0) { | |
| 183 deleted_in_flight_surface_count_ -= 1; | |
| 184 return; | |
| 185 } | |
| 186 | |
| 164 DCHECK(!in_flight_surfaces_.empty()); | 187 DCHECK(!in_flight_surfaces_.empty()); |
| 165 | 188 if (displayed_surface_) |
| 166 if (displayed_surface_.texture) | 189 available_surfaces_.push_back(displayed_surface_.Pass()); |
| 167 available_surfaces_.push_back(displayed_surface_); | 190 displayed_surface_ = in_flight_surfaces_.take_front(); |
| 168 | |
| 169 displayed_surface_ = in_flight_surfaces_.front(); | |
| 170 in_flight_surfaces_.pop_front(); | |
| 171 } | 191 } |
| 172 | 192 |
| 173 void BufferQueue::FreeAllSurfaces() { | 193 void BufferQueue::FreeAllSurfaces() { |
| 174 FreeSurface(&displayed_surface_); | 194 FreeSurface(displayed_surface_.Pass()); |
| 175 FreeSurface(¤t_surface_); | 195 FreeSurface(current_surface_.Pass()); |
| 176 // This is intentionally not emptied since the swap buffers acks are still | |
| 177 // expected to arrive. | |
| 178 for (auto& surface : in_flight_surfaces_) | |
| 179 FreeSurface(&surface); | |
| 180 | 196 |
| 181 for (size_t i = 0; i < available_surfaces_.size(); i++) | 197 // Track the number of in-flight surfaces that have been destroyed, so that |
| 182 FreeSurface(&available_surfaces_[i]); | 198 // we account for them in PageFlipComplete. |
| 199 deleted_in_flight_surface_count_ += in_flight_surfaces_.size(); | |
| 200 while (!in_flight_surfaces_.empty()) | |
| 201 FreeSurface(in_flight_surfaces_.take_front().Pass()); | |
| 183 | 202 |
| 184 available_surfaces_.clear(); | 203 while (!available_surfaces_.empty()) { |
| 185 } | 204 FreeSurface(available_surfaces_.take_back().Pass()); |
| 186 | 205 available_surfaces_.pop_back(); |
| 187 void BufferQueue::FreeSurface(AllocatedSurface* surface) { | |
| 188 if (surface->texture) { | |
| 189 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | |
| 190 gl->BindTexture(texture_target_, surface->texture); | |
| 191 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); | |
| 192 gl->DeleteTextures(1, &surface->texture); | |
| 193 gl->DestroyImageCHROMIUM(surface->image); | |
| 194 surface->image = 0; | |
| 195 surface->texture = 0; | |
| 196 allocated_count_--; | |
| 197 } | 206 } |
| 198 } | 207 } |
| 199 | 208 |
| 200 BufferQueue::AllocatedSurface BufferQueue::GetNextSurface() { | 209 void BufferQueue::FreeSurface(scoped_ptr<AllocatedSurface> surface) { |
|
reveman
2015/10/27 17:03:43
can we move all this into the AllocatedSurface dto
| |
| 210 if (!surface) | |
| 211 return; | |
| 212 | |
| 213 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | |
| 214 gl->BindTexture(texture_target_, surface->texture); | |
| 215 gl->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image); | |
| 216 gl->DeleteTextures(1, &surface->texture); | |
| 217 gl->DestroyImageCHROMIUM(surface->image); | |
| 218 surface->image = 0; | |
| 219 surface->texture = 0; | |
| 220 allocated_count_--; | |
| 221 } | |
| 222 | |
| 223 scoped_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() { | |
| 201 if (!available_surfaces_.empty()) { | 224 if (!available_surfaces_.empty()) { |
| 202 AllocatedSurface surface = available_surfaces_.back(); | 225 scoped_ptr<AllocatedSurface> result = |
| 226 available_surfaces_.take_back().Pass(); | |
|
reveman
2015/10/27 17:03:43
hm, is .Pass() really needed here?
| |
| 203 available_surfaces_.pop_back(); | 227 available_surfaces_.pop_back(); |
| 204 return surface; | 228 return result.Pass(); |
| 205 } | 229 } |
| 206 | 230 |
| 207 unsigned int texture = 0; | 231 unsigned int texture = 0; |
| 208 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); | 232 gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL(); |
| 209 gl->GenTextures(1, &texture); | 233 gl->GenTextures(1, &texture); |
| 210 if (!texture) | 234 if (!texture) |
| 211 return AllocatedSurface(); | 235 return scoped_ptr<AllocatedSurface>(); |
|
reveman
2015/10/27 17:03:44
nullptr
| |
| 212 | 236 |
| 213 // We don't want to allow anything more than triple buffering. | 237 // We don't want to allow anything more than triple buffering. |
| 214 DCHECK_LT(allocated_count_, 4U); | 238 DCHECK_LT(allocated_count_, 4U); |
| 215 | 239 |
| 216 scoped_ptr<gfx::GpuMemoryBuffer> buffer( | 240 scoped_ptr<gfx::GpuMemoryBuffer> buffer( |
| 217 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( | 241 gpu_memory_buffer_manager_->AllocateGpuMemoryBufferForScanout( |
| 218 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( | 242 size_, gpu::ImageFactory::DefaultBufferFormatForImageFormat( |
| 219 internal_format_), | 243 internal_format_), |
| 220 surface_id_)); | 244 surface_id_)); |
| 221 if (!buffer.get()) { | 245 if (!buffer.get()) { |
| 222 gl->DeleteTextures(1, &texture); | 246 gl->DeleteTextures(1, &texture); |
| 223 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; | 247 DLOG(ERROR) << "Failed to allocate GPU memory buffer"; |
| 224 return AllocatedSurface(); | 248 return scoped_ptr<AllocatedSurface>(); |
|
reveman
2015/10/27 17:03:43
nullptr
| |
| 225 } | 249 } |
| 226 | 250 |
| 227 unsigned int id = gl->CreateImageCHROMIUM( | 251 unsigned int id = gl->CreateImageCHROMIUM( |
| 228 buffer->AsClientBuffer(), size_.width(), size_.height(), | 252 buffer->AsClientBuffer(), size_.width(), size_.height(), |
| 229 internal_format_); | 253 internal_format_); |
| 230 | 254 |
| 231 if (!id) { | 255 if (!id) { |
| 232 LOG(ERROR) << "Failed to allocate backing image surface"; | 256 LOG(ERROR) << "Failed to allocate backing image surface"; |
| 233 gl->DeleteTextures(1, &texture); | 257 gl->DeleteTextures(1, &texture); |
| 234 return AllocatedSurface(); | 258 return scoped_ptr<AllocatedSurface>(); |
|
reveman
2015/10/27 17:03:44
nullptr
| |
| 235 } | 259 } |
| 236 allocated_count_++; | 260 allocated_count_++; |
|
reveman
2015/10/27 17:03:43
is this member needed? is this just not the sum of
| |
| 237 gl->BindTexture(texture_target_, texture); | 261 gl->BindTexture(texture_target_, texture); |
| 238 gl->BindTexImage2DCHROMIUM(texture_target_, id); | 262 gl->BindTexImage2DCHROMIUM(texture_target_, id); |
| 239 return AllocatedSurface(buffer.Pass(), texture, id, gfx::Rect(size_)); | 263 return scoped_ptr<AllocatedSurface>( |
|
reveman
2015/10/27 17:03:44
make_scoped_ptr(new All...)?
| |
| 264 new AllocatedSurface(buffer.Pass(), texture, id, gfx::Rect(size_))) | |
| 265 .Pass(); | |
| 240 } | 266 } |
| 241 | 267 |
| 242 BufferQueue::AllocatedSurface::AllocatedSurface() : texture(0), image(0) {} | 268 BufferQueue::AllocatedSurface::AllocatedSurface() : texture(0), image(0) {} |
| 243 | 269 |
| 244 BufferQueue::AllocatedSurface::AllocatedSurface( | 270 BufferQueue::AllocatedSurface::AllocatedSurface( |
| 245 scoped_ptr<gfx::GpuMemoryBuffer> buffer, | 271 scoped_ptr<gfx::GpuMemoryBuffer> buffer, |
| 246 unsigned int texture, | 272 unsigned int texture, |
| 247 unsigned int image, | 273 unsigned int image, |
| 248 const gfx::Rect& rect) | 274 const gfx::Rect& rect) |
| 249 : buffer(buffer.release()), texture(texture), image(image), damage(rect) {} | 275 : buffer(buffer.release()), texture(texture), image(image), damage(rect) {} |
| 250 | 276 |
| 251 BufferQueue::AllocatedSurface::~AllocatedSurface() {} | 277 BufferQueue::AllocatedSurface::~AllocatedSurface() {} |
| 252 | 278 |
| 253 } // namespace content | 279 } // namespace content |
| OLD | NEW |