| Index: cc/resources/resource_provider.cc
|
| diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b2bb61c3daac3ae05a2f6d4f3f1c8cc6942375ac
|
| --- /dev/null
|
| +++ b/cc/resources/resource_provider.cc
|
| @@ -0,0 +1,2172 @@
|
| +// Copyright 2012 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 "cc/resources/resource_provider.h"
|
| +
|
| +#include <algorithm>
|
| +#include <limits>
|
| +
|
| +#include "base/containers/hash_tables.h"
|
| +#include "base/metrics/histogram.h"
|
| +#include "base/stl_util.h"
|
| +#include "base/strings/string_split.h"
|
| +#include "base/strings/string_util.h"
|
| +#include "base/trace_event/trace_event.h"
|
| +#include "cc/base/util.h"
|
| +#include "cc/output/gl_renderer.h" // For the GLC() macro.
|
| +#include "cc/resources/platform_color.h"
|
| +#include "cc/resources/returned_resource.h"
|
| +#include "cc/resources/shared_bitmap_manager.h"
|
| +#include "cc/resources/texture_uploader.h"
|
| +#include "cc/resources/transferable_resource.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 "third_party/khronos/GLES2/gl2.h"
|
| +#include "third_party/khronos/GLES2/gl2ext.h"
|
| +#include "third_party/skia/include/core/SkSurface.h"
|
| +#include "third_party/skia/include/gpu/GrContext.h"
|
| +#include "ui/gfx/frame_time.h"
|
| +#include "ui/gfx/geometry/rect.h"
|
| +#include "ui/gfx/geometry/vector2d.h"
|
| +#include "ui/gfx/gpu_memory_buffer.h"
|
| +
|
| +using gpu::gles2::GLES2Interface;
|
| +
|
| +namespace cc {
|
| +
|
| +class IdAllocator {
|
| + public:
|
| + virtual ~IdAllocator() {}
|
| +
|
| + virtual GLuint NextId() = 0;
|
| +
|
| + protected:
|
| + IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size)
|
| + : gl_(gl),
|
| + id_allocation_chunk_size_(id_allocation_chunk_size),
|
| + ids_(new GLuint[id_allocation_chunk_size]),
|
| + next_id_index_(id_allocation_chunk_size) {
|
| + DCHECK(id_allocation_chunk_size_);
|
| + }
|
| +
|
| + GLES2Interface* gl_;
|
| + const size_t id_allocation_chunk_size_;
|
| + scoped_ptr<GLuint[]> ids_;
|
| + size_t next_id_index_;
|
| +};
|
| +
|
| +namespace {
|
| +
|
| +// Measured in seconds.
|
| +const double kSoftwareUploadTickRate = 0.000250;
|
| +const double kTextureUploadTickRate = 0.004;
|
| +
|
| +GLenum TextureToStorageFormat(ResourceFormat format) {
|
| + GLenum storage_format = GL_RGBA8_OES;
|
| + switch (format) {
|
| + case RGBA_8888:
|
| + break;
|
| + case BGRA_8888:
|
| + storage_format = GL_BGRA8_EXT;
|
| + break;
|
| + case RGBA_4444:
|
| + case ALPHA_8:
|
| + case LUMINANCE_8:
|
| + case RGB_565:
|
| + case ETC1:
|
| + case RED_8:
|
| + NOTREACHED();
|
| + break;
|
| + }
|
| +
|
| + return storage_format;
|
| +}
|
| +
|
| +bool IsFormatSupportedForStorage(ResourceFormat format, bool use_bgra) {
|
| + switch (format) {
|
| + case RGBA_8888:
|
| + return true;
|
| + case BGRA_8888:
|
| + return use_bgra;
|
| + case RGBA_4444:
|
| + case ALPHA_8:
|
| + case LUMINANCE_8:
|
| + case RGB_565:
|
| + case ETC1:
|
| + case RED_8:
|
| + return false;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +GrPixelConfig ToGrPixelConfig(ResourceFormat format) {
|
| + switch (format) {
|
| + case RGBA_8888:
|
| + return kRGBA_8888_GrPixelConfig;
|
| + case BGRA_8888:
|
| + return kBGRA_8888_GrPixelConfig;
|
| + case RGBA_4444:
|
| + return kRGBA_4444_GrPixelConfig;
|
| + default:
|
| + break;
|
| + }
|
| + DCHECK(false) << "Unsupported resource format.";
|
| + return kSkia8888_GrPixelConfig;
|
| +}
|
| +
|
| +gfx::GpuMemoryBuffer::Format ToGpuMemoryBufferFormat(ResourceFormat format) {
|
| + switch (format) {
|
| + case RGBA_8888:
|
| + return gfx::GpuMemoryBuffer::Format::RGBA_8888;
|
| + case BGRA_8888:
|
| + return gfx::GpuMemoryBuffer::Format::BGRA_8888;
|
| + case RGBA_4444:
|
| + case ALPHA_8:
|
| + case LUMINANCE_8:
|
| + case RGB_565:
|
| + case ETC1:
|
| + case RED_8:
|
| + break;
|
| + }
|
| + NOTREACHED();
|
| + return gfx::GpuMemoryBuffer::Format::RGBA_8888;
|
| +}
|
| +
|
| +class ScopedSetActiveTexture {
|
| + public:
|
| + ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
|
| + : gl_(gl), unit_(unit) {
|
| + DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_));
|
| +
|
| + if (unit_ != GL_TEXTURE0)
|
| + GLC(gl_, gl_->ActiveTexture(unit_));
|
| + }
|
| +
|
| + ~ScopedSetActiveTexture() {
|
| + // Active unit being GL_TEXTURE0 is effectively the ground state.
|
| + if (unit_ != GL_TEXTURE0)
|
| + GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
|
| + }
|
| +
|
| + private:
|
| + GLES2Interface* gl_;
|
| + GLenum unit_;
|
| +};
|
| +
|
| +class TextureIdAllocator : public IdAllocator {
|
| + public:
|
| + TextureIdAllocator(GLES2Interface* gl,
|
| + size_t texture_id_allocation_chunk_size)
|
| + : IdAllocator(gl, texture_id_allocation_chunk_size) {}
|
| + ~TextureIdAllocator() override {
|
| + gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_,
|
| + ids_.get() + next_id_index_);
|
| + }
|
| +
|
| + // Overridden from IdAllocator:
|
| + GLuint NextId() override {
|
| + if (next_id_index_ == id_allocation_chunk_size_) {
|
| + gl_->GenTextures(id_allocation_chunk_size_, ids_.get());
|
| + next_id_index_ = 0;
|
| + }
|
| +
|
| + return ids_[next_id_index_++];
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator);
|
| +};
|
| +
|
| +class BufferIdAllocator : public IdAllocator {
|
| + public:
|
| + BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size)
|
| + : IdAllocator(gl, buffer_id_allocation_chunk_size) {}
|
| + ~BufferIdAllocator() override {
|
| + gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_,
|
| + ids_.get() + next_id_index_);
|
| + }
|
| +
|
| + // Overridden from IdAllocator:
|
| + GLuint NextId() override {
|
| + if (next_id_index_ == id_allocation_chunk_size_) {
|
| + gl_->GenBuffers(id_allocation_chunk_size_, ids_.get());
|
| + next_id_index_ = 0;
|
| + }
|
| +
|
| + return ids_[next_id_index_++];
|
| + }
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
|
| +};
|
| +
|
| +// Query object based fence implementation used to detect completion of copy
|
| +// texture operations. Fence has passed when query result is available.
|
| +class CopyTextureFence : public ResourceProvider::Fence {
|
| + public:
|
| + CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
|
| + : gl_(gl), query_id_(query_id) {}
|
| +
|
| + // Overridden from ResourceProvider::Fence:
|
| + void Set() override {}
|
| + bool HasPassed() override {
|
| + unsigned available = 1;
|
| + gl_->GetQueryObjectuivEXT(
|
| + query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
|
| + if (!available)
|
| + return false;
|
| +
|
| + ProcessResult();
|
| + return true;
|
| + }
|
| + void Wait() override {
|
| + // ProcessResult() will wait for result to become available.
|
| + ProcessResult();
|
| + }
|
| +
|
| + private:
|
| + ~CopyTextureFence() override {}
|
| +
|
| + void ProcessResult() {
|
| + unsigned time_elapsed_us = 0;
|
| + gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
|
| + UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
|
| + 0, 256000, 50);
|
| + }
|
| +
|
| + gpu::gles2::GLES2Interface* gl_;
|
| + unsigned query_id_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +ResourceProvider::Resource::Resource()
|
| + : child_id(0),
|
| + gl_id(0),
|
| + gl_pixel_buffer_id(0),
|
| + gl_upload_query_id(0),
|
| + gl_read_lock_query_id(0),
|
| + pixels(NULL),
|
| + lock_for_read_count(0),
|
| + imported_count(0),
|
| + exported_count(0),
|
| + dirty_image(false),
|
| + locked_for_write(false),
|
| + lost(false),
|
| + marked_for_deletion(false),
|
| + pending_set_pixels(false),
|
| + set_pixels_completion_forced(false),
|
| + allocated(false),
|
| + read_lock_fences_enabled(false),
|
| + has_shared_bitmap_id(false),
|
| + allow_overlay(false),
|
| + read_lock_fence(NULL),
|
| + size(),
|
| + origin(INTERNAL),
|
| + target(0),
|
| + original_filter(0),
|
| + filter(0),
|
| + image_id(0),
|
| + bound_image_id(0),
|
| + texture_pool(0),
|
| + wrap_mode(0),
|
| + hint(TEXTURE_HINT_IMMUTABLE),
|
| + type(RESOURCE_TYPE_INVALID),
|
| + format(RGBA_8888),
|
| + shared_bitmap(NULL),
|
| + gpu_memory_buffer(NULL) {
|
| +}
|
| +
|
| +ResourceProvider::Resource::~Resource() {}
|
| +
|
| +ResourceProvider::Resource::Resource(GLuint texture_id,
|
| + const gfx::Size& size,
|
| + Origin origin,
|
| + GLenum target,
|
| + GLenum filter,
|
| + GLenum texture_pool,
|
| + GLint wrap_mode,
|
| + TextureHint hint,
|
| + ResourceFormat format)
|
| + : child_id(0),
|
| + gl_id(texture_id),
|
| + gl_pixel_buffer_id(0),
|
| + gl_upload_query_id(0),
|
| + gl_read_lock_query_id(0),
|
| + pixels(NULL),
|
| + lock_for_read_count(0),
|
| + imported_count(0),
|
| + exported_count(0),
|
| + dirty_image(false),
|
| + locked_for_write(false),
|
| + lost(false),
|
| + marked_for_deletion(false),
|
| + pending_set_pixels(false),
|
| + set_pixels_completion_forced(false),
|
| + allocated(false),
|
| + read_lock_fences_enabled(false),
|
| + has_shared_bitmap_id(false),
|
| + allow_overlay(false),
|
| + read_lock_fence(NULL),
|
| + size(size),
|
| + origin(origin),
|
| + target(target),
|
| + original_filter(filter),
|
| + filter(filter),
|
| + image_id(0),
|
| + bound_image_id(0),
|
| + texture_pool(texture_pool),
|
| + wrap_mode(wrap_mode),
|
| + hint(hint),
|
| + type(RESOURCE_TYPE_GL_TEXTURE),
|
| + format(format),
|
| + shared_bitmap(NULL),
|
| + gpu_memory_buffer(NULL) {
|
| + DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
|
| + DCHECK_EQ(origin == INTERNAL, !!texture_pool);
|
| +}
|
| +
|
| +ResourceProvider::Resource::Resource(uint8_t* pixels,
|
| + SharedBitmap* bitmap,
|
| + const gfx::Size& size,
|
| + Origin origin,
|
| + GLenum filter,
|
| + GLint wrap_mode)
|
| + : child_id(0),
|
| + gl_id(0),
|
| + gl_pixel_buffer_id(0),
|
| + gl_upload_query_id(0),
|
| + gl_read_lock_query_id(0),
|
| + pixels(pixels),
|
| + lock_for_read_count(0),
|
| + imported_count(0),
|
| + exported_count(0),
|
| + dirty_image(false),
|
| + locked_for_write(false),
|
| + lost(false),
|
| + marked_for_deletion(false),
|
| + pending_set_pixels(false),
|
| + set_pixels_completion_forced(false),
|
| + allocated(false),
|
| + read_lock_fences_enabled(false),
|
| + has_shared_bitmap_id(!!bitmap),
|
| + allow_overlay(false),
|
| + read_lock_fence(NULL),
|
| + size(size),
|
| + origin(origin),
|
| + target(0),
|
| + original_filter(filter),
|
| + filter(filter),
|
| + image_id(0),
|
| + bound_image_id(0),
|
| + texture_pool(0),
|
| + wrap_mode(wrap_mode),
|
| + hint(TEXTURE_HINT_IMMUTABLE),
|
| + type(RESOURCE_TYPE_BITMAP),
|
| + format(RGBA_8888),
|
| + shared_bitmap(bitmap),
|
| + gpu_memory_buffer(NULL) {
|
| + DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
|
| + DCHECK(origin == DELEGATED || pixels);
|
| + if (bitmap)
|
| + shared_bitmap_id = bitmap->id();
|
| +}
|
| +
|
| +ResourceProvider::Resource::Resource(const SharedBitmapId& bitmap_id,
|
| + const gfx::Size& size,
|
| + Origin origin,
|
| + GLenum filter,
|
| + GLint wrap_mode)
|
| + : child_id(0),
|
| + gl_id(0),
|
| + gl_pixel_buffer_id(0),
|
| + gl_upload_query_id(0),
|
| + gl_read_lock_query_id(0),
|
| + pixels(NULL),
|
| + lock_for_read_count(0),
|
| + imported_count(0),
|
| + exported_count(0),
|
| + dirty_image(false),
|
| + locked_for_write(false),
|
| + lost(false),
|
| + marked_for_deletion(false),
|
| + pending_set_pixels(false),
|
| + set_pixels_completion_forced(false),
|
| + allocated(false),
|
| + read_lock_fences_enabled(false),
|
| + has_shared_bitmap_id(true),
|
| + allow_overlay(false),
|
| + read_lock_fence(NULL),
|
| + size(size),
|
| + origin(origin),
|
| + target(0),
|
| + original_filter(filter),
|
| + filter(filter),
|
| + image_id(0),
|
| + bound_image_id(0),
|
| + texture_pool(0),
|
| + wrap_mode(wrap_mode),
|
| + hint(TEXTURE_HINT_IMMUTABLE),
|
| + type(RESOURCE_TYPE_BITMAP),
|
| + format(RGBA_8888),
|
| + shared_bitmap_id(bitmap_id),
|
| + shared_bitmap(NULL),
|
| + gpu_memory_buffer(NULL) {
|
| + DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
|
| +}
|
| +
|
| +ResourceProvider::Child::Child() : marked_for_deletion(false) {}
|
| +
|
| +ResourceProvider::Child::~Child() {}
|
| +
|
| +scoped_ptr<ResourceProvider> ResourceProvider::Create(
|
| + OutputSurface* output_surface,
|
| + SharedBitmapManager* shared_bitmap_manager,
|
| + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
|
| + BlockingTaskRunner* blocking_main_thread_task_runner,
|
| + int highp_threshold_min,
|
| + bool use_rgba_4444_texture_format,
|
| + size_t id_allocation_chunk_size) {
|
| + scoped_ptr<ResourceProvider> resource_provider(
|
| + new ResourceProvider(output_surface,
|
| + shared_bitmap_manager,
|
| + gpu_memory_buffer_manager,
|
| + blocking_main_thread_task_runner,
|
| + highp_threshold_min,
|
| + use_rgba_4444_texture_format,
|
| + id_allocation_chunk_size));
|
| +
|
| + if (resource_provider->ContextGL())
|
| + resource_provider->InitializeGL();
|
| + else
|
| + resource_provider->InitializeSoftware();
|
| +
|
| + DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type());
|
| + return resource_provider.Pass();
|
| +}
|
| +
|
| +ResourceProvider::~ResourceProvider() {
|
| + while (!children_.empty())
|
| + DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
|
| + while (!resources_.empty())
|
| + DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
|
| +
|
| + CleanUpGLIfNeeded();
|
| +}
|
| +
|
| +bool ResourceProvider::InUseByConsumer(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + return resource->lock_for_read_count > 0 || resource->exported_count > 0 ||
|
| + resource->lost;
|
| +}
|
| +
|
| +bool ResourceProvider::IsLost(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + return resource->lost;
|
| +}
|
| +
|
| +bool ResourceProvider::AllowOverlay(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + return resource->allow_overlay;
|
| +}
|
| +
|
| +ResourceProvider::ResourceId ResourceProvider::CreateResource(
|
| + const gfx::Size& size,
|
| + GLint wrap_mode,
|
| + TextureHint hint,
|
| + ResourceFormat format) {
|
| + DCHECK(!size.IsEmpty());
|
| + switch (default_resource_type_) {
|
| + case RESOURCE_TYPE_GL_TEXTURE:
|
| + return CreateGLTexture(size,
|
| + GL_TEXTURE_2D,
|
| + GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
|
| + wrap_mode,
|
| + hint,
|
| + format);
|
| + case RESOURCE_TYPE_BITMAP:
|
| + DCHECK_EQ(RGBA_8888, format);
|
| + return CreateBitmap(size, wrap_mode);
|
| + case RESOURCE_TYPE_INVALID:
|
| + break;
|
| + }
|
| +
|
| + LOG(FATAL) << "Invalid default resource type.";
|
| + return 0;
|
| +}
|
| +
|
| +ResourceProvider::ResourceId ResourceProvider::CreateManagedResource(
|
| + const gfx::Size& size,
|
| + GLenum target,
|
| + GLint wrap_mode,
|
| + TextureHint hint,
|
| + ResourceFormat format) {
|
| + DCHECK(!size.IsEmpty());
|
| + switch (default_resource_type_) {
|
| + case RESOURCE_TYPE_GL_TEXTURE:
|
| + return CreateGLTexture(size,
|
| + target,
|
| + GL_TEXTURE_POOL_MANAGED_CHROMIUM,
|
| + wrap_mode,
|
| + hint,
|
| + format);
|
| + case RESOURCE_TYPE_BITMAP:
|
| + DCHECK_EQ(RGBA_8888, format);
|
| + return CreateBitmap(size, wrap_mode);
|
| + case RESOURCE_TYPE_INVALID:
|
| + break;
|
| + }
|
| +
|
| + LOG(FATAL) << "Invalid default resource type.";
|
| + return 0;
|
| +}
|
| +
|
| +ResourceProvider::ResourceId ResourceProvider::CreateGLTexture(
|
| + const gfx::Size& size,
|
| + GLenum target,
|
| + GLenum texture_pool,
|
| + GLint wrap_mode,
|
| + TextureHint hint,
|
| + ResourceFormat format) {
|
| + DCHECK_LE(size.width(), max_texture_size_);
|
| + DCHECK_LE(size.height(), max_texture_size_);
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + ResourceId id = next_id_++;
|
| + Resource resource(0, size, Resource::INTERNAL, target, GL_LINEAR,
|
| + texture_pool, wrap_mode, hint, format);
|
| + resource.allocated = false;
|
| + resources_[id] = resource;
|
| + return id;
|
| +}
|
| +
|
| +ResourceProvider::ResourceId ResourceProvider::CreateBitmap(
|
| + const gfx::Size& size, GLint wrap_mode) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + scoped_ptr<SharedBitmap> bitmap =
|
| + shared_bitmap_manager_->AllocateSharedBitmap(size);
|
| + uint8_t* pixels = bitmap->pixels();
|
| + DCHECK(pixels);
|
| +
|
| + ResourceId id = next_id_++;
|
| + Resource resource(pixels, bitmap.release(), size, Resource::INTERNAL,
|
| + GL_LINEAR, wrap_mode);
|
| + resource.allocated = true;
|
| + resources_[id] = resource;
|
| + return id;
|
| +}
|
| +
|
| +ResourceProvider::ResourceId ResourceProvider::CreateResourceFromIOSurface(
|
| + const gfx::Size& size,
|
| + unsigned io_surface_id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + ResourceId id = next_id_++;
|
| + Resource resource(0, gfx::Size(), Resource::INTERNAL,
|
| + GL_TEXTURE_RECTANGLE_ARB, GL_LINEAR,
|
| + GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE,
|
| + TEXTURE_HINT_IMMUTABLE, RGBA_8888);
|
| + LazyCreate(&resource);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + gl->BindTexture(GL_TEXTURE_RECTANGLE_ARB, resource.gl_id);
|
| + gl->TexImageIOSurface2DCHROMIUM(
|
| + GL_TEXTURE_RECTANGLE_ARB, size.width(), size.height(), io_surface_id, 0);
|
| + resource.allocated = true;
|
| + resources_[id] = resource;
|
| + return id;
|
| +}
|
| +
|
| +ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox(
|
| + const TextureMailbox& mailbox,
|
| + scoped_ptr<SingleReleaseCallbackImpl> release_callback_impl) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + // Just store the information. Mailbox will be consumed in LockForRead().
|
| + ResourceId id = next_id_++;
|
| + DCHECK(mailbox.IsValid());
|
| + Resource& resource = resources_[id];
|
| + if (mailbox.IsTexture()) {
|
| + resource = Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
|
| + mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
|
| + GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888);
|
| + } else {
|
| + DCHECK(mailbox.IsSharedMemory());
|
| + SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
|
| + uint8_t* pixels = shared_bitmap->pixels();
|
| + DCHECK(pixels);
|
| + resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
|
| + Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE);
|
| + }
|
| + resource.allocated = true;
|
| + resource.mailbox = mailbox;
|
| + resource.release_callback_impl =
|
| + base::Bind(&SingleReleaseCallbackImpl::Run,
|
| + base::Owned(release_callback_impl.release()));
|
| + resource.allow_overlay = mailbox.allow_overlay();
|
| + return id;
|
| +}
|
| +
|
| +void ResourceProvider::DeleteResource(ResourceId id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + ResourceMap::iterator it = resources_.find(id);
|
| + CHECK(it != resources_.end());
|
| + Resource* resource = &it->second;
|
| + DCHECK(!resource->marked_for_deletion);
|
| + DCHECK_EQ(resource->imported_count, 0);
|
| + DCHECK(resource->pending_set_pixels || !resource->locked_for_write);
|
| +
|
| + if (resource->exported_count > 0 || resource->lock_for_read_count > 0) {
|
| + resource->marked_for_deletion = true;
|
| + return;
|
| + } else {
|
| + DeleteResourceInternal(it, NORMAL);
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
|
| + DeleteStyle style) {
|
| + TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal");
|
| + Resource* resource = &it->second;
|
| + bool lost_resource = resource->lost;
|
| +
|
| + DCHECK(resource->exported_count == 0 || style != NORMAL);
|
| + if (style == FOR_SHUTDOWN && resource->exported_count > 0)
|
| + lost_resource = true;
|
| +
|
| + if (resource->image_id) {
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
|
| + }
|
| + if (resource->gl_upload_query_id) {
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
|
| + }
|
| + if (resource->gl_read_lock_query_id) {
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id));
|
| + }
|
| + if (resource->gl_pixel_buffer_id) {
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
|
| + }
|
| + if (resource->origin == Resource::EXTERNAL) {
|
| + DCHECK(resource->mailbox.IsValid());
|
| + GLuint sync_point = resource->mailbox.sync_point();
|
| + if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
|
| + DCHECK(resource->mailbox.IsTexture());
|
| + lost_resource |= lost_output_surface_;
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + if (resource->gl_id) {
|
| + GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
|
| + resource->gl_id = 0;
|
| + if (!lost_resource)
|
| + sync_point = gl->InsertSyncPointCHROMIUM();
|
| + }
|
| + } else {
|
| + DCHECK(resource->mailbox.IsSharedMemory());
|
| + resource->shared_bitmap = nullptr;
|
| + resource->pixels = nullptr;
|
| + }
|
| + resource->release_callback_impl.Run(
|
| + sync_point, lost_resource, blocking_main_thread_task_runner_);
|
| + }
|
| + if (resource->gl_id) {
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + GLC(gl, gl->DeleteTextures(1, &resource->gl_id));
|
| + resource->gl_id = 0;
|
| + }
|
| + if (resource->shared_bitmap) {
|
| + DCHECK(resource->origin != Resource::EXTERNAL);
|
| + DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
|
| + delete resource->shared_bitmap;
|
| + resource->pixels = NULL;
|
| + }
|
| + if (resource->pixels) {
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + delete[] resource->pixels;
|
| + resource->pixels = NULL;
|
| + }
|
| + if (resource->gpu_memory_buffer) {
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + delete resource->gpu_memory_buffer;
|
| + resource->gpu_memory_buffer = NULL;
|
| + }
|
| + resources_.erase(it);
|
| +}
|
| +
|
| +ResourceProvider::ResourceType ResourceProvider::GetResourceType(
|
| + ResourceId id) {
|
| + return GetResource(id)->type;
|
| +}
|
| +
|
| +void ResourceProvider::SetPixels(ResourceId id,
|
| + const uint8_t* image,
|
| + const gfx::Rect& image_rect,
|
| + const gfx::Rect& source_rect,
|
| + const gfx::Vector2d& dest_offset) {
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(!resource->locked_for_write);
|
| + DCHECK(!resource->lock_for_read_count);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(ReadLockFenceHasPassed(resource));
|
| + LazyAllocate(resource);
|
| +
|
| + if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
|
| + DCHECK(resource->gl_id);
|
| + DCHECK(!resource->pending_set_pixels);
|
| + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + DCHECK(texture_uploader_.get());
|
| + gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
|
| + texture_uploader_->Upload(image,
|
| + image_rect,
|
| + source_rect,
|
| + dest_offset,
|
| + resource->format,
|
| + resource->size);
|
| + } else {
|
| + DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
|
| + DCHECK(resource->allocated);
|
| + DCHECK_EQ(RGBA_8888, resource->format);
|
| + DCHECK(source_rect.x() >= image_rect.x());
|
| + DCHECK(source_rect.y() >= image_rect.y());
|
| + DCHECK(source_rect.right() <= image_rect.right());
|
| + DCHECK(source_rect.bottom() <= image_rect.bottom());
|
| + SkImageInfo source_info =
|
| + SkImageInfo::MakeN32Premul(source_rect.width(), source_rect.height());
|
| + size_t image_row_bytes = image_rect.width() * 4;
|
| + gfx::Vector2d source_offset = source_rect.origin() - image_rect.origin();
|
| + image += source_offset.y() * image_row_bytes + source_offset.x() * 4;
|
| +
|
| + ScopedWriteLockSoftware lock(this, id);
|
| + SkCanvas dest(lock.sk_bitmap());
|
| + dest.writePixels(source_info, image, image_row_bytes, dest_offset.x(),
|
| + dest_offset.y());
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::CopyToResource(ResourceId id,
|
| + const uint8_t* image,
|
| + const gfx::Size& image_size) {
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(!resource->locked_for_write);
|
| + DCHECK(!resource->lock_for_read_count);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(ReadLockFenceHasPassed(resource));
|
| + LazyAllocate(resource);
|
| +
|
| + DCHECK_EQ(image_size.width(), resource->size.width());
|
| + DCHECK_EQ(image_size.height(), resource->size.height());
|
| +
|
| + if (resource->type == RESOURCE_TYPE_BITMAP) {
|
| + DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
|
| + DCHECK(resource->allocated);
|
| + DCHECK_EQ(RGBA_8888, resource->format);
|
| + SkImageInfo source_info =
|
| + SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
|
| + size_t image_stride = image_size.width() * 4;
|
| +
|
| + ScopedWriteLockSoftware lock(this, id);
|
| + SkCanvas dest(lock.sk_bitmap());
|
| + dest.writePixels(source_info, image, image_stride, 0, 0);
|
| + } else {
|
| + DCHECK(resource->gl_id);
|
| + DCHECK(!resource->pending_set_pixels);
|
| + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + DCHECK(texture_uploader_.get());
|
| + gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
|
| +
|
| + if (resource->format == ETC1) {
|
| + size_t num_bytes = static_cast<size_t>(image_size.width()) *
|
| + image_size.height() * BitsPerPixel(ETC1) / 8;
|
| + gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
|
| + image_size.width(), image_size.height(), 0,
|
| + num_bytes, image);
|
| + } else {
|
| + gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
|
| + image_size.height(), GLDataFormat(resource->format),
|
| + GLDataType(resource->format), image);
|
| + }
|
| + }
|
| +}
|
| +
|
| +size_t ResourceProvider::NumBlockingUploads() {
|
| + if (!texture_uploader_)
|
| + return 0;
|
| +
|
| + return texture_uploader_->NumBlockingUploads();
|
| +}
|
| +
|
| +void ResourceProvider::MarkPendingUploadsAsNonBlocking() {
|
| + if (!texture_uploader_)
|
| + return;
|
| +
|
| + texture_uploader_->MarkPendingUploadsAsNonBlocking();
|
| +}
|
| +
|
| +size_t ResourceProvider::EstimatedUploadsPerTick() {
|
| + if (!texture_uploader_)
|
| + return 1u;
|
| +
|
| + double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond();
|
| + size_t textures_per_tick = floor(
|
| + kTextureUploadTickRate * textures_per_second);
|
| + return textures_per_tick ? textures_per_tick : 1u;
|
| +}
|
| +
|
| +void ResourceProvider::FlushUploads() {
|
| + if (!texture_uploader_)
|
| + return;
|
| +
|
| + texture_uploader_->Flush();
|
| +}
|
| +
|
| +void ResourceProvider::ReleaseCachedData() {
|
| + if (!texture_uploader_)
|
| + return;
|
| +
|
| + texture_uploader_->ReleaseCachedQueries();
|
| +}
|
| +
|
| +base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime(
|
| + size_t uploads_per_tick) {
|
| + if (lost_output_surface_)
|
| + return base::TimeTicks();
|
| +
|
| + // Software resource uploads happen on impl thread, so don't bother batching
|
| + // them up and trying to wait for them to complete.
|
| + if (!texture_uploader_) {
|
| + return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds(
|
| + base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate);
|
| + }
|
| +
|
| + base::TimeDelta upload_one_texture_time =
|
| + base::TimeDelta::FromMicroseconds(
|
| + base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) /
|
| + uploads_per_tick;
|
| +
|
| + size_t total_uploads = NumBlockingUploads() + uploads_per_tick;
|
| + return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads;
|
| +}
|
| +
|
| +ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + ResourceMap::iterator it = resources_.find(id);
|
| + CHECK(it != resources_.end());
|
| + return &it->second;
|
| +}
|
| +
|
| +const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(!resource->locked_for_write ||
|
| + resource->set_pixels_completion_forced) <<
|
| + "locked for write: " << resource->locked_for_write <<
|
| + " pixels completion forced: " << resource->set_pixels_completion_forced;
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + // Uninitialized! Call SetPixels or LockForWrite first.
|
| + DCHECK(resource->allocated);
|
| +
|
| + LazyCreate(resource);
|
| +
|
| + if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
|
| + DCHECK(resource->origin != Resource::INTERNAL);
|
| + DCHECK(resource->mailbox.IsTexture());
|
| +
|
| + // Mailbox sync_points must be processed by a call to
|
| + // WaitSyncPointIfNeeded() prior to calling LockForRead().
|
| + DCHECK(!resource->mailbox.sync_point());
|
| +
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + resource->gl_id =
|
| + GLC(gl, gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.target(),
|
| + resource->mailbox.name()));
|
| + }
|
| +
|
| + if (!resource->pixels && resource->has_shared_bitmap_id &&
|
| + shared_bitmap_manager_) {
|
| + scoped_ptr<SharedBitmap> bitmap =
|
| + shared_bitmap_manager_->GetSharedBitmapFromId(
|
| + resource->size, resource->shared_bitmap_id);
|
| + if (bitmap) {
|
| + resource->shared_bitmap = bitmap.release();
|
| + resource->pixels = resource->shared_bitmap->pixels();
|
| + }
|
| + }
|
| +
|
| + resource->lock_for_read_count++;
|
| + if (resource->read_lock_fences_enabled) {
|
| + if (current_read_lock_fence_.get())
|
| + current_read_lock_fence_->Set();
|
| + resource->read_lock_fence = current_read_lock_fence_;
|
| + }
|
| +
|
| + return resource;
|
| +}
|
| +
|
| +void ResourceProvider::UnlockForRead(ResourceId id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + ResourceMap::iterator it = resources_.find(id);
|
| + CHECK(it != resources_.end());
|
| +
|
| + Resource* resource = &it->second;
|
| + DCHECK_GT(resource->lock_for_read_count, 0);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + resource->lock_for_read_count--;
|
| + if (resource->marked_for_deletion && !resource->lock_for_read_count) {
|
| + if (!resource->child_id) {
|
| + // The resource belongs to this ResourceProvider, so it can be destroyed.
|
| + DeleteResourceInternal(it, NORMAL);
|
| + } else {
|
| + ChildMap::iterator child_it = children_.find(resource->child_id);
|
| + ResourceIdArray unused;
|
| + unused.push_back(id);
|
| + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
|
| + }
|
| + }
|
| +}
|
| +
|
| +ResourceProvider::Resource* ResourceProvider::LockForWrite(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(CanLockForWrite(id));
|
| +
|
| + resource->locked_for_write = true;
|
| + return resource;
|
| +}
|
| +
|
| +bool ResourceProvider::CanLockForWrite(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + return !resource->locked_for_write && !resource->lock_for_read_count &&
|
| + !resource->exported_count && resource->origin == Resource::INTERNAL &&
|
| + !resource->lost && ReadLockFenceHasPassed(resource);
|
| +}
|
| +
|
| +void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
|
| + DCHECK(resource->locked_for_write);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + resource->locked_for_write = false;
|
| +}
|
| +
|
| +ResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id)
|
| + : resource_provider_(resource_provider),
|
| + resource_id_(resource_id),
|
| + texture_id_(resource_provider->LockForRead(resource_id)->gl_id) {
|
| + DCHECK(texture_id_);
|
| +}
|
| +
|
| +ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
|
| + resource_provider_->UnlockForRead(resource_id_);
|
| +}
|
| +
|
| +ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id,
|
| + GLenum filter)
|
| + : ScopedReadLockGL(resource_provider, resource_id),
|
| + unit_(GL_TEXTURE0),
|
| + target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
|
| +}
|
| +
|
| +ResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id,
|
| + GLenum unit,
|
| + GLenum filter)
|
| + : ScopedReadLockGL(resource_provider, resource_id),
|
| + unit_(unit),
|
| + target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {
|
| +}
|
| +
|
| +ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() {
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id)
|
| + : resource_provider_(resource_provider),
|
| + resource_(resource_provider->LockForWrite(resource_id)) {
|
| + resource_provider_->LazyAllocate(resource_);
|
| + texture_id_ = resource_->gl_id;
|
| + DCHECK(texture_id_);
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() {
|
| + resource_provider_->UnlockForWrite(resource_);
|
| +}
|
| +
|
| +void ResourceProvider::PopulateSkBitmapWithResource(
|
| + SkBitmap* sk_bitmap, const Resource* resource) {
|
| + DCHECK_EQ(RGBA_8888, resource->format);
|
| + SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
|
| + resource->size.height());
|
| + sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
|
| +}
|
| +
|
| +ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id)
|
| + : resource_provider_(resource_provider),
|
| + resource_id_(resource_id) {
|
| + const Resource* resource = resource_provider->LockForRead(resource_id);
|
| + wrap_mode_ = resource->wrap_mode;
|
| + ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource);
|
| +}
|
| +
|
| +ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
|
| + resource_provider_->UnlockForRead(resource_id_);
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id)
|
| + : resource_provider_(resource_provider),
|
| + resource_(resource_provider->LockForWrite(resource_id)) {
|
| + ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource_);
|
| + DCHECK(valid());
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + resource_provider_->UnlockForWrite(resource_);
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
|
| + ScopedWriteLockGpuMemoryBuffer(ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id)
|
| + : resource_provider_(resource_provider),
|
| + resource_(resource_provider->LockForWrite(resource_id)),
|
| + gpu_memory_buffer_manager_(resource_provider->gpu_memory_buffer_manager_),
|
| + gpu_memory_buffer_(nullptr),
|
| + size_(resource_->size),
|
| + format_(resource_->format) {
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
|
| + std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockGpuMemoryBuffer::
|
| + ~ScopedWriteLockGpuMemoryBuffer() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + resource_provider_->UnlockForWrite(resource_);
|
| + if (!gpu_memory_buffer_)
|
| + return;
|
| +
|
| + if (!resource_->image_id) {
|
| + GLES2Interface* gl = resource_provider_->ContextGL();
|
| + DCHECK(gl);
|
| +
|
| +#if defined(OS_CHROMEOS)
|
| + // TODO(reveman): GL_COMMANDS_ISSUED_CHROMIUM is used for synchronization
|
| + // on ChromeOS to avoid some performance issues. This only works with
|
| + // shared memory backed buffers. crbug.com/436314
|
| + DCHECK_EQ(gpu_memory_buffer_->GetHandle().type, gfx::SHARED_MEMORY_BUFFER);
|
| +#endif
|
| +
|
| + resource_->image_id =
|
| + gl->CreateImageCHROMIUM(gpu_memory_buffer_->AsClientBuffer(),
|
| + size_.width(),
|
| + size_.height(),
|
| + GL_RGBA);
|
| + }
|
| +
|
| + std::swap(resource_->gpu_memory_buffer, gpu_memory_buffer_);
|
| + resource_->allocated = true;
|
| + resource_->dirty_image = true;
|
| +
|
| + // GpuMemoryBuffer provides direct access to the memory used by the GPU.
|
| + // Read lock fences are required to ensure that we're not trying to map a
|
| + // buffer that is currently in-use by the GPU.
|
| + resource_->read_lock_fences_enabled = true;
|
| +}
|
| +
|
| +gfx::GpuMemoryBuffer*
|
| +ResourceProvider::ScopedWriteLockGpuMemoryBuffer::GetGpuMemoryBuffer() {
|
| + if (!gpu_memory_buffer_) {
|
| + scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer =
|
| + gpu_memory_buffer_manager_->AllocateGpuMemoryBuffer(
|
| + size_, ToGpuMemoryBufferFormat(format_), gfx::GpuMemoryBuffer::MAP);
|
| + gpu_memory_buffer_ = gpu_memory_buffer.release();
|
| + }
|
| +
|
| + return gpu_memory_buffer_;
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
|
| + ResourceProvider* resource_provider,
|
| + ResourceProvider::ResourceId resource_id)
|
| + : resource_provider_(resource_provider),
|
| + resource_(resource_provider->LockForWrite(resource_id)) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + resource_provider_->LazyAllocate(resource_);
|
| +}
|
| +
|
| +ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(resource_->locked_for_write);
|
| + resource_provider_->UnlockForWrite(resource_);
|
| +}
|
| +
|
| +void ResourceProvider::ScopedWriteLockGr::InitSkSurface(
|
| + bool use_worker_context,
|
| + bool use_distance_field_text,
|
| + bool can_use_lcd_text,
|
| + int msaa_sample_count) {
|
| + DCHECK(resource_->locked_for_write);
|
| +
|
| + GrBackendTextureDesc desc;
|
| + desc.fFlags = kRenderTarget_GrBackendTextureFlag;
|
| + desc.fWidth = resource_->size.width();
|
| + desc.fHeight = resource_->size.height();
|
| + desc.fConfig = ToGrPixelConfig(resource_->format);
|
| + desc.fOrigin = kTopLeft_GrSurfaceOrigin;
|
| + desc.fTextureHandle = resource_->gl_id;
|
| + desc.fSampleCnt = msaa_sample_count;
|
| +
|
| + class GrContext* gr_context =
|
| + resource_provider_->GrContext(use_worker_context);
|
| + skia::RefPtr<GrTexture> gr_texture =
|
| + skia::AdoptRef(gr_context->textureProvider()->wrapBackendTexture(desc));
|
| + if (gr_texture) {
|
| + uint32_t flags = use_distance_field_text
|
| + ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
|
| + : 0;
|
| + // Use unknown pixel geometry to disable LCD text.
|
| + SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
|
| + if (can_use_lcd_text) {
|
| + // LegacyFontHost will get LCD text and skia figures out what type to use.
|
| + surface_props =
|
| + SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
|
| + }
|
| + sk_surface_ = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
|
| + gr_texture->asRenderTarget(), &surface_props));
|
| + return;
|
| + }
|
| + sk_surface_.clear();
|
| +}
|
| +
|
| +void ResourceProvider::ScopedWriteLockGr::ReleaseSkSurface() {
|
| + sk_surface_.clear();
|
| +}
|
| +
|
| +ResourceProvider::SynchronousFence::SynchronousFence(
|
| + gpu::gles2::GLES2Interface* gl)
|
| + : gl_(gl), has_synchronized_(true) {
|
| +}
|
| +
|
| +ResourceProvider::SynchronousFence::~SynchronousFence() {
|
| +}
|
| +
|
| +void ResourceProvider::SynchronousFence::Set() {
|
| + has_synchronized_ = false;
|
| +}
|
| +
|
| +bool ResourceProvider::SynchronousFence::HasPassed() {
|
| + if (!has_synchronized_) {
|
| + has_synchronized_ = true;
|
| + Synchronize();
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void ResourceProvider::SynchronousFence::Wait() {
|
| + HasPassed();
|
| +}
|
| +
|
| +void ResourceProvider::SynchronousFence::Synchronize() {
|
| + TRACE_EVENT0("cc", "ResourceProvider::SynchronousFence::Synchronize");
|
| + gl_->Finish();
|
| +}
|
| +
|
| +ResourceProvider::ResourceProvider(
|
| + OutputSurface* output_surface,
|
| + SharedBitmapManager* shared_bitmap_manager,
|
| + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
|
| + BlockingTaskRunner* blocking_main_thread_task_runner,
|
| + int highp_threshold_min,
|
| + bool use_rgba_4444_texture_format,
|
| + size_t id_allocation_chunk_size)
|
| + : output_surface_(output_surface),
|
| + shared_bitmap_manager_(shared_bitmap_manager),
|
| + gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
|
| + blocking_main_thread_task_runner_(blocking_main_thread_task_runner),
|
| + lost_output_surface_(false),
|
| + highp_threshold_min_(highp_threshold_min),
|
| + next_id_(1),
|
| + next_child_(1),
|
| + default_resource_type_(RESOURCE_TYPE_INVALID),
|
| + use_texture_storage_ext_(false),
|
| + use_texture_format_bgra_(false),
|
| + use_texture_usage_hint_(false),
|
| + use_compressed_texture_etc1_(false),
|
| + yuv_resource_format_(LUMINANCE_8),
|
| + max_texture_size_(0),
|
| + best_texture_format_(RGBA_8888),
|
| + use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
|
| + id_allocation_chunk_size_(id_allocation_chunk_size),
|
| + use_sync_query_(false) {
|
| + DCHECK(output_surface_->HasClient());
|
| + DCHECK(id_allocation_chunk_size_);
|
| +}
|
| +
|
| +void ResourceProvider::InitializeSoftware() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_);
|
| +
|
| + CleanUpGLIfNeeded();
|
| +
|
| + default_resource_type_ = RESOURCE_TYPE_BITMAP;
|
| + // Pick an arbitrary limit here similar to what hardware might.
|
| + max_texture_size_ = 16 * 1024;
|
| + best_texture_format_ = RGBA_8888;
|
| +}
|
| +
|
| +void ResourceProvider::InitializeGL() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(!texture_uploader_);
|
| + DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, default_resource_type_);
|
| + DCHECK(!texture_id_allocator_);
|
| + DCHECK(!buffer_id_allocator_);
|
| +
|
| + default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
|
| +
|
| + const ContextProvider::Capabilities& caps =
|
| + output_surface_->context_provider()->ContextCapabilities();
|
| +
|
| + bool use_bgra = caps.gpu.texture_format_bgra8888;
|
| + use_texture_storage_ext_ = caps.gpu.texture_storage;
|
| + use_texture_format_bgra_ = caps.gpu.texture_format_bgra8888;
|
| + use_texture_usage_hint_ = caps.gpu.texture_usage;
|
| + use_compressed_texture_etc1_ = caps.gpu.texture_format_etc1;
|
| + yuv_resource_format_ = caps.gpu.texture_rg ? RED_8 : LUMINANCE_8;
|
| + use_sync_query_ = caps.gpu.sync_query;
|
| +
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| +
|
| + texture_uploader_ = TextureUploader::Create(gl);
|
| + max_texture_size_ = 0; // Context expects cleared value.
|
| + GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_));
|
| + best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra);
|
| +
|
| + texture_id_allocator_.reset(
|
| + new TextureIdAllocator(gl, id_allocation_chunk_size_));
|
| + buffer_id_allocator_.reset(
|
| + new BufferIdAllocator(gl, id_allocation_chunk_size_));
|
| +}
|
| +
|
| +void ResourceProvider::CleanUpGLIfNeeded() {
|
| + GLES2Interface* gl = ContextGL();
|
| + if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
|
| + // We are not in GL mode, but double check before returning.
|
| + DCHECK(!gl);
|
| + DCHECK(!texture_uploader_);
|
| + return;
|
| + }
|
| +
|
| + DCHECK(gl);
|
| +#if DCHECK_IS_ON()
|
| + // Check that all GL resources has been deleted.
|
| + for (ResourceMap::const_iterator itr = resources_.begin();
|
| + itr != resources_.end();
|
| + ++itr) {
|
| + DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
|
| + }
|
| +#endif // DCHECK_IS_ON()
|
| +
|
| + texture_uploader_ = nullptr;
|
| + texture_id_allocator_ = nullptr;
|
| + buffer_id_allocator_ = nullptr;
|
| + gl->Finish();
|
| +}
|
| +
|
| +int ResourceProvider::CreateChild(const ReturnCallback& return_callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + Child child_info;
|
| + child_info.return_callback = return_callback;
|
| +
|
| + int child = next_child_++;
|
| + children_[child] = child_info;
|
| + return child;
|
| +}
|
| +
|
| +void ResourceProvider::DestroyChild(int child_id) {
|
| + ChildMap::iterator it = children_.find(child_id);
|
| + DCHECK(it != children_.end());
|
| + DestroyChildInternal(it, NORMAL);
|
| +}
|
| +
|
| +void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
|
| + DeleteStyle style) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + Child& child = it->second;
|
| + DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
|
| +
|
| + ResourceIdArray resources_for_child;
|
| +
|
| + for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin();
|
| + child_it != child.child_to_parent_map.end();
|
| + ++child_it) {
|
| + ResourceId id = child_it->second;
|
| + resources_for_child.push_back(id);
|
| + }
|
| +
|
| + // If the child is going away, don't consider any resources in use.
|
| + child.in_use_resources.clear();
|
| + child.marked_for_deletion = true;
|
| +
|
| + DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
|
| +}
|
| +
|
| +const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap(
|
| + int child) const {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + ChildMap::const_iterator it = children_.find(child);
|
| + DCHECK(it != children_.end());
|
| + DCHECK(!it->second.marked_for_deletion);
|
| + return it->second.child_to_parent_map;
|
| +}
|
| +
|
| +void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources,
|
| + TransferableResourceArray* list) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + GLES2Interface* gl = ContextGL();
|
| + bool need_sync_point = false;
|
| + for (ResourceIdArray::const_iterator it = resources.begin();
|
| + it != resources.end();
|
| + ++it) {
|
| + TransferableResource resource;
|
| + TransferResource(gl, *it, &resource);
|
| + if (!resource.mailbox_holder.sync_point && !resource.is_software)
|
| + need_sync_point = true;
|
| + ++resources_.find(*it)->second.exported_count;
|
| + list->push_back(resource);
|
| + }
|
| + if (need_sync_point) {
|
| + GLuint sync_point = gl->InsertSyncPointCHROMIUM();
|
| + for (TransferableResourceArray::iterator it = list->begin();
|
| + it != list->end();
|
| + ++it) {
|
| + if (!it->mailbox_holder.sync_point)
|
| + it->mailbox_holder.sync_point = sync_point;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::ReceiveFromChild(
|
| + int child, const TransferableResourceArray& resources) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + GLES2Interface* gl = ContextGL();
|
| + Child& child_info = children_.find(child)->second;
|
| + DCHECK(!child_info.marked_for_deletion);
|
| + for (TransferableResourceArray::const_iterator it = resources.begin();
|
| + it != resources.end();
|
| + ++it) {
|
| + ResourceIdMap::iterator resource_in_map_it =
|
| + child_info.child_to_parent_map.find(it->id);
|
| + if (resource_in_map_it != child_info.child_to_parent_map.end()) {
|
| + Resource& resource = resources_[resource_in_map_it->second];
|
| + resource.marked_for_deletion = false;
|
| + resource.imported_count++;
|
| + continue;
|
| + }
|
| +
|
| + if ((!it->is_software && !gl) ||
|
| + (it->is_software && !shared_bitmap_manager_)) {
|
| + TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid");
|
| + ReturnedResourceArray to_return;
|
| + to_return.push_back(it->ToReturnedResource());
|
| + child_info.return_callback.Run(to_return,
|
| + blocking_main_thread_task_runner_);
|
| + continue;
|
| + }
|
| +
|
| + ResourceId local_id = next_id_++;
|
| + Resource& resource = resources_[local_id];
|
| + if (it->is_software) {
|
| + resource =
|
| + Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
|
| + GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
| + } else {
|
| + resource = Resource(0, it->size, Resource::DELEGATED,
|
| + it->mailbox_holder.texture_target, it->filter, 0,
|
| + it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
|
| + TEXTURE_HINT_IMMUTABLE, it->format);
|
| + resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
|
| + it->mailbox_holder.texture_target,
|
| + it->mailbox_holder.sync_point);
|
| + }
|
| + resource.child_id = child;
|
| + // Don't allocate a texture for a child.
|
| + resource.allocated = true;
|
| + resource.imported_count = 1;
|
| + resource.allow_overlay = it->allow_overlay;
|
| + child_info.parent_to_child_map[local_id] = it->id;
|
| + child_info.child_to_parent_map[it->id] = local_id;
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::DeclareUsedResourcesFromChild(
|
| + int child,
|
| + const ResourceIdArray& resources_from_child) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + ChildMap::iterator child_it = children_.find(child);
|
| + DCHECK(child_it != children_.end());
|
| + Child& child_info = child_it->second;
|
| + DCHECK(!child_info.marked_for_deletion);
|
| + child_info.in_use_resources.clear();
|
| +
|
| + for (size_t i = 0; i < resources_from_child.size(); ++i) {
|
| + ResourceIdMap::iterator it =
|
| + child_info.child_to_parent_map.find(resources_from_child[i]);
|
| + DCHECK(it != child_info.child_to_parent_map.end());
|
| +
|
| + ResourceId local_id = it->second;
|
| + DCHECK(!resources_[local_id].marked_for_deletion);
|
| + child_info.in_use_resources.insert(local_id);
|
| + }
|
| +
|
| + ResourceIdArray unused;
|
| + for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin();
|
| + it != child_info.child_to_parent_map.end();
|
| + ++it) {
|
| + ResourceId local_id = it->second;
|
| + bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0;
|
| + if (!resource_is_in_use)
|
| + unused.push_back(local_id);
|
| + }
|
| + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
|
| +}
|
| +
|
| +// static
|
| +bool ResourceProvider::CompareResourceMapIteratorsByChildId(
|
| + const std::pair<ReturnedResource, ResourceMap::iterator>& a,
|
| + const std::pair<ReturnedResource, ResourceMap::iterator>& b) {
|
| + const ResourceMap::iterator& a_it = a.second;
|
| + const ResourceMap::iterator& b_it = b.second;
|
| + const Resource& a_resource = a_it->second;
|
| + const Resource& b_resource = b_it->second;
|
| + return a_resource.child_id < b_resource.child_id;
|
| +}
|
| +
|
| +void ResourceProvider::ReceiveReturnsFromParent(
|
| + const ReturnedResourceArray& resources) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + GLES2Interface* gl = ContextGL();
|
| +
|
| + int child_id = 0;
|
| + ResourceIdArray resources_for_child;
|
| +
|
| + std::vector<std::pair<ReturnedResource, ResourceMap::iterator>>
|
| + sorted_resources;
|
| +
|
| + for (ReturnedResourceArray::const_iterator it = resources.begin();
|
| + it != resources.end();
|
| + ++it) {
|
| + ResourceId local_id = it->id;
|
| + ResourceMap::iterator map_iterator = resources_.find(local_id);
|
| +
|
| + // Resource was already lost (e.g. it belonged to a child that was
|
| + // destroyed).
|
| + if (map_iterator == resources_.end())
|
| + continue;
|
| +
|
| + sorted_resources.push_back(
|
| + std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator));
|
| + }
|
| +
|
| + std::sort(sorted_resources.begin(),
|
| + sorted_resources.end(),
|
| + CompareResourceMapIteratorsByChildId);
|
| +
|
| + ChildMap::iterator child_it = children_.end();
|
| + for (size_t i = 0; i < sorted_resources.size(); ++i) {
|
| + ReturnedResource& returned = sorted_resources[i].first;
|
| + ResourceMap::iterator& map_iterator = sorted_resources[i].second;
|
| + ResourceId local_id = map_iterator->first;
|
| + Resource* resource = &map_iterator->second;
|
| +
|
| + CHECK_GE(resource->exported_count, returned.count);
|
| + resource->exported_count -= returned.count;
|
| + resource->lost |= returned.lost;
|
| + if (resource->exported_count)
|
| + continue;
|
| +
|
| + // Need to wait for the current read lock fence to pass before we can
|
| + // recycle this resource.
|
| + if (resource->read_lock_fences_enabled) {
|
| + if (current_read_lock_fence_.get())
|
| + current_read_lock_fence_->Set();
|
| + resource->read_lock_fence = current_read_lock_fence_;
|
| + }
|
| +
|
| + if (returned.sync_point) {
|
| + DCHECK(!resource->has_shared_bitmap_id);
|
| + if (resource->origin == Resource::INTERNAL) {
|
| + DCHECK(resource->gl_id);
|
| + GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
|
| + } else {
|
| + DCHECK(!resource->gl_id);
|
| + resource->mailbox.set_sync_point(returned.sync_point);
|
| + }
|
| + }
|
| +
|
| + if (!resource->marked_for_deletion)
|
| + continue;
|
| +
|
| + if (!resource->child_id) {
|
| + // The resource belongs to this ResourceProvider, so it can be destroyed.
|
| + DeleteResourceInternal(map_iterator, NORMAL);
|
| + continue;
|
| + }
|
| +
|
| + DCHECK(resource->origin == Resource::DELEGATED);
|
| + // Delete the resource and return it to the child it came from one.
|
| + if (resource->child_id != child_id) {
|
| + if (child_id) {
|
| + DCHECK_NE(resources_for_child.size(), 0u);
|
| + DCHECK(child_it != children_.end());
|
| + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
|
| + resources_for_child);
|
| + resources_for_child.clear();
|
| + }
|
| +
|
| + child_it = children_.find(resource->child_id);
|
| + DCHECK(child_it != children_.end());
|
| + child_id = resource->child_id;
|
| + }
|
| + resources_for_child.push_back(local_id);
|
| + }
|
| +
|
| + if (child_id) {
|
| + DCHECK_NE(resources_for_child.size(), 0u);
|
| + DCHECK(child_it != children_.end());
|
| + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
|
| + resources_for_child);
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::TransferResource(GLES2Interface* gl,
|
| + ResourceId id,
|
| + TransferableResource* resource) {
|
| + Resource* source = GetResource(id);
|
| + DCHECK(!source->locked_for_write);
|
| + DCHECK(!source->lock_for_read_count);
|
| + DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
|
| + DCHECK(source->allocated);
|
| + resource->id = id;
|
| + resource->format = source->format;
|
| + resource->mailbox_holder.texture_target = source->target;
|
| + resource->filter = source->filter;
|
| + resource->size = source->size;
|
| + resource->is_repeated = (source->wrap_mode == GL_REPEAT);
|
| + resource->allow_overlay = source->allow_overlay;
|
| +
|
| + if (source->type == RESOURCE_TYPE_BITMAP) {
|
| + resource->mailbox_holder.mailbox = source->shared_bitmap_id;
|
| + resource->is_software = true;
|
| + } else if (!source->mailbox.IsValid()) {
|
| + LazyCreate(source);
|
| + DCHECK(source->gl_id);
|
| + DCHECK(source->origin == Resource::INTERNAL);
|
| + if (source->image_id) {
|
| + DCHECK(source->dirty_image);
|
| + BindImageForSampling(source);
|
| + }
|
| + // This is a resource allocated by the compositor, we need to produce it.
|
| + // Don't set a sync point, the caller will do it.
|
| + GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox_holder.mailbox.name));
|
| + GLC(gl, gl->ProduceTextureDirectCHROMIUM(
|
| + source->gl_id, resource->mailbox_holder.texture_target,
|
| + resource->mailbox_holder.mailbox.name));
|
| +
|
| + source->mailbox = TextureMailbox(resource->mailbox_holder);
|
| + } else {
|
| + DCHECK(source->mailbox.IsTexture());
|
| + if (source->image_id && source->dirty_image) {
|
| + DCHECK(source->gl_id);
|
| + DCHECK(source->origin == Resource::INTERNAL);
|
| + GLC(gl,
|
| + gl->BindTexture(resource->mailbox_holder.texture_target,
|
| + source->gl_id));
|
| + BindImageForSampling(source);
|
| + }
|
| + // This is either an external resource, or a compositor resource that we
|
| + // already exported. Make sure to forward the sync point that we were given.
|
| + resource->mailbox_holder.mailbox = source->mailbox.mailbox();
|
| + resource->mailbox_holder.texture_target = source->mailbox.target();
|
| + resource->mailbox_holder.sync_point = source->mailbox.sync_point();
|
| + source->mailbox.set_sync_point(0);
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::DeleteAndReturnUnusedResourcesToChild(
|
| + ChildMap::iterator child_it,
|
| + DeleteStyle style,
|
| + const ResourceIdArray& unused) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(child_it != children_.end());
|
| + Child* child_info = &child_it->second;
|
| +
|
| + if (unused.empty() && !child_info->marked_for_deletion)
|
| + return;
|
| +
|
| + ReturnedResourceArray to_return;
|
| +
|
| + GLES2Interface* gl = ContextGL();
|
| + bool need_sync_point = false;
|
| + for (size_t i = 0; i < unused.size(); ++i) {
|
| + ResourceId local_id = unused[i];
|
| +
|
| + ResourceMap::iterator it = resources_.find(local_id);
|
| + CHECK(it != resources_.end());
|
| + Resource& resource = it->second;
|
| +
|
| + DCHECK(!resource.locked_for_write);
|
| + DCHECK_EQ(0u, child_info->in_use_resources.count(local_id));
|
| + DCHECK(child_info->parent_to_child_map.count(local_id));
|
| +
|
| + ResourceId child_id = child_info->parent_to_child_map[local_id];
|
| + DCHECK(child_info->child_to_parent_map.count(child_id));
|
| +
|
| + bool is_lost =
|
| + resource.lost ||
|
| + (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
|
| + if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
|
| + if (style != FOR_SHUTDOWN) {
|
| + // Defer this until we receive the resource back from the parent or
|
| + // the read lock is released.
|
| + resource.marked_for_deletion = true;
|
| + continue;
|
| + }
|
| +
|
| + // We still have an exported_count, so we'll have to lose it.
|
| + is_lost = true;
|
| + }
|
| +
|
| + if (gl && resource.filter != resource.original_filter) {
|
| + DCHECK(resource.target);
|
| + DCHECK(resource.gl_id);
|
| +
|
| + GLC(gl, gl->BindTexture(resource.target, resource.gl_id));
|
| + GLC(gl,
|
| + gl->TexParameteri(resource.target,
|
| + GL_TEXTURE_MIN_FILTER,
|
| + resource.original_filter));
|
| + GLC(gl,
|
| + gl->TexParameteri(resource.target,
|
| + GL_TEXTURE_MAG_FILTER,
|
| + resource.original_filter));
|
| + }
|
| +
|
| + ReturnedResource returned;
|
| + returned.id = child_id;
|
| + returned.sync_point = resource.mailbox.sync_point();
|
| + if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
|
| + need_sync_point = true;
|
| + returned.count = resource.imported_count;
|
| + returned.lost = is_lost;
|
| + to_return.push_back(returned);
|
| +
|
| + child_info->parent_to_child_map.erase(local_id);
|
| + child_info->child_to_parent_map.erase(child_id);
|
| + resource.imported_count = 0;
|
| + DeleteResourceInternal(it, style);
|
| + }
|
| + if (need_sync_point) {
|
| + DCHECK(gl);
|
| + GLuint sync_point = gl->InsertSyncPointCHROMIUM();
|
| + for (size_t i = 0; i < to_return.size(); ++i) {
|
| + if (!to_return[i].sync_point)
|
| + to_return[i].sync_point = sync_point;
|
| + }
|
| + }
|
| +
|
| + if (!to_return.empty())
|
| + child_info->return_callback.Run(to_return,
|
| + blocking_main_thread_task_runner_);
|
| +
|
| + if (child_info->marked_for_deletion &&
|
| + child_info->parent_to_child_map.empty()) {
|
| + DCHECK(child_info->child_to_parent_map.empty());
|
| + children_.erase(child_it);
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::AcquirePixelBuffer(ResourceId id) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::AcquirePixelBuffer");
|
| +
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(!resource->image_id);
|
| + DCHECK_NE(ETC1, resource->format);
|
| +
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + if (!resource->gl_pixel_buffer_id)
|
| + resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId();
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
|
| + resource->gl_pixel_buffer_id);
|
| + unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8;
|
| + gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
|
| + resource->size.height() *
|
| + RoundUp(bytes_per_pixel * resource->size.width(), 4u),
|
| + NULL,
|
| + GL_DYNAMIC_DRAW);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
| +}
|
| +
|
| +void ResourceProvider::ReleasePixelBuffer(ResourceId id) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::ReleasePixelBuffer");
|
| +
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(!resource->image_id);
|
| +
|
| + // The pixel buffer can be released while there is a pending "set pixels"
|
| + // if completion has been forced. Any shared memory associated with this
|
| + // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM
|
| + // command has been processed on the service side. It is also safe to
|
| + // reuse any query id associated with this resource before they complete
|
| + // as each new query has a unique submit count.
|
| + if (resource->pending_set_pixels) {
|
| + DCHECK(resource->set_pixels_completion_forced);
|
| + resource->pending_set_pixels = false;
|
| + resource->locked_for_write = false;
|
| + }
|
| +
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
|
| + if (!resource->gl_pixel_buffer_id)
|
| + return;
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
|
| + resource->gl_pixel_buffer_id);
|
| + gl->BufferData(
|
| + GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
| +}
|
| +
|
| +uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id, int* stride) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::MapPixelBuffer");
|
| +
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(!resource->image_id);
|
| +
|
| + *stride = 0;
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + DCHECK(resource->gl_pixel_buffer_id);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
|
| + resource->gl_pixel_buffer_id);
|
| + uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
|
| + GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY));
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
| + // Buffer is required to be 4-byte aligned.
|
| + CHECK(!(reinterpret_cast<intptr_t>(image) & 3));
|
| + return image;
|
| +}
|
| +
|
| +void ResourceProvider::UnmapPixelBuffer(ResourceId id) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::UnmapPixelBuffer");
|
| +
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(!resource->image_id);
|
| +
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + DCHECK(resource->gl_pixel_buffer_id);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
|
| + resource->gl_pixel_buffer_id);
|
| + gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
| +}
|
| +
|
| +GLenum ResourceProvider::BindForSampling(ResourceId resource_id,
|
| + GLenum unit,
|
| + GLenum filter) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + GLES2Interface* gl = ContextGL();
|
| + ResourceMap::iterator it = resources_.find(resource_id);
|
| + DCHECK(it != resources_.end());
|
| + Resource* resource = &it->second;
|
| + DCHECK(resource->lock_for_read_count);
|
| + DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced);
|
| +
|
| + ScopedSetActiveTexture scoped_active_tex(gl, unit);
|
| + GLenum target = resource->target;
|
| + GLC(gl, gl->BindTexture(target, resource->gl_id));
|
| + if (filter != resource->filter) {
|
| + GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter));
|
| + GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter));
|
| + resource->filter = filter;
|
| + }
|
| +
|
| + if (resource->image_id && resource->dirty_image)
|
| + BindImageForSampling(resource);
|
| +
|
| + return target;
|
| +}
|
| +
|
| +void ResourceProvider::BeginSetPixels(ResourceId id) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::BeginSetPixels");
|
| +
|
| + Resource* resource = GetResource(id);
|
| + DCHECK(!resource->pending_set_pixels);
|
| +
|
| + LazyCreate(resource);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK(resource->gl_id || resource->allocated);
|
| + DCHECK(ReadLockFenceHasPassed(resource));
|
| + DCHECK(!resource->image_id);
|
| +
|
| + bool allocate = !resource->allocated;
|
| + resource->allocated = true;
|
| + LockForWrite(id);
|
| +
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
|
| + DCHECK(resource->gl_id);
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + DCHECK(resource->gl_pixel_buffer_id);
|
| + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
|
| + gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM,
|
| + resource->gl_pixel_buffer_id);
|
| + if (!resource->gl_upload_query_id)
|
| + gl->GenQueriesEXT(1, &resource->gl_upload_query_id);
|
| + gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM,
|
| + resource->gl_upload_query_id);
|
| + if (allocate) {
|
| + gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D,
|
| + 0, /* level */
|
| + GLInternalFormat(resource->format),
|
| + resource->size.width(),
|
| + resource->size.height(),
|
| + 0, /* border */
|
| + GLDataFormat(resource->format),
|
| + GLDataType(resource->format),
|
| + NULL);
|
| + } else {
|
| + gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D,
|
| + 0, /* level */
|
| + 0, /* x */
|
| + 0, /* y */
|
| + resource->size.width(),
|
| + resource->size.height(),
|
| + GLDataFormat(resource->format),
|
| + GLDataType(resource->format),
|
| + NULL);
|
| + }
|
| + gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM);
|
| + gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0);
|
| +
|
| + resource->pending_set_pixels = true;
|
| + resource->set_pixels_completion_forced = false;
|
| +}
|
| +
|
| +void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::ForceSetPixelsToComplete");
|
| +
|
| + Resource* resource = GetResource(id);
|
| +
|
| + DCHECK(resource->locked_for_write);
|
| + DCHECK(resource->pending_set_pixels);
|
| + DCHECK(!resource->set_pixels_completion_forced);
|
| +
|
| + if (resource->gl_id) {
|
| + GLES2Interface* gl = ContextGL();
|
| + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
|
| + GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D));
|
| + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0));
|
| + }
|
| +
|
| + resource->set_pixels_completion_forced = true;
|
| +}
|
| +
|
| +bool ResourceProvider::DidSetPixelsComplete(ResourceId id) {
|
| + TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
|
| + "ResourceProvider::DidSetPixelsComplete");
|
| +
|
| + Resource* resource = GetResource(id);
|
| +
|
| + DCHECK(resource->locked_for_write);
|
| + DCHECK(resource->pending_set_pixels);
|
| +
|
| + if (resource->gl_id) {
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + DCHECK(resource->gl_upload_query_id);
|
| + GLuint complete = 1;
|
| + gl->GetQueryObjectuivEXT(
|
| + resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete);
|
| + if (!complete)
|
| + return false;
|
| + }
|
| +
|
| + resource->pending_set_pixels = false;
|
| + UnlockForWrite(resource);
|
| +
|
| + // Async set pixels commands are not necessarily processed in-sequence with
|
| + // drawing commands. Read lock fences are required to ensure that async
|
| + // commands don't access the resource while used for drawing.
|
| + resource->read_lock_fences_enabled = true;
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void ResourceProvider::CreateForTesting(ResourceId id) {
|
| + LazyCreate(GetResource(id));
|
| +}
|
| +
|
| +GLenum ResourceProvider::TargetForTesting(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + return resource->target;
|
| +}
|
| +
|
| +void ResourceProvider::LazyCreate(Resource* resource) {
|
| + if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
|
| + resource->origin != Resource::INTERNAL)
|
| + return;
|
| +
|
| + if (resource->gl_id)
|
| + return;
|
| +
|
| + DCHECK(resource->texture_pool);
|
| + DCHECK(resource->origin == Resource::INTERNAL);
|
| + DCHECK(!resource->mailbox.IsValid());
|
| + resource->gl_id = texture_id_allocator_->NextId();
|
| +
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| +
|
| + // Create and set texture properties. Allocation is delayed until needed.
|
| + GLC(gl, gl->BindTexture(resource->target, resource->gl_id));
|
| + GLC(gl,
|
| + gl->TexParameteri(
|
| + resource->target, GL_TEXTURE_MIN_FILTER, resource->original_filter));
|
| + GLC(gl,
|
| + gl->TexParameteri(
|
| + resource->target, GL_TEXTURE_MAG_FILTER, resource->original_filter));
|
| + GLC(gl,
|
| + gl->TexParameteri(
|
| + resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode));
|
| + GLC(gl,
|
| + gl->TexParameteri(
|
| + resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode));
|
| + GLC(gl,
|
| + gl->TexParameteri(
|
| + resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool));
|
| + if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
|
| + GLC(gl,
|
| + gl->TexParameteri(resource->target,
|
| + GL_TEXTURE_USAGE_ANGLE,
|
| + GL_FRAMEBUFFER_ATTACHMENT_ANGLE));
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::AllocateForTesting(ResourceId id) {
|
| + LazyAllocate(GetResource(id));
|
| +}
|
| +
|
| +void ResourceProvider::LazyAllocate(Resource* resource) {
|
| + DCHECK(resource);
|
| + if (resource->allocated)
|
| + return;
|
| + LazyCreate(resource);
|
| + if (!resource->gl_id)
|
| + return;
|
| + resource->allocated = true;
|
| + GLES2Interface* gl = ContextGL();
|
| + gfx::Size& size = resource->size;
|
| + DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
|
| + ResourceFormat format = resource->format;
|
| + GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
|
| + if (use_texture_storage_ext_ &&
|
| + IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
|
| + (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
|
| + GLenum storage_format = TextureToStorageFormat(format);
|
| + GLC(gl,
|
| + gl->TexStorage2DEXT(
|
| + GL_TEXTURE_2D, 1, storage_format, size.width(), size.height()));
|
| + } else {
|
| + // ETC1 does not support preallocation.
|
| + if (format != ETC1) {
|
| + GLC(gl,
|
| + gl->TexImage2D(GL_TEXTURE_2D,
|
| + 0,
|
| + GLInternalFormat(format),
|
| + size.width(),
|
| + size.height(),
|
| + 0,
|
| + GLDataFormat(format),
|
| + GLDataType(format),
|
| + NULL));
|
| + }
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::BindImageForSampling(Resource* resource) {
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(resource->gl_id);
|
| + DCHECK(resource->image_id);
|
| +
|
| + // Release image currently bound to texture.
|
| + if (resource->bound_image_id)
|
| + gl->ReleaseTexImage2DCHROMIUM(resource->target, resource->bound_image_id);
|
| + gl->BindTexImage2DCHROMIUM(resource->target, resource->image_id);
|
| + resource->bound_image_id = resource->image_id;
|
| + resource->dirty_image = false;
|
| +}
|
| +
|
| +void ResourceProvider::CopyResource(ResourceId source_id, ResourceId dest_id) {
|
| + TRACE_EVENT0("cc", "ResourceProvider::CopyResource");
|
| +
|
| + Resource* source_resource = GetResource(source_id);
|
| + DCHECK(!source_resource->lock_for_read_count);
|
| + DCHECK(source_resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(source_resource->exported_count, 0);
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
|
| + DCHECK(source_resource->allocated);
|
| + LazyCreate(source_resource);
|
| +
|
| + Resource* dest_resource = GetResource(dest_id);
|
| + DCHECK(!dest_resource->locked_for_write);
|
| + DCHECK(!dest_resource->lock_for_read_count);
|
| + DCHECK(dest_resource->origin == Resource::INTERNAL);
|
| + DCHECK_EQ(dest_resource->exported_count, 0);
|
| + DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
|
| + LazyAllocate(dest_resource);
|
| +
|
| + DCHECK_EQ(source_resource->type, dest_resource->type);
|
| + DCHECK_EQ(source_resource->format, dest_resource->format);
|
| + DCHECK(source_resource->size == dest_resource->size);
|
| +
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + if (source_resource->image_id && source_resource->dirty_image) {
|
| + gl->BindTexture(source_resource->target, source_resource->gl_id);
|
| + BindImageForSampling(source_resource);
|
| + }
|
| + if (use_sync_query_) {
|
| + if (!source_resource->gl_read_lock_query_id)
|
| + gl->GenQueriesEXT(1, &source_resource->gl_read_lock_query_id);
|
| +#if defined(OS_CHROMEOS)
|
| + // TODO(reveman): This avoids a performance problem on some ChromeOS
|
| + // devices. This needs to be removed to support native GpuMemoryBuffer
|
| + // implementations. crbug.com/436314
|
| + gl->BeginQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM,
|
| + source_resource->gl_read_lock_query_id);
|
| +#else
|
| + gl->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM,
|
| + source_resource->gl_read_lock_query_id);
|
| +#endif
|
| + }
|
| + DCHECK(!dest_resource->image_id);
|
| + dest_resource->allocated = true;
|
| + gl->CopySubTextureCHROMIUM(dest_resource->target, source_resource->gl_id,
|
| + dest_resource->gl_id, 0, 0);
|
| + if (source_resource->gl_read_lock_query_id) {
|
| + // End query and create a read lock fence that will prevent access to
|
| +// source resource until CopySubTextureCHROMIUM command has completed.
|
| +#if defined(OS_CHROMEOS)
|
| + gl->EndQueryEXT(GL_COMMANDS_ISSUED_CHROMIUM);
|
| +#else
|
| + gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
|
| +#endif
|
| + source_resource->read_lock_fence = make_scoped_refptr(
|
| + new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
|
| + } else {
|
| + // Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
|
| + // Try to use one synchronous fence for as many CopyResource operations as
|
| + // possible as that reduce the number of times we have to synchronize with
|
| + // the GL.
|
| + if (!synchronous_fence_.get() || synchronous_fence_->has_synchronized())
|
| + synchronous_fence_ = make_scoped_refptr(new SynchronousFence(gl));
|
| + source_resource->read_lock_fence = synchronous_fence_;
|
| + source_resource->read_lock_fence->Set();
|
| + }
|
| +}
|
| +
|
| +void ResourceProvider::WaitSyncPointIfNeeded(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + DCHECK(resource->allocated);
|
| + if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
|
| + return;
|
| + if (!resource->mailbox.sync_point())
|
| + return;
|
| + DCHECK(resource->mailbox.IsValid());
|
| + GLES2Interface* gl = ContextGL();
|
| + DCHECK(gl);
|
| + GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point()));
|
| + resource->mailbox.set_sync_point(0);
|
| +}
|
| +
|
| +void ResourceProvider::WaitReadLockIfNeeded(ResourceId id) {
|
| + Resource* resource = GetResource(id);
|
| + DCHECK_EQ(resource->exported_count, 0);
|
| + if (!resource->read_lock_fence.get())
|
| + return;
|
| +
|
| + resource->read_lock_fence->Wait();
|
| +}
|
| +
|
| +GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) {
|
| + GLint active_unit = 0;
|
| + gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
|
| + return active_unit;
|
| +}
|
| +
|
| +GLES2Interface* ResourceProvider::ContextGL() const {
|
| + ContextProvider* context_provider = output_surface_->context_provider();
|
| + return context_provider ? context_provider->ContextGL() : NULL;
|
| +}
|
| +
|
| +class GrContext* ResourceProvider::GrContext(bool worker_context) const {
|
| + ContextProvider* context_provider =
|
| + worker_context ? output_surface_->worker_context_provider()
|
| + : output_surface_->context_provider();
|
| + return context_provider ? context_provider->GrContext() : NULL;
|
| +}
|
| +
|
| +} // namespace cc
|
|
|