blob: 00925bfa33379c9d681242b6882362ad8abb2ed9 [file] [log] [blame]
// Copyright 2017 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 "third_party/blink/renderer/platform/graphics/gpu_memory_buffer_image_copy.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/platform/graphics/graphics_types_3d.h"
#include "third_party/blink/renderer/platform/graphics/image.h"
#include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
namespace blink {
GpuMemoryBufferImageCopy::GpuMemoryBufferImageCopy(
gpu::gles2::GLES2Interface* gl)
: gl_(gl) {}
GpuMemoryBufferImageCopy::~GpuMemoryBufferImageCopy() {}
bool GpuMemoryBufferImageCopy::EnsureMemoryBuffer(int width, int height) {
// Create a new memorybuffer if the size has changed, or we don't have one.
if (last_width_ != width || last_height_ != height || !gpu_memory_buffer_) {
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager =
Platform::Current()->GetGpuMemoryBufferManager();
if (!gpu_memory_buffer_manager)
return false;
gpu_memory_buffer_ = gpu_memory_buffer_manager->CreateGpuMemoryBuffer(
gfx::Size(width, height), gfx::BufferFormat::RGBA_8888,
gfx::BufferUsage::SCANOUT, gpu::kNullSurfaceHandle);
if (!gpu_memory_buffer_)
return false;
last_width_ = width;
last_height_ = height;
}
return true;
}
gfx::GpuMemoryBuffer* GpuMemoryBufferImageCopy::CopyImage(Image* image) {
if (!image)
return nullptr;
TRACE_EVENT0("gpu", "GpuMemoryBufferImageCopy::CopyImage");
int width = image->width();
int height = image->height();
if (!EnsureMemoryBuffer(width, height))
return nullptr;
// Bind the write framebuffer to our memory buffer.
GLuint image_id = gl_->CreateImageCHROMIUM(
gpu_memory_buffer_->AsClientBuffer(), width, height, GL_RGBA);
if (!image_id)
return nullptr;
GLuint dest_texture_id;
gl_->GenTextures(1, &dest_texture_id);
GLenum target = GL_TEXTURE_2D;
{
gl_->BindTexture(target, dest_texture_id);
gl_->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl_->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
gl_->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl_->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl_->BindTexImage2DCHROMIUM(target, image_id);
}
gl_->BindTexture(GL_TEXTURE_2D, 0);
// Bind the read framebuffer to our image.
StaticBitmapImage* static_image = static_cast<StaticBitmapImage*>(image);
auto mailbox_holder = static_image->GetMailboxHolder();
// Not strictly necessary since we are on the same context, but keeping
// for cleanliness and in case we ever move off the same context.
gl_->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetData());
GLuint source_texture_id;
if (mailbox_holder.mailbox.IsSharedImage()) {
source_texture_id = gl_->CreateAndTexStorage2DSharedImageCHROMIUM(
mailbox_holder.mailbox.name);
gl_->BeginSharedImageAccessDirectCHROMIUM(
source_texture_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
} else {
source_texture_id =
gl_->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
}
gl_->BindTexture(GL_TEXTURE_2D, 0);
gl_->CopySubTextureCHROMIUM(source_texture_id, 0, GL_TEXTURE_2D,
dest_texture_id, 0, 0, 0, 0, 0, width, height,
false, false, false);
// Cleanup the read framebuffer, associated image and texture.
gl_->BindTexture(GL_TEXTURE_2D, 0);
if (mailbox_holder.mailbox.IsSharedImage())
gl_->EndSharedImageAccessDirectCHROMIUM(source_texture_id);
gl_->DeleteTextures(1, &source_texture_id);
gpu::SyncToken copy_done_sync_token;
gl_->GenSyncTokenCHROMIUM(copy_done_sync_token.GetData());
static_image->UpdateSyncToken(copy_done_sync_token);
// Cleanup the draw framebuffer, associated image and texture.
gl_->BindTexture(target, dest_texture_id);
gl_->ReleaseTexImage2DCHROMIUM(target, image_id);
gl_->DestroyImageCHROMIUM(image_id);
gl_->DeleteTextures(1, &dest_texture_id);
gl_->BindTexture(target, 0);
gl_->ShallowFlushCHROMIUM();
return gpu_memory_buffer_.get();
}
} // namespace blink