diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc index 70853e09ca3279..f57728dd4ef249 100644 --- a/cc/paint/paint_image.cc +++ b/cc/paint/paint_image.cc @@ -298,11 +298,6 @@ void PaintImage::FlushPendingSkiaOps() { texture_backing_->FlushPendingSkiaOps(); } -bool PaintImage::HasExclusiveTextureAccess() const { - DCHECK(IsTextureBacked()); - return texture_backing_->unique(); -} - int PaintImage::width() const { return paint_worklet_input_ ? static_cast(paint_worklet_input_->GetSize().width()) diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h index 237ab4d857616f..256e0fd92702cd 100644 --- a/cc/paint/paint_image.h +++ b/cc/paint/paint_image.h @@ -235,11 +235,12 @@ class CC_PAINT_EXPORT PaintImage { int src_x, int src_y) const; - SkImageInfo GetSkImageInfo() const; + // Returned mailbox must not outlive this PaintImage. + gpu::Mailbox GetMailbox() const; Id stable_id() const { return id_; } const sk_sp& GetSkImage() const; - gpu::Mailbox GetMailbox() const; + SkImageInfo GetSkImageInfo() const; AnimationType animation_type() const { return animation_type_; } CompletionState completion_state() const { return completion_state_; } bool is_multipart() const { return is_multipart_; } @@ -262,7 +263,6 @@ class CC_PAINT_EXPORT PaintImage { // Skia internally buffers commands and flushes them as necessary but there // are some cases where we need to force a flush. void FlushPendingSkiaOps(); - bool HasExclusiveTextureAccess() const; int width() const; int height() const; SkColorSpace* color_space() const { diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc index 8b6e8e8e947f35..ee63ac39180d03 100644 --- a/cc/paint/paint_op_buffer.cc +++ b/cc/paint/paint_op_buffer.cc @@ -1431,9 +1431,14 @@ void DrawImageOp::RasterWithFlags(const DrawImageOp* op, canvas->scale(1.f / op->scale_adjustment.width(), 1.f / op->scale_adjustment.height()); } - auto sk_image = op->image.IsTextureBacked() - ? op->image.GetAcceleratedSkImage() - : op->image.GetSwSkImage(); + sk_sp sk_image; + if (op->image.IsTextureBacked()) { + sk_image = op->image.GetAcceleratedSkImage(); + DCHECK(sk_image || !canvas->recordingContext()); + } + if (!sk_image) + sk_image = op->image.GetSwSkImage(); + canvas->drawImage(sk_image.get(), op->left, op->top, &paint); return; } @@ -1505,9 +1510,13 @@ void DrawImageRectOp::RasterWithFlags(const DrawImageRectOp* op, if (!params.image_provider) { SkRect adjusted_src = AdjustSrcRectForScale(op->src, op->scale_adjustment); flags->DrawToSk(canvas, [op, adjusted_src](SkCanvas* c, const SkPaint& p) { - auto sk_image = op->image.IsTextureBacked() - ? op->image.GetAcceleratedSkImage() - : op->image.GetSwSkImage(); + sk_sp sk_image; + if (op->image.IsTextureBacked()) { + sk_image = op->image.GetAcceleratedSkImage(); + DCHECK(sk_image || !c->recordingContext()); + } + if (!sk_image) + sk_image = op->image.GetSwSkImage(); c->drawImageRect(sk_image.get(), adjusted_src, op->dst, &p, op->constraint); }); diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index a08e0f048e2b6a..8963e0d18dd45b 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc @@ -1347,8 +1347,9 @@ void WebMediaPlayerImpl::Paint(cc::PaintCanvas* canvas, if (video_frame && video_frame->HasTextures()) { if (!raster_context_provider_) return; // Unable to get/create a shared main thread context. - if (!raster_context_provider_->GrContext()) - return; // The context has been lost since and can't setup a GrContext. + DCHECK( + raster_context_provider_->ContextCapabilities().supports_oop_raster || + raster_context_provider_->GrContext()); } if (out_metadata && video_frame) { // WebGL last-uploaded-frame-metadata API enabled. https://crbug.com/639174 diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc index 861600c71afcbb..fdb634a29df3ce 100644 --- a/media/renderers/paint_canvas_video_renderer.cc +++ b/media/renderers/paint_canvas_video_renderer.cc @@ -789,28 +789,67 @@ class VideoImageGenerator : public cc::PaintImageGenerator { DISALLOW_IMPLICIT_CONSTRUCTORS(VideoImageGenerator); }; -// TODO(jochin): Add support for all OOP-R specific APIs (eg. GetMailbox() and -// GetSkImageViaReadback()) class VideoTextureBacking : public cc::TextureBacking { public: explicit VideoTextureBacking( sk_sp sk_image, + const gpu::Mailbox& mailbox, + bool wraps_video_frame_texture, scoped_refptr raster_context_provider) - : sk_image_(std::move(sk_image)) { + : sk_image_(std::move(sk_image)), + sk_image_info_(sk_image_->imageInfo()), + mailbox_(mailbox), + wraps_video_frame_texture_(wraps_video_frame_texture) { raster_context_provider_ = std::move(raster_context_provider); } - const SkImageInfo& GetSkImageInfo() override { - return sk_image_->imageInfo(); + explicit VideoTextureBacking( + const gpu::Mailbox& mailbox, + const SkImageInfo& info, + bool wraps_video_frame_texture, + scoped_refptr raster_context_provider) + : sk_image_info_(info), + mailbox_(mailbox), + wraps_video_frame_texture_(wraps_video_frame_texture) { + raster_context_provider_ = std::move(raster_context_provider); } + + ~VideoTextureBacking() override { + auto* ri = raster_context_provider_->RasterInterface(); + if (!wraps_video_frame_texture_) { + gpu::SyncToken sync_token; + ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); + auto* sii = raster_context_provider_->SharedImageInterface(); + sii->DestroySharedImage(sync_token, mailbox_); + } + } + + const SkImageInfo& GetSkImageInfo() override { return sk_image_info_; } gpu::Mailbox GetMailbox() const override { return mailbox_; } sk_sp GetAcceleratedSkImage() override { return sk_image_; } + bool wraps_video_frame_texture() const { return wraps_video_frame_texture_; } + const scoped_refptr& raster_context_provider() + const { + return raster_context_provider_; + } + sk_sp GetSkImageViaReadback() override { - if (sk_image_) { + if (sk_image_) return sk_image_->makeNonTextureImage(); - } - return nullptr; + + sk_sp image_pixels = + SkData::MakeUninitialized(sk_image_info_.computeMinByteSize()); + uint8_t* writable_pixels = + static_cast(image_pixels->writable_data()); + gpu::raster::RasterInterface* ri = + raster_context_provider_->RasterInterface(); + ri->ReadbackImagePixels(mailbox_, sk_image_info_, + sk_image_info_.minRowBytes(), 0, 0, + writable_pixels); + return SkImage::MakeRasterData(sk_image_info_, std::move(image_pixels), + sk_image_info_.minRowBytes()); } + bool readPixels(const SkImageInfo& dst_info, void* dst_pixels, size_t dst_row_bytes, @@ -820,8 +859,13 @@ class VideoTextureBacking : public cc::TextureBacking { return sk_image_->readPixels(dst_info, dst_pixels, dst_row_bytes, src_x, src_y); } - return false; + gpu::raster::RasterInterface* ri = + raster_context_provider_->RasterInterface(); + ri->ReadbackImagePixels(mailbox_, dst_info, dst_info.minRowBytes(), src_x, + src_y, dst_pixels); + return true; } + void FlushPendingSkiaOps() override { if (!raster_context_provider_ || !sk_image_) return; @@ -829,9 +873,19 @@ class VideoTextureBacking : public cc::TextureBacking { } private: - const sk_sp sk_image_; - const gpu::Mailbox mailbox_; + sk_sp sk_image_; + SkImageInfo sk_image_info_; scoped_refptr raster_context_provider_; + + // 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. + const gpu::Mailbox mailbox_; + + // Whether |mailbox_| directly points to a texture of the VideoFrame + // (if true), or to an allocated shared image (if false). + const bool wraps_video_frame_texture_; }; PaintCanvasVideoRenderer::PaintCanvasVideoRenderer() @@ -883,11 +937,11 @@ void PaintCanvasVideoRenderer::Paint( DCHECK(image); base::Optional source_access; - if (video_frame->HasTextures()) { - DCHECK(!cache_->source_mailbox.IsZero()); - DCHECK(cache_->source_texture); + if (video_frame->HasTextures() && cache_->source_texture) { + DCHECK(cache_->texture_backing); source_access.emplace(raster_context_provider->RasterInterface(), - cache_->source_texture, cache_->source_mailbox); + cache_->source_texture, + cache_->texture_backing->GetMailbox()); } cc::PaintFlags video_flags; @@ -979,9 +1033,9 @@ void PaintCanvasVideoRenderer::Paint( raster_context_provider->ContextSupport()); } // Because we are not retaining a reference to the VideoFrame, it would be - // invalid for the cache to directly wrap its texture(s), as they will be - // recycled. - DCHECK(!cache_ || !cache_->wraps_video_frame_texture); + // invalid for the texture_backing to directly wrap its texture(s), as they + // will be recycled. + DCHECK(!CacheBackingWrapsTexture()); } void PaintCanvasVideoRenderer::Copy( @@ -1311,7 +1365,8 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( if (!raster_context_provider) return false; GrDirectContext* gr_context = raster_context_provider->GrContext(); - if (!gr_context) + if (!gr_context && + !raster_context_provider->ContextCapabilities().supports_oop_raster) return false; // TODO(crbug.com/1108154): Expand this uploading path to macOS, linux // chromeOS after collecting perf data and resolve failure cases. @@ -1332,7 +1387,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( } DCHECK(cache_); - DCHECK(!cache_->source_mailbox.IsZero()); + DCHECK(cache_->texture_backing); gpu::raster::RasterInterface* canvas_ri = raster_context_provider->RasterInterface(); @@ -1342,10 +1397,10 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( canvas_ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); uint32_t intermediate_texture = SynchronizeAndImportMailbox( - destination_gl, sync_token, cache_->source_mailbox); + destination_gl, sync_token, cache_->texture_backing->GetMailbox()); { ScopedSharedImageAccess access(destination_gl, intermediate_texture, - cache_->source_mailbox); + cache_->texture_backing->GetMailbox()); VideoFrameCopyTextureOrSubTexture( destination_gl, cache_->coded_size, cache_->visible_rect, intermediate_texture, target, texture, internal_format, format, type, @@ -1363,7 +1418,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( // Because we are not retaining a reference to the VideoFrame, it would be // invalid to keep the cache around if it directly wraps the VideoFrame // texture(s), as they will be recycled. - if (cache_->wraps_video_frame_texture) + if (cache_->texture_backing->wraps_video_frame_texture()) cache_.reset(); // Synchronize |video_frame| with the read operations in UpdateLastImage(), @@ -1378,8 +1433,7 @@ bool PaintCanvasVideoRenderer::CopyVideoFrameTexturesToGLTexture( WaitAndReplaceSyncTokenClient client(destination_gl); video_frame->UpdateReleaseSyncToken(&client); } - DCHECK(!cache_ || !cache_->wraps_video_frame_texture); - + DCHECK(!CacheBackingWrapsTexture()); return true; } @@ -1413,6 +1467,7 @@ bool PaintCanvasVideoRenderer::UploadVideoFrameToGLTexture( return false; } + // TODO(nazabris): Support OOP-R code path here that does not have GrContext. if (!raster_context_provider || !raster_context_provider->GrContext()) return false; @@ -1472,6 +1527,7 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrameForWebGL( return false; } + // TODO(nazabris): Support OOP-R code path here that does not have GrContext. if (!raster_context_provider || !raster_context_provider->GrContext()) return false; @@ -1509,7 +1565,7 @@ bool PaintCanvasVideoRenderer::PrepareVideoFrameForWebGL( WaitAndReplaceSyncTokenClient client(source_ri); video_frame->UpdateReleaseSyncToken(&client); - DCHECK(!cache_ || !cache_->wraps_video_frame_texture); + DCHECK(!CacheBackingWrapsTexture()); return true; } @@ -1683,33 +1739,17 @@ void PaintCanvasVideoRenderer::ResetCache() { PaintCanvasVideoRenderer::Cache::Cache(int frame_id) : frame_id(frame_id) {} -PaintCanvasVideoRenderer::Cache::~Cache() { - if (!raster_context_provider) - return; - - DCHECK(!source_mailbox.IsZero()); - DCHECK(source_texture); - auto* ri = raster_context_provider->RasterInterface(); - if (!wraps_video_frame_texture) { - gpu::SyncToken sync_token; - ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData()); - auto* sii = raster_context_provider->SharedImageInterface(); - sii->DestroySharedImage(sync_token, source_mailbox); - } -} +PaintCanvasVideoRenderer::Cache::~Cache() = default; bool PaintCanvasVideoRenderer::Cache::Recycle() { - DCHECK(!wraps_video_frame_texture); - if (!paint_image.HasExclusiveTextureAccess()) + DCHECK(!texture_backing->wraps_video_frame_texture()); + + paint_image = cc::PaintImage(); + if (!texture_backing->unique()) return false; // Flush any pending GPU work using this texture. - paint_image.FlushPendingSkiaOps(); - - paint_image = cc::PaintImage(); - // We need a new texture ID because skia will destroy the previous one with - // the SkImage. - source_texture = 0; + texture_backing->FlushPendingSkiaOps(); return true; } @@ -1717,9 +1757,9 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( scoped_refptr video_frame, viz::RasterContextProvider* raster_context_provider, bool allow_wrap_texture) { - DCHECK(!cache_ || !cache_->wraps_video_frame_texture); + DCHECK(!CacheBackingWrapsTexture()); if (!cache_ || video_frame->unique_id() != cache_->frame_id || - cache_->source_mailbox.IsZero()) { + !cache_->paint_image) { auto paint_image_builder = cc::PaintImageBuilder::WithDefault() .set_id(renderer_stable_id_) @@ -1733,24 +1773,30 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( // could cause problems since the pool of VideoFrames has a fixed size. if (video_frame->HasTextures()) { DCHECK(raster_context_provider); - DCHECK(raster_context_provider->GrContext()); + bool supports_oop_raster = + raster_context_provider->ContextCapabilities().supports_oop_raster; + DCHECK(supports_oop_raster || raster_context_provider->GrContext()); auto* ri = raster_context_provider->RasterInterface(); DCHECK(ri); + bool wraps_video_frame_texture = false; + gpu::Mailbox mailbox; if (allow_wrap_texture && video_frame->NumTextures() == 1) { cache_.emplace(video_frame->unique_id()); const gpu::MailboxHolder& holder = GetVideoFrameMailboxHolder(video_frame.get()); - cache_->source_mailbox = holder.mailbox; + mailbox = holder.mailbox; ri->WaitSyncTokenCHROMIUM(holder.sync_token.GetConstData()); - cache_->wraps_video_frame_texture = true; + wraps_video_frame_texture = true; } else { - if (cache_ && - cache_->raster_context_provider == raster_context_provider && + if (cache_ && cache_->texture_backing && + cache_->texture_backing->raster_context_provider() == + raster_context_provider && cache_->coded_size == video_frame->coded_size() && cache_->Recycle()) { // We can reuse the shared image from the previous cache. cache_->frame_id = video_frame->unique_id(); + mailbox = cache_->texture_backing->GetMailbox(); } else { cache_.emplace(video_frame->unique_id()); auto* sii = raster_context_provider->SharedImageInterface(); @@ -1758,11 +1804,10 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( // cached shared image is created without it. uint32_t flags = gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER; - if (raster_context_provider->ContextCapabilities() - .supports_oop_raster) { + if (supports_oop_raster) { flags |= gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION; } - cache_->source_mailbox = sii->CreateSharedImage( + mailbox = sii->CreateSharedImage( viz::ResourceFormat::RGBA_8888, video_frame->coded_size(), gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, flags, gpu::kNullSurfaceHandle); @@ -1772,48 +1817,55 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( if (video_frame->NumTextures() == 1) { auto frame_mailbox = SynchronizeVideoFrameSingleMailbox(ri, video_frame.get()); - ri->CopySubTexture( - frame_mailbox, cache_->source_mailbox, GL_TEXTURE_2D, 0, 0, 0, 0, - video_frame->coded_size().width(), - video_frame->coded_size().height(), GL_FALSE, GL_FALSE); + ri->CopySubTexture(frame_mailbox, mailbox, GL_TEXTURE_2D, 0, 0, 0, 0, + video_frame->coded_size().width(), + video_frame->coded_size().height(), GL_FALSE, + GL_FALSE); } else { - gpu::MailboxHolder dest_holder{cache_->source_mailbox, - gpu::SyncToken(), GL_TEXTURE_2D}; + gpu::MailboxHolder dest_holder{mailbox, gpu::SyncToken(), + GL_TEXTURE_2D}; VideoFrameYUVConverter::ConvertYUVVideoFrameNoCaching( video_frame.get(), raster_context_provider, dest_holder); } - raster_context_provider->GrContext()->flushAndSubmit(); + if (!supports_oop_raster) + raster_context_provider->GrContext()->flushAndSubmit(); } - // TODO(jochin): Don't always generate SkImage here. - DCHECK(cache_->source_texture == 0); - cache_->source_texture = - ri->CreateAndConsumeForGpuRaster(cache_->source_mailbox); - - // TODO(nazabris): Handle scoped access correctly. This follows the - // current pattern but is most likely bugged. Access should last for the - // lifetime of the SkImage. - ScopedSharedImageAccess(ri, cache_->source_texture, - cache_->source_mailbox); - auto source_image = - WrapGLTexture(cache_->wraps_video_frame_texture - ? video_frame->mailbox_holder(0).texture_target - : GL_TEXTURE_2D, - cache_->source_texture, video_frame->coded_size(), - video_frame->ColorSpace(), raster_context_provider); - if (!source_image) { - // Couldn't create the SkImage. - cache_.reset(); - return false; - } - cache_->raster_context_provider = raster_context_provider; cache_->coded_size = video_frame->coded_size(); cache_->visible_rect = video_frame->visible_rect(); - + if (!cache_->texture_backing) { + if (supports_oop_raster) { + SkImageInfo sk_image_info = SkImageInfo::Make( + gfx::SizeToSkISize(cache_->coded_size), kRGBA_8888_SkColorType, + kPremul_SkAlphaType, video_frame->ColorSpace().ToSkColorSpace()); + cache_->texture_backing = sk_make_sp( + mailbox, sk_image_info, wraps_video_frame_texture, + raster_context_provider); + } else { + cache_->source_texture = ri->CreateAndConsumeForGpuRaster(mailbox); + + // TODO(nazabris): Handle scoped access correctly. This follows the + // current pattern but is most likely bugged. Access should last for + // the lifetime of the SkImage. + ScopedSharedImageAccess(ri, cache_->source_texture, mailbox); + auto source_image = + WrapGLTexture(wraps_video_frame_texture + ? video_frame->mailbox_holder(0).texture_target + : GL_TEXTURE_2D, + cache_->source_texture, video_frame->coded_size(), + video_frame->ColorSpace(), raster_context_provider); + if (!source_image) { + // Couldn't create the SkImage. + cache_.reset(); + return false; + } + cache_->texture_backing = sk_make_sp( + std::move(source_image), mailbox, wraps_video_frame_texture, + raster_context_provider); + } + } paint_image_builder.set_texture_backing( - sk_sp(new VideoTextureBacking( - std::move(source_image), raster_context_provider)), - cc::PaintImage::GetNextContentId()); + cache_->texture_backing, cc::PaintImage::GetNextContentId()); } else { cache_.emplace(video_frame->unique_id()); paint_image_builder.set_paint_image_generator( @@ -1821,7 +1873,7 @@ bool PaintCanvasVideoRenderer::UpdateLastImage( } cache_->paint_image = paint_image_builder.TakePaintImage(); if (!cache_->paint_image) { - // Couldn't create the SkImage. + // Couldn't create the PaintImage. cache_.reset(); return false; } @@ -1884,4 +1936,9 @@ gfx::Size PaintCanvasVideoRenderer::LastImageDimensionsForTesting() { return gfx::Size(cache_->paint_image.width(), cache_->paint_image.height()); } +bool PaintCanvasVideoRenderer::CacheBackingWrapsTexture() const { + return cache_ && cache_->texture_backing && + cache_->texture_backing->wraps_video_frame_texture(); +} + } // namespace media diff --git a/media/renderers/paint_canvas_video_renderer.h b/media/renderers/paint_canvas_video_renderer.h index a422e23dd0563e..0c6b4062d8816e 100644 --- a/media/renderers/paint_canvas_video_renderer.h +++ b/media/renderers/paint_canvas_video_renderer.h @@ -41,6 +41,7 @@ class RasterContextProvider; } namespace media { +class VideoTextureBacking; // Handles rendering of VideoFrames to PaintCanvases. class MEDIA_EXPORT PaintCanvasVideoRenderer { @@ -211,22 +212,15 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer { // to the visible size of the VideoFrame. Its contents are generated lazily. cc::PaintImage paint_image; - // The context provider used to generate |source_mailbox| and - // |source_texture|. This is only set if the VideoFrame was texture-backed. - scoped_refptr raster_context_provider; - - // 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 backing for the source texture. This is also responsible for managing + // the lifetime of the texture. + sk_sp texture_backing; - // The texture ID created when importing |source_mailbox|. + // The GL texture ID used in non-OOP code path. // This is only set if the VideoFrame was texture-backed. uint32_t source_texture = 0; - // The allocated size of |source_mailbox|. + // The allocated size of VideoFrame texture. // This is only set if the VideoFrame was texture-backed. gfx::Size coded_size; @@ -235,10 +229,6 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer { // This is only set if the VideoFrame was texture-backed. gfx::Rect visible_rect; - // Whether |source_mailbox| directly points to a texture of the VideoFrame - // (if true), or to an allocated shared image (if false). - bool wraps_video_frame_texture = false; - // Used to allow recycling of the previous shared image. This requires that // no external users have access to this resource via SkImage. Returns true // if the existing resource can be recycled. @@ -266,6 +256,8 @@ class MEDIA_EXPORT PaintCanvasVideoRenderer { unsigned int type, bool flip_y); + bool CacheBackingWrapsTexture() const; + base::Optional cache_; // If |cache_| is not used for a while, it's deleted to save memory. diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc index 3e02b1983c01ab..2a37d497b46ba5 100644 --- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc +++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc @@ -377,8 +377,8 @@ gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() { class GrDirectContext* ContextProviderCommandBuffer::GrContext() { DCHECK(bind_tried_); DCHECK_EQ(bind_result_, gpu::ContextResult::kSuccess); - DCHECK(support_grcontext_); - DCHECK(ContextSupport()->HasGrContextSupport()); + if (!support_grcontext_ || !ContextSupport()->HasGrContextSupport()) + return nullptr; CheckValidThreadOrLockAcquired(); if (gr_context_)