Skip to content

Commit

Permalink
Adapt new wpebackend-android API
Browse files Browse the repository at this point in the history
New WPEBackend-android API introduces sync fence which
is used when posting buffers to surface control
  • Loading branch information
zhani committed Oct 25, 2023
1 parent 5fb3088 commit 44b60cd
Show file tree
Hide file tree
Showing 18 changed files with 838 additions and 304 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id 'com.android.application' version '8.0.2' apply false
id 'com.android.library' version '8.0.2' apply false
id 'com.android.application' version '8.1.2' apply false
id 'com.android.library' version '8.1.2' apply false
}

tasks.register("clean", Delete) {
Expand Down
3 changes: 1 addition & 2 deletions tools/mediaplayer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ plugins {
android {
namespace 'com.wpe.tools.mediaplayer'
compileSdk 33
buildToolsVersion '33.0.1'

defaultConfig {
minSdk 29
minSdk 31
targetSdk 33
versionCode 1
versionName '1.0'
Expand Down
3 changes: 1 addition & 2 deletions tools/minibrowser/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ plugins {
android {
namespace 'com.wpe.tools.minibrowser'
compileSdk 33
buildToolsVersion '33.0.1'

defaultConfig {
minSdk 29
minSdk 31
targetSdk 33
versionCode 1
versionName '1.0'
Expand Down
3 changes: 1 addition & 2 deletions wpe/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ plugins {
android {
namespace 'com.wpe.wpe'
compileSdk 33
buildToolsVersion '34.0.0'
ndkVersion '25.2.9519653'

defaultConfig {
minSdk 29
minSdk 31
targetSdk 33
}

Expand Down
122 changes: 122 additions & 0 deletions wpe/src/main/cpp/Browser/Fence.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* Copyright (C) 2023 Igalia S.L. <[email protected]>
* Author: Jani Hautakangas <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "Fence.h"

#include <algorithm>
#include <android/sync.h>
#include <memory>
#include <poll.h>

// constexpr uint32_t NO_ERROR = 0;

using sync_file_info_data = struct sync_file_info;

/*
* virtual inline Status getStatus() {
// The sync_wait call underlying wait() has been measured to be
// significantly faster than the sync_fence_info call underlying
// getSignalTime(), which might otherwise appear to be the more obvious
// way to check whether a fence has signaled.
switch (wait(0)) {
case NO_ERROR:
return Status::Signaled;
case -ETIME:
return Status::Unsignaled;
default:
return Status::Invalid;
}
}
*/
/*
namespace {
int syncWait(int fileDescriptor, int timeout)
{
struct pollfd fds = {};
int ret = -1;
if (fileDescriptor < 0) {
errno = EINVAL;
return -1;
}
fds.fd = fileDescriptor;
fds.events = POLLIN;
do {
ret = poll(&fds, 1, timeout);
if (ret > 0) {
if ((static_cast<unsigned int>(fds.revents) & (static_cast<unsigned int>(POLLERR) | static_cast<unsigned
int>(POLLNVAL))) != 0U) {
errno = EINVAL;
return -1;
}
return 0;
}
if (ret == 0) {
errno = ETIME;
return -1;
}
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
return ret;
}
int32_t wait(int fileDescriptor)
{
if (fileDescriptor == -1) {
return NO_ERROR;
}
int const err = syncWait(fileDescriptor, 0);
return err < 0 ? -errno : static_cast<int32_t>(NO_ERROR);
}
} // namespace
*/
Fence::FenceStatus Fence::getStatus(int fileDescriptor)
{
/*
switch (wait(fileDescriptor)) {
case NO_ERROR:
return FenceStatus::Signaled;
case -ETIME:
return FenceStatus::NotSignaled;
default:
return FenceStatus::Invalid;
}
*/
auto info = std::unique_ptr<sync_file_info_data, void (*)(sync_file_info_data*)> {
sync_file_info(fileDescriptor), sync_file_info_free};
if (info == nullptr) {
return FenceStatus::Invalid;
}

if (info->status != 1) {
return FenceStatus::NotSignaled;
}

__u64 timestamp = 0U;
auto* fenceInfo = sync_get_fence_info(info.get());
for (size_t i = 0; i < info->num_fences; i++) {
timestamp = std::max(timestamp, fenceInfo->timestamp_ns);
}

return FenceStatus::Signaled;
}
31 changes: 31 additions & 0 deletions wpe/src/main/cpp/Browser/Fence.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (C) 2023 Igalia S.L. <[email protected]>
* Author: Jani Hautakangas <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#pragma once

class Fence {
public:
enum FenceStatus {
Signaled,
NotSignaled,
Invalid
};

static FenceStatus getStatus(int fileDescriptor);
};
71 changes: 37 additions & 34 deletions wpe/src/main/cpp/Browser/Page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,21 @@

#include "Browser.h"
#include "Logging.h"
#include "RendererASurfaceTransaction.h"
#include "RendererSurfaceControl.h"

#include <android/native_window_jni.h>
#include <unistd.h>
#include <wpe-android/view-backend.h>

namespace {

void handleCommitBuffer(void* context, WPEAndroidBuffer* buffer, int fenceID)
{
auto* page = static_cast<Page*>(context);
page->commitBuffer(buffer, fenceID);
}

} // namespace

/***********************************************************************************************************************
* JNI mapping with Java Page class
Expand Down Expand Up @@ -69,14 +80,14 @@ class JNIPageCache final : public JNI::TypedClass<JNIPage> {

static bool onFullscreenRequest(Page* page, bool fullscreen) noexcept
{
if (page->m_viewBackendExportable != nullptr) {
if (page->m_viewBackend != nullptr) {
page->m_isFullscreenRequested = fullscreen;
if (fullscreen) {
callJavaMethod(getJNIPageCache().m_onEnterFullscreenMode, page->m_pageJavaInstance.get());
} else {
callJavaMethod(getJNIPageCache().m_onExitFullscreenMode, page->m_pageJavaInstance.get());
wpe_view_backend_dispatch_did_exit_fullscreen(
wpe_android_view_backend_exportable_get_view_backend(page->m_viewBackendExportable));
WPEAndroidViewBackend_getWPEViewBackend(page->m_viewBackend));
}
}

Expand Down Expand Up @@ -256,11 +267,11 @@ void JNIPageCache::nativeSurfaceChanged(
{
Logging::logDebug("Page::nativeSurfaceChanged(%d, %d, %d) [tid %d]", format, width, height, gettid());
Page* page = reinterpret_cast<Page*>(pagePtr); // NOLINT(performance-no-int-to-ptr)
if ((page != nullptr) && (page->m_viewBackendExportable != nullptr) && page->m_renderer) {
if ((page != nullptr) && (page->m_viewBackend != nullptr) && page->m_renderer) {
uint32_t uWidth = std::max(0, width);
uint32_t uHeight = std::max(0, height);
wpe_view_backend_dispatch_set_size(
wpe_android_view_backend_exportable_get_view_backend(page->m_viewBackendExportable), uWidth, uHeight);
WPEAndroidViewBackend_getWPEViewBackend(page->m_viewBackend), uWidth, uHeight);
page->m_renderer->onSurfaceChanged(format, uWidth, uHeight);
}
}
Expand Down Expand Up @@ -292,9 +303,8 @@ void JNIPageCache::nativeSetZoomLevel(JNIEnv* /*env*/, jobject /*obj*/, jlong pa
void JNIPageCache::nativeOnTouchEvent(
JNIEnv* /*env*/, jobject /*obj*/, jlong pagePtr, jlong time, jint type, jfloat xCoord, jfloat yCoord) noexcept
{
Logging::logDebug("Page::nativeOnTouchEvent(%ld, %d, %f, %f) [tid %d]", time, type, xCoord, yCoord, gettid());
Page* page = reinterpret_cast<Page*>(pagePtr); // NOLINT(performance-no-int-to-ptr)
if ((page != nullptr) && (page->m_viewBackendExportable != nullptr)) {
if ((page != nullptr) && (page->m_viewBackend != nullptr)) {
wpe_input_touch_event_type touchEventType = wpe_input_touch_event_type_null;
switch (type) {
case 0:
Expand Down Expand Up @@ -327,7 +337,7 @@ void JNIPageCache::nativeOnTouchEvent(
.modifiers = 0};

wpe_view_backend_dispatch_touch_event(
wpe_android_view_backend_exportable_get_view_backend(page->m_viewBackendExportable), &touchEvent);
WPEAndroidViewBackend_getWPEViewBackend(page->m_viewBackend), &touchEvent);
}
}

Expand Down Expand Up @@ -356,9 +366,8 @@ void JNIPageCache::nativeRequestExitFullscreenMode(JNIEnv* /*env*/, jobject /*ob
{
Logging::logDebug("Page::nativeRequestExitFullscreenMode() [tid %d]", gettid());
Page* page = reinterpret_cast<Page*>(pagePtr); // NOLINT(performance-no-int-to-ptr)
if ((page != nullptr) && (page->m_viewBackendExportable != nullptr)) {
wpe_view_backend_dispatch_request_exit_fullscreen(
wpe_android_view_backend_exportable_get_view_backend(page->m_viewBackendExportable));
if ((page != nullptr) && (page->m_viewBackend != nullptr)) {
wpe_view_backend_dispatch_request_exit_fullscreen(WPEAndroidViewBackend_getWPEViewBackend(page->m_viewBackend));
}
}

Expand All @@ -372,22 +381,15 @@ Page::Page(JNIEnv* env, JNIPage jniPage, int width, int height)
: m_pageJavaInstance(JNI::createTypedProtectedRef(env, jniPage, true))
, m_inputMethodContext(this)
{
static const wpe_android_view_backend_exportable_client s_exportableClient
= {.export_buffer = +[](void* data, AHardwareBuffer* buffer, uint32_t poolId, uint32_t bufferId) noexcept {
Logging::logDebug("s_exportableClient::export_buffer(%p, %u, %u)", buffer, poolId, bufferId);
Page* page = reinterpret_cast<Page*>(data);
page->handleExportedBuffer(std::make_shared<ExportedBuffer>(buffer, poolId, bufferId));
}};

uint32_t uWidth = std::max(0, width);
uint32_t uHeight = std::max(0, height);

m_viewBackendExportable = wpe_android_view_backend_exportable_create(&s_exportableClient, this, uWidth, uHeight);
m_renderer = std::make_shared<RendererASurfaceTransaction>(m_viewBackendExportable, uWidth, uHeight);
m_viewBackend = WPEAndroidViewBackend_create(uWidth, uHeight);
m_renderer = std::make_shared<RendererSurfaceControl>(m_viewBackend, uWidth, uHeight);

wpe_view_backend* wpeBackend = wpe_android_view_backend_exportable_get_view_backend(m_viewBackendExportable);
WebKitWebViewBackend* viewBackend = webkit_web_view_backend_new(wpeBackend,
reinterpret_cast<GDestroyNotify>(wpe_android_view_backend_exportable_destroy), m_viewBackendExportable);
WPEViewBackend* wpeBackend = WPEAndroidViewBackend_getWPEViewBackend(m_viewBackend);
WebKitWebViewBackend* viewBackend = webkit_web_view_backend_new(
wpeBackend, reinterpret_cast<GDestroyNotify>(WPEAndroidViewBackend_destroy), m_viewBackend);

m_webView = webkit_web_view_new_with_context(viewBackend, Browser::instance().webContext());
webkit_web_view_set_input_method_context(m_webView, m_inputMethodContext.webKitInputMethodContext());
Expand All @@ -403,6 +405,8 @@ Page::Page(JNIEnv* env, JNIPage jniPage, int width, int height)

wpe_view_backend_set_fullscreen_handler(
wpeBackend, reinterpret_cast<wpe_view_backend_fullscreen_handler>(JNIPageCache::onFullscreenRequest), this);

WPEAndroidViewBackend_setCommitBufferHandler(m_viewBackend, this, handleCommitBuffer);
}

void Page::close() noexcept
Expand All @@ -419,7 +423,7 @@ void Page::close() noexcept

webkit_web_view_try_close(m_webView);

m_viewBackendExportable = nullptr;
m_viewBackend = nullptr;
g_object_unref(m_webView);
m_webView = nullptr;
}
Expand All @@ -429,20 +433,19 @@ void Page::onInputMethodContextIn() noexcept { getJNIPageCache().onInputMethodCo

void Page::onInputMethodContextOut() noexcept { getJNIPageCache().onInputMethodContextOut(m_pageJavaInstance.get()); }

void Page::handleExportedBuffer(const std::shared_ptr<ExportedBuffer>& exportedBuffer) noexcept
void Page::commitBuffer(WPEAndroidBuffer* buffer, int fenceFD) noexcept
{
if (m_renderer && (m_viewBackendExportable != nullptr)) {
Logging::logDebug("Page::handleExportedBuffer(%p) - Size (%ux%u)", exportedBuffer.get(),
exportedBuffer->width(), exportedBuffer->height());
if (m_renderer && (m_viewBackend != nullptr)) {
auto scopedBuffer = std::make_shared<ScopedWPEAndroidBuffer>(buffer);
auto scopedFenceFD = std::make_shared<ScopedFD>(fenceFD);

m_renderer->handleExportedBuffer(exportedBuffer);

if (m_isFullscreenRequested && (exportedBuffer->width() == m_renderer->width())
&& (exportedBuffer->height() == m_renderer->height())) {
if (m_isFullscreenRequested && (scopedBuffer->width() == m_renderer->width())
&& (scopedBuffer->height() == m_renderer->height())) {
Logging::logDebug("Fullscreen ready");
m_isFullscreenRequested = false;
wpe_view_backend_dispatch_did_enter_fullscreen(
wpe_android_view_backend_exportable_get_view_backend(m_viewBackendExportable));
wpe_view_backend_dispatch_did_enter_fullscreen(WPEAndroidViewBackend_getWPEViewBackend(m_viewBackend));
}

m_renderer->commitBuffer(scopedBuffer, scopedFenceFD);
}
}
9 changes: 5 additions & 4 deletions wpe/src/main/cpp/Browser/Page.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
#include "Renderer.h"

#include <vector>
#include <wpe-android/view-backend-exportable.h>

DECLARE_JNI_CLASS_SIGNATURE(JNIPage, "com/wpe/wpe/Page");

struct WPEAndroidViewBackend;

class Page final : public InputMethodContextObserver {
public:
static void configureJNIMappings();
Expand All @@ -49,6 +50,8 @@ class Page final : public InputMethodContextObserver {
void onInputMethodContextIn() noexcept override;
void onInputMethodContextOut() noexcept override;

void commitBuffer(WPEAndroidBuffer* buffer, int fenceFD) noexcept;

private:
friend class JNIPageCache;

Expand All @@ -58,10 +61,8 @@ class Page final : public InputMethodContextObserver {
InputMethodContext m_inputMethodContext;
std::shared_ptr<Renderer> m_renderer;

wpe_android_view_backend_exportable* m_viewBackendExportable = nullptr;
WPEAndroidViewBackend* m_viewBackend = nullptr;
WebKitWebView* m_webView = nullptr;
std::vector<gulong> m_signalHandlers;
bool m_isFullscreenRequested = false;

void handleExportedBuffer(const std::shared_ptr<ExportedBuffer>& exportedBuffer) noexcept;
};
Loading

0 comments on commit 44b60cd

Please sign in to comment.