10826e83eSopenharmony_ci/*
20826e83eSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
30826e83eSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
40826e83eSopenharmony_ci * you may not use this file except in compliance with the License.
50826e83eSopenharmony_ci * You may obtain a copy of the License at
60826e83eSopenharmony_ci *
70826e83eSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
80826e83eSopenharmony_ci *
90826e83eSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
100826e83eSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
110826e83eSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120826e83eSopenharmony_ci * See the License for the specific language governing permissions and
130826e83eSopenharmony_ci * limitations under the License.
140826e83eSopenharmony_ci */
150826e83eSopenharmony_ci
160826e83eSopenharmony_ci#include "nweb_surface_adapter.h"
170826e83eSopenharmony_ci
180826e83eSopenharmony_ci#include <display_type.h>
190826e83eSopenharmony_ci#include <securec.h>
200826e83eSopenharmony_ci#include <sync_fence.h>
210826e83eSopenharmony_ci
220826e83eSopenharmony_ci#include "graphic_common.h"
230826e83eSopenharmony_ci#include "graphic_common_c.h"
240826e83eSopenharmony_ci#include "nweb_log.h"
250826e83eSopenharmony_ci#include "surface_type.h"
260826e83eSopenharmony_ci
270826e83eSopenharmony_cinamespace {
280826e83eSopenharmony_ciconstexpr int BITS_PER_PIXEL = 4;
290826e83eSopenharmony_ci}
300826e83eSopenharmony_ci
310826e83eSopenharmony_cinamespace OHOS::NWeb {
320826e83eSopenharmony_ciclass NWebOutputFrameCallbackImpl : public NWebOutputFrameCallback {
330826e83eSopenharmony_cipublic:
340826e83eSopenharmony_ci    NWebOutputFrameCallbackImpl(wptr<Surface> surface, NWebSurfaceAdapter *adapter) : surface_(surface),
350826e83eSopenharmony_ci                                                                                      adapter_(adapter) {}
360826e83eSopenharmony_ci    ~NWebOutputFrameCallbackImpl() = default;
370826e83eSopenharmony_ci
380826e83eSopenharmony_ci    bool Handle(const char* buffer, uint32_t width, uint32_t height) override
390826e83eSopenharmony_ci    {
400826e83eSopenharmony_ci        return adapter_->OutputFrameCallback(buffer, width, height, surface_);
410826e83eSopenharmony_ci    }
420826e83eSopenharmony_ci
430826e83eSopenharmony_ciprivate:
440826e83eSopenharmony_ci    wptr<Surface> surface_ = nullptr;
450826e83eSopenharmony_ci    NWebSurfaceAdapter *adapter_ = nullptr;
460826e83eSopenharmony_ci};
470826e83eSopenharmony_ci
480826e83eSopenharmony_ciNWebSurfaceAdapter &NWebSurfaceAdapter::Instance()
490826e83eSopenharmony_ci{
500826e83eSopenharmony_ci    static NWebSurfaceAdapter surfaceAdapter;
510826e83eSopenharmony_ci    return surfaceAdapter;
520826e83eSopenharmony_ci}
530826e83eSopenharmony_ci
540826e83eSopenharmony_cistd::shared_ptr<NWebCreateInfoImpl> NWebSurfaceAdapter::GetCreateInfo(sptr<Surface> surface,
550826e83eSopenharmony_ci    std::shared_ptr<NWebEngineInitArgs> initArgs, uint32_t width, uint32_t height, bool incognitoMode)
560826e83eSopenharmony_ci{
570826e83eSopenharmony_ci    std::shared_ptr<NWebCreateInfoImpl> createInfo = std::make_shared<NWebCreateInfoImpl>();
580826e83eSopenharmony_ci    createInfo->SetEngineInitArgs(initArgs);
590826e83eSopenharmony_ci    createInfo->SetProducerSurface(reinterpret_cast<void *>(&surface));
600826e83eSopenharmony_ci
610826e83eSopenharmony_ci    if (surface == nullptr) {
620826e83eSopenharmony_ci        return createInfo;
630826e83eSopenharmony_ci    }
640826e83eSopenharmony_ci
650826e83eSopenharmony_ci    createInfo->SetIsIncognitoMode(incognitoMode);
660826e83eSopenharmony_ci    createInfo->SetWidth((width == 0) ? (uint32_t)surface->GetDefaultWidth() : width);
670826e83eSopenharmony_ci    createInfo->SetHeight((height == 0) ? (uint32_t)surface->GetDefaultHeight() : height);
680826e83eSopenharmony_ci
690826e83eSopenharmony_ci    wptr<Surface> surfaceWeak(surface);
700826e83eSopenharmony_ci    createInfo->SetOutputFrameCallback(std::make_shared<NWebOutputFrameCallbackImpl>(surfaceWeak, this));
710826e83eSopenharmony_ci    return createInfo;
720826e83eSopenharmony_ci}
730826e83eSopenharmony_ci
740826e83eSopenharmony_cibool NWebSurfaceAdapter::OutputFrameCallback(const char *buffer, uint32_t width, uint32_t height,
750826e83eSopenharmony_ci                                             wptr<Surface> surfaceWeak)
760826e83eSopenharmony_ci{
770826e83eSopenharmony_ci    sptr<Surface> surface = surfaceWeak.promote();
780826e83eSopenharmony_ci    if (surface == nullptr) {
790826e83eSopenharmony_ci        WVLOG_E("surface is nullptr or has expired");
800826e83eSopenharmony_ci        return false;
810826e83eSopenharmony_ci    }
820826e83eSopenharmony_ci
830826e83eSopenharmony_ci    sptr<SurfaceBuffer> surfaceBuffer = this->RequestBuffer(surface, width, height);
840826e83eSopenharmony_ci    if (surfaceBuffer == nullptr) {
850826e83eSopenharmony_ci        return false;
860826e83eSopenharmony_ci    }
870826e83eSopenharmony_ci
880826e83eSopenharmony_ci    if (!this->CopyFrame(surfaceBuffer, buffer, width, height)) {
890826e83eSopenharmony_ci        surface->CancelBuffer(surfaceBuffer);
900826e83eSopenharmony_ci        return false;
910826e83eSopenharmony_ci    }
920826e83eSopenharmony_ci
930826e83eSopenharmony_ci    return this->FlushBuffer(surface, surfaceBuffer, width, height);
940826e83eSopenharmony_ci}
950826e83eSopenharmony_ci
960826e83eSopenharmony_cisptr<SurfaceBuffer> NWebSurfaceAdapter::RequestBuffer(sptr<Surface> surface, uint32_t width, uint32_t height)
970826e83eSopenharmony_ci{
980826e83eSopenharmony_ci    if (surface == nullptr) {
990826e83eSopenharmony_ci        return nullptr;
1000826e83eSopenharmony_ci    }
1010826e83eSopenharmony_ci
1020826e83eSopenharmony_ci    BufferRequestConfig config = {
1030826e83eSopenharmony_ci        .width = width,
1040826e83eSopenharmony_ci        .height = height,
1050826e83eSopenharmony_ci        .strideAlignment = sizeof(void *),
1060826e83eSopenharmony_ci        .format = PIXEL_FMT_RGBA_8888,
1070826e83eSopenharmony_ci        .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
1080826e83eSopenharmony_ci        .timeout = 0,
1090826e83eSopenharmony_ci    };
1100826e83eSopenharmony_ci
1110826e83eSopenharmony_ci    sptr<SurfaceBuffer> surfaceBuffer = nullptr;
1120826e83eSopenharmony_ci    int32_t releaseFence = -1;
1130826e83eSopenharmony_ci    SurfaceError ret = surface->RequestBuffer(surfaceBuffer, releaseFence, config);
1140826e83eSopenharmony_ci    if (ret != SURFACE_ERROR_OK) {
1150826e83eSopenharmony_ci        WVLOG_E("fail to request buffer from surface, errorcode=%{public}d", ret);
1160826e83eSopenharmony_ci        return nullptr;
1170826e83eSopenharmony_ci    }
1180826e83eSopenharmony_ci
1190826e83eSopenharmony_ci    sptr<SyncFence> tempFence = new (std::nothrow) SyncFence(releaseFence);
1200826e83eSopenharmony_ci    if (tempFence == nullptr) {
1210826e83eSopenharmony_ci        WVLOG_E("new tempFence failed");
1220826e83eSopenharmony_ci        return nullptr;
1230826e83eSopenharmony_ci    }
1240826e83eSopenharmony_ci    tempFence->Wait(100); // 100 ms
1250826e83eSopenharmony_ci
1260826e83eSopenharmony_ci    return surfaceBuffer;
1270826e83eSopenharmony_ci}
1280826e83eSopenharmony_ci
1290826e83eSopenharmony_cibool NWebSurfaceAdapter::CopyFrame(
1300826e83eSopenharmony_ci    sptr<SurfaceBuffer> surfaceBuffer, const char *src, uint32_t width, uint32_t height)
1310826e83eSopenharmony_ci{
1320826e83eSopenharmony_ci    if (surfaceBuffer == nullptr) {
1330826e83eSopenharmony_ci        return false;
1340826e83eSopenharmony_ci    }
1350826e83eSopenharmony_ci
1360826e83eSopenharmony_ci    char *dst = reinterpret_cast<char *>(surfaceBuffer->GetVirAddr());
1370826e83eSopenharmony_ci    if (dst == nullptr) {
1380826e83eSopenharmony_ci        WVLOG_E("fail to get buffer addr");
1390826e83eSopenharmony_ci        return false;
1400826e83eSopenharmony_ci    }
1410826e83eSopenharmony_ci
1420826e83eSopenharmony_ci    uint32_t srcStride = width * BITS_PER_PIXEL;
1430826e83eSopenharmony_ci    uint32_t dstStride = (uint32_t)surfaceBuffer->GetStride();
1440826e83eSopenharmony_ci    uint32_t copiedSize = 0;
1450826e83eSopenharmony_ci
1460826e83eSopenharmony_ci    for (uint32_t currHeight = 0; currHeight < height; ++currHeight) {
1470826e83eSopenharmony_ci        if (copiedSize + dstStride > surfaceBuffer->GetSize()) {
1480826e83eSopenharmony_ci            WVLOG_E("copy size overflow, drop this frame(%{public}u*%{public}u)", width, height);
1490826e83eSopenharmony_ci            return false;
1500826e83eSopenharmony_ci        }
1510826e83eSopenharmony_ci        errno_t ret = memcpy_s(dst, static_cast<size_t>(srcStride), src, static_cast<size_t>(srcStride));
1520826e83eSopenharmony_ci        if (ret != EOK) {
1530826e83eSopenharmony_ci            WVLOG_E("memcpy_s failed");
1540826e83eSopenharmony_ci            return false;
1550826e83eSopenharmony_ci        }
1560826e83eSopenharmony_ci        src += srcStride;
1570826e83eSopenharmony_ci        dst += dstStride;
1580826e83eSopenharmony_ci        copiedSize += dstStride;
1590826e83eSopenharmony_ci    }
1600826e83eSopenharmony_ci
1610826e83eSopenharmony_ci    return true;
1620826e83eSopenharmony_ci}
1630826e83eSopenharmony_ci
1640826e83eSopenharmony_cibool NWebSurfaceAdapter::FlushBuffer(
1650826e83eSopenharmony_ci    sptr<Surface> surface, sptr<SurfaceBuffer> surfaceBuffer, uint32_t width, uint32_t height)
1660826e83eSopenharmony_ci{
1670826e83eSopenharmony_ci    if (surface == nullptr) {
1680826e83eSopenharmony_ci        return false;
1690826e83eSopenharmony_ci    }
1700826e83eSopenharmony_ci
1710826e83eSopenharmony_ci    BufferFlushConfig flushConfig = {
1720826e83eSopenharmony_ci        .damage = {
1730826e83eSopenharmony_ci            .w = width,
1740826e83eSopenharmony_ci            .h = height,
1750826e83eSopenharmony_ci        },
1760826e83eSopenharmony_ci        .timestamp = 0,
1770826e83eSopenharmony_ci    };
1780826e83eSopenharmony_ci
1790826e83eSopenharmony_ci    SurfaceError ret = surface->FlushBuffer(surfaceBuffer, -1, flushConfig);
1800826e83eSopenharmony_ci    if (ret != SURFACE_ERROR_OK) {
1810826e83eSopenharmony_ci        WVLOG_E("FAIL flush nweb render frame, ret=%{public}d", ret);
1820826e83eSopenharmony_ci        return false;
1830826e83eSopenharmony_ci    }
1840826e83eSopenharmony_ci
1850826e83eSopenharmony_ci    return true;
1860826e83eSopenharmony_ci}
1870826e83eSopenharmony_ci} // namespace OHOS::NWeb
188