prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "cc/raster/zero_copy_raster_buffer_provider.h" |
| 6 | |
| 7 | #include <stdint.h> |
| 8 | |
| 9 | #include <algorithm> |
| 10 | |
| 11 | #include "base/macros.h" |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 12 | #include "base/trace_event/trace_event.h" |
| 13 | #include "base/trace_event/trace_event_argument.h" |
Xu Xing | c101c86 | 2017-08-24 17:26:45 | [diff] [blame] | 14 | #include "cc/resources/layer_tree_resource_provider.h" |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 15 | #include "cc/resources/resource_pool.h" |
| 16 | #include "components/viz/common/gpu/context_provider.h" |
Fady Samuel | 555c8d1 | 2017-07-07 23:14:09 | [diff] [blame] | 17 | #include "components/viz/common/resources/platform_color.h" |
danakj | bf124ca | 2018-01-04 16:35:51 | [diff] [blame] | 18 | #include "components/viz/common/resources/resource_format_utils.h" |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 19 | #include "gpu/command_buffer/client/gles2_interface.h" |
| 20 | #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" |
| 21 | #include "gpu/command_buffer/common/gpu_memory_buffer_support.h" |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 22 | #include "ui/gfx/buffer_format_util.h" |
| 23 | #include "ui/gfx/gpu_memory_buffer.h" |
| 24 | |
| 25 | namespace cc { |
| 26 | namespace { |
| 27 | |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 28 | constexpr static auto kBufferUsage = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE; |
| 29 | |
| 30 | // Subclass for InUsePoolResource that holds ownership of a zero-copy backing |
| 31 | // and does cleanup of the backing when destroyed. |
| 32 | class ZeroCopyGpuBacking : public ResourcePool::GpuBacking { |
| 33 | public: |
| 34 | ~ZeroCopyGpuBacking() override { |
| 35 | gpu::gles2::GLES2Interface* gl = compositor_context_provider->ContextGL(); |
| 36 | if (returned_sync_token.HasData()) |
| 37 | gl->WaitSyncTokenCHROMIUM(returned_sync_token.GetConstData()); |
| 38 | if (texture_id) |
| 39 | gl->DeleteTextures(1, &texture_id); |
| 40 | if (image_id) |
| 41 | gl->DestroyImageCHROMIUM(image_id); |
| 42 | } |
| 43 | |
| 44 | base::trace_event::MemoryAllocatorDumpGuid MemoryDumpGuid( |
| 45 | uint64_t tracing_process_id) override { |
| 46 | if (!gpu_memory_buffer) |
| 47 | return {}; |
| 48 | return gpu_memory_buffer->GetGUIDForTracing(tracing_process_id); |
| 49 | } |
| 50 | |
| 51 | base::UnguessableToken SharedMemoryGuid() override { |
danakj | 2c201ec3 | 2018-02-08 18:25:36 | [diff] [blame] | 52 | if (!gpu_memory_buffer) |
| 53 | return {}; |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 54 | return gpu_memory_buffer->GetHandle().handle.GetGUID(); |
| 55 | } |
| 56 | |
| 57 | // The ContextProvider used to clean up the texture and image ids. |
| 58 | viz::ContextProvider* compositor_context_provider = nullptr; |
| 59 | // The backing for zero-copy gpu resources. The |texture_id| is bound to |
| 60 | // this. |
| 61 | std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer; |
| 62 | // The texture id bound to the GpuMemoryBuffer. |
| 63 | uint32_t texture_id = 0; |
| 64 | // The image id that associates the |gpu_memory_buffer| and the |
| 65 | // |texture_id|. |
| 66 | uint32_t image_id = 0; |
| 67 | }; |
| 68 | |
| 69 | // RasterBuffer for the zero copy upload, which is given to the raster worker |
| 70 | // threads for raster/upload. |
Daniel Bratell | 1bddcb33 | 2017-11-21 11:08:29 | [diff] [blame] | 71 | class ZeroCopyRasterBufferImpl : public RasterBuffer { |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 72 | public: |
danakj | 4e871d8 | 2018-01-18 21:56:57 | [diff] [blame] | 73 | ZeroCopyRasterBufferImpl( |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 74 | viz::ContextProvider* context_provider, |
| 75 | gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, |
| 76 | const ResourcePool::InUsePoolResource& in_use_resource, |
| 77 | ZeroCopyGpuBacking* backing) |
| 78 | : backing_(backing), |
| 79 | gpu_memory_buffer_manager_(gpu_memory_buffer_manager), |
danakj | 4e871d8 | 2018-01-18 21:56:57 | [diff] [blame] | 80 | resource_size_(in_use_resource.size()), |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 81 | resource_format_(in_use_resource.format()), |
| 82 | resource_color_space_(in_use_resource.color_space()), |
| 83 | gpu_memory_buffer_(std::move(backing_->gpu_memory_buffer)) {} |
| 84 | |
| 85 | ~ZeroCopyRasterBufferImpl() override { |
| 86 | // This is destroyed on the compositor thread when raster is complete, but |
| 87 | // before the backing is prepared for export to the display compositor. So |
| 88 | // we can set up the texture and SyncToken here. |
| 89 | // TODO(danakj): This could be done with the worker context in Playback. Do |
| 90 | // we need to do things in IsResourceReadyToDraw() and OrderingBarrier then? |
| 91 | gpu::gles2::GLES2Interface* gl = |
| 92 | backing_->compositor_context_provider->ContextGL(); |
| 93 | const gpu::Capabilities& caps = |
| 94 | backing_->compositor_context_provider->ContextCapabilities(); |
| 95 | |
| 96 | if (backing_->returned_sync_token.HasData()) { |
| 97 | gl->WaitSyncTokenCHROMIUM(backing_->returned_sync_token.GetConstData()); |
| 98 | backing_->returned_sync_token = gpu::SyncToken(); |
| 99 | } |
| 100 | |
| 101 | if (!backing_->texture_id) { |
| 102 | // Make a texture and a mailbox for export of the GpuMemoryBuffer to the |
| 103 | // display compositor. |
| 104 | gl->GenTextures(1, &backing_->texture_id); |
| 105 | backing_->texture_target = gpu::GetBufferTextureTarget( |
| 106 | kBufferUsage, viz::BufferFormat(resource_format_), caps); |
| 107 | backing_->mailbox = gpu::Mailbox::Generate(); |
| 108 | gl->ProduceTextureDirectCHROMIUM(backing_->texture_id, |
| 109 | backing_->mailbox.name); |
danakj | af3170e | 2018-02-09 17:31:58 | [diff] [blame] | 110 | backing_->overlay_candidate = true; |
danakj | 63c438c | 2018-02-20 23:51:44 | [diff] [blame] | 111 | // This RasterBufferProvider will modify the resource outside of the |
| 112 | // GL command stream. So resources should not become available for reuse |
| 113 | // until they are not in use by the gpu anymore, which a fence is used to |
| 114 | // determine. |
| 115 | backing_->wait_on_fence_required = true; |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 116 | |
| 117 | gl->BindTexture(backing_->texture_target, backing_->texture_id); |
| 118 | gl->TexParameteri(backing_->texture_target, GL_TEXTURE_MIN_FILTER, |
| 119 | GL_LINEAR); |
| 120 | gl->TexParameteri(backing_->texture_target, GL_TEXTURE_MAG_FILTER, |
| 121 | GL_LINEAR); |
| 122 | gl->TexParameteri(backing_->texture_target, GL_TEXTURE_WRAP_S, |
| 123 | GL_CLAMP_TO_EDGE); |
| 124 | gl->TexParameteri(backing_->texture_target, GL_TEXTURE_WRAP_T, |
| 125 | GL_CLAMP_TO_EDGE); |
| 126 | } else { |
| 127 | gl->BindTexture(backing_->texture_target, backing_->texture_id); |
| 128 | } |
| 129 | |
| 130 | if (!backing_->image_id) { |
| 131 | // If GpuMemoryBuffer allocation failed (https://crbug.com/554541), then |
| 132 | // we don't have anything to give to the display compositor, but also no |
| 133 | // way to report an error, so we just make a texture but don't bind |
| 134 | // anything to it.. |
| 135 | if (gpu_memory_buffer_) { |
| 136 | backing_->image_id = gl->CreateImageCHROMIUM( |
| 137 | gpu_memory_buffer_->AsClientBuffer(), resource_size_.width(), |
| 138 | resource_size_.height(), viz::GLInternalFormat(resource_format_)); |
| 139 | gl->BindTexImage2DCHROMIUM(backing_->texture_target, |
| 140 | backing_->image_id); |
| 141 | } |
| 142 | } else { |
| 143 | gl->ReleaseTexImage2DCHROMIUM(backing_->texture_target, |
| 144 | backing_->image_id); |
| 145 | gl->BindTexImage2DCHROMIUM(backing_->texture_target, backing_->image_id); |
| 146 | } |
| 147 | gl->BindTexture(backing_->texture_target, 0); |
| 148 | |
| 149 | backing_->mailbox_sync_token = |
| 150 | LayerTreeResourceProvider::GenerateSyncTokenHelper(gl); |
| 151 | backing_->gpu_memory_buffer = std::move(gpu_memory_buffer_); |
| 152 | } |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 153 | |
| 154 | // Overridden from RasterBuffer: |
| 155 | void Playback( |
| 156 | const RasterSource* raster_source, |
| 157 | const gfx::Rect& raster_full_rect, |
| 158 | const gfx::Rect& raster_dirty_rect, |
| 159 | uint64_t new_content_id, |
trchen | 178ac91 | 2017-04-04 10:11:10 | [diff] [blame] | 160 | const gfx::AxisTransform2d& transform, |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 161 | const RasterSource::PlaybackSettings& playback_settings) override { |
prashant.n | 60e135b0 | 2016-06-08 04:12:23 | [diff] [blame] | 162 | TRACE_EVENT0("cc", "ZeroCopyRasterBuffer::Playback"); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 163 | |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 164 | if (!gpu_memory_buffer_) { |
| 165 | gpu_memory_buffer_ = gpu_memory_buffer_manager_->CreateGpuMemoryBuffer( |
| 166 | resource_size_, viz::BufferFormat(resource_format_), kBufferUsage, |
| 167 | gpu::kNullSurfaceHandle); |
| 168 | // GpuMemoryBuffer allocation can fail (https://crbug.com/554541). |
| 169 | if (!gpu_memory_buffer_) |
| 170 | return; |
Christopher Cameron | 3cf3eea | 2018-04-03 23:49:55 | [diff] [blame] | 171 | gpu_memory_buffer_->SetColorSpace(resource_color_space_); |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | DCHECK_EQ(1u, gfx::NumberOfPlanesForBufferFormat( |
| 175 | gpu_memory_buffer_->GetFormat())); |
| 176 | bool rv = gpu_memory_buffer_->Map(); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 177 | DCHECK(rv); |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 178 | DCHECK(gpu_memory_buffer_->memory(0)); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 179 | // RasterBufferProvider::PlaybackToMemory only supports unsigned strides. |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 180 | DCHECK_GE(gpu_memory_buffer_->stride(0), 0); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 181 | |
| 182 | // TODO(danakj): Implement partial raster with raster_dirty_rect. |
| 183 | RasterBufferProvider::PlaybackToMemory( |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 184 | gpu_memory_buffer_->memory(0), resource_format_, resource_size_, |
| 185 | gpu_memory_buffer_->stride(0), raster_source, raster_full_rect, |
danakj | a32578c | 2018-04-25 21:18:36 | [diff] [blame^] | 186 | raster_full_rect, transform, resource_color_space_, |
| 187 | /*gpu_compositing=*/true, playback_settings); |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 188 | gpu_memory_buffer_->Unmap(); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | private: |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 192 | // This field may only be used on the compositor thread. |
| 193 | ZeroCopyGpuBacking* backing_; |
| 194 | |
| 195 | // These fields are for use on the worker thread. |
| 196 | gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_; |
danakj | 4e871d8 | 2018-01-18 21:56:57 | [diff] [blame] | 197 | gfx::Size resource_size_; |
| 198 | viz::ResourceFormat resource_format_; |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 199 | gfx::ColorSpace resource_color_space_; |
| 200 | std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_; |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 201 | |
Daniel Bratell | 1bddcb33 | 2017-11-21 11:08:29 | [diff] [blame] | 202 | DISALLOW_COPY_AND_ASSIGN(ZeroCopyRasterBufferImpl); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 203 | }; |
| 204 | |
| 205 | } // namespace |
| 206 | |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 207 | ZeroCopyRasterBufferProvider::ZeroCopyRasterBufferProvider( |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 208 | gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, |
| 209 | viz::ContextProvider* compositor_context_provider, |
danakj | a32578c | 2018-04-25 21:18:36 | [diff] [blame^] | 210 | viz::ResourceFormat tile_format) |
| 211 | : gpu_memory_buffer_manager_(gpu_memory_buffer_manager), |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 212 | compositor_context_provider_(compositor_context_provider), |
danakj | a32578c | 2018-04-25 21:18:36 | [diff] [blame^] | 213 | tile_format_(tile_format) {} |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 214 | |
Chris Watkins | f635329 | 2017-12-04 02:36:05 | [diff] [blame] | 215 | ZeroCopyRasterBufferProvider::~ZeroCopyRasterBufferProvider() = default; |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 216 | |
| 217 | std::unique_ptr<RasterBuffer> |
| 218 | ZeroCopyRasterBufferProvider::AcquireBufferForRaster( |
danakj | 4e871d8 | 2018-01-18 21:56:57 | [diff] [blame] | 219 | const ResourcePool::InUsePoolResource& resource, |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 220 | uint64_t resource_content_id, |
| 221 | uint64_t previous_content_id) { |
danakj | bd63605 | 2018-02-06 18:28:49 | [diff] [blame] | 222 | if (!resource.gpu_backing()) { |
| 223 | auto backing = std::make_unique<ZeroCopyGpuBacking>(); |
| 224 | backing->compositor_context_provider = compositor_context_provider_; |
| 225 | resource.set_gpu_backing(std::move(backing)); |
| 226 | } |
| 227 | ZeroCopyGpuBacking* backing = |
| 228 | static_cast<ZeroCopyGpuBacking*>(resource.gpu_backing()); |
| 229 | |
| 230 | return std::make_unique<ZeroCopyRasterBufferImpl>( |
| 231 | compositor_context_provider_, gpu_memory_buffer_manager_, resource, |
| 232 | backing); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 233 | } |
| 234 | |
Sunny Sachanandani | 5f5419e2 | 2017-05-12 20:35:30 | [diff] [blame] | 235 | void ZeroCopyRasterBufferProvider::Flush() {} |
| 236 | |
danakj | a32578c | 2018-04-25 21:18:36 | [diff] [blame^] | 237 | viz::ResourceFormat ZeroCopyRasterBufferProvider::GetResourceFormat() const { |
| 238 | return tile_format_; |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 239 | } |
| 240 | |
danakj | a32578c | 2018-04-25 21:18:36 | [diff] [blame^] | 241 | bool ZeroCopyRasterBufferProvider::IsResourceSwizzleRequired() const { |
| 242 | return !viz::PlatformColor::SameComponentOrder(GetResourceFormat()); |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 243 | } |
| 244 | |
danakj | a32578c | 2018-04-25 21:18:36 | [diff] [blame^] | 245 | bool ZeroCopyRasterBufferProvider::IsResourcePremultiplied() const { |
Eric Karl | 247f09c | 2018-03-15 02:06:36 | [diff] [blame] | 246 | return true; |
| 247 | } |
| 248 | |
ericrk | 5ac42f32 | 2016-07-14 01:06:51 | [diff] [blame] | 249 | bool ZeroCopyRasterBufferProvider::CanPartialRasterIntoProvidedResource() |
| 250 | const { |
ericrk | eeda5899 | 2016-07-07 02:34:27 | [diff] [blame] | 251 | return false; |
| 252 | } |
| 253 | |
ericrk | 7f6a27f | 2017-01-31 22:34:32 | [diff] [blame] | 254 | bool ZeroCopyRasterBufferProvider::IsResourceReadyToDraw( |
danakj | 4e871d8 | 2018-01-18 21:56:57 | [diff] [blame] | 255 | const ResourcePool::InUsePoolResource& resource) const { |
ericrk | 7f6a27f | 2017-01-31 22:34:32 | [diff] [blame] | 256 | // Zero-copy resources are immediately ready to draw. |
| 257 | return true; |
| 258 | } |
| 259 | |
| 260 | uint64_t ZeroCopyRasterBufferProvider::SetReadyToDrawCallback( |
danakj | 4e871d8 | 2018-01-18 21:56:57 | [diff] [blame] | 261 | const std::vector<const ResourcePool::InUsePoolResource*>& resources, |
ericrk | 7f6a27f | 2017-01-31 22:34:32 | [diff] [blame] | 262 | const base::Closure& callback, |
| 263 | uint64_t pending_callback_id) const { |
| 264 | // Zero-copy resources are immediately ready to draw. |
| 265 | return 0; |
| 266 | } |
| 267 | |
prashant.n | b4d4f49 | 2016-04-29 12:51:28 | [diff] [blame] | 268 | void ZeroCopyRasterBufferProvider::Shutdown() {} |
| 269 | |
| 270 | } // namespace cc |