Commit 13b03208 authored by Andres Calderon Jaramillo's avatar Andres Calderon Jaramillo Committed by Commit Bot

Reland viz: Teach the BufferQueue to use SharedImage.

(See the diff since PS1 for the changes since the original change).

This CL relands https://crrev.com/c/1637737. That CL broke Android Q
compositing of some mixed WebGL/Canvas2D content. The root cause was an
incorrect assumption: that when the framebuffer for the root render pass
is bound, we wouldn't try to bind it again before swapping it. This
assumption was wrong in the case of drawing a render pass quad onto the
root render pass. See [1]. The aforementioned CL would call
BeginSharedImageAccessDirectCHROMIUM() upon binding the root render
pass' framebuffer and would call EndSharedImageAccessDirectCHROMIUM()
only when the buffer is swapped. So, binding the framebuffer multiple
times would result in the shared image system thinking that we wanted
concurrent access to the SharedImage.

This CL fixes that assumption: in case BindFramebuffer gets called more
than once before swapping, we just rebind the GL framebuffer without
requesting to begin access to the shared image.

Additionally, the following changes are made since the original change:

- We cache the textures that are produced by consuming the SharedImages
  from the buffer queue. That way, we don't have to call
  CreateAndTexStorage2DSharedImageCHROMIUM() for the same SharedImage.

- We make sure to delete those textures.

- GpuSurfacelessBrowserCompositorOutputSurface no longer exists, so the
  changes in the original CL for that component are discarded.

- We add some unit test coverage to GLOutputSurfaceBufferQueue to avoid
  this regression in the future. The GLOutputSurfaceBufferQueue
  interface is changed to make it possible to inject a mock buffer queue
  for testing. This in turn, requires a change in the BufferQueue
  interface: instead of passing a SyncTokenProvider on construction, we
  provide a setter method. That way the BufferQueue can be constructed
  before the GLOutputSurfaceBufferQueue (and the latter sets itself as
  the SyncTokenProvider).

  There are also, unfortunately, some #include changes to satisfy the
  bots.

Original change's description:
> This CL migrates the BufferQueue to use SharedImage in order to get
> rid of direct GL dependencies (necessary to eventually be able to use
> Vulkan).
>
> Stencil buffer management depends on the specific graphics API (e.g.,
> GL), so it is moved out of the BufferQueue into its user classes
> GpuSurfacelessBrowserCompositorOutputSurface and
> GLOutputSurfaceBufferQueue. Note that we don't need to have one
> stencil buffer per color buffer: we can reuse the same stencil buffer
> across all the color buffers.
>
> Bug: 958670
> Test: Compositing and overdraw feedback works normally on a nocturne.
> Change-Id: Ia85ea8fea81e125b49a3ce2be195873e77397237
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1637737
> Commit-Queue: Andres Calderon Jaramillo <andrescj@chromium.org>
> Reviewed-by: kylechar <kylechar@chromium.org>
> Reviewed-by: Khushal <khushalsagar@chromium.org>
> Reviewed-by: Eric Karl <ericrk@chromium.org>
> Reviewed-by: Robert Kroeger <rjkroege@chromium.org>
> Reviewed-by: Daniele Castagna <dcastagna@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#723697}

Bug: 958670,1033279
Test: visit https://toji.github.io/dinosaurs-static/ on Android Q.
Change-Id: I176af87749c90b775f95c54e2155f27ea9177a94
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1977969
Commit-Queue: Andres Calderon Jaramillo <andrescj@chromium.org>
Reviewed-by: default avatarEric Karl <ericrk@chromium.org>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735022}
parent da043399
......@@ -382,7 +382,7 @@ class RasterBufferProviderTest
worker_context_provider_ = base::MakeRefCounted<viz::TestContextProvider>(
std::make_unique<viz::TestContextSupport>(),
std::move(worker_gl_owned), std::move(worker_ri_owned),
true /* support_locking */);
nullptr /* sii */, true /* support_locking */);
worker_context_provider_->BindToCurrentThread();
} else {
worker_context_provider_ = viz::TestContextProvider::CreateWorker();
......
......@@ -311,6 +311,7 @@ class GPUImageDecodeTestMockContextProvider : public viz::TestContextProvider {
: TestContextProvider(std::move(support),
std::move(gl),
std::move(raster),
nullptr /* sii */,
true) {}
};
......
......@@ -441,6 +441,7 @@ viz_source_set("unit_tests") {
"display/surface_aggregator_unittest.cc",
"display/texture_deleter_unittest.cc",
"display_embedder/buffer_queue_unittest.cc",
"display_embedder/gl_output_surface_buffer_queue_unittest.cc",
"display_embedder/server_shared_bitmap_manager_unittest.cc",
"display_embedder/skia_output_device_buffer_queue_unittest.cc",
"display_embedder/skia_output_surface_impl_unittest.cc",
......
......@@ -8,29 +8,20 @@
#include "base/containers/adapters.h"
#include "build/build_config.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "ui/display/types/display_snapshot.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_image.h"
namespace viz {
BufferQueue::BufferQueue(gpu::gles2::GLES2Interface* gl,
BufferQueue::BufferQueue(gpu::SharedImageInterface* sii,
gfx::BufferFormat format,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::SurfaceHandle surface_handle,
const gpu::Capabilities& capabilities)
: gl_(gl),
gpu::SurfaceHandle surface_handle)
: sii_(sii),
allocated_count_(0),
texture_target_(gpu::GetBufferTextureTarget(gfx::BufferUsage::SCANOUT,
format,
capabilities)),
internal_format_(base::strict_cast<uint32_t>(
gl::BufferFormatToGLInternalFormat(format))),
format_(format),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
surface_handle_(surface_handle) {}
......@@ -39,16 +30,17 @@ BufferQueue::~BufferQueue() {
FreeAllSurfaces();
}
unsigned BufferQueue::GetCurrentBuffer(unsigned* stencil) {
DCHECK(stencil);
void BufferQueue::SetSyncTokenProvider(SyncTokenProvider* sync_token_provider) {
DCHECK(!sync_token_provider_);
sync_token_provider_ = sync_token_provider;
}
gpu::Mailbox BufferQueue::GetCurrentBuffer(
gpu::SyncToken* creation_sync_token) {
DCHECK(creation_sync_token);
if (!current_surface_)
current_surface_ = GetNextSurface();
if (current_surface_) {
*stencil = current_surface_->stencil;
return current_surface_->texture;
}
*stencil = 0u;
return 0u;
current_surface_ = GetNextSurface(creation_sync_token);
return current_surface_ ? current_surface_->mailbox : gpu::Mailbox();
}
void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
......@@ -75,11 +67,8 @@ void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
}
bool BufferQueue::Reshape(const gfx::Size& size,
float scale_factor,
const gfx::ColorSpace& color_space,
bool use_stencil) {
if (size == size_ && color_space == color_space_ &&
use_stencil == use_stencil_) {
const gfx::ColorSpace& color_space) {
if (size == size_ && color_space == color_space_) {
return false;
}
#if !defined(OS_MACOSX)
......@@ -90,7 +79,6 @@ bool BufferQueue::Reshape(const gfx::Size& size,
#endif
size_ = size;
color_space_ = color_space;
use_stencil_ = use_stencil;
FreeAllSurfaces();
return true;
......@@ -108,30 +96,37 @@ void BufferQueue::PageFlipComplete() {
}
void BufferQueue::FreeAllSurfaces() {
displayed_surface_.reset();
current_surface_.reset();
DCHECK(sync_token_provider_);
const gpu::SyncToken destruction_sync_token =
sync_token_provider_->GenSyncToken();
FreeSurface(std::move(displayed_surface_), destruction_sync_token);
FreeSurface(std::move(current_surface_), destruction_sync_token);
// This is intentionally not emptied since the swap buffers acks are still
// expected to arrive.
for (auto& surface : in_flight_surfaces_)
surface = nullptr;
for (auto& surface : in_flight_surfaces_) {
FreeSurface(std::move(surface), destruction_sync_token);
}
for (auto& surface : available_surfaces_) {
FreeSurface(std::move(surface), destruction_sync_token);
}
available_surfaces_.clear();
}
void BufferQueue::FreeSurfaceResources(AllocatedSurface* surface) {
if (!surface->texture)
void BufferQueue::FreeSurface(std::unique_ptr<AllocatedSurface> surface,
const gpu::SyncToken& sync_token) {
if (!surface)
return;
gl_->BindTexture(texture_target_, surface->texture);
gl_->ReleaseTexImage2DCHROMIUM(texture_target_, surface->image);
gl_->DeleteTextures(1, &surface->texture);
gl_->DestroyImageCHROMIUM(surface->image);
if (surface->stencil)
gl_->DeleteRenderbuffers(1, &surface->stencil);
DCHECK(!surface->mailbox.IsZero());
sii_->DestroySharedImage(sync_token, surface->mailbox);
surface->buffer.reset();
allocated_count_--;
}
std::unique_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() {
std::unique_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface(
gpu::SyncToken* creation_sync_token) {
DCHECK(creation_sync_token);
if (!available_surfaces_.empty()) {
std::unique_ptr<AllocatedSurface> surface =
std::move(available_surfaces_.back());
......@@ -139,66 +134,43 @@ std::unique_ptr<BufferQueue::AllocatedSurface> BufferQueue::GetNextSurface() {
return surface;
}
unsigned texture;
gl_->GenTextures(1, &texture);
unsigned stencil = 0;
if (use_stencil_) {
gl_->GenRenderbuffers(1, &stencil);
gl_->BindRenderbuffer(GL_RENDERBUFFER, stencil);
gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, size_.width(),
size_.height());
gl_->BindRenderbuffer(GL_RENDERBUFFER, 0);
}
// We don't want to allow anything more than triple buffering.
DCHECK_LT(allocated_count_, 3U);
// TODO(crbug.com/958670): if we can have a CreateSharedImage() that takes a
// SurfaceHandle, we don't have to create a GpuMemoryBuffer here.
std::unique_ptr<gfx::GpuMemoryBuffer> buffer(
gpu_memory_buffer_manager_->CreateGpuMemoryBuffer(
size_, format_, gfx::BufferUsage::SCANOUT, surface_handle_));
if (!buffer) {
gl_->DeleteTextures(1, &texture);
DLOG(ERROR) << "Failed to allocate GPU memory buffer";
LOG(ERROR) << "Failed to allocate GPU memory buffer";
return nullptr;
}
buffer->SetColorSpace(color_space_);
unsigned id =
gl_->CreateImageCHROMIUM(buffer->AsClientBuffer(), size_.width(),
size_.height(), internal_format_);
if (!id) {
LOG(ERROR) << "Failed to allocate backing image surface";
gl_->DeleteTextures(1, &texture);
const gpu::Mailbox mailbox = sii_->CreateSharedImage(
buffer.get(), gpu_memory_buffer_manager_, color_space_,
gpu::SHARED_IMAGE_USAGE_SCANOUT |
gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT);
if (mailbox.IsZero()) {
LOG(ERROR) << "Failed to create SharedImage";
return nullptr;
}
allocated_count_++;
gl_->BindTexture(texture_target_, texture);
gl_->BindTexImage2DCHROMIUM(texture_target_, id);
// The texture must be bound to the image before setting the color space.
gl_->SetColorSpaceMetadataCHROMIUM(texture, color_space_.AsGLColorSpace());
return std::make_unique<AllocatedSurface>(this, std::move(buffer), texture,
id, stencil, gfx::Rect(size_));
*creation_sync_token = sii_->GenUnverifiedSyncToken();
return std::make_unique<AllocatedSurface>(std::move(buffer), mailbox,
gfx::Rect(size_));
}
BufferQueue::AllocatedSurface::AllocatedSurface(
BufferQueue* buffer_queue,
std::unique_ptr<gfx::GpuMemoryBuffer> buffer,
unsigned texture,
unsigned image,
unsigned stencil,
const gpu::Mailbox& mailbox,
const gfx::Rect& rect)
: buffer_queue(buffer_queue),
buffer(buffer.release()),
texture(texture),
image(image),
stencil(stencil),
damage(rect) {}
: buffer(buffer.release()), mailbox(mailbox), damage(rect) {}
BufferQueue::AllocatedSurface::~AllocatedSurface() {
buffer_queue->FreeSurfaceResources(this);
DCHECK(!buffer);
}
} // namespace viz
......@@ -11,10 +11,11 @@
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/ipc/common/surface_handle.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/color_space.h"
......@@ -27,101 +28,126 @@ class GpuMemoryBuffer;
namespace gpu {
class GpuMemoryBufferManager;
namespace gles2 {
class GLES2Interface;
}
class SharedImageInterface;
struct SyncToken;
} // namespace gpu
namespace viz {
// Provides a surface that manages its own buffers, backed by GpuMemoryBuffers
// created using CHROMIUM_image. Double/triple buffering is implemented
// internally. Doublebuffering occurs if PageFlipComplete is called before the
// Encapsulates a queue of buffers for compositing backed by SharedImages (in
// turn backed by GpuMemoryBuffers). Double/triple buffering is implemented
// internally. Double buffering occurs if PageFlipComplete is called before the
// next BindFramebuffer call, otherwise it creates extra buffers.
//
// SetSyncTokenProvider() must be called prior to using the BufferQueue. The
// reason the SyncTokenProvider is not passed in the constructor is testing:
// this allows us to create a mock BufferQueue that can be injected into a
// GLOutputSurfaceBufferQueue. The surface can then set itself as the
// SyncTokenProvider and fully own the BufferQueue thus guaranteeing that the
// queue's SyncTokenProvider outlives the queue.
class VIZ_SERVICE_EXPORT BufferQueue {
public:
BufferQueue(gpu::gles2::GLES2Interface* gl,
// A BufferQueue uses a SyncTokenProvider to get sync tokens that ensure
// operations on the buffers done by the BufferQueue client are synchronized
// with respect to other work.
//
// TODO(crbug.com/958670): extend this abstraction to allow both fences and
// sync tokens.
class SyncTokenProvider {
public:
SyncTokenProvider() = default;
virtual ~SyncTokenProvider() = default;
virtual gpu::SyncToken GenSyncToken() = 0;
};
// Creates a BufferQueue that allocates buffers using
// |gpu_memory_buffer_manager| and associates them with SharedImages using
// |sii|.
BufferQueue(gpu::SharedImageInterface* sii,
gfx::BufferFormat format,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::SurfaceHandle surface_handle,
const gpu::Capabilities& capabilities);
gpu::SurfaceHandle surface_handle);
virtual ~BufferQueue();
// Returns the texture name of the current buffer and the name of the
// corresponding stencil buffer. The returned values are 0u if there is no
// current buffer and one could not be created.
unsigned GetCurrentBuffer(unsigned* stencil);
// Sets the provider of sync tokens that the BufferQueue needs to ensure
// operations on a SharedImage are ordered correctly with respect to the
// operations issued by the client of the BufferQueue. |sync_token_provider|
// is not used after the BufferQueue is destroyed.
virtual void SetSyncTokenProvider(SyncTokenProvider* sync_token_provider);
// Returns the SharedImage backed by the current buffer (i.e., the render
// target for compositing). A zeroed mailbox is returned if there is no
// current buffer and one could not be created. The caller needs to wait on
// *|creation_sync_token| if non-empty before consuming the mailbox.
virtual gpu::Mailbox GetCurrentBuffer(gpu::SyncToken* creation_sync_token);
// Returns a rectangle whose contents may have changed since the current
// buffer was last submitted and needs to be redrawn. For partial swap,
// only the contents outside this rectangle can be considered valid and do not
// need to be redrawn.
gfx::Rect CurrentBufferDamage() const;
virtual gfx::Rect CurrentBufferDamage() const;
// Called by the user of this object to indicate that the buffer currently
// marked for drawing should be moved to the list of in-flight buffers.
// |damage| represents the rectangle containing the damaged area since the
// last SwapBuffers.
void SwapBuffers(const gfx::Rect& damage);
virtual void SwapBuffers(const gfx::Rect& damage);
// Called by the user of this object to indicate that a previous request to
// swap buffers has completed. This allows us to correctly keep track of the
// state of the buffers: the buffer currently marked as being displayed will
// now marked as available, and the next buffer marked as in-flight will now
// be marked as displayed.
void PageFlipComplete();
virtual void PageFlipComplete();
// Destroys all the buffers (useful if for some reason, the buffers are no
// longer presentable).
void FreeAllSurfaces();
// Requests a sync token from the SyncTokenProvider passed in the constructor
// and frees all buffers after that sync token has passed.
virtual void FreeAllSurfaces();
// Frees all buffers if |size|, |color_space|, or |use_stencil| correspond to
// a change of state. Otherwise, it's a no-op. Returns true if there was a
// change of state, false otherwise.
bool Reshape(const gfx::Size& size,
float scale_factor,
const gfx::ColorSpace& color_space,
bool use_stencil);
// If |size| or |color_space| correspond to a change of state, requests a sync
// token from the SyncTokenProvider passed in the constructor and frees all
// the buffers after that sync token passes. Otherwise, it's a no-op. Returns
// true if there was a change of state, false otherwise.
virtual bool Reshape(const gfx::Size& size,
const gfx::ColorSpace& color_space);
uint32_t internal_format() const { return internal_format_; }
gfx::BufferFormat buffer_format() const { return format_; }
uint32_t texture_target() const { return texture_target_; }
private:
friend class BufferQueueTest;
friend class AllocatedSurface;
FRIEND_TEST_ALL_PREFIXES(BufferQueueTest, AllocateFails);
// TODO(andrescj): consider renaming this to AllocatedBuffer because 'surface'
// is an overloaded term (also problematic in the unit tests).
struct VIZ_SERVICE_EXPORT AllocatedSurface {
AllocatedSurface(BufferQueue* buffer_queue,
std::unique_ptr<gfx::GpuMemoryBuffer> buffer,
unsigned texture,
unsigned image,
unsigned stencil,
AllocatedSurface(std::unique_ptr<gfx::GpuMemoryBuffer> buffer,
const gpu::Mailbox& mailbox,
const gfx::Rect& rect);
~AllocatedSurface();
BufferQueue* const buffer_queue;
// TODO(crbug.com/958670): if we can have a CreateSharedImage() that takes a
// SurfaceHandle, we don't have to keep track of |buffer|.
std::unique_ptr<gfx::GpuMemoryBuffer> buffer;
const unsigned texture;
const unsigned image;
const unsigned stencil;
gpu::Mailbox mailbox;
gfx::Rect damage; // This is the damage for this frame from the previous.
};
void FreeSurfaceResources(AllocatedSurface* surface);
void FreeSurface(std::unique_ptr<AllocatedSurface> surface,
const gpu::SyncToken& sync_token);
void UpdateBufferDamage(const gfx::Rect& damage);
// Return a surface, available to be drawn into.
std::unique_ptr<AllocatedSurface> GetNextSurface();
// Return a buffer that is available to be drawn into or nullptr if there is
// no available buffer and one cannot be created. If a new buffer is created
// *|creation_sync_token| is set to a sync token that the client must wait on
// before using the buffer.
std::unique_ptr<AllocatedSurface> GetNextSurface(
gpu::SyncToken* creation_sync_token);
gpu::gles2::GLES2Interface* const gl_;
gpu::SharedImageInterface* const sii_;
gfx::Size size_;
gfx::ColorSpace color_space_;
bool use_stencil_ = false;
size_t allocated_count_;
uint32_t texture_target_;
uint32_t internal_format_;
gfx::BufferFormat format_;
// This surface is currently bound. This may be nullptr if no surface has
// been bound, or if allocation failed at bind.
......@@ -135,6 +161,7 @@ class VIZ_SERVICE_EXPORT BufferQueue {
base::circular_deque<std::unique_ptr<AllocatedSurface>> in_flight_surfaces_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
gpu::SurfaceHandle surface_handle_;
SyncTokenProvider* sync_token_provider_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(BufferQueue);
};
......
......@@ -19,6 +19,7 @@
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/common/swap_buffers_flags.h"
#include "gpu/config/gpu_feature_info.h"
#include "ui/gfx/overlay_transform_utils.h"
namespace viz {
......
......@@ -11,9 +11,12 @@
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display_embedder/buffer_queue.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_enums.h"
namespace viz {
......@@ -21,11 +24,13 @@ namespace viz {
GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue(
scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gfx::BufferFormat buffer_format)
std::unique_ptr<BufferQueue> buffer_queue)
: GLOutputSurface(context_provider, surface_handle),
current_texture_(0u),
fbo_(0u) {
buffer_queue_(std::move(buffer_queue)),
texture_target_(gpu::GetBufferTextureTarget(
gfx::BufferUsage::SCANOUT,
buffer_queue_->buffer_format(),
context_provider_->ContextCapabilities())) {
capabilities_.only_invalidates_damage_rect = false;
capabilities_.uses_default_gl_framebuffer = false;
capabilities_.flipped_output_surface = true;
......@@ -38,31 +43,57 @@ GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue(
// implementation.
capabilities_.max_frames_pending = 2;
buffer_queue_ = std::make_unique<BufferQueue>(
context_provider->ContextGL(), buffer_format, gpu_memory_buffer_manager,
surface_handle, context_provider->ContextCapabilities());
// It is safe to pass a raw pointer to *this because |buffer_queue_| is fully
// owned and it doesn't use the SyncTokenProvider after it's destroyed.
DCHECK(buffer_queue_);
buffer_queue_->SetSyncTokenProvider(this);
context_provider_->ContextGL()->GenFramebuffers(1, &fbo_);
}
GLOutputSurfaceBufferQueue::~GLOutputSurfaceBufferQueue() {
auto* gl = context_provider_->ContextGL();
DCHECK_NE(0u, fbo_);
context_provider_->ContextGL()->DeleteFramebuffers(1, &fbo_);
gl->DeleteFramebuffers(1, &fbo_);
if (stencil_buffer_)
gl->DeleteRenderbuffers(1, &stencil_buffer_);
for (const auto& buffer_texture : buffer_queue_textures_)
gl->DeleteTextures(1u, &buffer_texture.second);
buffer_queue_textures_.clear();
current_texture_ = 0u;
// Freeing the BufferQueue here ensures that *this is fully alive in case the
// BufferQueue needs the SyncTokenProvider functionality.
buffer_queue_.reset();
fbo_ = 0u;
stencil_buffer_ = 0u;
}
void GLOutputSurfaceBufferQueue::BindFramebuffer() {
auto* gl = context_provider_->ContextGL();
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
// If we have a |current_texture_|, it means we haven't swapped the buffer, so
// we're just wanting to rebind the GL framebuffer.
if (current_texture_)
return;
DCHECK(buffer_queue_);
unsigned stencil;
current_texture_ = buffer_queue_->GetCurrentBuffer(&stencil);
if (!current_texture_)
gpu::SyncToken creation_sync_token;
const gpu::Mailbox current_buffer =
buffer_queue_->GetCurrentBuffer(&creation_sync_token);
if (current_buffer.IsZero())
return;
// TODO(andrescj): if the texture hasn't changed since the last call to
// BindFrameBuffer(), we may be able to avoid mutating the FBO which may lead
// to performance improvements.
gl->WaitSyncTokenCHROMIUM(creation_sync_token.GetConstData());
unsigned& buffer_texture = buffer_queue_textures_[current_buffer];
if (!buffer_texture) {
buffer_texture =
gl->CreateAndTexStorage2DSharedImageCHROMIUM(current_buffer.name);
}
current_texture_ = buffer_texture;
gl->BeginSharedImageAccessDirectCHROMIUM(
current_texture_, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
buffer_queue_->texture_target(), current_texture_,
0);
texture_target_, current_texture_, 0);
#if DCHECK_IS_ON() && defined(OS_CHROMEOS)
const GLenum result = gl->CheckFramebufferStatus(GL_FRAMEBUFFER);
......@@ -70,9 +101,17 @@ void GLOutputSurfaceBufferQueue::BindFramebuffer() {
DLOG(ERROR) << " Incomplete fb: " << gl::GLEnums::GetStringError(result);
#endif
if (stencil) {
// Reshape() must be called to go from using a stencil buffer to not using it.
DCHECK(use_stencil_ || !stencil_buffer_);
if (use_stencil_ && !stencil_buffer_) {
gl->GenRenderbuffers(1, &stencil_buffer_);
CHECK_NE(stencil_buffer_, 0u);
gl->BindRenderbuffer(GL_RENDERBUFFER, stencil_buffer_);
gl->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
reshape_size_.width(), reshape_size_.height());
gl->BindRenderbuffer(GL_RENDERBUFFER, 0);
gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencil);
GL_RENDERBUFFER, stencil_buffer_);
}
}
......@@ -88,16 +127,29 @@ void GLOutputSurfaceBufferQueue::Reshape(const gfx::Size& size,
bool has_alpha,
bool use_stencil) {
reshape_size_ = size;
use_stencil_ = use_stencil;
GLOutputSurface::Reshape(size, device_scale_factor, color_space, has_alpha,
use_stencil);
if (buffer_queue_->Reshape(size, device_scale_factor, color_space,
use_stencil)) {
DCHECK(buffer_queue_);
const bool freed_buffers = buffer_queue_->Reshape(size, color_space);
if (freed_buffers || (stencil_buffer_ && !use_stencil)) {
auto* gl = context_provider_->ContextGL();
gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
buffer_queue_->texture_target(), 0, 0);
gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, 0);
if (stencil_buffer_) {
gl->DeleteRenderbuffers(1, &stencil_buffer_);
stencil_buffer_ = 0u;
}
if (freed_buffers) {
gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
texture_target_, 0, 0);
gl->BindFramebuffer(GL_FRAMEBUFFER, 0u);
for (const auto& buffer_texture : buffer_queue_textures_)
gl->DeleteTextures(1u, &buffer_texture.second);
buffer_queue_textures_.clear();
current_texture_ = 0u;
}
}
}
......@@ -112,8 +164,13 @@ void GLOutputSurfaceBufferQueue::SwapBuffers(OutputSurfaceFrame frame) {
gfx::Rect damage_rect =
frame.sub_buffer_rect ? *frame.sub_buffer_rect : gfx::Rect(swap_size_);
buffer_queue_->SwapBuffers(damage_rect);
GLOutputSurface::SwapBuffers(std::move(frame));
auto* gl = context_provider_->ContextGL();
gl->BindFramebuffer(GL_FRAMEBUFFER, 0u);
if (current_texture_) {
gl->EndSharedImageAccessDirectCHROMIUM(current_texture_);
current_texture_ = 0u;
}
}
gfx::Rect GLOutputSurfaceBufferQueue::GetCurrentFramebufferDamage() const {
......@@ -121,7 +178,8 @@ gfx::Rect GLOutputSurfaceBufferQueue::GetCurrentFramebufferDamage() const {
}
uint32_t GLOutputSurfaceBufferQueue::GetFramebufferCopyTextureFormat() {
return buffer_queue_->internal_format();
return base::strict_cast<GLenum>(
gl::BufferFormatToGLInternalFormat(buffer_queue_->buffer_format()));
}
bool GLOutputSurfaceBufferQueue::IsDisplayedAsOverlayPlane() const {
......@@ -155,6 +213,20 @@ void GLOutputSurfaceBufferQueue::DidReceiveSwapBuffersAck(
client()->SetNeedsRedrawRect(gfx::Rect(swap_size_));
}
gpu::SyncToken GLOutputSurfaceBufferQueue::GenSyncToken() {
// This should only be called as long as the BufferQueue is alive. We cannot
// use |buffer_queue_| to detect this because in the dtor, |buffer_queue_|
// becomes nullptr before BufferQueue's dtor is called, so GenSyncToken()
// would be called after |buffer_queue_| is nullptr when in fact, the
// BufferQueue is still alive. Hence, we use |fbo_| to detect that the
// BufferQueue is still alive.
DCHECK(fbo_);
gpu::SyncToken sync_token;
context_provider_->ContextGL()->GenUnverifiedSyncTokenCHROMIUM(
sync_token.GetData());
return sync_token;
}
void GLOutputSurfaceBufferQueue::SetDisplayTransformHint(
gfx::OverlayTransform transform) {
display_transform_ = transform;
......
......@@ -9,37 +9,39 @@
#include <memory>
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display_embedder/buffer_queue.h"
#include "components/viz/service/display_embedder/gl_output_surface.h"
#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/swap_result.h"
#include "ui/gl/gl_surface.h"
namespace gpu {
class GpuMemoryBufferManager;
}
namespace viz {
class BufferQueue;
// An OutputSurface implementation that directly draws and swap to a GL
// "buffer_queue" surface (aka one backed by a buffer managed explicitly).
class GLOutputSurfaceBufferQueue : public GLOutputSurface {
class VIZ_SERVICE_EXPORT GLOutputSurfaceBufferQueue
: public GLOutputSurface,
public BufferQueue::SyncTokenProvider {
public:
GLOutputSurfaceBufferQueue(
scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gfx::BufferFormat buffer_format);
std::unique_ptr<BufferQueue> buffer_queue);
~GLOutputSurfaceBufferQueue() override;
// BufferQueue::SyncTokenProvider implementation.
gpu::SyncToken GenSyncToken() override;
protected:
// OutputSurface implementation.
void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
......@@ -64,8 +66,21 @@ class GLOutputSurfaceBufferQueue : public GLOutputSurface {
void DidReceiveSwapBuffersAck(const gfx::SwapResponse& response) override;
std::unique_ptr<BufferQueue> buffer_queue_;
unsigned current_texture_;
uint32_t fbo_;
// |buffer_queue_textures_| caches the textures generated by consuming the
// SharedImage mailboxes from the |buffer_queue_| so that we don't have to
// generate a new texture every time a shared image is re-used.
base::flat_map<gpu::Mailbox, unsigned> buffer_queue_textures_;
// The texture currently attached to |fbo_|. It's one of
// |buffer_queue_textures_|.
unsigned current_texture_ = 0u;
const unsigned texture_target_;
unsigned fbo_ = 0u;
bool use_stencil_ = false;
unsigned stencil_buffer_ = 0u;
gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
gfx::Size reshape_size_;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display_embedder/buffer_queue.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_context_support.h"
#include "components/viz/test/test_gles2_interface.h"
#include "gpu/command_buffer/common/command_buffer_id.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/ipc/common/surface_handle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/buffer_types.h"
using testing::_;
using testing::DoAll;
using testing::Eq;
using testing::InSequence;
using testing::Mock;
using testing::Ne;
using testing::NotNull;
using testing::Pointee;
using testing::Return;
using testing::SetArgPointee;
using testing::StrictMock;
namespace viz {
namespace {
class MockGLES2Interface : public TestGLES2Interface {
public:
MockGLES2Interface() = default;
~MockGLES2Interface() override = default;
MOCK_METHOD2(DeleteTextures, void(GLsizei, const GLuint*));
MOCK_METHOD2(BindFramebuffer, void(GLenum, GLuint));
MOCK_METHOD1(CreateAndTexStorage2DSharedImageCHROMIUM, GLuint(const GLbyte*));
MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte*));
MOCK_METHOD2(BeginSharedImageAccessDirectCHROMIUM, void(GLuint, GLenum));
MOCK_METHOD1(EndSharedImageAccessDirectCHROMIUM, void(GLuint));
};
class MockBufferQueue : public BufferQueue {
public:
MockBufferQueue()
: BufferQueue(/*sii_=*/nullptr,
/*buffer_format=*/gfx::BufferFormat::RGBA_8888,
/*gpu_memory_buffer_manager=*/nullptr,
gpu::kNullSurfaceHandle) {}
~MockBufferQueue() override = default;
MOCK_METHOD1(GetCurrentBuffer, gpu::Mailbox(gpu::SyncToken*));
MOCK_CONST_METHOD0(CurrentBufferDamage, gfx::Rect());
MOCK_METHOD1(SwapBuffers, void(const gfx::Rect&));
MOCK_METHOD0(PageFlipComplete, void());
MOCK_METHOD0(FreeAllSurfaces, void());
MOCK_METHOD2(Reshape, bool(const gfx::Size&, const gfx::ColorSpace&));
MOCK_METHOD0(DoSetSyncTokenProvider, void());
void SetSyncTokenProvider(SyncTokenProvider* sync_token_provider) override {
BufferQueue::SetSyncTokenProvider(sync_token_provider);
DoSetSyncTokenProvider();
}
};
class GLOutputSurfaceBufferQueueTest : public ::testing::Test {
public:
GLOutputSurfaceBufferQueueTest() = default;
~GLOutputSurfaceBufferQueueTest() override = default;
void SetUp() override {
auto buffer_queue = std::make_unique<StrictMock<MockBufferQueue>>();
buffer_queue_ = buffer_queue.get();
auto gles2_interface = std::make_unique<StrictMock<MockGLES2Interface>>();
gles2_interface_ = gles2_interface.get();
EXPECT_CALL(*buffer_queue_, DoSetSyncTokenProvider());
surface_ = std::make_unique<GLOutputSurfaceBufferQueue>(
base::MakeRefCounted<TestVizProcessContextProvider>(
std::make_unique<TestContextSupport>(), std::move(gles2_interface)),
gpu::kNullSurfaceHandle, std::move(buffer_queue));
Mock::VerifyAndClearExpectations(gles2_interface_);
Mock::VerifyAndClearExpectations(buffer_queue_);
}
protected:
std::unique_ptr<OutputSurface> surface_;
StrictMock<MockGLES2Interface>* gles2_interface_;
StrictMock<MockBufferQueue>* buffer_queue_;
};
MATCHER_P(SyncTokenEqualTo, expected_sync_token, "") {
auto* actual_sync_token = reinterpret_cast<const gpu::SyncToken*>(arg);
return expected_sync_token == *actual_sync_token;
}
MATCHER_P(SharedImageEqualTo, expected_shared_image, "") {
gpu::Mailbox actual_shared_image;
actual_shared_image.SetName(arg);
return expected_shared_image == actual_shared_image;
}
// Make sure that the surface uses the buffer queue and the GL context correctly
// when we request it to bind the framebuffer twice and then swap the buffer.
TEST_F(GLOutputSurfaceBufferQueueTest, BindFramebufferAndSwap) {
const gpu::SyncToken fake_sync_token(
gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(567u),
/*release_count=*/5u);
const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
constexpr GLuint kFakeTexture = 123u;
{
InSequence dummy_sequence;
// The first call to |surface_|->BindFramebuffer() should result in binding
// the GL framebuffer, requesting a new buffer, waiting on the corresponding
// sync token, and beginning read/write access to the shared image.
EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
Return(fake_shared_image)));
EXPECT_CALL(*gles2_interface_,
WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
SharedImageEqualTo(fake_shared_image)))
.WillOnce(Return(kFakeTexture));
EXPECT_CALL(
*gles2_interface_,
BeginSharedImageAccessDirectCHROMIUM(
kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
// The second call to |surface_|->BindFramebuffer() should only result in
// binding the GL framebuffer because the underlying buffer hasn't been
// swapped.
EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
// Calling |surface_|->SwapBuffers() should result in unbinding the GL
// framebuffer and ending read/write access to the underlying buffer.
EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
EXPECT_CALL(*gles2_interface_,
EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
// Destroying |surface_| should result in the deletion of the texture
// obtained from consuming the shared image.
EXPECT_CALL(*gles2_interface_,
DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
}
surface_->BindFramebuffer();
surface_->BindFramebuffer();
surface_->SwapBuffers(OutputSurfaceFrame());
}
} // namespace
} // namespace viz
......@@ -16,6 +16,7 @@
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "ui/gfx/swap_result.h"
#include "ui/gl/gl_utils.h"
namespace viz {
......
......@@ -185,19 +185,26 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
#if defined(USE_OZONE)
output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
std::move(context_provider), surface_handle,
gpu_memory_buffer_manager_.get(),
display::DisplaySnapshot::PrimaryFormat());
std::make_unique<BufferQueue>(
context_provider->SharedImageInterface(),
display::DisplaySnapshot::PrimaryFormat(),
gpu_memory_buffer_manager_.get(), surface_handle));
#elif defined(OS_MACOSX)
output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
std::move(context_provider), surface_handle,
gpu_memory_buffer_manager_.get(), gfx::BufferFormat::RGBA_8888);
std::make_unique<BufferQueue>(
context_provider->SharedImageInterface(),
gfx::BufferFormat::RGBA_8888, gpu_memory_buffer_manager_.get(),
surface_handle));
#elif defined(OS_ANDROID)
auto buffer_format = context_provider->UseRGB565PixelFormat()
? gfx::BufferFormat::BGR_565
: gfx::BufferFormat::RGBA_8888;
output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
std::move(context_provider), surface_handle,
gpu_memory_buffer_manager_.get(), buffer_format);
std::make_unique<BufferQueue>(
context_provider->SharedImageInterface(), buffer_format,
gpu_memory_buffer_manager_.get(), surface_handle));
#else
NOTREACHED();
#endif
......
......@@ -31,6 +31,7 @@
#include "gpu/config/gpu_preferences.h"
#include "gpu/config/skia_limits.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "gpu/skia_bindings/gles2_implementation_with_grcontext_support.h"
#include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
#include "third_party/khronos/GLES2/gl2.h"
......@@ -133,6 +134,8 @@ VizProcessContextProvider::VizProcessContextProvider(
}
}
VizProcessContextProvider::VizProcessContextProvider() = default;
VizProcessContextProvider::~VizProcessContextProvider() {
if (context_result_ == gpu::ContextResult::kSuccess) {
base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
......
......@@ -9,14 +9,17 @@
#include <memory>
#include "base/callback_helpers.h"
#include "base/observer_list.h"
#include "base/trace_event/memory_dump_provider.h"
#include "components/viz/common/display/update_vsync_parameters_callback.h"
#include "components/viz/common/gpu/context_cache_controller.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/gpu_vsync_callback.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/gpu_task_scheduler_helper.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "ui/gfx/native_widget_types.h"
class GrContext;
......@@ -26,9 +29,11 @@ namespace gles2 {
class GLES2CmdHelper;
class GLES2Implementation;
} // namespace gles2
class CommandBufferTaskExecutor;
class GpuChannelManagerDelegate;
class GpuMemoryBufferManager;
class ImageFactory;
class InProcessCommandBuffer;
class TransferBuffer;
struct SharedMemoryLimits;
} // namespace gpu
......@@ -73,23 +78,26 @@ class VIZ_SERVICE_EXPORT VizProcessContextProvider
void RemoveObserver(ContextLostObserver* obs) override;
gpu::SharedImageManager* GetSharedImageManager() override;
void SetUpdateVSyncParametersCallback(UpdateVSyncParametersCallback callback);
void SetGpuVSyncCallback(GpuVSyncCallback callback);
void SetGpuVSyncEnabled(bool enabled);
bool UseRGB565PixelFormat() const;
virtual void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback);
virtual void SetGpuVSyncCallback(GpuVSyncCallback callback);
virtual void SetGpuVSyncEnabled(bool enabled);
virtual bool UseRGB565PixelFormat() const;
// Provides the GL internal format that should be used when calling
// glCopyTexImage2D() on the default framebuffer.
uint32_t GetCopyTextureInternalFormat();
virtual uint32_t GetCopyTextureInternalFormat();
base::ScopedClosureRunner GetCacheBackBufferCb();
virtual base::ScopedClosureRunner GetCacheBackBufferCb();
scoped_refptr<gpu::GpuTaskSchedulerHelper> GetGpuTaskSchedulerHelper();
private:
protected:
friend class base::RefCountedThreadSafe<VizProcessContextProvider>;
VizProcessContextProvider(); // For testing only.
~VizProcessContextProvider() override;
private:
void InitializeContext(
gpu::CommandBufferTaskExecutor* task_executor,
gpu::SurfaceHandle surface_handle,
......
......@@ -13,6 +13,7 @@
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/stl_util.h"
......@@ -250,7 +251,7 @@ scoped_refptr<TestContextProvider> TestContextProvider::Create(
std::make_unique<TestContextSupport>(),
std::make_unique<TestGLES2InterfaceForContextProvider>(
std::move(additional_extensions)),
support_locking);
/*sii=*/nullptr, support_locking);
}
// static
......@@ -258,7 +259,7 @@ scoped_refptr<TestContextProvider> TestContextProvider::CreateWorker() {
constexpr bool support_locking = true;
auto worker_context_provider = base::MakeRefCounted<TestContextProvider>(
std::make_unique<TestContextSupport>(),
std::make_unique<TestGLES2InterfaceForContextProvider>(),
std::make_unique<TestGLES2InterfaceForContextProvider>(), /*sii=*/nullptr,
support_locking);
// Worker contexts are bound to the thread they are created on.
auto result = worker_context_provider->BindToCurrentThread();
......@@ -273,7 +274,18 @@ scoped_refptr<TestContextProvider> TestContextProvider::Create(
DCHECK(gl);
constexpr bool support_locking = false;
return new TestContextProvider(std::make_unique<TestContextSupport>(),
std::move(gl), support_locking);
std::move(gl), /*sii=*/nullptr,
support_locking);
}
// static
scoped_refptr<TestContextProvider> TestContextProvider::Create(
std::unique_ptr<TestSharedImageInterface> sii) {
DCHECK(sii);
constexpr bool support_locking = false;
return new TestContextProvider(std::make_unique<TestContextSupport>(),
/*gl=*/nullptr, std::move(sii),
support_locking);
}
// static
......@@ -284,7 +296,7 @@ scoped_refptr<TestContextProvider> TestContextProvider::Create(
return new TestContextProvider(
std::move(support),
std::make_unique<TestGLES2InterfaceForContextProvider>(),
support_locking);
/*sii=*/nullptr, support_locking);
}
// static
......@@ -295,7 +307,7 @@ scoped_refptr<TestContextProvider> TestContextProvider::CreateWorker(
auto worker_context_provider = base::MakeRefCounted<TestContextProvider>(
std::move(support),
std::make_unique<TestGLES2InterfaceForContextProvider>(),
support_locking);
/*sii=*/nullptr, support_locking);
// Worker contexts are bound to the thread they are created on.
auto result = worker_context_provider->BindToCurrentThread();
if (result != gpu::ContextResult::kSuccess)
......@@ -306,21 +318,27 @@ scoped_refptr<TestContextProvider> TestContextProvider::CreateWorker(
TestContextProvider::TestContextProvider(
std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl,
std::unique_ptr<TestSharedImageInterface> sii,
bool support_locking)
: TestContextProvider(std::move(support),
std::move(gl),
/*raster=*/nullptr,
std::move(sii),
support_locking) {}
TestContextProvider::TestContextProvider(
std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl,
std::unique_ptr<gpu::raster::RasterInterface> raster,
std::unique_ptr<TestSharedImageInterface> sii,
bool support_locking)
: support_(std::move(support)),
context_gl_(std::move(gl)),
context_gl_(
gl ? std::move(gl)
: std::make_unique<TestGLES2InterfaceForContextProvider>()),
raster_context_(std::move(raster)),
shared_image_interface_(std::make_unique<TestSharedImageInterface>()),
shared_image_interface_(
sii ? std::move(sii) : std::make_unique<TestSharedImageInterface>()),
support_locking_(support_locking) {
DCHECK(main_thread_checker_.CalledOnValidThread());
DCHECK(context_gl_);
......@@ -452,4 +470,50 @@ void TestContextProvider::RemoveObserver(ContextLostObserver* obs) {
observers_.RemoveObserver(obs);
}
TestVizProcessContextProvider::TestVizProcessContextProvider(
std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl)
: support_(std::move(support)), context_gl_(std::move(gl)) {}
TestVizProcessContextProvider::~TestVizProcessContextProvider() = default;
gpu::gles2::GLES2Interface* TestVizProcessContextProvider::ContextGL() {
return context_gl_.get();
}
gpu::ContextSupport* TestVizProcessContextProvider::ContextSupport() {
return support_.get();
}
const gpu::Capabilities& TestVizProcessContextProvider::ContextCapabilities()
const {
return gpu_capabilities_;
}
const gpu::GpuFeatureInfo& TestVizProcessContextProvider::GetGpuFeatureInfo()
const {
return gpu_feature_info_;
}
void TestVizProcessContextProvider::SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) {}
void TestVizProcessContextProvider::SetGpuVSyncCallback(
GpuVSyncCallback callback) {}
void TestVizProcessContextProvider::SetGpuVSyncEnabled(bool enabled) {}
bool TestVizProcessContextProvider::UseRGB565PixelFormat() const {
return false;
}
uint32_t TestVizProcessContextProvider::GetCopyTextureInternalFormat() {
return 0u;
}
base::ScopedClosureRunner
TestVizProcessContextProvider::GetCacheBackBufferCb() {
return base::ScopedClosureRunner(base::DoNothing());
}
} // namespace viz
......@@ -20,6 +20,7 @@
#include "build/build_config.h"
#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/raster_context_provider.h"
#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "components/viz/test/test_context_support.h"
#include "gpu/command_buffer/client/gles2_interface_stub.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
......@@ -119,17 +120,20 @@ class TestContextProvider
std::unique_ptr<TestContextSupport> support);
static scoped_refptr<TestContextProvider> Create(
std::unique_ptr<TestGLES2Interface> gl);
static scoped_refptr<TestContextProvider> Create(
std::unique_ptr<TestSharedImageInterface> sii);
static scoped_refptr<TestContextProvider> Create(
std::unique_ptr<TestContextSupport> support);
explicit TestContextProvider(
std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl,
bool support_locking);
explicit TestContextProvider(std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl,
std::unique_ptr<TestSharedImageInterface> sii,
bool support_locking);
explicit TestContextProvider(
std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl,
std::unique_ptr<gpu::raster::RasterInterface> raster,
std::unique_ptr<TestSharedImageInterface> sii,
bool support_locking);
// ContextProvider / RasterContextProvider implementation.
......@@ -195,6 +199,38 @@ class TestContextProvider
DISALLOW_COPY_AND_ASSIGN(TestContextProvider);
};
class TestVizProcessContextProvider : public VizProcessContextProvider {
public:
TestVizProcessContextProvider(std::unique_ptr<TestContextSupport> support,
std::unique_ptr<TestGLES2Interface> gl);
TestVizProcessContextProvider(const TestVizProcessContextProvider&) = delete;
TestVizProcessContextProvider& operator=(
const TestVizProcessContextProvider&) = delete;
// ContextProvider implementation.
gpu::gles2::GLES2Interface* ContextGL() override;
gpu::ContextSupport* ContextSupport() override;
const gpu::Capabilities& ContextCapabilities() const override;
const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override;
void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) override;
void SetGpuVSyncCallback(GpuVSyncCallback callback) override;
void SetGpuVSyncEnabled(bool enabled) override;
bool UseRGB565PixelFormat() const override;
uint32_t GetCopyTextureInternalFormat() override;
base::ScopedClosureRunner GetCacheBackBufferCb() override;
protected:
~TestVizProcessContextProvider() override;
private:
std::unique_ptr<TestContextSupport> support_;
std::unique_ptr<TestGLES2Interface> context_gl_;
gpu::Capabilities gpu_capabilities_;
gpu::GpuFeatureInfo gpu_feature_info_;
};
} // namespace viz
#endif // COMPONENTS_VIZ_TEST_TEST_CONTEXT_PROVIDER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment