Commit 8c97b259 authored by Yan, Shaobo's avatar Yan, Shaobo Committed by Commit Bot

WebGL: Add a direct uploading path for texImage2D with video frame backed by GPU

Current fast path for webgl uploading video frame is to render YUV planars to a RGBA8
intermediate gl texture and than do gpu to gpu copy to update the dst webgl texture.

It is possible to further optimize this progress by drawing the content from YUV planars
to dst webgl texture directly. This will save the extra gpu-gpu texture copy which may
hurt performance when uploading large resolution video (e.g. 4k/8k video).

BUG=1108154

Change-Id: I0abb269944f9eac9fb77e13b01860152a918ad95
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2319543Reviewed-by: default avatarBrian Salomon <bsalomon@google.com>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Commit-Queue: Shaobo Yan <shaobo.yan@intel.com>
Cr-Commit-Position: refs/heads/master@{#800811}
parent ab0dc87b
......@@ -17,6 +17,7 @@
#include "base/system/sys_info.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h"
......@@ -591,6 +592,27 @@ void ConvertVideoFrameToRGBPixelsTask(const VideoFrame* video_frame,
done->Run();
}
// Valid gl texture internal format that can try to use direct uploading path.
bool ValidFormatForDirectUploading(GrGLenum format, unsigned int type) {
switch (format) {
case GL_RGBA:
return type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_4_4_4_4;
case GL_RGB:
return type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT_5_6_5;
// WebGL2 supported sized formats
case GL_RGBA8:
case GL_RGB565:
case GL_RGBA16F:
case GL_RGB8:
case GL_RGB10_A2:
case GL_RGBA4:
case GL_SRGB8_ALPHA8:
return true;
default:
return false;
}
}
} // anonymous namespace
// Generates an RGB image from a VideoFrame. Convert YUV to RGB plain on GPU.
......@@ -1240,6 +1262,21 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
GrContext* gr_context = raster_context_provider->GrContext();
if (!gr_context)
return false;
// TODO(crbug.com/1108154): This uploading path failed on mac with error
// invalid mailbox name. Suspect it is related to texture target. Disable
// direct uploading path on mac platform for now.
#if !defined(OS_MAC)
// Try direct uploading path
if (!premultiply_alpha && level == 0) {
if (UploadVideoFrameToGLTexture(raster_context_provider, destination_gl,
video_frame, target, texture,
internal_format, format, type, flip_y)) {
return true;
}
}
#endif // !defined(OS_MAC)
if (!UpdateLastImage(video_frame, raster_context_provider,
true /* allow_wrap_texture */)) {
return false;
......@@ -1297,6 +1334,75 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
return true;
}
bool PaintCanvasVideoRenderer::UploadVideoFrameToGLTexture(
viz::RasterContextProvider* raster_context_provider,
gpu::gles2::GLES2Interface* destination_gl,
scoped_refptr<VideoFrame> video_frame,
unsigned int target,
unsigned int texture,
unsigned int internal_format,
unsigned int format,
unsigned int type,
bool flip_y) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(video_frame);
DCHECK(video_frame->HasTextures());
// Support uploading for NV12 and I420 video frame only.
if (video_frame->format() != PIXEL_FORMAT_I420 &&
video_frame->format() != PIXEL_FORMAT_NV12) {
return false;
}
// TODO(crbug.com/1108154): Investigate how to support other texture target
if (target != GL_TEXTURE_2D) {
return false;
}
if (!ValidFormatForDirectUploading(static_cast<GLenum>(internal_format),
type)) {
return false;
}
if (!raster_context_provider || !raster_context_provider->GrContext())
return false;
// Trigger resource allocation for dst texture to back SkSurface.
// Dst texture size should equal to video frame visible rect.
destination_gl->BindTexture(target, texture);
destination_gl->TexImage2D(
target, 0, internal_format, video_frame->visible_rect().width(),
video_frame->visible_rect().height(), 0, format, type, nullptr);
gpu::MailboxHolder mailbox_holder;
mailbox_holder.texture_target = target;
destination_gl->ProduceTextureDirectCHROMIUM(texture,
mailbox_holder.mailbox.name);
destination_gl->GenUnverifiedSyncTokenCHROMIUM(
mailbox_holder.sync_token.GetData());
ConvertFromVideoFrameYUV(video_frame.get(), raster_context_provider,
mailbox_holder, internal_format, type, flip_y,
true // use visible_rect
);
gpu::raster::RasterInterface* source_ri =
raster_context_provider->RasterInterface();
// Wait for mailbox creation on canvas context before consuming it and
// copying from it on the consumer context.
source_ri->GenUnverifiedSyncTokenCHROMIUM(
mailbox_holder.sync_token.GetData());
destination_gl->WaitSyncTokenCHROMIUM(
mailbox_holder.sync_token.GetConstData());
SyncTokenClientImpl client(source_ri);
video_frame->UpdateReleaseSyncToken(&client);
DCHECK(!cache_ || !cache_->wraps_video_frame_texture);
return true;
}
bool PaintCanvasVideoRenderer::PrepareVideoFrameForWebGL(
viz::RasterContextProvider* raster_context_provider,
gpu::gles2::GLES2Interface* destination_gl,
......
......@@ -257,6 +257,17 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer {
viz::RasterContextProvider* raster_context_provider,
const gpu::MailboxHolder& dest_holder);
bool UploadVideoFrameToGLTexture(
viz::RasterContextProvider* raster_context_provider,
gpu::gles2::GLES2Interface* destination_gl,
scoped_refptr<VideoFrame> video_frame,
unsigned int target,
unsigned int texture,
unsigned int internal_format,
unsigned int format,
unsigned int type,
bool flip_y);
base::Optional<Cache> cache_;
// If |cache_| is not used for a while, it's deleted to save memory.
......
This diff is collapsed.
......@@ -5,16 +5,12 @@
#ifndef MEDIA_RENDERERS_YUV_UTIL_H_
#define MEDIA_RENDERERS_YUV_UTIL_H_
#include "gpu/GLES2/gl2extchromium.h"
#include "media/base/media_export.h"
#include "media/base/video_types.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/color_space.h"
// Skia forward declarations
class GrBackendTexture;
class GrDirectContext;
class SkImage;
namespace gpu {
struct MailboxHolder;
}
......@@ -35,20 +31,11 @@ class VideoFrame;
MEDIA_EXPORT void ConvertFromVideoFrameYUV(
const VideoFrame* video_frame,
viz::RasterContextProvider* raster_context_provider,
const gpu::MailboxHolder& dest_mailbox_holder);
MEDIA_EXPORT sk_sp<SkImage> NewSkImageFromVideoFrameYUV(
const VideoFrame* video_frame,
viz::RasterContextProvider* raster_context_provider,
unsigned int texture_target,
unsigned int texture_id);
MEDIA_EXPORT sk_sp<SkImage> YUVGrBackendTexturesToSkImage(
GrDirectContext* gr_context,
gfx::ColorSpace video_color_space,
VideoPixelFormat video_format,
GrBackendTexture* yuv_textures,
const GrBackendTexture& result_texture);
const gpu::MailboxHolder& dest_mailbox_holder,
unsigned int internal_format = GL_RGBA,
unsigned int type = GL_UNSIGNED_BYTE,
bool flip_y = false,
bool use_visible_rect = false);
} // namespace media
......
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