11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/browser/compositor/buffer_queue.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/browser/compositor/image_transport_factory.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/common/gpu/client/context_provider_command_buffer.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/common/gpu/client/gl_helper.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "gpu/GLES2/gl2extchromium.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "gpu/command_buffer/client/gles2_interface.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/skia/include/core/SkRect.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/skia/include/core/SkRegion.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace content {
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBufferQueue::BufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                         unsigned int internalformat)
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : context_provider_(context_provider),
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      fbo_(0),
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      allocated_count_(0),
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      internalformat_(internalformat) {
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBufferQueue::~BufferQueue() {
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  FreeAllSurfaces();
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (fbo_)
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->DeleteFramebuffers(1, &fbo_);
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool BufferQueue::Initialize() {
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->GenFramebuffers(1, &fbo_);
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return fbo_ != 0;
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::BindFramebuffer() {
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!current_surface_.texture) {
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    current_surface_ = GetNextSurface();
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->FramebufferTexture2D(GL_FRAMEBUFFER,
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             GL_COLOR_ATTACHMENT0,
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             GL_TEXTURE_2D,
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             current_surface_.texture,
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             0);
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::CopyBufferDamage(int texture,
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   int source_texture,
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   const gfx::Rect& new_damage,
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                   const gfx::Rect& old_damage) {
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ImageTransportFactory::GetInstance()->GetGLHelper()->CopySubBufferDamage(
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      texture,
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      source_texture,
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      SkRegion(SkIRect::MakeXYWH(new_damage.x(),
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 new_damage.y(),
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 new_damage.width(),
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 new_damage.height())),
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      SkRegion(SkIRect::MakeXYWH(old_damage.x(),
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 old_damage.y(),
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 old_damage.width(),
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 old_damage.height())));
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < available_surfaces_.size(); i++)
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    available_surfaces_[i].damage.Union(damage);
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (std::deque<AllocatedSurface>::iterator it =
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           in_flight_surfaces_.begin();
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       it != in_flight_surfaces_.end();
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++it)
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    it->damage.Union(damage);
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::SwapBuffers(const gfx::Rect& damage) {
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (damage != gfx::Rect(size_)) {
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // We must have a frame available to copy from.
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(!in_flight_surfaces_.empty());
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CopyBufferDamage(current_surface_.texture,
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                     in_flight_surfaces_.back().texture,
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                     damage,
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                     current_surface_.damage);
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UpdateBufferDamage(damage);
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  current_surface_.damage = gfx::Rect();
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  in_flight_surfaces_.push_back(current_surface_);
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  current_surface_.texture = 0;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  current_surface_.image = 0;
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::Reshape(const gfx::Size& size, float scale_factor) {
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!current_surface_.texture);
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (size == size_)
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_ = size;
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO: add stencil buffer when needed.
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->FramebufferTexture2D(
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  FreeAllSurfaces();
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::PageFlipComplete() {
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (in_flight_surfaces_.size() > 1) {
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    available_surfaces_.push_back(in_flight_surfaces_.front());
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    in_flight_surfaces_.pop_front();
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::FreeAllSurfaces() {
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  FreeSurface(&current_surface_);
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!in_flight_surfaces_.empty()) {
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    FreeSurface(&in_flight_surfaces_.front());
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    in_flight_surfaces_.pop_front();
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < available_surfaces_.size(); i++)
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    FreeSurface(&available_surfaces_[i]);
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  available_surfaces_.clear();
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid BufferQueue::FreeSurface(AllocatedSurface* surface) {
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (surface->texture) {
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->BindTexture(GL_TEXTURE_2D, surface->texture);
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, surface->image);
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->DeleteTextures(1, &surface->texture);
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->DestroyImageCHROMIUM(surface->image);
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    surface->image = 0;
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    surface->texture = 0;
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    allocated_count_--;
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciBufferQueue::AllocatedSurface BufferQueue::GetNextSurface() {
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!available_surfaces_.empty()) {
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    AllocatedSurface surface = available_surfaces_.back();
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    available_surfaces_.pop_back();
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return surface;
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  unsigned int texture = 0;
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->GenTextures(1, &texture);
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!texture)
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return AllocatedSurface();
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We don't want to allow anything more than triple buffering.
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_LT(allocated_count_, 4U);
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  unsigned int id = gl->CreateImageCHROMIUM(
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      size_.width(),
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      size_.height(),
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      internalformat_,
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GL_IMAGE_SCANOUT_CHROMIUM);
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!id) {
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(ERROR) << "Failed to allocate backing CreateImageCHROMIUM surface";
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gl->DeleteTextures(1, &texture);
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return AllocatedSurface();
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  allocated_count_++;
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->BindTexture(GL_TEXTURE_2D, texture);
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gl->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, id);
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return AllocatedSurface(texture, id, gfx::Rect(size_));
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace content
175