cef/tests/cefclient/browser/osr_render_handler_win_gl.cc
reito 260dd0ca24 osr: Implement shared texture support (fixes #1006, fixes #2575)
Adds support for the OnAcceleratedPaint callback. Verified to work
on macOS and Windows. Linux support is present but not implemented
for cefclient, so it is not verified to work.

To test:
Run `cefclient --off-screen-rendering-enabled --shared-texture-enabled`
2024-04-23 13:03:56 -04:00

196 lines
5.0 KiB
C++

// Copyright 2018 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "tests/cefclient/browser/osr_render_handler_win_gl.h"
#include "include/base/cef_callback.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "tests/shared/browser/util_win.h"
namespace client {
namespace {
// Helper that calls wglMakeCurrent.
class ScopedGLContext {
public:
ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers)
: hdc_(hdc), swap_buffers_(swap_buffers) {
[[maybe_unused]] BOOL result = wglMakeCurrent(hdc, hglrc);
DCHECK(result);
}
~ScopedGLContext() {
BOOL result = wglMakeCurrent(nullptr, nullptr);
DCHECK(result);
if (swap_buffers_) {
result = SwapBuffers(hdc_);
DCHECK(result);
}
}
private:
const HDC hdc_;
const bool swap_buffers_;
};
} // namespace
OsrRenderHandlerWinGL::OsrRenderHandlerWinGL(
const OsrRendererSettings& settings,
HWND hwnd)
: OsrRenderHandlerWin(settings, hwnd), renderer_(settings) {}
void OsrRenderHandlerWinGL::Initialize(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
SetBrowser(browser);
}
OsrRenderHandlerWinGL::~OsrRenderHandlerWinGL() {
CEF_REQUIRE_UI_THREAD();
DisableGL();
}
void OsrRenderHandlerWinGL::SetSpin(float spinX, float spinY) {
CEF_REQUIRE_UI_THREAD();
renderer_.SetSpin(spinX, spinY);
Invalidate();
}
void OsrRenderHandlerWinGL::IncrementSpin(float spinDX, float spinDY) {
CEF_REQUIRE_UI_THREAD();
renderer_.IncrementSpin(spinDX, spinDY);
Invalidate();
}
bool OsrRenderHandlerWinGL::IsOverPopupWidget(int x, int y) const {
CEF_REQUIRE_UI_THREAD();
const CefRect& rc = renderer_.popup_rect();
int popup_right = rc.x + rc.width;
int popup_bottom = rc.y + rc.height;
return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
}
int OsrRenderHandlerWinGL::GetPopupXOffset() const {
CEF_REQUIRE_UI_THREAD();
return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
}
int OsrRenderHandlerWinGL::GetPopupYOffset() const {
CEF_REQUIRE_UI_THREAD();
return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
}
void OsrRenderHandlerWinGL::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
CEF_REQUIRE_UI_THREAD();
if (!show) {
renderer_.ClearPopupRects();
browser->GetHost()->Invalidate(PET_VIEW);
}
renderer_.OnPopupShow(browser, show);
}
void OsrRenderHandlerWinGL::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
renderer_.OnPopupSize(browser, rect);
}
void OsrRenderHandlerWinGL::OnPaint(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) {
CEF_REQUIRE_UI_THREAD();
if (painting_popup_) {
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
return;
}
if (!hdc_) {
EnableGL();
}
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
painting_popup_ = true;
browser->GetHost()->Invalidate(PET_POPUP);
painting_popup_ = false;
}
renderer_.Render();
}
void OsrRenderHandlerWinGL::OnAcceleratedPaint(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const CefAcceleratedPaintInfo& info) {
// Not used with this implementation.
NOTREACHED();
}
void OsrRenderHandlerWinGL::Render() {
if (!hdc_) {
EnableGL();
}
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
renderer_.Render();
}
void OsrRenderHandlerWinGL::EnableGL() {
PIXELFORMATDESCRIPTOR pfd;
int format;
// Get the device context.
hdc_ = GetDC(hwnd());
// Set the pixel format for the DC.
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ChoosePixelFormat(hdc_, &pfd);
SetPixelFormat(hdc_, format, &pfd);
// Create and enable the render context.
hrc_ = wglCreateContext(hdc_);
ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
renderer_.Initialize();
}
void OsrRenderHandlerWinGL::DisableGL() {
if (!hdc_) {
return;
}
{
ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
renderer_.Cleanup();
}
if (IsWindow(hwnd())) {
// wglDeleteContext will make the context not current before deleting it.
[[maybe_unused]] BOOL result = wglDeleteContext(hrc_);
DCHECK(result);
ReleaseDC(hwnd(), hdc_);
}
hdc_ = nullptr;
hrc_ = nullptr;
}
} // namespace client