/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "nweb_surface_adapter.h" #include #include #include #include "graphic_common.h" #include "graphic_common_c.h" #include "nweb_log.h" #include "surface_type.h" namespace { constexpr int BITS_PER_PIXEL = 4; } namespace OHOS::NWeb { class NWebOutputFrameCallbackImpl : public NWebOutputFrameCallback { public: NWebOutputFrameCallbackImpl(wptr surface, NWebSurfaceAdapter *adapter) : surface_(surface), adapter_(adapter) {} ~NWebOutputFrameCallbackImpl() = default; bool Handle(const char* buffer, uint32_t width, uint32_t height) override { return adapter_->OutputFrameCallback(buffer, width, height, surface_); } private: wptr surface_ = nullptr; NWebSurfaceAdapter *adapter_ = nullptr; }; NWebSurfaceAdapter &NWebSurfaceAdapter::Instance() { static NWebSurfaceAdapter surfaceAdapter; return surfaceAdapter; } std::shared_ptr NWebSurfaceAdapter::GetCreateInfo(sptr surface, std::shared_ptr initArgs, uint32_t width, uint32_t height, bool incognitoMode) { std::shared_ptr createInfo = std::make_shared(); createInfo->SetEngineInitArgs(initArgs); createInfo->SetProducerSurface(reinterpret_cast(&surface)); if (surface == nullptr) { return createInfo; } createInfo->SetIsIncognitoMode(incognitoMode); createInfo->SetWidth((width == 0) ? (uint32_t)surface->GetDefaultWidth() : width); createInfo->SetHeight((height == 0) ? (uint32_t)surface->GetDefaultHeight() : height); wptr surfaceWeak(surface); createInfo->SetOutputFrameCallback(std::make_shared(surfaceWeak, this)); return createInfo; } bool NWebSurfaceAdapter::OutputFrameCallback(const char *buffer, uint32_t width, uint32_t height, wptr surfaceWeak) { sptr surface = surfaceWeak.promote(); if (surface == nullptr) { WVLOG_E("surface is nullptr or has expired"); return false; } sptr surfaceBuffer = this->RequestBuffer(surface, width, height); if (surfaceBuffer == nullptr) { return false; } if (!this->CopyFrame(surfaceBuffer, buffer, width, height)) { surface->CancelBuffer(surfaceBuffer); return false; } return this->FlushBuffer(surface, surfaceBuffer, width, height); } sptr NWebSurfaceAdapter::RequestBuffer(sptr surface, uint32_t width, uint32_t height) { if (surface == nullptr) { return nullptr; } BufferRequestConfig config = { .width = width, .height = height, .strideAlignment = sizeof(void *), .format = PIXEL_FMT_RGBA_8888, .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA, .timeout = 0, }; sptr surfaceBuffer = nullptr; int32_t releaseFence = -1; SurfaceError ret = surface->RequestBuffer(surfaceBuffer, releaseFence, config); if (ret != SURFACE_ERROR_OK) { WVLOG_E("fail to request buffer from surface, errorcode=%{public}d", ret); return nullptr; } sptr tempFence = new (std::nothrow) SyncFence(releaseFence); if (tempFence == nullptr) { WVLOG_E("new tempFence failed"); return nullptr; } tempFence->Wait(100); // 100 ms return surfaceBuffer; } bool NWebSurfaceAdapter::CopyFrame( sptr surfaceBuffer, const char *src, uint32_t width, uint32_t height) { if (surfaceBuffer == nullptr) { return false; } char *dst = reinterpret_cast(surfaceBuffer->GetVirAddr()); if (dst == nullptr) { WVLOG_E("fail to get buffer addr"); return false; } uint32_t srcStride = width * BITS_PER_PIXEL; uint32_t dstStride = (uint32_t)surfaceBuffer->GetStride(); uint32_t copiedSize = 0; for (uint32_t currHeight = 0; currHeight < height; ++currHeight) { if (copiedSize + dstStride > surfaceBuffer->GetSize()) { WVLOG_E("copy size overflow, drop this frame(%{public}u*%{public}u)", width, height); return false; } errno_t ret = memcpy_s(dst, static_cast(srcStride), src, static_cast(srcStride)); if (ret != EOK) { WVLOG_E("memcpy_s failed"); return false; } src += srcStride; dst += dstStride; copiedSize += dstStride; } return true; } bool NWebSurfaceAdapter::FlushBuffer( sptr surface, sptr surfaceBuffer, uint32_t width, uint32_t height) { if (surface == nullptr) { return false; } BufferFlushConfig flushConfig = { .damage = { .w = width, .h = height, }, .timestamp = 0, }; SurfaceError ret = surface->FlushBuffer(surfaceBuffer, -1, flushConfig); if (ret != SURFACE_ERROR_OK) { WVLOG_E("FAIL flush nweb render frame, ret=%{public}d", ret); return false; } return true; } } // namespace OHOS::NWeb