Commit 5371a41d authored by xidachen's avatar xidachen Committed by Commit bot

Implement commit for unaccelerated canvas with GPU compositing

This CL implements OffscreenCanvas2d's commit API in the case where the
canvas is not GPU-accelerated, but the compositor is. In this case, we
extract a StaticBitmapImage from the imageBuffer, upload the CPU memory
that the StaticBitmapImage holds to GPU texture, and prepare a
CompositorFrame from the GPU texture.

A GPU pixel test is added to test this code path.

BUG=563852
TBR=kbr@chromium.org
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel;master.tryserver.chromium.android:android_optional_gpu_tests_rel

Review-Url: https://codereview.chromium.org/2376743002
Cr-Commit-Position: refs/heads/master@{#422927}
parent 84af4a12
......@@ -34,6 +34,8 @@ class PixelExpectations(GpuTestExpectations):
# TODO(xlai) check / generate reference images.
self.Fail('Pixel_OffscreenCanvasUnaccelerated2D', bug=563852)
self.Fail('Pixel_OffscreenCanvasUnaccelerated2DWorker', bug=563858)
self.Fail('Pixel_OffscreenCanvasUnaccelerated2DGPUCompositing', bug=563852)
self.Fail('Pixel_OffscreenCanvasUnaccelerated2DGPUCompositingWorker', bug=563858)
# TODO(kbr): flakily timing out on this configuration.
self.Flaky('*', ['linux', 'intel', 'debug'], bug=648369)
......@@ -193,6 +193,20 @@ def ExperimentalCanvasFeaturesPages(base_name):
test_rect=[0, 0, 350, 350],
revision=1,
browser_args=browser_args + unaccelerated_args),
PixelTestPage(
'pixel_offscreenCanvas_2d_commit_main.html',
base_name + '_OffscreenCanvasUnaccelerated2DGPUCompositing',
test_rect=[0, 0, 350, 350],
revision=1,
browser_args=browser_args + ['--disable-accelerated-2d-canvas']),
PixelTestPage(
'pixel_offscreenCanvas_2d_commit_worker.html',
base_name + '_OffscreenCanvasUnaccelerated2DGPUCompositingWorker',
test_rect=[0, 0, 350, 350],
revision=1,
browser_args=browser_args + ['--disable-accelerated-2d-canvas']),
]
......
......@@ -11,16 +11,23 @@
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/texture_draw_quad.h"
#include "cc/resources/returned_resource.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/graphics/gpu/SharedGpuContext.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "public/platform/InterfaceProvider.h"
#include "public/platform/Platform.h"
#include "public/platform/WebGraphicsContext3DProvider.h"
#include "public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom-blink.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"
#include "wtf/typed_arrays/ArrayBuffer.h"
#include "wtf/typed_arrays/Uint8Array.h"
namespace blink {
......@@ -44,6 +51,103 @@ OffscreenCanvasFrameDispatcherImpl::OffscreenCanvasFrameDispatcherImpl(
mojo::GetProxy(&m_sink));
}
// Case 1: both canvas and compositor are not gpu accelerated.
void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceInMemory(
cc::TransferableResource& resource,
RefPtr<StaticBitmapImage> image) {
std::unique_ptr<cc::SharedBitmap> bitmap =
Platform::current()->allocateSharedBitmap(IntSize(m_width, m_height));
if (!bitmap)
return;
unsigned char* pixels = bitmap->pixels();
DCHECK(pixels);
SkImageInfo imageInfo = SkImageInfo::Make(
m_width, m_height, kN32_SkColorType,
image->isPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
// TODO(xlai): Optimize to avoid copying pixels. See crbug.com/651456.
image->imageForCurrentFrame()->readPixels(imageInfo, pixels,
imageInfo.minRowBytes(), 0, 0);
resource.mailbox_holder.mailbox = bitmap->id();
resource.mailbox_holder.texture_target = 0;
resource.is_software = true;
// Hold ref to |bitmap|, to keep it alive until the browser ReturnResources.
// It guarantees that the shared bitmap is not re-used or deleted.
m_sharedBitmaps.add(m_nextResourceId, std::move(bitmap));
}
// Case 2: canvas is not gpu-accelerated, but compositor is
void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceMemoryToTexture(
cc::TransferableResource& resource,
RefPtr<StaticBitmapImage> image) {
// TODO(crbug.com/652707): When committing the first frame, there is no
// instance of SharedGpuContext yet, calling SharedGpuContext::gl() will
// trigger a creation of an instace, which requires to create a
// WebGraphicsContext3DProvider. This process is quite expensive, because
// WebGraphicsContext3DProvider can only be constructed on the main thread,
// and bind to the worker thread if commit() is called on worker. In the
// subsequent frame, we should already have a SharedGpuContext, then getting
// the gl interface should not be expensive.
gpu::gles2::GLES2Interface* gl = SharedGpuContext::gl();
SkImageInfo info = SkImageInfo::Make(
m_width, m_height, kN32_SkColorType,
image->isPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
RefPtr<ArrayBuffer> dstBuffer =
ArrayBuffer::createOrNull(m_width * m_height, info.bytesPerPixel());
// If it fails to create a buffer for copying the pixel data, then exit early.
if (!dstBuffer)
return;
RefPtr<Uint8Array> dstPixels =
Uint8Array::create(dstBuffer, 0, dstBuffer->byteLength());
image->imageForCurrentFrame()->readPixels(info, dstPixels->data(),
info.minRowBytes(), 0, 0);
GLuint textureId = 0u;
gl->GenTextures(1, &textureId);
gl->BindTexture(GL_TEXTURE_2D, textureId);
GLenum format =
(kN32_SkColorType == kRGBA_8888_SkColorType) ? GL_RGBA : GL_BGRA_EXT;
gl->TexImage2D(GL_TEXTURE_2D, 0, format, m_width, m_height, 0, format,
GL_UNSIGNED_BYTE, 0);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// The pixel data will be uploaded to GPU memory, we have to keep the GPU
// memory alive until browser ReturnResources, so here we put textureId for
// that piece of GPU memory into a hashmap.
m_cachedTextureIds.add(m_nextResourceId, textureId);
gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, format,
GL_UNSIGNED_BYTE, dstPixels->data());
gpu::Mailbox mailbox;
gl->GenMailboxCHROMIUM(mailbox.name);
gl->ProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
const GLuint64 fenceSync = gl->InsertFenceSyncCHROMIUM();
gl->ShallowFlushCHROMIUM();
gpu::SyncToken syncToken;
gl->GenSyncTokenCHROMIUM(fenceSync, syncToken.GetData());
resource.mailbox_holder =
gpu::MailboxHolder(mailbox, syncToken, GL_TEXTURE_2D);
resource.read_lock_fences_enabled = false;
resource.is_software = false;
}
// Case 3: both canvas and compositor are gpu accelerated.
void OffscreenCanvasFrameDispatcherImpl::setTransferableResourceInTexture(
cc::TransferableResource& resource,
RefPtr<StaticBitmapImage> image) {
image->ensureMailbox();
resource.mailbox_holder = gpu::MailboxHolder(
image->getMailbox(), image->getSyncToken(), GL_TEXTURE_2D);
resource.read_lock_fences_enabled = false;
resource.is_software = false;
// Hold ref to |image|, to keep it alive until the browser ReturnResources.
// It guarantees that the resource is not re-used or deleted.
m_cachedImages.add(m_nextResourceId, std::move(image));
}
void OffscreenCanvasFrameDispatcherImpl::dispatchFrame(
RefPtr<StaticBitmapImage> image) {
if (!image)
......@@ -66,42 +170,23 @@ void OffscreenCanvasFrameDispatcherImpl::dispatchFrame(
cc::TransferableResource resource;
resource.id = m_nextResourceId;
resource.format = cc::ResourceFormat::RGBA_8888;
// TODO(crbug.com/645590): filter should respect the image-rendering CSS property of associated canvas element.
// TODO(crbug.com/645590): filter should respect the image-rendering CSS
// property of associated canvas element.
resource.filter = GL_LINEAR;
resource.size = gfx::Size(m_width, m_height);
if (image->isTextureBacked()) {
image->ensureMailbox();
resource.mailbox_holder = gpu::MailboxHolder(
image->getMailbox(), image->getSyncToken(), GL_TEXTURE_2D);
resource.read_lock_fences_enabled = false;
resource.is_software = false;
// Hold ref to |image|, to keep it alive until the browser ReturnResources.
// It guarantees that the resource is not re-used or deleted.
m_cachedImages.add(getNextResourceIdAndIncrement(), std::move(image));
} else {
std::unique_ptr<cc::SharedBitmap> bitmap =
Platform::current()->allocateSharedBitmap(IntSize(m_width, m_height));
if (!bitmap)
return;
unsigned char* pixels = bitmap->pixels();
DCHECK(pixels);
SkImageInfo imageInfo = SkImageInfo::Make(
m_width, m_height, kN32_SkColorType,
image->isPremultiplied() ? kPremul_SkAlphaType : kUnpremul_SkAlphaType);
// TODO(xlai): Optimize to avoid copying pixels. See crbug.com/651456.
image->imageForCurrentFrame()->readPixels(imageInfo, pixels,
imageInfo.minRowBytes(), 0, 0);
resource.mailbox_holder.mailbox = bitmap->id();
resource.is_software = true;
// Hold ref to |bitmap|, to keep it alive until the browser ReturnResources.
// It guarantees that the shared bitmap is not re-used or deleted.
m_sharedBitmaps.add(getNextResourceIdAndIncrement(), std::move(bitmap));
}
// TODO(crbug.com/646022): making this overlay-able.
resource.is_overlay_candidate = false;
if (!image->isTextureBacked() &&
!RuntimeEnabledFeatures::gpuCompositingEnabled())
setTransferableResourceInMemory(resource, image);
else if (!image->isTextureBacked() &&
RuntimeEnabledFeatures::gpuCompositingEnabled())
setTransferableResourceMemoryToTexture(resource, image);
else
setTransferableResourceInTexture(resource, image);
m_nextResourceId++;
frame.delegated_frame_data->resource_list.push_back(std::move(resource));
cc::TextureDrawQuad* quad =
......@@ -109,13 +194,15 @@ void OffscreenCanvasFrameDispatcherImpl::dispatchFrame(
gfx::Size rectSize(m_width, m_height);
const bool needsBlending = true;
// TOOD(crbug.com/645993): this should be inherited from WebGL context's creation settings.
// TOOD(crbug.com/645993): this should be inherited from WebGL context's
// creation settings.
const bool premultipliedAlpha = true;
const gfx::PointF uvTopLeft(0.f, 0.f);
const gfx::PointF uvBottomRight(1.f, 1.f);
float vertexOpacity[4] = {1.f, 1.f, 1.f, 1.f};
const bool yflipped = false;
// TODO(crbug.com/645994): this should be true when using style "image-rendering: pixelated".
// TODO(crbug.com/645994): this should be true when using style
// "image-rendering: pixelated".
const bool nearestNeighbor = false;
quad->SetAll(sqs, bounds, bounds, bounds, needsBlending, resource.id,
gfx::Size(), premultipliedAlpha, uvTopLeft, uvBottomRight,
......@@ -132,6 +219,7 @@ void OffscreenCanvasFrameDispatcherImpl::ReturnResources(
for (const auto& resource : resources) {
m_cachedImages.remove(resource->id);
m_sharedBitmaps.remove(resource->id);
m_cachedTextureIds.remove(resource->id);
}
}
......
......@@ -41,14 +41,21 @@ class PLATFORM_EXPORT OffscreenCanvasFrameDispatcherImpl final
const int m_height;
unsigned m_nextResourceId;
unsigned getNextResourceIdAndIncrement() { return m_nextResourceId++; }
HashMap<unsigned, RefPtr<StaticBitmapImage>> m_cachedImages;
HashMap<unsigned, std::unique_ptr<cc::SharedBitmap>> m_sharedBitmaps;
HashMap<unsigned, GLuint> m_cachedTextureIds;
bool verifyImageSize(const sk_sp<SkImage>&);
cc::mojom::blink::MojoCompositorFrameSinkPtr m_sink;
mojo::Binding<cc::mojom::blink::MojoCompositorFrameSinkClient> m_binding;
void setTransferableResourceInMemory(cc::TransferableResource&,
RefPtr<StaticBitmapImage>);
void setTransferableResourceMemoryToTexture(cc::TransferableResource&,
RefPtr<StaticBitmapImage>);
void setTransferableResourceInTexture(cc::TransferableResource&,
RefPtr<StaticBitmapImage>);
};
} // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment