Commit 93f4ddb1 authored by Antoine Labour's avatar Antoine Labour Committed by Commit Bot

Migrate PaintCanvasVideoRenderer to shared images

This CL ensures:
- VideoFrame mailboxes are imported using the
  CreateAndTexStorage2DSharedImage API if they are shared images, and
  that the Begin/EndSharedImageAccessDirect scope are properly used.
- Intermediate copies are allocated as shared images instead of
  internally to skia.

The cache is modified to track the mailbox for the source texture,
rather than a SkImage, to be able to import it into multiple contexts.
Also the cached shared image is reused if possible (same context
provider, same size) to reflect equivalent skia optimizations (SkImage
pooling).

Note: this CL doesn't cover PrepareVideoFrameForWebGL, used for the
(still experimental) WEBGL_video_texture extension, which requires a
fairly significant refactoring all the way to WebGL bindings to support
shared image.

Bug: 882547
Change-Id: I77b374526f3617db0fd936ffa5b71885e2c8fab3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1616978
Commit-Queue: Antoine Labour <piman@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Auto-Submit: Antoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680021}
parent a02ac85b
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "cc/paint/paint_flags.h" #include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image_builder.h" #include "cc/paint/paint_image_builder.h"
#include "components/viz/common/gpu/context_provider.h" #include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/resources/resource_format.h"
#include "gpu/GLES2/gl2extchromium.h" #include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/client/gles2_interface.h"
...@@ -90,7 +91,7 @@ sk_sp<SkImage> YUVGrBackendTexturesToSkImage( ...@@ -90,7 +91,7 @@ sk_sp<SkImage> YUVGrBackendTexturesToSkImage(
gfx::ColorSpace video_color_space, gfx::ColorSpace video_color_space,
VideoPixelFormat video_format, VideoPixelFormat video_format,
GrBackendTexture* yuv_textures, GrBackendTexture* yuv_textures,
GrBackendTexture* result_texture = nullptr) { const GrBackendTexture& result_texture) {
// TODO(hubbe): This should really default to rec709. // TODO(hubbe): This should really default to rec709.
// https://crbug.com/828599 // https://crbug.com/828599
SkYUVColorSpace color_space = kRec601_SkYUVColorSpace; SkYUVColorSpace color_space = kRec601_SkYUVColorSpace;
...@@ -98,34 +99,62 @@ sk_sp<SkImage> YUVGrBackendTexturesToSkImage( ...@@ -98,34 +99,62 @@ sk_sp<SkImage> YUVGrBackendTexturesToSkImage(
switch (video_format) { switch (video_format) {
case PIXEL_FORMAT_NV12: case PIXEL_FORMAT_NV12:
if (result_texture) { return SkImage::MakeFromNV12TexturesCopyWithExternalBackend(
return SkImage::MakeFromNV12TexturesCopyWithExternalBackend( gr_context, color_space, yuv_textures, kTopLeft_GrSurfaceOrigin,
gr_context, color_space, yuv_textures, kTopLeft_GrSurfaceOrigin, result_texture);
result_texture[0]);
} else {
return SkImage::MakeFromNV12TexturesCopy(
gr_context, color_space, yuv_textures, kTopLeft_GrSurfaceOrigin);
}
case PIXEL_FORMAT_I420: case PIXEL_FORMAT_I420:
if (result_texture) { return SkImage::MakeFromYUVTexturesCopyWithExternalBackend(
return SkImage::MakeFromYUVTexturesCopyWithExternalBackend( gr_context, color_space, yuv_textures, kTopLeft_GrSurfaceOrigin,
gr_context, color_space, yuv_textures, kTopLeft_GrSurfaceOrigin, result_texture);
result_texture[0]);
} else {
return SkImage::MakeFromYUVTexturesCopy(
gr_context, color_space, yuv_textures, kTopLeft_GrSurfaceOrigin);
}
default: default:
NOTREACHED(); NOTREACHED();
return nullptr; return nullptr;
} }
} }
// Helper class that begins/ends access to a mailbox within a scope. The mailbox
// must have been imported into |texture|.
class ScopedSharedImageAccess {
public:
ScopedSharedImageAccess(
gpu::gles2::GLES2Interface* gl,
GLuint texture,
const gpu::Mailbox& mailbox,
GLenum access = GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM)
: gl(gl), texture(texture), is_shared_image(mailbox.IsSharedImage()) {
if (is_shared_image)
gl->BeginSharedImageAccessDirectCHROMIUM(texture, access);
}
~ScopedSharedImageAccess() {
if (is_shared_image)
gl->EndSharedImageAccessDirectCHROMIUM(texture);
}
private:
gpu::gles2::GLES2Interface* gl;
GLuint texture;
bool is_shared_image;
};
// Waits for a sync token and import the mailbox as texture.
GLuint SynchronizeAndImportMailbox(gpu::gles2::GLES2Interface* gl,
const gpu::SyncToken& sync_token,
const gpu::Mailbox& mailbox) {
gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
if (mailbox.IsSharedImage()) {
return gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
} else {
return gl->CreateAndConsumeTextureCHROMIUM(mailbox.name);
}
}
static constexpr size_t kNumYUVPlanes = 3; static constexpr size_t kNumYUVPlanes = 3;
struct YUVPlaneTextureInfo { struct YUVPlaneTextureInfo {
GrGLTextureInfo texture = {0, 0}; GrGLTextureInfo texture = {0, 0};
GLint minFilter = 0; GLint minFilter = 0;
GLint magFilter = 0; GLint magFilter = 0;
bool is_shared_image = false;
}; };
using YUVTexturesInfo = std::array<YUVPlaneTextureInfo, kNumYUVPlanes>; using YUVTexturesInfo = std::array<YUVPlaneTextureInfo, kNumYUVPlanes>;
...@@ -147,9 +176,15 @@ YUVTexturesInfo GetYUVTexturesInfo(const VideoFrame* video_frame, ...@@ -147,9 +176,15 @@ YUVTexturesInfo GetYUVTexturesInfo(const VideoFrame* video_frame,
mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB) mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB)
<< "Unsupported texture target " << std::hex << std::showbase << "Unsupported texture target " << std::hex << std::showbase
<< mailbox_holder.texture_target; << mailbox_holder.texture_target;
gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); yuv_textures_info[i].texture.fID = SynchronizeAndImportMailbox(
yuv_textures_info[i].texture.fID = gl, mailbox_holder.sync_token, mailbox_holder.mailbox);
gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name); if (mailbox_holder.mailbox.IsSharedImage()) {
yuv_textures_info[i].is_shared_image = true;
gl->BeginSharedImageAccessDirectCHROMIUM(
yuv_textures_info[i].texture.fID,
GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
}
yuv_textures_info[i].texture.fTarget = mailbox_holder.texture_target; yuv_textures_info[i].texture.fTarget = mailbox_holder.texture_target;
yuv_textures_info[i].texture.fFormat = skia_texture_format; yuv_textures_info[i].texture.fFormat = skia_texture_format;
...@@ -177,47 +212,12 @@ void DeleteYUVTextures(const VideoFrame* video_frame, ...@@ -177,47 +212,12 @@ void DeleteYUVTextures(const VideoFrame* video_frame,
GL_TEXTURE_MIN_FILTER, yuv_textures_info[i].minFilter); GL_TEXTURE_MIN_FILTER, yuv_textures_info[i].minFilter);
gl->TexParameteri(yuv_textures_info[i].texture.fTarget, gl->TexParameteri(yuv_textures_info[i].texture.fTarget,
GL_TEXTURE_MAG_FILTER, yuv_textures_info[i].magFilter); GL_TEXTURE_MAG_FILTER, yuv_textures_info[i].magFilter);
if (yuv_textures_info[i].is_shared_image)
gl->EndSharedImageAccessDirectCHROMIUM(yuv_textures_info[i].texture.fID);
gl->DeleteTextures(1, &yuv_textures_info[i].texture.fID); gl->DeleteTextures(1, &yuv_textures_info[i].texture.fID);
} }
} }
sk_sp<SkImage> NewSkImageFromVideoFrameYUVTextures(
const VideoFrame* video_frame,
viz::ContextProvider* context_provider) {
DCHECK(video_frame->HasTextures());
GrContext* gr_context = context_provider->GrContext();
DCHECK(gr_context);
// TODO: We should compare the DCHECK vs when UpdateLastImage calls this
// function. (crbug.com/674185)
DCHECK(video_frame->format() == PIXEL_FORMAT_I420 ||
video_frame->format() == PIXEL_FORMAT_NV12);
gfx::Size ya_tex_size = video_frame->coded_size();
gfx::Size uv_tex_size((ya_tex_size.width() + 1) / 2,
(ya_tex_size.height() + 1) / 2);
YUVTexturesInfo yuv_textures_info =
GetYUVTexturesInfo(video_frame, context_provider);
GrBackendTexture yuv_textures[3] = {
GrBackendTexture(ya_tex_size.width(), ya_tex_size.height(),
GrMipMapped::kNo, yuv_textures_info[0].texture),
GrBackendTexture(uv_tex_size.width(), uv_tex_size.height(),
GrMipMapped::kNo, yuv_textures_info[1].texture),
GrBackendTexture(uv_tex_size.width(), uv_tex_size.height(),
GrMipMapped::kNo, yuv_textures_info[2].texture),
};
sk_sp<SkImage> img =
YUVGrBackendTexturesToSkImage(gr_context, video_frame->ColorSpace(),
video_frame->format(), yuv_textures);
gr_context->flush();
DeleteYUVTextures(video_frame, context_provider, yuv_textures_info);
return img;
}
sk_sp<SkImage> NewSkImageFromVideoFrameYUVTexturesWithExternalBackend( sk_sp<SkImage> NewSkImageFromVideoFrameYUVTexturesWithExternalBackend(
const VideoFrame* video_frame, const VideoFrame* video_frame,
viz::ContextProvider* context_provider, viz::ContextProvider* context_provider,
...@@ -251,11 +251,9 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTexturesWithExternalBackend( ...@@ -251,11 +251,9 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTexturesWithExternalBackend(
backend_texture.fID = texture_id; backend_texture.fID = texture_id;
backend_texture.fTarget = texture_target; backend_texture.fTarget = texture_target;
backend_texture.fFormat = GL_RGBA8; backend_texture.fFormat = GL_RGBA8;
GrBackendTexture result_texture[1] = { GrBackendTexture result_texture(video_frame->coded_size().width(),
GrBackendTexture(video_frame->coded_size().width(), video_frame->coded_size().height(),
video_frame->coded_size().height(), GrMipMapped::kNo, GrMipMapped::kNo, backend_texture);
backend_texture),
};
sk_sp<SkImage> img = YUVGrBackendTexturesToSkImage( sk_sp<SkImage> img = YUVGrBackendTexturesToSkImage(
gr_context, video_frame->ColorSpace(), video_frame->format(), gr_context, video_frame->ColorSpace(), video_frame->format(),
...@@ -267,12 +265,15 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTexturesWithExternalBackend( ...@@ -267,12 +265,15 @@ sk_sp<SkImage> NewSkImageFromVideoFrameYUVTexturesWithExternalBackend(
return img; return img;
} }
// Creates a SkImage from a |video_frame| backed by native resources. // Imports a VideoFrame that contains a single mailbox into a newly created GL
// The SkImage will take ownership of the underlying resource. // texture, after synchronization with the sync token. Returns the GL texture.
sk_sp<SkImage> NewSkImageFromVideoFrameNative( // |mailbox| is set to the imported mailbox.
VideoFrame* video_frame, GLuint ImportVideoFrameSingleMailbox(gpu::gles2::GLES2Interface* gl,
viz::ContextProvider* context_provider, VideoFrame* video_frame,
bool wrap_texture) { gpu::Mailbox* mailbox) {
DCHECK(video_frame->HasTextures());
DCHECK_EQ(video_frame->NumTextures(), 1u);
DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() || DCHECK(PIXEL_FORMAT_ARGB == video_frame->format() ||
PIXEL_FORMAT_XRGB == video_frame->format() || PIXEL_FORMAT_XRGB == video_frame->format() ||
PIXEL_FORMAT_RGB24 == video_frame->format() || PIXEL_FORMAT_RGB24 == video_frame->format() ||
...@@ -285,43 +286,31 @@ sk_sp<SkImage> NewSkImageFromVideoFrameNative( ...@@ -285,43 +286,31 @@ sk_sp<SkImage> NewSkImageFromVideoFrameNative(
DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D || DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB || mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES) mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
<< "Unsupported texture target " << std::hex << std::showbase
<< mailbox_holder.texture_target; << mailbox_holder.texture_target;
gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); *mailbox = mailbox_holder.mailbox;
gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); return SynchronizeAndImportMailbox(gl, mailbox_holder.sync_token, *mailbox);
GLuint frame_texture = }
gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
unsigned source_texture = 0; // Wraps a GL RGBA texture into a SkImage.
gfx::ColorSpace color_space_for_skia; sk_sp<SkImage> WrapGLTexture(GLenum target,
if (wrap_texture) { GLuint texture_id,
// Fast path where we can avoid a copy, by having last_image_ directly wrap const gfx::Size& size,
// the VideoFrame texture. const gfx::ColorSpace& color_space,
source_texture = frame_texture; viz::ContextProvider* context_provider) {
color_space_for_skia = video_frame->ColorSpace(); GrGLTextureInfo texture_info;
} else { texture_info.fID = texture_id;
gl->GenTextures(1, &source_texture); texture_info.fTarget = target;
DCHECK(source_texture); // TODO(bsalomon): GrGLTextureInfo::fFormat and SkColorType passed to
gl->BindTexture(GL_TEXTURE_2D, source_texture); // SkImage factory should reflect video_frame->format(). Update once
gl->CopyTextureCHROMIUM(frame_texture, 0, GL_TEXTURE_2D, source_texture, 0, // Skia supports GL_RGB. skbug.com/7533
GL_RGBA, GL_UNSIGNED_BYTE, false, false, false); texture_info.fFormat = GL_RGBA8_OES;
gl->DeleteTextures(1, &frame_texture); GrBackendTexture backend_texture(size.width(), size.height(),
} GrMipMapped::kNo, texture_info);
GrGLTextureInfo source_texture_info; return SkImage::MakeFromTexture(
source_texture_info.fID = source_texture; context_provider->GrContext(), backend_texture, kTopLeft_GrSurfaceOrigin,
source_texture_info.fTarget = GL_TEXTURE_2D; kRGBA_8888_SkColorType, kPremul_SkAlphaType, color_space.ToSkColorSpace(),
// TODO(bsalomon): GrGLTextureInfo::fFormat and SkColorType passed to SkImage nullptr, nullptr);
// factory should reflect video_frame->format(). Update once Skia supports
// GL_RGB.
// skbug.com/7533
source_texture_info.fFormat = GL_RGBA8_OES;
GrBackendTexture source_backend_texture(
video_frame->coded_size().width(), video_frame->coded_size().height(),
GrMipMapped::kNo, source_texture_info);
return SkImage::MakeFromAdoptedTexture(
context_provider->GrContext(), source_backend_texture,
kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
color_space_for_skia.ToSkColorSpace());
} }
void VideoFrameCopyTextureOrSubTexture(gpu::gles2::GLES2Interface* gl, void VideoFrameCopyTextureOrSubTexture(gpu::gles2::GLES2Interface* gl,
...@@ -593,6 +582,14 @@ void PaintCanvasVideoRenderer::Paint(scoped_refptr<VideoFrame> video_frame, ...@@ -593,6 +582,14 @@ void PaintCanvasVideoRenderer::Paint(scoped_refptr<VideoFrame> video_frame,
cc::PaintImage image = cache_->paint_image; cc::PaintImage image = cache_->paint_image;
DCHECK(image); DCHECK(image);
base::Optional<ScopedSharedImageAccess> source_access;
if (video_frame->HasTextures()) {
DCHECK(!cache_->source_mailbox.IsZero());
DCHECK(cache_->source_texture);
source_access.emplace(context_provider->ContextGL(), cache_->source_texture,
cache_->source_mailbox);
}
cc::PaintFlags video_flags; cc::PaintFlags video_flags;
video_flags.setAlpha(flags.getAlpha()); video_flags.setAlpha(flags.getAlpha());
video_flags.setBlendMode(flags.getBlendMode()); video_flags.setBlendMode(flags.getBlendMode());
...@@ -659,6 +656,7 @@ void PaintCanvasVideoRenderer::Paint(scoped_refptr<VideoFrame> video_frame, ...@@ -659,6 +656,7 @@ void PaintCanvasVideoRenderer::Paint(scoped_refptr<VideoFrame> video_frame,
canvas->flush(); canvas->flush();
if (video_frame->HasTextures()) { if (video_frame->HasTextures()) {
source_access.reset();
// Synchronize |video_frame| with the read operations in UpdateLastImage(), // Synchronize |video_frame| with the read operations in UpdateLastImage(),
// which are triggered by canvas->flush(). // which are triggered by canvas->flush().
SynchronizeVideoFrameRead(std::move(video_frame), SynchronizeVideoFrameRead(std::move(video_frame),
...@@ -1056,19 +1054,16 @@ void PaintCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture( ...@@ -1056,19 +1054,16 @@ void PaintCanvasVideoRenderer::CopyVideoFrameSingleTextureToGLTexture(
DCHECK(video_frame); DCHECK(video_frame);
DCHECK(video_frame->HasTextures()); DCHECK(video_frame->HasTextures());
const gpu::MailboxHolder& mailbox_holder = video_frame->mailbox_holder(0); gpu::Mailbox mailbox;
DCHECK(mailbox_holder.texture_target == GL_TEXTURE_2D ||
mailbox_holder.texture_target == GL_TEXTURE_RECTANGLE_ARB ||
mailbox_holder.texture_target == GL_TEXTURE_EXTERNAL_OES)
<< mailbox_holder.texture_target;
gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
uint32_t source_texture = uint32_t source_texture =
gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name); ImportVideoFrameSingleMailbox(gl, video_frame, &mailbox);
VideoFrameCopyTextureOrSubTexture(gl, video_frame->coded_size(), {
video_frame->visible_rect(), source_texture, ScopedSharedImageAccess access(gl, source_texture, mailbox);
target, texture, internal_format, format, VideoFrameCopyTextureOrSubTexture(
type, level, premultiply_alpha, flip_y); gl, video_frame->coded_size(), video_frame->visible_rect(),
source_texture, target, texture, internal_format, format, type, level,
premultiply_alpha, flip_y);
}
gl->DeleteTextures(1, &source_texture); gl->DeleteTextures(1, &source_texture);
gl->ShallowFlushCHROMIUM(); gl->ShallowFlushCHROMIUM();
// The caller must call SynchronizeVideoFrameRead() after this operation, but // The caller must call SynchronizeVideoFrameRead() after this operation, but
...@@ -1104,36 +1099,24 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( ...@@ -1104,36 +1099,24 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture(
} }
DCHECK(cache_); DCHECK(cache_);
DCHECK(cache_->source_image); DCHECK(!cache_->source_mailbox.IsZero());
GrBackendTexture backend_texture =
cache_->source_image->getBackendTexture(true);
if (!backend_texture.isValid())
return false;
GrGLTextureInfo texture_info;
if (!backend_texture.getGLTextureInfo(&texture_info))
return false;
gpu::gles2::GLES2Interface* canvas_gl = context_provider->ContextGL(); gpu::gles2::GLES2Interface* canvas_gl = context_provider->ContextGL();
gpu::MailboxHolder mailbox_holder;
mailbox_holder.texture_target = texture_info.fTarget;
canvas_gl->ProduceTextureDirectCHROMIUM(texture_info.fID,
mailbox_holder.mailbox.name);
gpu::SyncToken sync_token;
// Wait for mailbox creation on canvas context before consuming it and // Wait for mailbox creation on canvas context before consuming it and
// copying from it on the consumer context. // copying from it on the consumer context.
canvas_gl->GenUnverifiedSyncTokenCHROMIUM( canvas_gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
mailbox_holder.sync_token.GetData());
uint32_t intermediate_texture = SynchronizeAndImportMailbox(
destination_gl->WaitSyncTokenCHROMIUM( destination_gl, sync_token, cache_->source_mailbox);
mailbox_holder.sync_token.GetConstData()); {
uint32_t intermediate_texture = ScopedSharedImageAccess access(destination_gl, intermediate_texture,
destination_gl->CreateAndConsumeTextureCHROMIUM( cache_->source_mailbox);
mailbox_holder.mailbox.name); VideoFrameCopyTextureOrSubTexture(
destination_gl, cache_->coded_size, cache_->visible_rect,
VideoFrameCopyTextureOrSubTexture( intermediate_texture, target, texture, internal_format, format, type,
destination_gl, cache_->coded_size, cache_->visible_rect, level, premultiply_alpha, flip_y);
intermediate_texture, target, texture, internal_format, format, type, }
level, premultiply_alpha, flip_y);
destination_gl->DeleteTextures(1, &intermediate_texture); destination_gl->DeleteTextures(1, &intermediate_texture);
...@@ -1322,10 +1305,8 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture( ...@@ -1322,10 +1305,8 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture(
yuv_cache_.mailbox = sii->CreateSharedImage( yuv_cache_.mailbox = sii->CreateSharedImage(
viz::ResourceFormat::RGBA_8888, video_frame.coded_size(), viz::ResourceFormat::RGBA_8888, video_frame.coded_size(),
gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2); gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2);
auto creation_sync_token = sii->GenUnverifiedSyncToken(); yuv_cache_.texture = SynchronizeAndImportMailbox(
source_gl->WaitSyncTokenCHROMIUM(creation_sync_token.GetConstData()); source_gl, sii->GenUnverifiedSyncToken(), yuv_cache_.mailbox);
yuv_cache_.texture = source_gl->CreateAndTexStorage2DSharedImageCHROMIUM(
yuv_cache_.mailbox.name);
} }
// On the source GL context, do the YUV->RGB conversion using Skia. // On the source GL context, do the YUV->RGB conversion using Skia.
...@@ -1344,7 +1325,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture( ...@@ -1344,7 +1325,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture(
sk_sp<SkImage> yuv_image = YUVGrBackendTexturesToSkImage( sk_sp<SkImage> yuv_image = YUVGrBackendTexturesToSkImage(
gr_context, video_frame.ColorSpace(), video_frame.format(), gr_context, video_frame.ColorSpace(), video_frame.format(),
yuv_textures, &result_texture); yuv_textures, result_texture);
gr_context->flush(); gr_context->flush();
source_gl->EndSharedImageAccessDirectCHROMIUM(yuv_cache_.texture); source_gl->EndSharedImageAccessDirectCHROMIUM(yuv_cache_.texture);
...@@ -1362,25 +1343,19 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture( ...@@ -1362,25 +1343,19 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameYUVDataToGLTexture(
// On the destination GL context, do a copy (with cropping) into the // On the destination GL context, do a copy (with cropping) into the
// destination texture. // destination texture.
GLuint intermediate_texture = SynchronizeAndImportMailbox(
destination_gl, post_conversion_sync_token, yuv_cache_.mailbox);
{ {
destination_gl->WaitSyncTokenCHROMIUM( ScopedSharedImageAccess access(destination_gl, intermediate_texture,
post_conversion_sync_token.GetConstData()); yuv_cache_.mailbox);
GLuint intermediate_texture =
destination_gl->CreateAndTexStorage2DSharedImageCHROMIUM(
yuv_cache_.mailbox.name);
destination_gl->BeginSharedImageAccessDirectCHROMIUM(
intermediate_texture, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
VideoFrameCopyTextureOrSubTexture( VideoFrameCopyTextureOrSubTexture(
destination_gl, video_frame.coded_size(), video_frame.visible_rect(), destination_gl, video_frame.coded_size(), video_frame.visible_rect(),
intermediate_texture, target, texture, internal_format, format, type, intermediate_texture, target, texture, internal_format, format, type,
level, premultiply_alpha, flip_y); level, premultiply_alpha, flip_y);
destination_gl->EndSharedImageAccessDirectCHROMIUM(intermediate_texture);
destination_gl->DeleteTextures(1, &intermediate_texture);
destination_gl->GenUnverifiedSyncTokenCHROMIUM(
yuv_cache_.sync_token.GetData());
} }
destination_gl->DeleteTextures(1, &intermediate_texture);
destination_gl->GenUnverifiedSyncTokenCHROMIUM(
yuv_cache_.sync_token.GetData());
// video_frame->UpdateReleaseSyncToken is not necessary since the video frame // video_frame->UpdateReleaseSyncToken is not necessary since the video frame
// data we used was CPU-side (IsMappable) to begin with. If there were any // data we used was CPU-side (IsMappable) to begin with. If there were any
...@@ -1473,7 +1448,21 @@ void PaintCanvasVideoRenderer::ResetCache() { ...@@ -1473,7 +1448,21 @@ void PaintCanvasVideoRenderer::ResetCache() {
PaintCanvasVideoRenderer::Cache::Cache(int frame_id) : frame_id(frame_id) {} PaintCanvasVideoRenderer::Cache::Cache(int frame_id) : frame_id(frame_id) {}
PaintCanvasVideoRenderer::Cache::~Cache() = default; PaintCanvasVideoRenderer::Cache::~Cache() {
if (!context_provider)
return;
DCHECK(!source_mailbox.IsZero());
DCHECK(source_texture);
auto* gl = context_provider->ContextGL();
gl->DeleteTextures(1, &source_texture);
if (!wraps_video_frame_texture) {
gpu::SyncToken sync_token;
gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
auto* sii = context_provider->SharedImageInterface();
sii->DestroySharedImage(sync_token, source_mailbox);
}
}
bool PaintCanvasVideoRenderer::UpdateLastImage( bool PaintCanvasVideoRenderer::UpdateLastImage(
scoped_refptr<VideoFrame> video_frame, scoped_refptr<VideoFrame> video_frame,
...@@ -1481,14 +1470,13 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( ...@@ -1481,14 +1470,13 @@ bool PaintCanvasVideoRenderer::UpdateLastImage(
bool allow_wrap_texture) { bool allow_wrap_texture) {
DCHECK(!cache_ || !cache_->wraps_video_frame_texture); DCHECK(!cache_ || !cache_->wraps_video_frame_texture);
if (!cache_ || video_frame->unique_id() != cache_->frame_id || if (!cache_ || video_frame->unique_id() != cache_->frame_id ||
!cache_->source_image) { cache_->source_mailbox.IsZero()) {
cache_.emplace(video_frame->unique_id());
auto paint_image_builder = auto paint_image_builder =
cc::PaintImageBuilder::WithDefault() cc::PaintImageBuilder::WithDefault()
.set_id(renderer_stable_id_) .set_id(renderer_stable_id_)
.set_animation_type(cc::PaintImage::AnimationType::VIDEO) .set_animation_type(cc::PaintImage::AnimationType::VIDEO)
.set_completion_state(cc::PaintImage::CompletionState::DONE); .set_completion_state(cc::PaintImage::CompletionState::DONE);
// Generate a new image. // Generate a new image.
// Note: Skia will hold onto |video_frame| via |video_generator| only when // Note: Skia will hold onto |video_frame| via |video_generator| only when
// |video_frame| is software. // |video_frame| is software.
...@@ -1497,27 +1485,73 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( ...@@ -1497,27 +1485,73 @@ bool PaintCanvasVideoRenderer::UpdateLastImage(
if (video_frame->HasTextures()) { if (video_frame->HasTextures()) {
DCHECK(context_provider); DCHECK(context_provider);
DCHECK(context_provider->GrContext()); DCHECK(context_provider->GrContext());
DCHECK(context_provider->ContextGL()); auto* gl = context_provider->ContextGL();
if (video_frame->NumTextures() > 1) { DCHECK(gl);
cache_->source_image = NewSkImageFromVideoFrameYUVTextures(
video_frame.get(), context_provider); sk_sp<SkImage> source_image;
if (allow_wrap_texture && video_frame->NumTextures() == 1) {
cache_.emplace(video_frame->unique_id());
cache_->source_texture = ImportVideoFrameSingleMailbox(
gl, video_frame.get(), &cache_->source_mailbox);
cache_->wraps_video_frame_texture = true;
source_image =
WrapGLTexture(video_frame->mailbox_holder(0).texture_target,
cache_->source_texture, video_frame->coded_size(),
video_frame->ColorSpace(), context_provider);
} else { } else {
cache_->source_image = NewSkImageFromVideoFrameNative( if (cache_ && cache_->context_provider == context_provider &&
video_frame.get(), context_provider, allow_wrap_texture); cache_->coded_size == video_frame->coded_size()) {
cache_->wraps_video_frame_texture = allow_wrap_texture; // We can reuse the shared image from the previous cache.
cache_->frame_id = video_frame->unique_id();
} else {
cache_.emplace(video_frame->unique_id());
auto* sii = context_provider->SharedImageInterface();
cache_->source_mailbox = sii->CreateSharedImage(
viz::ResourceFormat::RGBA_8888, video_frame->coded_size(),
gfx::ColorSpace(), gpu::SHARED_IMAGE_USAGE_GLES2);
cache_->source_texture = SynchronizeAndImportMailbox(
gl, sii->GenUnverifiedSyncToken(), cache_->source_mailbox);
}
ScopedSharedImageAccess dest_access(
gl, cache_->source_texture, cache_->source_mailbox,
GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
if (video_frame->NumTextures() == 1) {
gpu::Mailbox mailbox;
GLuint frame_texture =
ImportVideoFrameSingleMailbox(gl, video_frame.get(), &mailbox);
{
ScopedSharedImageAccess access(gl, frame_texture, mailbox);
gl->CopySubTextureCHROMIUM(frame_texture, 0, GL_TEXTURE_2D,
cache_->source_texture, 0, 0, 0, 0, 0,
video_frame->coded_size().width(),
video_frame->coded_size().height(),
GL_FALSE, GL_FALSE, GL_FALSE);
}
gl->DeleteTextures(1, &frame_texture);
source_image = WrapGLTexture(GL_TEXTURE_2D, cache_->source_texture,
video_frame->coded_size(),
gfx::ColorSpace(), context_provider);
} else {
source_image = NewSkImageFromVideoFrameYUVTexturesWithExternalBackend(
video_frame.get(), context_provider, GL_TEXTURE_2D,
cache_->source_texture);
}
context_provider->GrContext()->flush();
} }
if (!cache_->source_image) { if (!source_image) {
// Couldn't create the SkImage. // Couldn't create the SkImage.
cache_.reset(); cache_.reset();
return false; return false;
} }
cache_->context_provider = context_provider;
cache_->coded_size = video_frame->coded_size(); cache_->coded_size = video_frame->coded_size();
cache_->visible_rect = video_frame->visible_rect(); cache_->visible_rect = video_frame->visible_rect();
paint_image_builder.set_image( paint_image_builder.set_image(
cache_->source_image->makeSubset( source_image->makeSubset(gfx::RectToSkIRect(cache_->visible_rect)),
gfx::RectToSkIRect(cache_->visible_rect)),
cc::PaintImage::GetNextContentId()); cc::PaintImage::GetNextContentId());
} else { } else {
cache_.emplace(video_frame->unique_id());
paint_image_builder.set_paint_image_generator( paint_image_builder.set_paint_image_generator(
sk_make_sp<VideoImageGenerator>(video_frame)); sk_make_sp<VideoImageGenerator>(video_frame));
} }
...@@ -1555,11 +1589,11 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrame( ...@@ -1555,11 +1589,11 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrame(
DCHECK(context_provider); DCHECK(context_provider);
DCHECK(context_provider->GrContext()); DCHECK(context_provider->GrContext());
DCHECK(context_provider->ContextGL()); DCHECK(context_provider->ContextGL());
sk_sp<SkImage> source_image;
if (video_frame->NumTextures() > 1) { if (video_frame->NumTextures() > 1) {
cache_->source_image = source_image = NewSkImageFromVideoFrameYUVTexturesWithExternalBackend(
NewSkImageFromVideoFrameYUVTexturesWithExternalBackend( video_frame.get(), context_provider, textureTarget, texture);
video_frame.get(), context_provider, textureTarget, texture); if (!source_image) {
if (!cache_->source_image) {
// Couldn't create the SkImage. // Couldn't create the SkImage.
cache_.reset(); cache_.reset();
return false; return false;
...@@ -1571,9 +1605,9 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrame( ...@@ -1571,9 +1605,9 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrame(
} }
cache_->coded_size = video_frame->coded_size(); cache_->coded_size = video_frame->coded_size();
cache_->visible_rect = video_frame->visible_rect(); cache_->visible_rect = video_frame->visible_rect();
paint_image_builder.set_image(cache_->source_image->makeSubset( paint_image_builder.set_image(
gfx::RectToSkIRect(cache_->visible_rect)), source_image->makeSubset(gfx::RectToSkIRect(cache_->visible_rect)),
cc::PaintImage::GetNextContentId()); cc::PaintImage::GetNextContentId());
} else { } else {
paint_image_builder.set_paint_image_generator( paint_image_builder.set_paint_image_generator(
sk_make_sp<VideoImageGenerator>(video_frame)); sk_make_sp<VideoImageGenerator>(video_frame));
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "cc/paint/paint_canvas.h" #include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h" #include "cc/paint/paint_flags.h"
#include "cc/paint/paint_image.h" #include "cc/paint/paint_image.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/media_export.h" #include "media/base/media_export.h"
#include "media/base/timestamp_constants.h" #include "media/base/timestamp_constants.h"
#include "media/base/video_frame.h" #include "media/base/video_frame.h"
...@@ -198,14 +199,22 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer { ...@@ -198,14 +199,22 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer {
// to the visible size of the VideoFrame. Its contents are generated lazily. // to the visible size of the VideoFrame. Its contents are generated lazily.
cc::PaintImage paint_image; cc::PaintImage paint_image;
// A SkImage that contain the source texture for |paint_image|. This can be // The context provider used to generate |source_mailbox| and
// either the source VideoFrame's texture (if wraps_video_frame_texture is // |source_texture|. This is only set if the VideoFrame was texture-backed.
// true) or a newly allocated texture (if wraps_video_frame_texture is scoped_refptr<viz::ContextProvider> context_provider;
// false) if a copy or conversion was necessary.
// The mailbox for the source texture. This can be either the source
// VideoFrame's texture (if |wraps_video_frame_texture| is true) or a newly
// allocated shared image (if |wraps_video_frame_texture| is false) if a
// copy or conversion was necessary.
// This is only set if the VideoFrame was texture-backed.
gpu::Mailbox source_mailbox;
// The texture ID created when importing |source_mailbox|.
// This is only set if the VideoFrame was texture-backed. // This is only set if the VideoFrame was texture-backed.
sk_sp<SkImage> source_image; uint32_t source_texture = 0;
// The allocated size of |source_image|. // The allocated size of |source_mailbox|.
// This is only set if the VideoFrame was texture-backed. // This is only set if the VideoFrame was texture-backed.
gfx::Size coded_size; gfx::Size coded_size;
...@@ -214,8 +223,8 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer { ...@@ -214,8 +223,8 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer {
// This is only set if the VideoFrame was texture-backed. // This is only set if the VideoFrame was texture-backed.
gfx::Rect visible_rect; gfx::Rect visible_rect;
// Whether |source_image| directly points to a texture of the VideoFrame // Whether |source_mailbox| directly points to a texture of the VideoFrame
// (if true), or to an allocated texture (if false). // (if true), or to an allocated shared image (if false).
bool wraps_video_frame_texture = false; bool wraps_video_frame_texture = false;
}; };
......
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