#include "media/gpu/android/codec_output_buffer_renderer.h"
#include <string.h>
#include <optional>
#include "base/android/scoped_hardware_buffer_fence_sync.h"
#include "base/functional/callback_helpers.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/scoped_make_current.h"
namespace media {
namespace {
BASE_FEATURE(kHandleUpdateTexImageFailures, base::FEATURE_ENABLED_BY_DEFAULT);
}
CodecOutputBufferRenderer::CodecOutputBufferRenderer(
std::unique_ptr<CodecOutputBuffer> output_buffer,
scoped_refptr<CodecBufferWaitCoordinator> codec_buffer_wait_coordinator,
scoped_refptr<gpu::RefCountedLock> drdc_lock)
: RefCountedLockHelperDrDc(std::move(drdc_lock)),
output_buffer_(std::move(output_buffer)),
codec_buffer_wait_coordinator_(std::move(codec_buffer_wait_coordinator)) {
}
CodecOutputBufferRenderer::~CodecOutputBufferRenderer() {
Invalidate();
}
bool CodecOutputBufferRenderer::RenderToTextureOwnerBackBuffer() {
AssertAcquiredDrDcLock();
DCHECK_NE(phase_, Phase::kInFrontBuffer);
if (phase_ == Phase::kInBackBuffer)
return true;
if (phase_ == Phase::kInvalidated)
return false;
if (!codec_buffer_wait_coordinator_)
return false;
if (codec_buffer_wait_coordinator_->IsExpectingFrameAvailable()) {
return false;
}
if (!output_buffer_->ReleaseToSurface()) {
Invalidate();
return false;
}
phase_ = Phase::kInBackBuffer;
codec_buffer_wait_coordinator_->SetReleaseTimeToNow();
return true;
}
bool CodecOutputBufferRenderer::RenderToTextureOwnerFrontBuffer() {
AssertAcquiredDrDcLock();
if (!codec_buffer_wait_coordinator_)
return false;
if (phase_ == Phase::kInFrontBuffer) {
return true;
}
if (phase_ == Phase::kInvalidated)
return false;
if (phase_ != Phase::kInBackBuffer) {
if (codec_buffer_wait_coordinator_->IsExpectingFrameAvailable()) {
codec_buffer_wait_coordinator_->WaitForFrameAvailable();
codec_buffer_wait_coordinator_->texture_owner()->UpdateTexImage(
true);
}
if (!RenderToTextureOwnerBackBuffer()) {
DCHECK_EQ(phase_, Phase::kInvalidated);
return false;
}
}
phase_ = Phase::kInFrontBuffer;
if (codec_buffer_wait_coordinator_->IsExpectingFrameAvailable())
codec_buffer_wait_coordinator_->WaitForFrameAvailable();
if (!codec_buffer_wait_coordinator_->texture_owner()->UpdateTexImage(
false)) {
if (base::FeatureList::IsEnabled(kHandleUpdateTexImageFailures)) {
return false;
}
}
if (frame_info_callback_) {
gfx::Size coded_size;
gfx::Rect visible_rect;
if (texture_owner() && texture_owner()->GetCodedSizeAndVisibleRect(
size(), &coded_size, &visible_rect)) {
std::move(frame_info_callback_).Run(coded_size, visible_rect);
} else {
std::move(frame_info_callback_).Run(std::nullopt, std::nullopt);
}
}
return true;
}
bool CodecOutputBufferRenderer::RenderToOverlay() {
AssertAcquiredDrDcLock();
if (phase_ == Phase::kInFrontBuffer)
return true;
if (phase_ == Phase::kInvalidated)
return false;
if (!output_buffer_->ReleaseToSurface()) {
Invalidate();
return false;
}
phase_ = Phase::kInFrontBuffer;
return true;
}
bool CodecOutputBufferRenderer::RenderToFrontBuffer() {
AssertAcquiredDrDcLock();
return codec_buffer_wait_coordinator_ ? RenderToTextureOwnerFrontBuffer()
: RenderToOverlay();
}
void CodecOutputBufferRenderer::Invalidate() {
phase_ = Phase::kInvalidated;
if (frame_info_callback_) {
std::move(frame_info_callback_).Run(std::nullopt, std::nullopt);
}
}
}