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