Chromium Code Reviews| Index: cc/raster/gpu_raster_buffer_provider.cc |
| diff --git a/cc/raster/gpu_raster_buffer_provider.cc b/cc/raster/gpu_raster_buffer_provider.cc |
| index 6e5b4c472a0db7c62290e3a1279d9a34da77404b..0b1516b995b8e6ddb045a8c1143c66c9ace160c5 100644 |
| --- a/cc/raster/gpu_raster_buffer_provider.cc |
| +++ b/cc/raster/gpu_raster_buffer_provider.cc |
| @@ -12,7 +12,6 @@ |
| #include "base/memory/ptr_util.h" |
| #include "base/trace_event/trace_event.h" |
| #include "cc/playback/raster_source.h" |
| -#include "cc/raster/gpu_rasterizer.h" |
| #include "cc/raster/scoped_gpu_raster.h" |
| #include "cc/resources/resource.h" |
| #include "gpu/command_buffer/client/gles2_interface.h" |
| @@ -24,89 +23,121 @@ |
| namespace cc { |
| namespace { |
| -class RasterBufferImpl : public RasterBuffer { |
| - public: |
| - RasterBufferImpl(GpuRasterizer* rasterizer, |
| - const Resource* resource, |
| - uint64_t resource_content_id, |
| - uint64_t previous_content_id) |
| - : rasterizer_(rasterizer), |
| - lock_(rasterizer->resource_provider(), resource->id()), |
| - resource_has_previous_content_( |
| - resource_content_id && resource_content_id == previous_content_id) { |
| +static sk_sp<SkPicture> PlaybackToPicture( |
| + const RasterSource* raster_source, |
| + bool resource_has_previous_content, |
| + const gfx::Size& resource_size, |
| + const gfx::Rect& raster_full_rect, |
| + const gfx::Rect& raster_dirty_rect, |
| + float scale, |
| + const RasterSource::PlaybackSettings& playback_settings) { |
| + // GPU raster doesn't do low res tiles, so should always include images. |
| + DCHECK(!playback_settings.skip_images); |
| + |
| + gfx::Rect playback_rect = raster_full_rect; |
| + if (resource_has_previous_content) { |
| + playback_rect.Intersect(raster_dirty_rect); |
| } |
| + DCHECK(!playback_rect.IsEmpty()) |
| + << "Why are we rastering a tile that's not dirty?"; |
| + |
| + // Play back raster_source into temp SkPicture. |
| + SkPictureRecorder recorder; |
| + const int flags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag; |
| + sk_sp<SkCanvas> canvas = sk_ref_sp(recorder.beginRecording( |
| + resource_size.width(), resource_size.height(), NULL, flags)); |
| + canvas->save(); |
| + raster_source->PlaybackToCanvas(canvas.get(), raster_full_rect, playback_rect, |
| + scale, playback_settings); |
| + canvas->restore(); |
| + return recorder.finishRecordingAsPicture(); |
| +} |
| - // Overridden from RasterBuffer: |
| - void Playback( |
| - const RasterSource* raster_source, |
| - const gfx::Rect& raster_full_rect, |
| - const gfx::Rect& raster_dirty_rect, |
| - uint64_t new_content_id, |
| - float scale, |
| - const RasterSource::PlaybackSettings& playback_settings) override { |
| - TRACE_EVENT0("cc", "GpuRasterBuffer::Playback"); |
| - // GPU raster doesn't do low res tiles, so should always include images. |
| - DCHECK(!playback_settings.skip_images); |
| - |
| - ContextProvider::ScopedContextLock scoped_context( |
| - rasterizer_->worker_context_provider()); |
| - |
| - gfx::Rect playback_rect = raster_full_rect; |
| - if (resource_has_previous_content_) { |
| - playback_rect.Intersect(raster_dirty_rect); |
| - } |
| - DCHECK(!playback_rect.IsEmpty()) |
| - << "Why are we rastering a tile that's not dirty?"; |
| - |
| - // TODO(danakj): Implement partial raster with raster_dirty_rect. |
| - // Rasterize source into resource. |
| - rasterizer_->RasterizeSource(&lock_, raster_source, raster_full_rect, |
| - playback_rect, scale, playback_settings); |
| - |
| - gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); |
| - const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); |
| - |
| - // Barrier to sync worker context output to cc context. |
| - gl->OrderingBarrierCHROMIUM(); |
| - |
| - // Generate sync token after the barrier for cross context synchronization. |
| - gpu::SyncToken sync_token; |
| - gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); |
| - lock_.UpdateResourceSyncToken(sync_token); |
| - } |
| +static void RasterizePicture(SkPicture* picture, |
| + ContextProvider* context_provider, |
| + ResourceProvider::ScopedWriteLockGL* resource_lock, |
| + bool async_worker_context_enabled, |
| + bool use_distance_field_text, |
| + bool can_use_lcd_text, |
| + int msaa_sample_count) { |
| + ScopedGpuRaster gpu_raster(context_provider); |
| + |
| + ResourceProvider::ScopedSkSurfaceProvider scoped_surface( |
| + context_provider, resource_lock, async_worker_context_enabled, |
| + use_distance_field_text, can_use_lcd_text, msaa_sample_count); |
| + SkSurface* sk_surface = scoped_surface.sk_surface(); |
| + // Allocating an SkSurface will fail after a lost context. Pretend we |
| + // rasterized, as the contents of the resource don't matter anymore. |
| + if (!sk_surface) |
| + return; |
| + |
| + SkMultiPictureDraw multi_picture_draw; |
| + multi_picture_draw.add(sk_surface->getCanvas(), picture); |
| + multi_picture_draw.draw(false); |
| +} |
| - private: |
| - GpuRasterizer* rasterizer_; |
| - ResourceProvider::ScopedWriteLockGr lock_; |
| - bool resource_has_previous_content_; |
| +} // namespace |
| - DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl); |
| -}; |
| +GpuRasterBufferProvider::RasterBufferImpl::RasterBufferImpl( |
| + GpuRasterBufferProvider* client, |
| + ResourceProvider* resource_provider, |
| + ResourceId resource_id, |
| + bool async_worker_context_enabled, |
| + bool resource_has_previous_content) |
| + : client_(client), |
| + lock_(resource_provider, resource_id, async_worker_context_enabled), |
| + resource_has_previous_content_(resource_has_previous_content) { |
| + client_->pending_raster_buffers_.insert(this); |
| +} |
| -} // namespace |
| +GpuRasterBufferProvider::RasterBufferImpl::~RasterBufferImpl() { |
| + client_->pending_raster_buffers_.erase(this); |
| +} |
| + |
| +void GpuRasterBufferProvider::RasterBufferImpl::Playback( |
| + const RasterSource* raster_source, |
| + const gfx::Rect& raster_full_rect, |
| + const gfx::Rect& raster_dirty_rect, |
| + uint64_t new_content_id, |
| + float scale, |
| + const RasterSource::PlaybackSettings& playback_settings) { |
| + TRACE_EVENT0("cc", "GpuRasterBuffer::Playback"); |
| + client_->PlaybackOnWorkerThread(&lock_, sync_token_, |
| + resource_has_previous_content_, raster_source, |
| + raster_full_rect, raster_dirty_rect, |
| + new_content_id, scale, playback_settings); |
| +} |
| GpuRasterBufferProvider::GpuRasterBufferProvider( |
| ContextProvider* compositor_context_provider, |
| ContextProvider* worker_context_provider, |
| ResourceProvider* resource_provider, |
| bool use_distance_field_text, |
| - int gpu_rasterization_msaa_sample_count) |
| + int gpu_rasterization_msaa_sample_count, |
| + bool async_worker_context_enabled) |
| : compositor_context_provider_(compositor_context_provider), |
| - rasterizer_(new GpuRasterizer(worker_context_provider, |
| - resource_provider, |
| - use_distance_field_text, |
| - gpu_rasterization_msaa_sample_count)) { |
| - DCHECK(compositor_context_provider_); |
| + worker_context_provider_(worker_context_provider), |
| + resource_provider_(resource_provider), |
| + use_distance_field_text_(use_distance_field_text), |
| + msaa_sample_count_(gpu_rasterization_msaa_sample_count), |
| + async_worker_context_enabled_(async_worker_context_enabled) { |
| + DCHECK(compositor_context_provider); |
| + DCHECK(worker_context_provider); |
| } |
| -GpuRasterBufferProvider::~GpuRasterBufferProvider() {} |
| +GpuRasterBufferProvider::~GpuRasterBufferProvider() { |
| + DCHECK(pending_raster_buffers_.empty()); |
| +} |
| std::unique_ptr<RasterBuffer> GpuRasterBufferProvider::AcquireBufferForRaster( |
| const Resource* resource, |
| uint64_t resource_content_id, |
| uint64_t previous_content_id) { |
| - return std::unique_ptr<RasterBuffer>(new RasterBufferImpl( |
| - rasterizer_.get(), resource, resource_content_id, previous_content_id)); |
| + bool resource_has_previous_content = |
| + resource_content_id && resource_content_id == previous_content_id; |
| + return base::WrapUnique(new RasterBufferImpl( |
| + this, resource_provider_, resource->id(), async_worker_context_enabled_, |
| + resource_has_previous_content)); |
| } |
| void GpuRasterBufferProvider::ReleaseBufferForRaster( |
| @@ -116,12 +147,25 @@ void GpuRasterBufferProvider::ReleaseBufferForRaster( |
| void GpuRasterBufferProvider::OrderingBarrier() { |
| TRACE_EVENT0("cc", "GpuRasterBufferProvider::OrderingBarrier"); |
| - compositor_context_provider_->ContextGL()->OrderingBarrierCHROMIUM(); |
| + |
| + gpu::gles2::GLES2Interface* gl = compositor_context_provider_->ContextGL(); |
| + GLuint64 fence = gl->InsertFenceSyncCHROMIUM(); |
| + gl->OrderingBarrierCHROMIUM(); |
| + |
| + gpu::SyncToken sync_token; |
| + gl->GenUnverifiedSyncTokenCHROMIUM(fence, sync_token.GetData()); |
| + |
| + DCHECK(sync_token.HasData() || |
| + gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR); |
| + |
| + for (RasterBufferImpl* buffer : pending_raster_buffers_) |
| + buffer->set_sync_token(sync_token); |
| + pending_raster_buffers_.clear(); |
| } |
| ResourceFormat GpuRasterBufferProvider::GetResourceFormat( |
| bool must_support_alpha) const { |
| - return rasterizer_->resource_provider()->best_render_buffer_format(); |
| + return resource_provider_->best_render_buffer_format(); |
| } |
| bool GpuRasterBufferProvider::GetResourceRequiresSwizzle( |
| @@ -130,6 +174,57 @@ bool GpuRasterBufferProvider::GetResourceRequiresSwizzle( |
| return false; |
| } |
| -void GpuRasterBufferProvider::Shutdown() {} |
| +void GpuRasterBufferProvider::Shutdown() { |
| + pending_raster_buffers_.clear(); |
| +} |
| + |
| +void GpuRasterBufferProvider::PlaybackOnWorkerThread( |
| + ResourceProvider::ScopedWriteLockGL* resource_lock, |
| + const gpu::SyncToken& sync_token, |
| + bool resource_has_previous_content, |
| + const RasterSource* raster_source, |
| + const gfx::Rect& raster_full_rect, |
| + const gfx::Rect& raster_dirty_rect, |
| + uint64_t new_content_id, |
| + float scale, |
| + const RasterSource::PlaybackSettings& playback_settings) { |
| + ContextProvider::ScopedContextLock scoped_context(worker_context_provider_); |
| + gpu::gles2::GLES2Interface* gl = scoped_context.ContextGL(); |
| + DCHECK(gl); |
| + |
| + // Early out if sync token is invalid. This happens when the context is lost |
| + // before ScheduleTasks was called. |
| + if (!sync_token.HasData()) { |
| + DCHECK(gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR); |
|
piman
2016/06/21 01:45:35
Because they're not in the same share group, it's
sunnyps
2016/06/21 01:57:39
Removed the DCHECK.
|
| + return; |
| + } |
| + |
| + // Synchronize with compositor. |
| + gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); |
| + |
| + sk_sp<SkPicture> picture = PlaybackToPicture( |
| + raster_source, resource_has_previous_content, resource_lock->size(), |
| + raster_full_rect, raster_dirty_rect, scale, playback_settings); |
| + |
| + // Turn on distance fields for layers that have ever animated. |
| + bool use_distance_field_text = |
| + use_distance_field_text_ || |
| + raster_source->ShouldAttemptToUseDistanceFieldText(); |
| + |
| + RasterizePicture(picture.get(), worker_context_provider_, resource_lock, |
| + async_worker_context_enabled_, use_distance_field_text, |
| + raster_source->CanUseLCDText(), msaa_sample_count_); |
| + |
| + const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); |
| + |
| + // Barrier to sync worker context output to cc context. |
| + gl->OrderingBarrierCHROMIUM(); |
| + |
| + // Generate sync token after the barrier for cross context synchronization. |
| + gpu::SyncToken resource_sync_token; |
| + gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, resource_sync_token.GetData()); |
| + resource_lock->set_sync_token(resource_sync_token); |
| + resource_lock->set_synchronized(!async_worker_context_enabled_); |
| +} |
| } // namespace cc |