1 // Copyright 2017 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 "third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.h"
6 #include "gpu/GLES2/gl2extchromium.h"
7 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
10 #include "third_party/blink/renderer/platform/graphics/graphics_types_3d.h"
11 #include "third_party/blink/renderer/platform/graphics/image.h"
12 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
13 
14 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
15 
16 namespace blink {
17 
GpuMemoryBufferImageCopy(gpu::gles2::GLES2Interface * gl)18 GpuMemoryBufferImageCopy::GpuMemoryBufferImageCopy(
19     gpu::gles2::GLES2Interface* gl)
20     : gl_(gl) {}
21 
~GpuMemoryBufferImageCopy()22 GpuMemoryBufferImageCopy::~GpuMemoryBufferImageCopy() {}
23 
EnsureMemoryBuffer(int width,int height)24 bool GpuMemoryBufferImageCopy::EnsureMemoryBuffer(int width, int height) {
25   // Create a new memorybuffer if the size has changed, or we don't have one.
26   if (last_width_ != width || last_height_ != height || !gpu_memory_buffer_) {
27     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager =
28         Platform::Current()->GetGpuMemoryBufferManager();
29     if (!gpu_memory_buffer_manager)
30       return false;
31 
32     gpu_memory_buffer_ = gpu_memory_buffer_manager->CreateGpuMemoryBuffer(
33         gfx::Size(width, height), gfx::BufferFormat::RGBA_8888,
34         gfx::BufferUsage::SCANOUT, gpu::kNullSurfaceHandle);
35     if (!gpu_memory_buffer_)
36       return false;
37 
38     last_width_ = width;
39     last_height_ = height;
40   }
41   return true;
42 }
43 
CopyImage(Image * image)44 gfx::GpuMemoryBuffer* GpuMemoryBufferImageCopy::CopyImage(Image* image) {
45   if (!image)
46     return nullptr;
47 
48   TRACE_EVENT0("gpu", "GpuMemoryBufferImageCopy::CopyImage");
49 
50   int width = image->width();
51   int height = image->height();
52   if (!EnsureMemoryBuffer(width, height))
53     return nullptr;
54 
55   // Bind the write framebuffer to our memory buffer.
56   GLuint image_id = gl_->CreateImageCHROMIUM(
57       gpu_memory_buffer_->AsClientBuffer(), width, height, GL_RGBA);
58   if (!image_id)
59     return nullptr;
60   GLuint dest_texture_id;
61   gl_->GenTextures(1, &dest_texture_id);
62   GLenum target = GL_TEXTURE_2D;
63   {
64     gl_->BindTexture(target, dest_texture_id);
65     gl_->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
66     gl_->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
67     gl_->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
68     gl_->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
69     gl_->BindTexImage2DCHROMIUM(target, image_id);
70   }
71   gl_->BindTexture(GL_TEXTURE_2D, 0);
72 
73   // Bind the read framebuffer to our image.
74   StaticBitmapImage* static_image = static_cast<StaticBitmapImage*>(image);
75   auto mailbox_holder = static_image->GetMailboxHolder();
76 
77   // Not strictly necessary since we are on the same context, but keeping
78   // for cleanliness and in case we ever move off the same context.
79   gl_->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetData());
80 
81   GLuint source_texture_id;
82   if (mailbox_holder.mailbox.IsSharedImage()) {
83     source_texture_id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM(
84         mailbox_holder.mailbox.name);
85     gl_->BeginSharedImageAccessDirectCHROMIUM(
86         source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
87   } else {
88     source_texture_id =
89         gl_->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
90   }
91 
92   gl_->BindTexture(GL_TEXTURE_2D, 0);
93 
94   gl_->CopySubTextureCHROMIUM(source_texture_id, 0, GL_TEXTURE_2D,
95                               dest_texture_id, 0, 0, 0, 0, 0, width, height,
96                               false, false, false);
97 
98   // Cleanup the read framebuffer, associated image and texture.
99   gl_->BindTexture(GL_TEXTURE_2D, 0);
100   if (mailbox_holder.mailbox.IsSharedImage())
101     gl_->EndSharedImageAccessDirectCHROMIUM(source_texture_id);
102   gl_->DeleteTextures(1, &source_texture_id);
103 
104   gpu::SyncToken copy_done_sync_token;
105   gl_->GenSyncTokenCHROMIUM(copy_done_sync_token.GetData());
106   static_image->UpdateSyncToken(copy_done_sync_token);
107 
108   // Cleanup the draw framebuffer, associated image and texture.
109   gl_->BindTexture(target, dest_texture_id);
110   gl_->ReleaseTexImage2DCHROMIUM(target, image_id);
111   gl_->DestroyImageCHROMIUM(image_id);
112   gl_->DeleteTextures(1, &dest_texture_id);
113   gl_->BindTexture(target, 0);
114 
115   gl_->ShallowFlushCHROMIUM();
116   return gpu_memory_buffer_.get();
117 }
118 
119 }  // namespace blink
120