Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor OSR rendering: modularized logic, added abstraction, and implemented DirectX 11 backend for Windows #469

Merged
merged 4 commits into from
Feb 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion example/QCefViewTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ if(OS_MACOS)
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks"
XCODE_LINK_BUILD_PHASE_MODE "KNOWN_LOCATION"
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY "YES"
XCODE_EMBED_FRAMEWORKS "${CMAKE_BINARY_DIR}/output/${CMAKE_BUILD_TYPE}/bin/QCefView.framework"
XCODE_EMBED_FRAMEWORKS "${CMAKE_BINARY_DIR}/output/$(CONFIGURATION)/bin/QCefView.framework"
)

add_custom_command(TARGET ${PROJECT_NAME}
Expand Down
19 changes: 13 additions & 6 deletions example/QCefViewTest/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ MainWindow::MainWindow(QWidget* parent)
// add a local folder to URL map (global)
QCefContext::instance()->addLocalFolderResource(webResourceDir, URL_ROOT);

createLeftCefView();
// createLeftCefView();
createRightCefView();
}

Expand All @@ -63,7 +63,12 @@ MainWindow::createLeftCefView()
m_pLeftCefViewWidget = nullptr;
}

m_pLeftCefViewWidget = new CefViewWidget(LEFT_INDEX_URL, nullptr, this);
QCefSetting setting;
setting.setWindowlessFrameRate(240);
setting.setHardwareAcceleration(true);
// setting.setBackgroundColor(Qt::magenta);

m_pLeftCefViewWidget = new CefViewWidget(LEFT_INDEX_URL, &setting, this);
// connect the invokeMethod to the slot
connect(m_pLeftCefViewWidget, &QCefView::invokeMethod, this, &MainWindow::onInvokeMethod);

Expand Down Expand Up @@ -91,12 +96,14 @@ MainWindow::createRightCefView()
#if CEF_VERSION_MAJOR < 100
setting.setPlugins(false);
#endif
setting.setWindowlessFrameRate(60);
//setting.setBackgroundColor(QColor::fromRgba(qRgba(255, 255, 220, 255)));
//setting.setBackgroundColor(Qt::blue);
setting.setWindowlessFrameRate(240);
setting.setHardwareAcceleration(true);
// setting.setBackgroundColor(Qt::cyan);
// setting.setBackgroundColor(QColor::fromRgba(qRgba(255, 255, 220, 255)));

// create the QCefView widget and add it to the layout container
m_pRightCefViewWidget = new QCefView(RIGHT_INDEX_URL, &setting, this);
// m_pRightCefViewWidget = new QCefView(RIGHT_INDEX_URL, &setting, this);
m_pRightCefViewWidget = new QCefView("https://www.testufo.com/", &setting, this);

// all the following values will disable the context menu for both NCW and OSR mode
// m_pRightCefViewWidget->setContextMenuPolicy(Qt::NoContextMenu);
Expand Down
2 changes: 1 addition & 1 deletion example/QCefViewTest/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ main(int argc, char* argv[])

// WindowlessRenderingEnabled is set to true by default,
// set to false to disable the OSR mode
config.setWindowlessRenderingEnabled(false);
config.setWindowlessRenderingEnabled(true);

// add command line args, you can any cef supported switches or parameters
config.addCommandLineSwitch("use-mock-keychain");
Expand Down
12 changes: 6 additions & 6 deletions include/CefVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
#pragma once

// clang-format off
#define CEF_VERSION "127.3.5+g114ea2a+chromium-127.0.6533.120"
#define CEF_VERSION_MAJOR 127
#define CEF_VERSION_MINOR 3
#define CEF_VERSION_PATCH 5
#define CEF_COMMIT_NUMBER 3037
#define CEF_COMMIT_HASH "114ea2af1ba9da18c4ac5e599ccdbb17d01ba75a"
#define CEF_VERSION "126.2.18+g3647d39+chromium-126.0.6478.183"
#define CEF_VERSION_MAJOR 126
#define CEF_VERSION_MINOR 2
#define CEF_VERSION_PATCH 18
#define CEF_COMMIT_NUMBER 3019
#define CEF_COMMIT_HASH "3647d39e700c215bd78172c5964eb1c550950f0f"
// clang-format on

#endif // CefVersion
14 changes: 14 additions & 0 deletions include/QCefSetting.h
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,20 @@ class QCEFVIEW_EXPORT QCefSetting
/// </summary>
/// <returns>The color</returns>
const QVariant backgroundColor() const;

#if CEF_VERSION_MAJOR >= 125
/// <summary>
///
/// </summary>
/// <param name="value"></param>
void setHardwareAcceleration(const bool value);

/// <summary>
///
/// </summary>
/// <returns></returns>
const bool hardwareAcceleration() const;
#endif
};

Q_DECLARE_METATYPE(QCefSetting);
Expand Down
99 changes: 67 additions & 32 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,100 @@

## Introduction

QCefView is a Qt-based QWidget that encapsulates CEF (Chromium Embedded Framework). With QCefView, you can build your application UI using modern frontend development techniques, boosting project efficiency while keeping UI and business logic decoupled. Most importantly, QCefView enables seamless CEF integration within Qt applications.

QCefView is a Qt based QWidget which encapsulates [CEF](https://bitbucket.org/chromiumembedded/cef). With QCefView you can build your application UI in frontend developing way to boost your project. And what's more you can completely decouple the UI and business logic in your project. The most important thing is to be able to better use CEF in Qt.
### Support platform
### Build Status
| Platform | Lastest Build Status | OSR Production Ready | NCW Production Ready |
|---|---|---|---|
| Windows-x86_64 | [![Build on Windows](https://github.com/CefView/QCefView/actions/workflows/build-windows-x86_64.yml/badge.svg)](https://github.com/CefView/QCefView/actions/workflows/build-windows-x86_64.yml) | :heavy_check_mark: | :heavy_check_mark: |
| macOS-x86_64 | [![Build on macOS](https://github.com/CefView/QCefView/actions/workflows/build-macos-x86_64.yml/badge.svg)](https://github.com/CefView/QCefView/actions/workflows/build-macos-x86_64.yml) | :heavy_check_mark: | :heavy_check_mark: |
| Linux-x86_64 | [![Build on Linux](https://github.com/CefView/QCefView/actions/workflows/build-linux-x86_64.yml/badge.svg)](https://github.com/CefView/QCefView/actions/workflows/build-linux-x86_64.yml) | :heavy_check_mark: | :x: |

+ **OSR** = Offscreen Rendering Mode
+ **OSR** = Offscreen Rendering Mode
+ **NCW** = Native Child Window Mode

### Feature Status
| Platform | NCW<br> CEF All Versions | OSR - Software Rendering<br> CEF All Versions | OSR - Hardware Rendering<br> CEF 125+ |
|---|:---:|:---:|:---:|
|Windows | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (DirectX 11) |
|MacOS | :heavy_check_mark: | :heavy_check_mark: | :x: WIP (Metal) |
|Linux | :heavy_check_mark: | :heavy_check_mark: | :x: WIP (OpenGL) |

**WIP (Work In Progress)**: Features under development, no guaranteed release date.

---

+ **NCW** = Native Child Window Mode
## Quick Start
### Clone this project
```

### Clone the Project

```sh
git clone https://github.com/CefView/QCefView.git
```
The dependency to CefViewCore has been converted to CMake FetchContent, submodule is not needed anymore.
Pleaser refer to: cmake/CefViewCoreConfig.cmake

The dependency on `CefViewCore` has been converted to **CMake FetchContent**, meaning submodules are no longer required. Refer to: `cmake/CefViewCoreConfig.cmake` for more details.

### Documentation
You can find the latest documentation here:
+ [English Documentation](https://cefview.github.io/QCefView/)
+ [中文文档](https://cefview.github.io/QCefView/zh/)

It can help you quickly understand how to use it.
Find the latest documentation here:

- 📖 [English Documentation](https://cefview.github.io/QCefView/)
- 📖 [中文文档](https://cefview.github.io/QCefView/zh/)

These resources will help you quickly understand and integrate QCefView into your projects.

---

## About OSR mode
## OSR Mode & Hardware Acceleration

QCefView supports **CEF offscreen rendering mode (OSR)**, which is **enabled by default**. To disable OSR mode, set `setWindowlessRenderingEnabled` to `false` in the configuration:

QCefView supports CEF offscreen rendering mode and this feature is enabled by default at runtime, to disable OSR mode you need to set the config item setWindowlessRenderingEnabled to false
```cpp
QCefConfig config;
QCefConfig config;

// WindowlessRenderingEnabled is set to true by default, set to false to disable the OSR mode
config.setWindowlessRenderingEnabled(false)
```
// OSR (Windowless Rendering) is enabled by default
// Set to false to disable OSR mode
config.setWindowlessRenderingEnabled(false);
```

QCefView currently uses Qt Software Rasterizer as the backend paint engine for best compatibility, thus the rendering performance is not so good to be applied for all business scenarios. If you want to host WebGL games, video sites or some other Web Apps with high rendering performance, Non OSR mode (Native Child Window mode) is recommended.
### Enabling Hardware Acceleration (CEF 125+)

## Question
### Why not OpenGL/DirectX/Metal?
Starting from CEF 125+, GPU resource sharing is generally available. QCefView now supports **hardware acceleration** for OSR mode. To enable it:

QCefView was designed to be a common Qt widget for Desktop application, so the compatibility is the first important requirement. We can switch the backend engine from Software Rasterizer to OpenGL/DirectX/Metal but this will increase the complexity and decrease the compatibility of QCefView.
```cpp
QCefSetting setting;

For example if we use OpenGL as the backend engine then all the applications with QCefView introduced will be switched to OpenGL backend automatically. I believe not all users want this to happen.
// Enable hardware renderer (only applicable in OSR mode)
setting.setHardwareAcceleration(true);

DirectX/Metal are platform dependent and they are not supported natively by Qt. If we provide QCefView with extra dependencies individually, this makes QCefView so different with other components in Qt Framework.
// Set frame rate limit
setting.setWindowlessFrameRate(240);

// Create the QCefView widget
auto qCefViewWidget = new QCefView("https://www.testufo.com/", &setting);
```
The performance comparison:
<div align="center">
<a href="docs/images/osr-software-vs-hardware-rendering.png"><img src="docs/images/osr-software-vs-hardware-rendering.png" alt></a>
<br/>
<em>Software VS Hardware Rendering</em>
</div>

But if you must use OSR and the rendering performance is vital, you can try to switch the backend with whatever you want.
---

## Contributing
This project welcomes contributions and suggestions. Make sure to align your code style with the configuration defined by .clang-format file

Making contributions is not a hard thing.
We welcome contributions and suggestions! To maintain consistency, please ensure your code adheres to the style defined in `.clang-format`.

### How You Can Contribute

- 📌 Solve an **issue** (e.g., answer a question in the Issues section or Gitter chat)
- 🛠 Fix a **bug** or report one
- 📖 Improve **documentation** (even fixing typos helps!)

If you're interested in becoming a QCefView **maintainer** (e.g., merging PRs, triaging issues), please contact me via email: `sheentianshen#gmail.com`. I'm happy to help set the right permissions for you.

---

- Solving an issue(maybe just answering a question raised in issues list or gitter)
- Fixing/Issuing a bug
- Improving the documents and even fixing a typo
💡 **Let's build a better QCefView together!** 🚀

are important contributions to QCefView
If you would like to become one of QCefView's maintainers to contribute more (e.g. help merge PR, triage issues), please contact me by email(sheentianshen#gmail.com). I am glad to help you to set the right permission.
6 changes: 6 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ if(OS_WINDOWS)
"/DELAYLOAD:libcef.dll"
)

target_link_libraries(QCefView
PRIVATE
d3d11
d3dcompiler
)

add_custom_command(TARGET QCefView
PRE_BUILD

Expand Down
16 changes: 16 additions & 0 deletions src/QCefSetting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,19 @@ QCefSetting::backgroundColor() const
Q_D(const QCefSetting);
return d->backgroundColor_;
}

#if CEF_VERSION_MAJOR >= 125
void
QCefSetting::setHardwareAcceleration(const bool value)
{
Q_D(QCefSetting);
d->hardwareAcceleration_ = value;
}

const bool
QCefSetting::hardwareAcceleration() const
{
Q_D(const QCefSetting);
return d->hardwareAcceleration_;
}
#endif]
25 changes: 13 additions & 12 deletions src/QCefView.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#include <QCefView.h>
#include <QCefView.h>

#pragma region qt_headers
#include <QPainter>
#include <QPoint>
#include <QResizeEvent>
#include <QVBoxLayout>
#include <QtDebug>
#pragma endregion
#pragma endregion

#include <QCefContext.h>

Expand All @@ -29,7 +29,10 @@ QCefView::QCefView(const QString& url,
: QWidget(parent, f)
, d_ptr(new QCefViewPrivate(QCefContext::instance()->d_func(), this))
{
// create browser
d_ptr->createCefBrowser(this, url, setting ? setting->d_func() : nullptr);

// set window attributes for OSR mode
if (d_ptr->isOSRModeEnabled_) {
// OSR mode
setBackgroundRole(QPalette::Window);
Expand All @@ -40,11 +43,10 @@ QCefView::QCefView(const QString& url,
setAttribute(Qt::WA_NoSystemBackground);
}

// track mouse
setMouseTracking(true);
// set focus policy
setFocusPolicy(Qt::WheelFocus);

// create browser
d_ptr->createCefBrowser(this, url, setting ? setting->d_func() : nullptr);
}

QCefView::QCefView(QWidget* parent /*= 0*/, Qt::WindowFlags f /*= Qt::WindowFlags()*/)
Expand Down Expand Up @@ -167,8 +169,7 @@ QCefView::triggerEvent(const QCefEvent& event)
{
Q_D(QCefView);

return d->triggerEvent(
event.eventName(), event.d_func()->args, QCefView::MainFrameID);
return d->triggerEvent(event.eventName(), event.d_func()->args, QCefView::MainFrameID);
}

bool
Expand All @@ -184,8 +185,7 @@ QCefView::broadcastEvent(const QCefEvent& event)
{
Q_D(QCefView);

return d->triggerEvent(
event.eventName(), event.d_func()->args, QCefView::AllFrameID);
return d->triggerEvent(event.eventName(), event.d_func()->args, QCefView::AllFrameID);
}

bool
Expand Down Expand Up @@ -383,10 +383,11 @@ QCefView::paintEngine() const
{
Q_D(const QCefView);

auto engine = QWidget::paintEngine();
d->onPaintEngine(engine);
if (d->isOSRModeEnabled_ && d->osr.pRenderer_ && d->osr.pRenderer_->isHardware()) {
return nullptr;
}

return engine;
return QWidget::paintEngine();
}

void
Expand Down
3 changes: 3 additions & 0 deletions src/details/QCefSettingPrivate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ QCefSettingPrivate::CopyFromCefBrowserSettings(QCefSetting* qs, const CefBrowser
qs->d_func()->copyFromCefBrowserSettings(cs);
}


void
QCefSettingPrivate::CopyFromCefBrowserSettings(QCefSettingPrivate* qsp, const CefBrowserSettings* cs)
{
Expand All @@ -51,6 +52,7 @@ QCefSettingPrivate::CopyToCefBrowserSettings(const QCefSetting* qs, CefBrowserSe
}
}


void
QCefSettingPrivate::CopyToCefBrowserSettings(const QCefSettingPrivate* qsp, CefBrowserSettings* cs)
{
Expand All @@ -66,6 +68,7 @@ QCefSettingPrivate::CopyToCefBrowserSettings(const QCefSettingPrivate* qsp, CefB
}
}


void
QCefSettingPrivate::copyFromCefBrowserSettings(const CefBrowserSettings* cs)
{
Expand Down
1 change: 1 addition & 0 deletions src/details/QCefSettingPrivate.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class QCefSettingPrivate
//////////////////////////////////////////////////////////////////////////
// Non CEF browser setting values
QSize windowInitialSize_;
bool hardwareAcceleration_ = false;

//////////////////////////////////////////////////////////////////////////
// CEF browser setting values
Expand Down
Loading
Loading