mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-03-30 11:50:10 +02:00
cefclient: Add support for shared texture and external BeginFrame in OSR mode (issue #1006)
This commit is contained in:
parent
713eebcafc
commit
1e6b870af0
BUILD.gncef_paths2.gypi
tests
cefclient
CMakeLists.txt.in
browser
browser_window_osr_gtk.ccbrowser_window_osr_gtk.hbrowser_window_osr_mac.hbrowser_window_osr_mac.mmbrowser_window_osr_win.ccbrowser_window_osr_win.hclient_handler.ccclient_handler_osr.ccclient_handler_osr.hmain_context.hmain_context_impl.ccmain_context_impl.hmain_context_impl_win.ccosr_d3d11_win.ccosr_d3d11_win.hosr_render_handler_win.ccosr_render_handler_win.hosr_render_handler_win_d3d11.ccosr_render_handler_win_d3d11.hosr_render_handler_win_gl.ccosr_render_handler_win_gl.hosr_renderer.ccosr_renderer.hosr_renderer_settings.hosr_window_win.ccosr_window_win.hroot_window_gtk.ccroot_window_mac.mmroot_window_win.cc
shared
1
BUILD.gn
1
BUILD.gn
@ -1956,6 +1956,7 @@ if (is_mac) {
|
||||
|
||||
libs = [
|
||||
"comctl32.lib",
|
||||
"d3d11.lib",
|
||||
"glu32.lib",
|
||||
"imm32.lib",
|
||||
"oleacc.lib",
|
||||
|
@ -233,6 +233,7 @@
|
||||
'tests/cefclient/browser/osr_dragdrop_events.h',
|
||||
'tests/cefclient/browser/osr_renderer.h',
|
||||
'tests/cefclient/browser/osr_renderer.cc',
|
||||
'tests/cefclient/browser/osr_renderer_settings.h',
|
||||
'tests/cefclient/browser/preferences_test.cc',
|
||||
'tests/cefclient/browser/preferences_test.h',
|
||||
'tests/cefclient/browser/resource.h',
|
||||
@ -316,6 +317,14 @@
|
||||
'tests/cefclient/browser/osr_dragdrop_win.h',
|
||||
'tests/cefclient/browser/osr_ime_handler_win.cc',
|
||||
'tests/cefclient/browser/osr_ime_handler_win.h',
|
||||
'tests/cefclient/browser/osr_d3d11_win.cc',
|
||||
'tests/cefclient/browser/osr_d3d11_win.h',
|
||||
'tests/cefclient/browser/osr_render_handler_win.cc',
|
||||
'tests/cefclient/browser/osr_render_handler_win.h',
|
||||
'tests/cefclient/browser/osr_render_handler_win_d3d11.cc',
|
||||
'tests/cefclient/browser/osr_render_handler_win_d3d11.h',
|
||||
'tests/cefclient/browser/osr_render_handler_win_gl.cc',
|
||||
'tests/cefclient/browser/osr_render_handler_win_gl.h',
|
||||
'tests/cefclient/browser/osr_window_win.cc',
|
||||
'tests/cefclient/browser/osr_window_win.h',
|
||||
'tests/cefclient/browser/resource_util_win_idmap.cc',
|
||||
|
@ -248,7 +248,7 @@ if(OS_WINDOWS)
|
||||
add_executable(${CEF_TARGET} WIN32 ${CEFCLIENT_SRCS})
|
||||
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
|
||||
add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
|
||||
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS} glu32.lib imm32.lib opengl32.lib)
|
||||
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS} d3d11.lib glu32.lib imm32.lib opengl32.lib)
|
||||
|
||||
if(USE_ATL)
|
||||
# Required by VS2013 to link accessibility API functions.
|
||||
|
@ -930,7 +930,7 @@ class ScopedGLContext {
|
||||
|
||||
BrowserWindowOsrGtk::BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
|
||||
const std::string& startup_url,
|
||||
const OsrRenderer::Settings& settings)
|
||||
const OsrRendererSettings& settings)
|
||||
: BrowserWindow(delegate),
|
||||
xdisplay_(nullptr),
|
||||
renderer_(settings),
|
||||
|
@ -24,7 +24,7 @@ class BrowserWindowOsrGtk : public BrowserWindow,
|
||||
// |delegate| must outlive this object.
|
||||
BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
|
||||
const std::string& startup_url,
|
||||
const OsrRenderer::Settings& settings);
|
||||
const OsrRendererSettings& settings);
|
||||
|
||||
// Called from RootWindowGtk::CreateRootWindow before CreateBrowser.
|
||||
void set_xdisplay(XDisplay* xdisplay);
|
||||
|
@ -23,7 +23,7 @@ class BrowserWindowOsrMac : public BrowserWindow,
|
||||
// |delegate| must outlive this object.
|
||||
BrowserWindowOsrMac(BrowserWindow::Delegate* delegate,
|
||||
const std::string& startup_url,
|
||||
const OsrRenderer::Settings& settings);
|
||||
const OsrRendererSettings& settings);
|
||||
~BrowserWindowOsrMac();
|
||||
|
||||
// BrowserWindow methods.
|
||||
|
@ -1208,7 +1208,7 @@ namespace client {
|
||||
|
||||
BrowserWindowOsrMac::BrowserWindowOsrMac(BrowserWindow::Delegate* delegate,
|
||||
const std::string& startup_url,
|
||||
const OsrRenderer::Settings& settings)
|
||||
const OsrRendererSettings& settings)
|
||||
: BrowserWindow(delegate),
|
||||
renderer_(settings),
|
||||
nsview_(NULL),
|
||||
|
@ -10,7 +10,7 @@ namespace client {
|
||||
|
||||
BrowserWindowOsrWin::BrowserWindowOsrWin(BrowserWindow::Delegate* delegate,
|
||||
const std::string& startup_url,
|
||||
const OsrRenderer::Settings& settings)
|
||||
const OsrRendererSettings& settings)
|
||||
: BrowserWindow(delegate), osr_hwnd_(NULL), device_scale_factor_(0) {
|
||||
osr_window_ = new OsrWindowWin(this, settings);
|
||||
client_handler_ = new ClientHandlerOsr(this, osr_window_.get(), startup_url);
|
||||
@ -36,6 +36,11 @@ void BrowserWindowOsrWin::GetPopupConfig(CefWindowHandle temp_handle,
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
windowInfo.SetAsWindowless(temp_handle);
|
||||
windowInfo.shared_texture_enabled =
|
||||
osr_window_->settings().shared_texture_enabled;
|
||||
windowInfo.external_begin_frame_enabled =
|
||||
osr_window_->settings().external_begin_frame_enabled;
|
||||
|
||||
client = client_handler_;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ class BrowserWindowOsrWin : public BrowserWindow,
|
||||
// |delegate| must outlive this object.
|
||||
BrowserWindowOsrWin(BrowserWindow::Delegate* delegate,
|
||||
const std::string& startup_url,
|
||||
const OsrRenderer::Settings& settings);
|
||||
const OsrRendererSettings& settings);
|
||||
|
||||
// BrowserWindow methods.
|
||||
void CreateBrowser(ClientWindowHandle parent_handle,
|
||||
|
@ -831,6 +831,8 @@ void ClientHandler::ShowDevTools(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefClient> client;
|
||||
CefBrowserSettings settings;
|
||||
|
||||
MainContext::Get()->PopulateBrowserSettings(&settings);
|
||||
|
||||
CefRefPtr<CefBrowserHost> host = browser->GetHost();
|
||||
|
||||
// Test if the DevTools browser already exists.
|
||||
|
@ -107,6 +107,17 @@ void ClientHandlerOsr::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
osr_delegate_->OnPaint(browser, type, dirtyRects, buffer, width, height);
|
||||
}
|
||||
|
||||
void ClientHandlerOsr::OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!osr_delegate_)
|
||||
return;
|
||||
osr_delegate_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
|
||||
}
|
||||
|
||||
void ClientHandlerOsr::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
CefCursorHandle cursor,
|
||||
CursorType type,
|
||||
|
@ -39,11 +39,16 @@ class ClientHandlerOsr : public ClientHandler,
|
||||
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) = 0;
|
||||
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
PaintElementType type,
|
||||
const RectList& dirtyRects,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) = 0;
|
||||
virtual void OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {}
|
||||
virtual void OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
CefCursorHandle cursor,
|
||||
CefRenderHandler::CursorType type,
|
||||
@ -103,6 +108,10 @@ class ClientHandlerOsr : public ClientHandler,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) OVERRIDE;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) OVERRIDE;
|
||||
void OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
CefCursorHandle cursor,
|
||||
CursorType type,
|
||||
|
@ -10,10 +10,16 @@
|
||||
|
||||
#include "include/base/cef_ref_counted.h"
|
||||
#include "include/internal/cef_types_wrappers.h"
|
||||
#include "tests/cefclient/browser/osr_renderer.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
namespace d3d11 {
|
||||
class Device;
|
||||
}
|
||||
#endif
|
||||
|
||||
class RootWindowManager;
|
||||
|
||||
// Used to store global context in the browser process. The methods of this
|
||||
@ -47,11 +53,15 @@ class MainContext {
|
||||
// Populate |settings| based on command-line arguments.
|
||||
virtual void PopulateSettings(CefSettings* settings) = 0;
|
||||
virtual void PopulateBrowserSettings(CefBrowserSettings* settings) = 0;
|
||||
virtual void PopulateOsrSettings(OsrRenderer::Settings* settings) = 0;
|
||||
virtual void PopulateOsrSettings(OsrRendererSettings* settings) = 0;
|
||||
|
||||
// Returns the object used to create/manage RootWindow instances.
|
||||
virtual RootWindowManager* GetRootWindowManager() = 0;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
virtual std::shared_ptr<d3d11::Device> GetD3D11Device() = 0;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
MainContext();
|
||||
virtual ~MainContext();
|
||||
|
@ -46,6 +46,7 @@ MainContextImpl::MainContextImpl(CefRefPtr<CefCommandLine> command_line,
|
||||
shutdown_(false),
|
||||
background_color_(0),
|
||||
browser_background_color_(0),
|
||||
windowless_frame_rate_(0),
|
||||
use_views_(false) {
|
||||
DCHECK(command_line_.get());
|
||||
|
||||
@ -59,11 +60,39 @@ MainContextImpl::MainContextImpl(CefRefPtr<CefCommandLine> command_line,
|
||||
use_windowless_rendering_ =
|
||||
command_line_->HasSwitch(switches::kOffScreenRenderingEnabled);
|
||||
|
||||
if (use_windowless_rendering_ &&
|
||||
command_line_->HasSwitch(switches::kOffScreenFrameRate)) {
|
||||
windowless_frame_rate_ =
|
||||
atoi(command_line_->GetSwitchValue(switches::kOffScreenFrameRate)
|
||||
.ToString()
|
||||
.c_str());
|
||||
}
|
||||
|
||||
// Whether transparent painting is used with windowless rendering.
|
||||
const bool use_transparent_painting =
|
||||
use_windowless_rendering_ &&
|
||||
command_line_->HasSwitch(switches::kTransparentPaintingEnabled);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Shared texture is only supported on Windows.
|
||||
shared_texture_enabled_ =
|
||||
use_windowless_rendering_ &&
|
||||
command_line_->HasSwitch(switches::kSharedTextureEnabled);
|
||||
#endif
|
||||
|
||||
external_begin_frame_enabled_ =
|
||||
use_windowless_rendering_ &&
|
||||
command_line_->HasSwitch(switches::kExternalBeginFrameEnabled);
|
||||
|
||||
if (windowless_frame_rate_ <= 0) {
|
||||
// Choose a reasonable default rate based on the OSR mode.
|
||||
#if defined(OS_WIN)
|
||||
windowless_frame_rate_ = shared_texture_enabled_ ? 60 : 30;
|
||||
#else
|
||||
windowless_frame_rate_ = 30;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(OS_WIN) || defined(OS_LINUX)
|
||||
// Whether the Views framework will be used.
|
||||
use_views_ = command_line_->HasSwitch(switches::kUseViews);
|
||||
@ -156,21 +185,22 @@ void MainContextImpl::PopulateSettings(CefSettings* settings) {
|
||||
}
|
||||
|
||||
void MainContextImpl::PopulateBrowserSettings(CefBrowserSettings* settings) {
|
||||
if (command_line_->HasSwitch(switches::kOffScreenFrameRate)) {
|
||||
settings->windowless_frame_rate =
|
||||
atoi(command_line_->GetSwitchValue(switches::kOffScreenFrameRate)
|
||||
.ToString()
|
||||
.c_str());
|
||||
}
|
||||
settings->windowless_frame_rate = windowless_frame_rate_;
|
||||
|
||||
if (browser_background_color_ != 0)
|
||||
settings->background_color = browser_background_color_;
|
||||
}
|
||||
|
||||
void MainContextImpl::PopulateOsrSettings(OsrRenderer::Settings* settings) {
|
||||
void MainContextImpl::PopulateOsrSettings(OsrRendererSettings* settings) {
|
||||
settings->show_update_rect =
|
||||
command_line_->HasSwitch(switches::kShowUpdateRect);
|
||||
|
||||
#if defined(OS_WIN)
|
||||
settings->shared_texture_enabled = shared_texture_enabled_;
|
||||
#endif
|
||||
settings->external_begin_frame_enabled = external_begin_frame_enabled_;
|
||||
settings->begin_frame_rate = windowless_frame_rate_;
|
||||
|
||||
if (browser_background_color_ != 0)
|
||||
settings->background_color = browser_background_color_;
|
||||
}
|
||||
|
@ -31,9 +31,13 @@ class MainContextImpl : public MainContext {
|
||||
bool UseWindowlessRendering() OVERRIDE;
|
||||
void PopulateSettings(CefSettings* settings) OVERRIDE;
|
||||
void PopulateBrowserSettings(CefBrowserSettings* settings) OVERRIDE;
|
||||
void PopulateOsrSettings(OsrRenderer::Settings* settings) OVERRIDE;
|
||||
void PopulateOsrSettings(OsrRendererSettings* settings) OVERRIDE;
|
||||
RootWindowManager* GetRootWindowManager() OVERRIDE;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
std::shared_ptr<d3d11::Device> GetD3D11Device() OVERRIDE;
|
||||
#endif
|
||||
|
||||
// Initialize CEF and associated main context state. This method must be
|
||||
// called on the same thread that created this object.
|
||||
bool Initialize(const CefMainArgs& args,
|
||||
@ -68,10 +72,18 @@ class MainContextImpl : public MainContext {
|
||||
cef_color_t background_color_;
|
||||
cef_color_t browser_background_color_;
|
||||
bool use_windowless_rendering_;
|
||||
int windowless_frame_rate_;
|
||||
bool use_views_;
|
||||
|
||||
scoped_ptr<RootWindowManager> root_window_manager_;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
bool shared_texture_enabled_;
|
||||
std::shared_ptr<d3d11::Device> d3d11_device_;
|
||||
#endif
|
||||
|
||||
bool external_begin_frame_enabled_;
|
||||
|
||||
// Used to verify that methods are called on the correct thread.
|
||||
base::ThreadChecker thread_checker_;
|
||||
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include <direct.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "tests/cefclient/browser/osr_d3d11_win.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
std::string MainContextImpl::GetDownloadPath(const std::string& file_name) {
|
||||
@ -36,4 +38,11 @@ std::string MainContextImpl::GetAppWorkingDirectory() {
|
||||
return szWorkingDir;
|
||||
}
|
||||
|
||||
std::shared_ptr<d3d11::Device> MainContextImpl::GetD3D11Device() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!d3d11_device_)
|
||||
d3d11_device_ = d3d11::Device::create();
|
||||
return d3d11_device_;
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
931
tests/cefclient/browser/osr_d3d11_win.cc
Normal file
931
tests/cefclient/browser/osr_d3d11_win.cc
Normal file
@ -0,0 +1,931 @@
|
||||
// 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.
|
||||
//
|
||||
// Portions Copyright (c) 2018 Daktronics with the following MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
#include "tests/cefclient/browser/osr_d3d11_win.h"
|
||||
|
||||
#include <iomanip> // For std::setw.
|
||||
|
||||
#include <d3dcompiler.h>
|
||||
#include <directxmath.h>
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/internal/cef_string.h"
|
||||
#include "tests/shared/browser/util_win.h"
|
||||
|
||||
namespace client {
|
||||
namespace d3d11 {
|
||||
|
||||
namespace {
|
||||
|
||||
// Wrap a raw COM pointer in a shared_ptr for auto Release().
|
||||
template <class T>
|
||||
std::shared_ptr<T> to_com_ptr(T* obj) {
|
||||
return std::shared_ptr<T>(obj, [](T* p) {
|
||||
if (p)
|
||||
p->Release();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct SimpleVertex {
|
||||
DirectX::XMFLOAT3 pos;
|
||||
DirectX::XMFLOAT2 tex;
|
||||
};
|
||||
|
||||
Context::Context(ID3D11DeviceContext* ctx) : ctx_(to_com_ptr(ctx)) {}
|
||||
|
||||
void Context::flush() {
|
||||
ctx_->Flush();
|
||||
}
|
||||
|
||||
SwapChain::SwapChain(IDXGISwapChain* swapchain,
|
||||
ID3D11RenderTargetView* rtv,
|
||||
ID3D11SamplerState* sampler,
|
||||
ID3D11BlendState* blender)
|
||||
: sampler_(to_com_ptr(sampler)),
|
||||
blender_(to_com_ptr(blender)),
|
||||
swapchain_(to_com_ptr(swapchain)),
|
||||
rtv_(to_com_ptr(rtv)),
|
||||
width_(0),
|
||||
height_(0) {}
|
||||
|
||||
void SwapChain::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
ID3D11RenderTargetView* rtv[1] = {rtv_.get()};
|
||||
d3d11_ctx->OMSetRenderTargets(1, rtv, nullptr);
|
||||
|
||||
// Set default blending state.
|
||||
if (blender_) {
|
||||
float factor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||
d3d11_ctx->OMSetBlendState(blender_.get(), factor, 0xffffffff);
|
||||
}
|
||||
|
||||
// Set default sampler state.
|
||||
if (sampler_) {
|
||||
ID3D11SamplerState* samplers[1] = {sampler_.get()};
|
||||
d3d11_ctx->PSSetSamplers(0, 1, samplers);
|
||||
}
|
||||
}
|
||||
|
||||
void SwapChain::unbind() {
|
||||
ctx_.reset();
|
||||
}
|
||||
|
||||
void SwapChain::clear(float red, float green, float blue, float alpha) {
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
|
||||
FLOAT color[4] = {red, green, blue, alpha};
|
||||
d3d11_ctx->ClearRenderTargetView(rtv_.get(), color);
|
||||
}
|
||||
|
||||
void SwapChain::present(int sync_interval) {
|
||||
swapchain_->Present(sync_interval, 0);
|
||||
}
|
||||
|
||||
void SwapChain::resize(int width, int height) {
|
||||
if (width <= 0 || height <= 0 || width == width_ || height == height_) {
|
||||
return;
|
||||
}
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
|
||||
d3d11_ctx->OMSetRenderTargets(0, 0, 0);
|
||||
rtv_.reset();
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC desc;
|
||||
swapchain_->GetDesc(&desc);
|
||||
auto hr = swapchain_->ResizeBuffers(0, width, height, desc.BufferDesc.Format,
|
||||
desc.Flags);
|
||||
if (FAILED(hr)) {
|
||||
LOG(ERROR) << "d3d11: Failed to resize swapchain (" << width << "x"
|
||||
<< height << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* buffer = nullptr;
|
||||
hr = swapchain_->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&buffer);
|
||||
if (FAILED(hr)) {
|
||||
LOG(ERROR) << "d3d11: Failed to resize swapchain (" << width << "x"
|
||||
<< height << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D11Device* dev = nullptr;
|
||||
d3d11_ctx->GetDevice(&dev);
|
||||
if (dev) {
|
||||
D3D11_RENDER_TARGET_VIEW_DESC vdesc = {};
|
||||
vdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
|
||||
vdesc.Texture2D.MipSlice = 0;
|
||||
vdesc.Format = desc.BufferDesc.Format;
|
||||
|
||||
ID3D11RenderTargetView* view = nullptr;
|
||||
hr = dev->CreateRenderTargetView(buffer, &vdesc, &view);
|
||||
if (SUCCEEDED(hr)) {
|
||||
rtv_ = to_com_ptr(view);
|
||||
d3d11_ctx->OMSetRenderTargets(1, &view, nullptr);
|
||||
}
|
||||
dev->Release();
|
||||
}
|
||||
buffer->Release();
|
||||
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.Width = static_cast<float>(width);
|
||||
vp.Height = static_cast<float>(height);
|
||||
vp.MinDepth = D3D11_MIN_DEPTH;
|
||||
vp.MaxDepth = D3D11_MAX_DEPTH;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
d3d11_ctx->RSSetViewports(1, &vp);
|
||||
}
|
||||
|
||||
Effect::Effect(ID3D11VertexShader* vsh,
|
||||
ID3D11PixelShader* psh,
|
||||
ID3D11InputLayout* layout)
|
||||
: vsh_(to_com_ptr(vsh)),
|
||||
psh_(to_com_ptr(psh)),
|
||||
layout_(to_com_ptr(layout)) {}
|
||||
|
||||
void Effect::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
d3d11_ctx->IASetInputLayout(layout_.get());
|
||||
d3d11_ctx->VSSetShader(vsh_.get(), nullptr, 0);
|
||||
d3d11_ctx->PSSetShader(psh_.get(), nullptr, 0);
|
||||
}
|
||||
|
||||
void Effect::unbind() {}
|
||||
|
||||
Geometry::Geometry(D3D_PRIMITIVE_TOPOLOGY primitive,
|
||||
uint32_t vertices,
|
||||
uint32_t stride,
|
||||
ID3D11Buffer* buffer)
|
||||
: primitive_(primitive),
|
||||
vertices_(vertices),
|
||||
stride_(stride),
|
||||
buffer_(to_com_ptr(buffer)) {}
|
||||
|
||||
void Geometry::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
// TODO: Handle offset.
|
||||
uint32_t offset = 0;
|
||||
|
||||
ID3D11Buffer* buffers[1] = {buffer_.get()};
|
||||
d3d11_ctx->IASetVertexBuffers(0, 1, buffers, &stride_, &offset);
|
||||
d3d11_ctx->IASetPrimitiveTopology(primitive_);
|
||||
}
|
||||
|
||||
void Geometry::unbind() {}
|
||||
|
||||
void Geometry::draw() {
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
|
||||
// TODO: Handle offset.
|
||||
d3d11_ctx->Draw(vertices_, 0);
|
||||
}
|
||||
|
||||
Texture2D::Texture2D(ID3D11Texture2D* tex, ID3D11ShaderResourceView* srv)
|
||||
: texture_(to_com_ptr(tex)), srv_(to_com_ptr(srv)) {
|
||||
share_handle_ = nullptr;
|
||||
|
||||
IDXGIResource* res = nullptr;
|
||||
if (SUCCEEDED(texture_->QueryInterface(__uuidof(IDXGIResource),
|
||||
reinterpret_cast<void**>(&res)))) {
|
||||
res->GetSharedHandle(&share_handle_);
|
||||
res->Release();
|
||||
}
|
||||
|
||||
// Are we using a keyed mutex?
|
||||
IDXGIKeyedMutex* mutex = nullptr;
|
||||
if (SUCCEEDED(texture_->QueryInterface(__uuidof(IDXGIKeyedMutex),
|
||||
(void**)&mutex))) {
|
||||
keyed_mutex_ = to_com_ptr(mutex);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Texture2D::width() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture_->GetDesc(&desc);
|
||||
return desc.Width;
|
||||
}
|
||||
|
||||
uint32_t Texture2D::height() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture_->GetDesc(&desc);
|
||||
return desc.Height;
|
||||
}
|
||||
|
||||
DXGI_FORMAT Texture2D::format() const {
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
texture_->GetDesc(&desc);
|
||||
return desc.Format;
|
||||
}
|
||||
|
||||
bool Texture2D::has_mutex() const {
|
||||
return (keyed_mutex_.get() != nullptr);
|
||||
}
|
||||
|
||||
bool Texture2D::lock_key(uint64_t key, uint32_t timeout_ms) {
|
||||
if (keyed_mutex_) {
|
||||
const auto hr = keyed_mutex_->AcquireSync(key, timeout_ms);
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Texture2D::unlock_key(uint64_t key) {
|
||||
if (keyed_mutex_) {
|
||||
keyed_mutex_->ReleaseSync(key);
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::bind(const std::shared_ptr<Context>& ctx) {
|
||||
ctx_ = ctx;
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
if (srv_) {
|
||||
ID3D11ShaderResourceView* views[1] = {srv_.get()};
|
||||
d3d11_ctx->PSSetShaderResources(0, 1, views);
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::unbind() {}
|
||||
|
||||
void* Texture2D::share_handle() const {
|
||||
return share_handle_;
|
||||
}
|
||||
|
||||
void Texture2D::copy_from(const std::shared_ptr<Texture2D>& other) {
|
||||
ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
CHECK(d3d11_ctx);
|
||||
if (other) {
|
||||
d3d11_ctx->CopyResource(texture_.get(), other->texture_.get());
|
||||
}
|
||||
}
|
||||
|
||||
Device::Device(ID3D11Device* pdev, ID3D11DeviceContext* pctx)
|
||||
: device_(to_com_ptr(pdev)), ctx_(std::make_shared<Context>(pctx)) {
|
||||
lib_compiler_ = LoadLibrary(L"d3dcompiler_47.dll");
|
||||
}
|
||||
|
||||
// static
|
||||
std::shared_ptr<Device> Device::create() {
|
||||
UINT flags = 0;
|
||||
#ifdef _DEBUG
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
|
||||
D3D_FEATURE_LEVEL feature_levels[] = {
|
||||
D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0,
|
||||
// D3D_FEATURE_LEVEL_9_3,
|
||||
};
|
||||
UINT num_feature_levels = sizeof(feature_levels) / sizeof(feature_levels[0]);
|
||||
|
||||
ID3D11Device* pdev = nullptr;
|
||||
ID3D11DeviceContext* pctx = nullptr;
|
||||
|
||||
D3D_FEATURE_LEVEL selected_level;
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, feature_levels,
|
||||
num_feature_levels, D3D11_SDK_VERSION, &pdev, &selected_level, &pctx);
|
||||
|
||||
if (hr == E_INVALIDARG) {
|
||||
// DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1
|
||||
// so we need to retry without it.
|
||||
hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
|
||||
&feature_levels[1], num_feature_levels - 1,
|
||||
D3D11_SDK_VERSION, &pdev, &selected_level, &pctx);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
const auto dev = std::make_shared<Device>(pdev, pctx);
|
||||
|
||||
LOG(INFO) << "d3d11: Selected adapter " << dev->adapter_name()
|
||||
<< " and feature level 0x" << std::setw(4) << std::hex
|
||||
<< selected_level;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string Device::adapter_name() const {
|
||||
IDXGIDevice* dxgi_dev = nullptr;
|
||||
auto hr = device_->QueryInterface(__uuidof(dxgi_dev), (void**)&dxgi_dev);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IDXGIAdapter* dxgi_adapt = nullptr;
|
||||
hr = dxgi_dev->GetAdapter(&dxgi_adapt);
|
||||
dxgi_dev->Release();
|
||||
if (SUCCEEDED(hr)) {
|
||||
DXGI_ADAPTER_DESC desc;
|
||||
hr = dxgi_adapt->GetDesc(&desc);
|
||||
dxgi_adapt->Release();
|
||||
if (SUCCEEDED(hr)) {
|
||||
return CefString(desc.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
std::shared_ptr<Context> Device::immedidate_context() {
|
||||
return ctx_;
|
||||
}
|
||||
|
||||
std::shared_ptr<SwapChain> Device::create_swapchain(HWND window,
|
||||
int width,
|
||||
int height) {
|
||||
HRESULT hr;
|
||||
IDXGIFactory1* dxgi_factory = nullptr;
|
||||
|
||||
// Default size to the window size unless specified.
|
||||
RECT rc_bounds;
|
||||
GetClientRect(window, &rc_bounds);
|
||||
if (width <= 0) {
|
||||
width = rc_bounds.right - rc_bounds.left;
|
||||
}
|
||||
if (height <= 0) {
|
||||
height = rc_bounds.bottom - rc_bounds.top;
|
||||
}
|
||||
|
||||
{
|
||||
IDXGIDevice* dxgi_dev = nullptr;
|
||||
hr = device_->QueryInterface(__uuidof(IDXGIDevice),
|
||||
reinterpret_cast<void**>(&dxgi_dev));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDXGIAdapter* adapter = nullptr;
|
||||
hr = dxgi_dev->GetAdapter(&adapter);
|
||||
dxgi_dev->Release();
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hr = adapter->GetParent(__uuidof(IDXGIFactory1),
|
||||
reinterpret_cast<void**>(&dxgi_factory));
|
||||
adapter->Release();
|
||||
}
|
||||
|
||||
if (!dxgi_factory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IDXGISwapChain* swapchain = nullptr;
|
||||
|
||||
// Create swap chain.
|
||||
IDXGIFactory2* dxgi_factory2 = nullptr;
|
||||
hr = dxgi_factory->QueryInterface(__uuidof(IDXGIFactory2),
|
||||
reinterpret_cast<void**>(&dxgi_factory2));
|
||||
if (dxgi_factory2) {
|
||||
DXGI_SWAP_CHAIN_DESC1 sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.Width = width;
|
||||
sd.Height = height;
|
||||
sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferCount = 1;
|
||||
|
||||
IDXGISwapChain1* swapchain1 = nullptr;
|
||||
hr = dxgi_factory2->CreateSwapChainForHwnd(device_.get(), window, &sd,
|
||||
nullptr, nullptr, &swapchain1);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain),
|
||||
reinterpret_cast<void**>(&swapchain));
|
||||
swapchain1->Release();
|
||||
}
|
||||
|
||||
dxgi_factory2->Release();
|
||||
} else {
|
||||
// DirectX 11.0 systems.
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = width;
|
||||
sd.BufferDesc.Height = height;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.OutputWindow = window;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
|
||||
hr = dxgi_factory->CreateSwapChain(device_.get(), &sd, &swapchain);
|
||||
}
|
||||
|
||||
// We don't handle full-screen swapchains so we block the ALT+ENTER shortcut.
|
||||
dxgi_factory->MakeWindowAssociation(window, DXGI_MWA_NO_ALT_ENTER);
|
||||
dxgi_factory->Release();
|
||||
|
||||
if (!swapchain) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11Texture2D* back_buffer = nullptr;
|
||||
hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D),
|
||||
reinterpret_cast<void**>(&back_buffer));
|
||||
if (FAILED(hr)) {
|
||||
swapchain->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
hr = device_->CreateRenderTargetView(back_buffer, nullptr, &rtv);
|
||||
back_buffer->Release();
|
||||
if (FAILED(hr)) {
|
||||
swapchain->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto ctx = (ID3D11DeviceContext*)(*ctx_);
|
||||
|
||||
ctx->OMSetRenderTargets(1, &rtv, nullptr);
|
||||
|
||||
// Setup the viewport.
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.Width = (FLOAT)width;
|
||||
vp.Height = (FLOAT)height;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
ctx->RSSetViewports(1, &vp);
|
||||
|
||||
// Create a default sampler to use.
|
||||
ID3D11SamplerState* sampler = nullptr;
|
||||
{
|
||||
D3D11_SAMPLER_DESC desc = {};
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
desc.MinLOD = 0.0f;
|
||||
desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
device_->CreateSamplerState(&desc, &sampler);
|
||||
}
|
||||
|
||||
// Create a default blend state to use (pre-multiplied alpha).
|
||||
ID3D11BlendState* blender = nullptr;
|
||||
{
|
||||
D3D11_BLEND_DESC desc;
|
||||
desc.AlphaToCoverageEnable = FALSE;
|
||||
desc.IndependentBlendEnable = FALSE;
|
||||
const auto count = sizeof(desc.RenderTarget) / sizeof(desc.RenderTarget[0]);
|
||||
for (size_t n = 0; n < count; ++n) {
|
||||
desc.RenderTarget[n].BlendEnable = TRUE;
|
||||
desc.RenderTarget[n].SrcBlend = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[n].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[n].SrcBlendAlpha = D3D11_BLEND_ONE;
|
||||
desc.RenderTarget[n].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
|
||||
desc.RenderTarget[n].BlendOp = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[n].BlendOpAlpha = D3D11_BLEND_OP_ADD;
|
||||
desc.RenderTarget[n].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
}
|
||||
device_->CreateBlendState(&desc, &blender);
|
||||
}
|
||||
|
||||
return std::make_shared<SwapChain>(swapchain, rtv, sampler, blender);
|
||||
}
|
||||
|
||||
std::shared_ptr<Geometry> Device::create_quad(float x,
|
||||
float y,
|
||||
float width,
|
||||
float height,
|
||||
bool flip) {
|
||||
x = (x * 2.0f) - 1.0f;
|
||||
y = 1.0f - (y * 2.0f);
|
||||
width = width * 2.0f;
|
||||
height = height * 2.0f;
|
||||
float z = 1.0f;
|
||||
|
||||
SimpleVertex vertices[] = {
|
||||
|
||||
{DirectX::XMFLOAT3(x, y, z), DirectX::XMFLOAT2(0.0f, 0.0f)},
|
||||
{DirectX::XMFLOAT3(x + width, y, z), DirectX::XMFLOAT2(1.0f, 0.0f)},
|
||||
{DirectX::XMFLOAT3(x, y - height, z), DirectX::XMFLOAT2(0.0f, 1.0f)},
|
||||
{DirectX::XMFLOAT3(x + width, y - height, z),
|
||||
DirectX::XMFLOAT2(1.0f, 1.0f)}};
|
||||
|
||||
if (flip) {
|
||||
DirectX::XMFLOAT2 tmp(vertices[2].tex);
|
||||
vertices[2].tex = vertices[0].tex;
|
||||
vertices[0].tex = tmp;
|
||||
|
||||
tmp = vertices[3].tex;
|
||||
vertices[3].tex = vertices[1].tex;
|
||||
vertices[1].tex = tmp;
|
||||
}
|
||||
|
||||
D3D11_BUFFER_DESC desc = {};
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.ByteWidth = sizeof(SimpleVertex) * 4;
|
||||
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
|
||||
desc.CPUAccessFlags = 0;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA srd = {};
|
||||
srd.pSysMem = vertices;
|
||||
|
||||
ID3D11Buffer* buffer = nullptr;
|
||||
const auto hr = device_->CreateBuffer(&desc, &srd, &buffer);
|
||||
if (SUCCEEDED(hr)) {
|
||||
return std::make_shared<Geometry>(
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4,
|
||||
static_cast<uint32_t>(sizeof(SimpleVertex)), buffer);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture2D> Device::open_shared_texture(void* handle) {
|
||||
ID3D11Texture2D* tex = nullptr;
|
||||
auto hr = device_->OpenSharedResource(handle, __uuidof(ID3D11Texture2D),
|
||||
(void**)(&tex));
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
tex->GetDesc(&td);
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
|
||||
if (td.BindFlags & D3D11_BIND_SHADER_RESOURCE) {
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
srv_desc.Format = td.Format;
|
||||
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
srv_desc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device_->CreateShaderResourceView(tex, &srv_desc, &srv);
|
||||
if (FAILED(hr)) {
|
||||
tex->Release();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_shared<Texture2D>(tex, srv);
|
||||
}
|
||||
|
||||
std::shared_ptr<Texture2D> Device::create_texture(int width,
|
||||
int height,
|
||||
DXGI_FORMAT format,
|
||||
const void* data,
|
||||
size_t row_stride) {
|
||||
D3D11_TEXTURE2D_DESC td;
|
||||
td.ArraySize = 1;
|
||||
td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
td.CPUAccessFlags = 0;
|
||||
td.Format = format;
|
||||
td.Width = width;
|
||||
td.Height = height;
|
||||
td.MipLevels = 1;
|
||||
td.MiscFlags = 0;
|
||||
td.SampleDesc.Count = 1;
|
||||
td.SampleDesc.Quality = 0;
|
||||
td.Usage = D3D11_USAGE_DEFAULT;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA srd;
|
||||
srd.pSysMem = data;
|
||||
srd.SysMemPitch = static_cast<uint32_t>(row_stride);
|
||||
srd.SysMemSlicePitch = 0;
|
||||
|
||||
ID3D11Texture2D* tex = nullptr;
|
||||
auto hr = device_->CreateTexture2D(&td, data ? &srd : nullptr, &tex);
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
|
||||
srv_desc.Format = td.Format;
|
||||
srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srv_desc.Texture2D.MostDetailedMip = 0;
|
||||
srv_desc.Texture2D.MipLevels = 1;
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
hr = device_->CreateShaderResourceView(tex, &srv_desc, &srv);
|
||||
if (FAILED(hr)) {
|
||||
tex->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_shared<Texture2D>(tex, srv);
|
||||
}
|
||||
|
||||
std::shared_ptr<ID3DBlob> Device::compile_shader(const std::string& source_code,
|
||||
const std::string& entry_point,
|
||||
const std::string& model) {
|
||||
if (!lib_compiler_) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
typedef HRESULT(WINAPI * PFN_D3DCOMPILE)(
|
||||
LPCVOID, SIZE_T, LPCSTR, const D3D_SHADER_MACRO*, ID3DInclude*, LPCSTR,
|
||||
LPCSTR, UINT, UINT, ID3DBlob**, ID3DBlob**);
|
||||
|
||||
const auto fnc_compile = reinterpret_cast<PFN_D3DCOMPILE>(
|
||||
GetProcAddress(lib_compiler_, "D3DCompile"));
|
||||
if (!fnc_compile) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DWORD flags = D3DCOMPILE_ENABLE_STRICTNESS;
|
||||
|
||||
#if defined(NDEBUG)
|
||||
// flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
|
||||
// flags |= D3DCOMPILE_AVOID_FLOW_CONTROL;
|
||||
#else
|
||||
flags |= D3DCOMPILE_DEBUG;
|
||||
flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||
#endif
|
||||
|
||||
ID3DBlob* blob = nullptr;
|
||||
ID3DBlob* blob_err = nullptr;
|
||||
|
||||
const auto psrc = source_code.c_str();
|
||||
const auto len = source_code.size() + 1;
|
||||
|
||||
const auto hr =
|
||||
fnc_compile(psrc, len, nullptr, nullptr, nullptr, entry_point.c_str(),
|
||||
model.c_str(), flags, 0, &blob, &blob_err);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
if (blob_err) {
|
||||
// TODO: Log the error.
|
||||
blob_err->Release();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (blob_err) {
|
||||
blob_err->Release();
|
||||
}
|
||||
|
||||
return std::shared_ptr<ID3DBlob>(blob, [](ID3DBlob* p) {
|
||||
if (p)
|
||||
p->Release();
|
||||
});
|
||||
}
|
||||
|
||||
std::shared_ptr<Effect> Device::create_default_effect() {
|
||||
const auto vsh =
|
||||
R"--(struct VS_INPUT
|
||||
{
|
||||
float4 pos : POSITION;
|
||||
float2 tex : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float2 tex : TEXCOORD0;
|
||||
};
|
||||
|
||||
VS_OUTPUT main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
output.pos = input.pos;
|
||||
output.tex = input.tex;
|
||||
return output;
|
||||
})--";
|
||||
|
||||
const auto psh =
|
||||
R"--(Texture2D tex0 : register(t0);
|
||||
SamplerState samp0 : register(s0);
|
||||
|
||||
struct VS_OUTPUT
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float2 tex : TEXCOORD0;
|
||||
};
|
||||
|
||||
float4 main(VS_OUTPUT input) : SV_Target
|
||||
{
|
||||
return tex0.Sample(samp0, input.tex);
|
||||
})--";
|
||||
|
||||
return create_effect(vsh, "main", "vs_4_0", psh, "main", "ps_4_0");
|
||||
}
|
||||
|
||||
std::shared_ptr<Effect> Device::create_effect(const std::string& vertex_code,
|
||||
const std::string& vertex_entry,
|
||||
const std::string& vertex_model,
|
||||
const std::string& pixel_code,
|
||||
const std::string& pixel_entry,
|
||||
const std::string& pixel_model) {
|
||||
const auto vs_blob = compile_shader(vertex_code, vertex_entry, vertex_model);
|
||||
|
||||
ID3D11VertexShader* vshdr = nullptr;
|
||||
ID3D11InputLayout* layout = nullptr;
|
||||
|
||||
if (vs_blob) {
|
||||
device_->CreateVertexShader(vs_blob->GetBufferPointer(),
|
||||
vs_blob->GetBufferSize(), nullptr, &vshdr);
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC layout_desc[] = {
|
||||
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
|
||||
D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,
|
||||
D3D11_INPUT_PER_VERTEX_DATA, 0},
|
||||
};
|
||||
|
||||
UINT elements = ARRAYSIZE(layout_desc);
|
||||
|
||||
// Create the input layout.
|
||||
device_->CreateInputLayout(layout_desc, elements,
|
||||
vs_blob->GetBufferPointer(),
|
||||
vs_blob->GetBufferSize(), &layout);
|
||||
}
|
||||
|
||||
const auto ps_blob = compile_shader(pixel_code, pixel_entry, pixel_model);
|
||||
ID3D11PixelShader* pshdr = nullptr;
|
||||
if (ps_blob) {
|
||||
device_->CreatePixelShader(ps_blob->GetBufferPointer(),
|
||||
ps_blob->GetBufferSize(), nullptr, &pshdr);
|
||||
}
|
||||
|
||||
return std::make_shared<Effect>(vshdr, pshdr, layout);
|
||||
}
|
||||
|
||||
Layer::Layer(const std::shared_ptr<Device>& device, bool flip)
|
||||
: device_(device), flip_(flip) {
|
||||
bounds_.x = bounds_.y = bounds_.width = bounds_.height = 0.0f;
|
||||
}
|
||||
|
||||
Layer::~Layer() {}
|
||||
|
||||
void Layer::attach(const std::shared_ptr<Composition>& parent) {
|
||||
composition_ = parent;
|
||||
}
|
||||
|
||||
std::shared_ptr<Composition> Layer::composition() const {
|
||||
return composition_.lock();
|
||||
}
|
||||
|
||||
Rect Layer::bounds() const {
|
||||
return bounds_;
|
||||
}
|
||||
|
||||
void Layer::move(float x, float y, float width, float height) {
|
||||
bounds_.x = x;
|
||||
bounds_.y = y;
|
||||
bounds_.width = width;
|
||||
bounds_.height = height;
|
||||
|
||||
// It's not efficient to create the quad everytime we move, but for now we're
|
||||
// just trying to get something on-screen.
|
||||
geometry_.reset();
|
||||
}
|
||||
|
||||
void Layer::tick(double) {
|
||||
// Nothing to update in the base class.
|
||||
}
|
||||
|
||||
void Layer::render_texture(const std::shared_ptr<Context>& ctx,
|
||||
const std::shared_ptr<Texture2D>& texture) {
|
||||
if (!geometry_) {
|
||||
geometry_ = device_->create_quad(bounds_.x, bounds_.y, bounds_.width,
|
||||
bounds_.height, flip_);
|
||||
}
|
||||
|
||||
if (geometry_ && texture) {
|
||||
// We need a shader.
|
||||
if (!effect_) {
|
||||
effect_ = device_->create_default_effect();
|
||||
}
|
||||
|
||||
// Bind our states/resource to the pipeline.
|
||||
ScopedBinder<Geometry> quad_binder(ctx, geometry_);
|
||||
ScopedBinder<Effect> fx_binder(ctx, effect_);
|
||||
ScopedBinder<Texture2D> tex_binder(ctx, texture);
|
||||
|
||||
// Draw the quad.
|
||||
geometry_->draw();
|
||||
}
|
||||
}
|
||||
|
||||
Composition::Composition(const std::shared_ptr<Device>& device,
|
||||
int width,
|
||||
int height)
|
||||
: width_(width), height_(height), vsync_(true), device_(device) {
|
||||
fps_ = 0.0;
|
||||
time_ = 0.0;
|
||||
frame_ = 0;
|
||||
fps_start_ = GetTimeNow();
|
||||
}
|
||||
|
||||
bool Composition::is_vsync() const {
|
||||
return vsync_;
|
||||
}
|
||||
|
||||
double Composition::time() const {
|
||||
return time_;
|
||||
}
|
||||
|
||||
double Composition::fps() const {
|
||||
return fps_;
|
||||
}
|
||||
|
||||
void Composition::add_layer(const std::shared_ptr<Layer>& layer) {
|
||||
if (layer) {
|
||||
layers_.push_back(layer);
|
||||
|
||||
// Attach ourselves as the parent.
|
||||
layer->attach(shared_from_this());
|
||||
}
|
||||
}
|
||||
|
||||
bool Composition::remove_layer(const std::shared_ptr<Layer>& layer) {
|
||||
size_t match = 0;
|
||||
if (layer) {
|
||||
for (auto i = layers_.begin(); i != layers_.end();) {
|
||||
if ((*i).get() == layer.get()) {
|
||||
i = layers_.erase(i);
|
||||
match++;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (match > 0);
|
||||
}
|
||||
|
||||
void Composition::resize(bool vsync, int width, int height) {
|
||||
vsync_ = vsync;
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
|
||||
void Composition::tick(double t) {
|
||||
time_ = t;
|
||||
for (const auto& layer : layers_) {
|
||||
layer->tick(t);
|
||||
}
|
||||
}
|
||||
|
||||
void Composition::render(const std::shared_ptr<Context>& ctx) {
|
||||
// Use painter's algorithm and render our layers in order (not doing any dept
|
||||
// or 3D here).
|
||||
for (const auto& layer : layers_) {
|
||||
layer->render(ctx);
|
||||
}
|
||||
|
||||
frame_++;
|
||||
const auto now = GetTimeNow();
|
||||
if ((now - fps_start_) > 1000000) {
|
||||
fps_ = frame_ / double((now - fps_start_) / 1000000.0);
|
||||
frame_ = 0;
|
||||
fps_start_ = now;
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(const std::shared_ptr<Device>& device)
|
||||
: device_(device) {}
|
||||
|
||||
void FrameBuffer::on_paint(void* shared_handle) {
|
||||
// Did the shared texture change?
|
||||
if (shared_buffer_ && shared_handle != shared_buffer_->share_handle()) {
|
||||
shared_buffer_.reset();
|
||||
}
|
||||
|
||||
// Open the shared texture.
|
||||
if (!shared_buffer_) {
|
||||
shared_buffer_ = device_->open_shared_texture((void*)shared_handle);
|
||||
if (!shared_buffer_) {
|
||||
LOG(ERROR) << "d3d11: Could not open shared texture!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace d3d11
|
||||
} // namespace client
|
330
tests/cefclient/browser/osr_d3d11_win.h
Normal file
330
tests/cefclient/browser/osr_d3d11_win.h
Normal file
@ -0,0 +1,330 @@
|
||||
// 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.
|
||||
//
|
||||
// Portions Copyright (c) 2018 Daktronics with the following MIT License:
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_D3D11_WIN_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_D3D11_WIN_H_
|
||||
#pragma once
|
||||
|
||||
#include <d3d11_1.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "include/base/cef_macros.h"
|
||||
|
||||
namespace client {
|
||||
namespace d3d11 {
|
||||
|
||||
class Composition;
|
||||
class Context;
|
||||
class Effect;
|
||||
class Geometry;
|
||||
class SwapChain;
|
||||
class Texture2D;
|
||||
|
||||
// Basic rect for floats.
|
||||
struct Rect {
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ScopedBinder {
|
||||
public:
|
||||
ScopedBinder(const std::shared_ptr<Context>& ctx,
|
||||
const std::shared_ptr<T>& target)
|
||||
: target_(target) {
|
||||
if (target_) {
|
||||
target_->bind(ctx);
|
||||
}
|
||||
}
|
||||
~ScopedBinder() {
|
||||
if (target_) {
|
||||
target_->unbind();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::shared_ptr<T> target_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedBinder);
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Context(ID3D11DeviceContext*);
|
||||
|
||||
void flush();
|
||||
|
||||
operator ID3D11DeviceContext*() { return ctx_.get(); }
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ID3D11DeviceContext> ctx_;
|
||||
};
|
||||
|
||||
// Encapsulate a D3D11 Device object.
|
||||
class Device {
|
||||
public:
|
||||
Device(ID3D11Device*, ID3D11DeviceContext*);
|
||||
|
||||
static std::shared_ptr<Device> create();
|
||||
|
||||
std::string adapter_name() const;
|
||||
|
||||
operator ID3D11Device*() { return device_.get(); }
|
||||
|
||||
std::shared_ptr<Context> immedidate_context();
|
||||
|
||||
std::shared_ptr<SwapChain> create_swapchain(HWND,
|
||||
int width = 0,
|
||||
int height = 0);
|
||||
|
||||
std::shared_ptr<Geometry> create_quad(float x,
|
||||
float y,
|
||||
float width,
|
||||
float height,
|
||||
bool flip = false);
|
||||
|
||||
std::shared_ptr<Texture2D> create_texture(int width,
|
||||
int height,
|
||||
DXGI_FORMAT format,
|
||||
const void* data,
|
||||
size_t row_stride);
|
||||
|
||||
std::shared_ptr<Texture2D> open_shared_texture(void*);
|
||||
|
||||
// Create some basic shaders so we can draw a textured-quad.
|
||||
std::shared_ptr<Effect> create_default_effect();
|
||||
|
||||
std::shared_ptr<Effect> create_effect(const std::string& vertex_code,
|
||||
const std::string& vertex_entry,
|
||||
const std::string& vertex_model,
|
||||
const std::string& pixel_code,
|
||||
const std::string& pixel_entry,
|
||||
const std::string& pixel_model);
|
||||
|
||||
private:
|
||||
std::shared_ptr<ID3DBlob> compile_shader(const std::string& source_code,
|
||||
const std::string& entry_point,
|
||||
const std::string& model);
|
||||
|
||||
HMODULE lib_compiler_;
|
||||
|
||||
const std::shared_ptr<ID3D11Device> device_;
|
||||
const std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Device);
|
||||
};
|
||||
|
||||
// Encapsulate a DXGI swapchain for a window.
|
||||
class SwapChain {
|
||||
public:
|
||||
SwapChain(IDXGISwapChain*,
|
||||
ID3D11RenderTargetView*,
|
||||
ID3D11SamplerState*,
|
||||
ID3D11BlendState*);
|
||||
|
||||
void bind(const std::shared_ptr<Context>& ctx);
|
||||
void unbind();
|
||||
|
||||
void clear(float red, float green, float blue, float alpha);
|
||||
|
||||
void present(int sync_interval);
|
||||
void resize(int width, int height);
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ID3D11SamplerState> sampler_;
|
||||
const std::shared_ptr<ID3D11BlendState> blender_;
|
||||
const std::shared_ptr<IDXGISwapChain> swapchain_;
|
||||
std::shared_ptr<ID3D11RenderTargetView> rtv_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
int width_;
|
||||
int height_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SwapChain);
|
||||
};
|
||||
|
||||
class Texture2D {
|
||||
public:
|
||||
Texture2D(ID3D11Texture2D* tex, ID3D11ShaderResourceView* srv);
|
||||
|
||||
void bind(std::shared_ptr<Context> const& ctx);
|
||||
void unbind();
|
||||
|
||||
uint32_t width() const;
|
||||
uint32_t height() const;
|
||||
DXGI_FORMAT format() const;
|
||||
|
||||
bool has_mutex() const;
|
||||
|
||||
bool lock_key(uint64_t key, uint32_t timeout_ms);
|
||||
void unlock_key(uint64_t key);
|
||||
|
||||
void* share_handle() const;
|
||||
|
||||
void copy_from(const std::shared_ptr<Texture2D>&);
|
||||
|
||||
private:
|
||||
HANDLE share_handle_;
|
||||
|
||||
const std::shared_ptr<ID3D11Texture2D> texture_;
|
||||
const std::shared_ptr<ID3D11ShaderResourceView> srv_;
|
||||
std::shared_ptr<IDXGIKeyedMutex> keyed_mutex_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Texture2D);
|
||||
};
|
||||
|
||||
class Effect {
|
||||
public:
|
||||
Effect(ID3D11VertexShader* vsh,
|
||||
ID3D11PixelShader* psh,
|
||||
ID3D11InputLayout* layout);
|
||||
|
||||
void bind(const std::shared_ptr<Context>& ctx);
|
||||
void unbind();
|
||||
|
||||
private:
|
||||
const std::shared_ptr<ID3D11VertexShader> vsh_;
|
||||
const std::shared_ptr<ID3D11PixelShader> psh_;
|
||||
const std::shared_ptr<ID3D11InputLayout> layout_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Effect);
|
||||
};
|
||||
|
||||
class Geometry {
|
||||
public:
|
||||
Geometry(D3D_PRIMITIVE_TOPOLOGY primitive,
|
||||
uint32_t vertices,
|
||||
uint32_t stride,
|
||||
ID3D11Buffer*);
|
||||
|
||||
void bind(const std::shared_ptr<Context>& ctx);
|
||||
void unbind();
|
||||
|
||||
void draw();
|
||||
|
||||
private:
|
||||
D3D_PRIMITIVE_TOPOLOGY primitive_;
|
||||
uint32_t vertices_;
|
||||
uint32_t stride_;
|
||||
const std::shared_ptr<ID3D11Buffer> buffer_;
|
||||
std::shared_ptr<Context> ctx_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Geometry);
|
||||
};
|
||||
|
||||
// Abstraction for a 2D layer within a composition.
|
||||
class Layer {
|
||||
public:
|
||||
Layer(const std::shared_ptr<Device>& device, bool flip);
|
||||
virtual ~Layer();
|
||||
|
||||
void attach(const std::shared_ptr<Composition>&);
|
||||
|
||||
// Uses normalized 0-1.0 coordinates.
|
||||
virtual void move(float x, float y, float width, float height);
|
||||
|
||||
virtual void tick(double t);
|
||||
virtual void render(const std::shared_ptr<Context>& ctx) = 0;
|
||||
|
||||
Rect bounds() const;
|
||||
|
||||
std::shared_ptr<Composition> composition() const;
|
||||
|
||||
protected:
|
||||
// Helper method for derived classes to draw a textured-quad.
|
||||
void render_texture(const std::shared_ptr<Context>& ctx,
|
||||
const std::shared_ptr<Texture2D>& texture);
|
||||
|
||||
const std::shared_ptr<Device> device_;
|
||||
const bool flip_;
|
||||
|
||||
Rect bounds_;
|
||||
std::shared_ptr<Geometry> geometry_;
|
||||
std::shared_ptr<Effect> effect_;
|
||||
|
||||
private:
|
||||
std::weak_ptr<Composition> composition_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Layer);
|
||||
};
|
||||
|
||||
// A collection of layers. Will render 1-N layers to a D3D11 device.
|
||||
class Composition : public std::enable_shared_from_this<Composition> {
|
||||
public:
|
||||
Composition(const std::shared_ptr<Device>& device,
|
||||
int width = 0,
|
||||
int height = 0);
|
||||
|
||||
int width() const { return width_; }
|
||||
int height() const { return height_; }
|
||||
|
||||
double fps() const;
|
||||
double time() const;
|
||||
|
||||
bool is_vsync() const;
|
||||
|
||||
void tick(double);
|
||||
void render(const std::shared_ptr<Context>&);
|
||||
|
||||
void add_layer(const std::shared_ptr<Layer>& layer);
|
||||
bool remove_layer(const std::shared_ptr<Layer>& layer);
|
||||
void resize(bool vsync, int width, int height);
|
||||
|
||||
private:
|
||||
int width_;
|
||||
int height_;
|
||||
uint32_t frame_;
|
||||
int64_t fps_start_;
|
||||
double fps_;
|
||||
double time_;
|
||||
bool vsync_;
|
||||
|
||||
const std::shared_ptr<Device> device_;
|
||||
std::vector<std::shared_ptr<Layer>> layers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Composition);
|
||||
};
|
||||
|
||||
class FrameBuffer {
|
||||
public:
|
||||
explicit FrameBuffer(const std::shared_ptr<Device>& device);
|
||||
|
||||
// Called in response to CEF's OnAcceleratedPaint notification.
|
||||
void on_paint(void* shared_handle);
|
||||
|
||||
// Returns what should be considered the front buffer.
|
||||
std::shared_ptr<Texture2D> texture() const { return shared_buffer_; }
|
||||
|
||||
private:
|
||||
const std::shared_ptr<Device> device_;
|
||||
std::shared_ptr<Texture2D> shared_buffer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FrameBuffer);
|
||||
};
|
||||
|
||||
} // namespace d3d11
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_D3D11_WIN_H_
|
83
tests/cefclient/browser/osr_render_handler_win.cc
Normal file
83
tests/cefclient/browser/osr_render_handler_win.cc
Normal file
@ -0,0 +1,83 @@
|
||||
// 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.h"
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "tests/shared/browser/util_win.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
OsrRenderHandlerWin::OsrRenderHandlerWin(const OsrRendererSettings& settings,
|
||||
HWND hwnd)
|
||||
: settings_(settings),
|
||||
hwnd_(hwnd),
|
||||
begin_frame_pending_(false),
|
||||
weak_factory_(this) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK(hwnd_);
|
||||
}
|
||||
|
||||
OsrRenderHandlerWin::~OsrRenderHandlerWin() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWin::SetBrowser(CefRefPtr<CefBrowser> browser) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
browser_ = browser;
|
||||
if (browser_ && settings_.external_begin_frame_enabled) {
|
||||
// Start the BeginFrame timer.
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWin::Invalidate() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (begin_frame_pending_) {
|
||||
// The timer is already running.
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger the BeginFrame timer.
|
||||
CHECK_GT(settings_.begin_frame_rate, 0);
|
||||
const float delay_us = (1.0 / double(settings_.begin_frame_rate)) * 1000000.0;
|
||||
TriggerBeginFrame(0, delay_us);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWin::TriggerBeginFrame(uint64_t last_time_us,
|
||||
float delay_us) {
|
||||
if (begin_frame_pending_ && !settings_.external_begin_frame_enabled) {
|
||||
// Render immediately and then wait for the next call to Invalidate() or
|
||||
// On[Accelerated]Paint().
|
||||
begin_frame_pending_ = false;
|
||||
Render();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto now = GetTimeNow();
|
||||
float offset = now - last_time_us;
|
||||
if (offset > delay_us) {
|
||||
offset = delay_us;
|
||||
}
|
||||
|
||||
if (!begin_frame_pending_) {
|
||||
begin_frame_pending_ = true;
|
||||
}
|
||||
|
||||
// Trigger again after the necessary delay to maintain the desired frame rate.
|
||||
CefPostDelayedTask(TID_UI,
|
||||
base::Bind(&OsrRenderHandlerWin::TriggerBeginFrame,
|
||||
weak_factory_.GetWeakPtr(), now, delay_us),
|
||||
int64(offset / 1000.0));
|
||||
|
||||
if (settings_.external_begin_frame_enabled && browser_) {
|
||||
// We're running the BeginFrame timer. Trigger rendering via
|
||||
// On[Accelerated]Paint().
|
||||
browser_->GetHost()->SendExternalBeginFrame();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace client
|
82
tests/cefclient/browser/osr_render_handler_win.h
Normal file
82
tests/cefclient/browser/osr_render_handler_win.h
Normal file
@ -0,0 +1,82 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/base/cef_weak_ptr.h"
|
||||
#include "include/cef_render_handler.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
// Abstract base class for implementing OSR rendering with different backends on
|
||||
// Windows. Methods are only called on the UI thread.
|
||||
class OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWin(const OsrRendererSettings& settings, HWND hwnd);
|
||||
virtual ~OsrRenderHandlerWin();
|
||||
|
||||
void SetBrowser(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
// Rotate the texture based on mouse events.
|
||||
virtual void SetSpin(float spinX, float spinY) = 0;
|
||||
virtual void IncrementSpin(float spinDX, float spinDY) = 0;
|
||||
|
||||
// Popup hit testing.
|
||||
virtual bool IsOverPopupWidget(int x, int y) const = 0;
|
||||
virtual int GetPopupXOffset() const = 0;
|
||||
virtual int GetPopupYOffset() const = 0;
|
||||
|
||||
// CefRenderHandler callbacks.
|
||||
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) = 0;
|
||||
// |rect| must be in pixel coordinates.
|
||||
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) = 0;
|
||||
|
||||
// Used when not rendering with shared textures.
|
||||
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) = 0;
|
||||
|
||||
// Used when rendering with shared textures.
|
||||
virtual void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) = 0;
|
||||
|
||||
bool send_begin_frame() const {
|
||||
return settings_.external_begin_frame_enabled;
|
||||
}
|
||||
HWND hwnd() const { return hwnd_; }
|
||||
|
||||
protected:
|
||||
// Called to trigger the BeginFrame timer.
|
||||
void Invalidate();
|
||||
|
||||
// Called by the BeginFrame timer.
|
||||
virtual void Render() = 0;
|
||||
|
||||
private:
|
||||
void TriggerBeginFrame(uint64_t last_time_us, float delay_us);
|
||||
|
||||
// The below members are only accessed on the UI thread.
|
||||
const OsrRendererSettings settings_;
|
||||
const HWND hwnd_;
|
||||
bool begin_frame_pending_;
|
||||
CefRefPtr<CefBrowser> browser_;
|
||||
|
||||
// Must be the last member.
|
||||
base::WeakPtrFactory<OsrRenderHandlerWin> weak_factory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWin);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_H_
|
218
tests/cefclient/browser/osr_render_handler_win_d3d11.cc
Normal file
218
tests/cefclient/browser/osr_render_handler_win_d3d11.cc
Normal file
@ -0,0 +1,218 @@
|
||||
// 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_d3d11.h"
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_helpers.h"
|
||||
#include "tests/cefclient/browser/main_context.h"
|
||||
#include "tests/shared/browser/util_win.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
BrowserLayer::BrowserLayer(const std::shared_ptr<d3d11::Device>& device)
|
||||
: d3d11::Layer(device, true /* flip */) {
|
||||
frame_buffer_ = std::make_shared<d3d11::FrameBuffer>(device_);
|
||||
}
|
||||
|
||||
void BrowserLayer::render(const std::shared_ptr<d3d11::Context>& ctx) {
|
||||
// Use the base class method to draw our texture.
|
||||
render_texture(ctx, frame_buffer_->texture());
|
||||
}
|
||||
|
||||
void BrowserLayer::on_paint(void* share_handle) {
|
||||
frame_buffer_->on_paint(share_handle);
|
||||
}
|
||||
|
||||
std::pair<uint32_t, uint32_t> BrowserLayer::texture_size() const {
|
||||
const auto texture = frame_buffer_->texture();
|
||||
return std::make_pair(texture->width(), texture->height());
|
||||
}
|
||||
|
||||
PopupLayer::PopupLayer(const std::shared_ptr<d3d11::Device>& device)
|
||||
: BrowserLayer(device) {}
|
||||
|
||||
void PopupLayer::set_bounds(const CefRect& bounds) {
|
||||
const auto comp = composition();
|
||||
if (!comp)
|
||||
return;
|
||||
|
||||
const auto outer_width = comp->width();
|
||||
const auto outer_height = comp->height();
|
||||
if (outer_width == 0 || outer_height == 0)
|
||||
return;
|
||||
|
||||
original_bounds_ = bounds;
|
||||
bounds_ = bounds;
|
||||
|
||||
// If x or y are negative, move them to 0.
|
||||
if (bounds_.x < 0)
|
||||
bounds_.x = 0;
|
||||
if (bounds_.y < 0)
|
||||
bounds_.y = 0;
|
||||
// If popup goes outside the view, try to reposition origin
|
||||
if (bounds_.x + bounds_.width > outer_width)
|
||||
bounds_.x = outer_width - bounds_.width;
|
||||
if (bounds_.y + bounds_.height > outer_height)
|
||||
bounds_.y = outer_height - bounds_.height;
|
||||
// If x or y became negative, move them to 0 again.
|
||||
if (bounds_.x < 0)
|
||||
bounds_.x = 0;
|
||||
if (bounds_.y < 0)
|
||||
bounds_.y = 0;
|
||||
|
||||
const auto x = bounds_.x / float(outer_width);
|
||||
const auto y = bounds_.y / float(outer_height);
|
||||
const auto w = bounds_.width / float(outer_width);
|
||||
const auto h = bounds_.height / float(outer_height);
|
||||
move(x, y, w, h);
|
||||
}
|
||||
|
||||
OsrRenderHandlerWinD3D11::OsrRenderHandlerWinD3D11(
|
||||
const OsrRendererSettings& settings,
|
||||
HWND hwnd)
|
||||
: OsrRenderHandlerWin(settings, hwnd), start_time_(0) {}
|
||||
|
||||
bool OsrRenderHandlerWinD3D11::Initialize(CefRefPtr<CefBrowser> browser,
|
||||
int width,
|
||||
int height) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Retrieve the shared D3D11 device instance.
|
||||
device_ = MainContext::Get()->GetD3D11Device();
|
||||
DCHECK(device_);
|
||||
if (!device_)
|
||||
return false;
|
||||
|
||||
// Create a D3D11 swapchain for the window.
|
||||
swap_chain_ = device_->create_swapchain(hwnd());
|
||||
DCHECK(swap_chain_);
|
||||
if (!swap_chain_)
|
||||
return false;
|
||||
|
||||
// Create the browser layer.
|
||||
browser_layer_ = std::make_shared<BrowserLayer>(device_);
|
||||
|
||||
// Set up the composition.
|
||||
composition_ = std::make_shared<d3d11::Composition>(device_, width, height);
|
||||
composition_->add_layer(browser_layer_);
|
||||
|
||||
// Size to the whole composition.
|
||||
browser_layer_->move(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
|
||||
start_time_ = GetTimeNow();
|
||||
|
||||
SetBrowser(browser);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::SetSpin(float spinX, float spinY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
// Spin support is not implemented.
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::IncrementSpin(float spinDX, float spinDY) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
// Spin support is not implemented.
|
||||
}
|
||||
|
||||
bool OsrRenderHandlerWinD3D11::IsOverPopupWidget(int x, int y) const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return popup_layer_ && popup_layer_->contains(x, y);
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinD3D11::GetPopupXOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (popup_layer_)
|
||||
return popup_layer_->xoffset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OsrRenderHandlerWinD3D11::GetPopupYOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (popup_layer_)
|
||||
return popup_layer_->yoffset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnPopupShow(CefRefPtr<CefBrowser> browser,
|
||||
bool show) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (show) {
|
||||
DCHECK(!popup_layer_);
|
||||
|
||||
// Create a new layer.
|
||||
popup_layer_ = std::make_shared<PopupLayer>(device_);
|
||||
composition_->add_layer(popup_layer_);
|
||||
} else {
|
||||
DCHECK(popup_layer_);
|
||||
|
||||
composition_->remove_layer(popup_layer_);
|
||||
popup_layer_ = nullptr;
|
||||
|
||||
Render();
|
||||
}
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
popup_layer_->set_bounds(rect);
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) {
|
||||
// Not used with this implementation.
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (type == PET_POPUP) {
|
||||
popup_layer_->on_paint(share_handle);
|
||||
} else {
|
||||
browser_layer_->on_paint(share_handle);
|
||||
}
|
||||
|
||||
Render();
|
||||
}
|
||||
|
||||
void OsrRenderHandlerWinD3D11::Render() {
|
||||
// Update composition + layers based on time.
|
||||
const auto t = (GetTimeNow() - start_time_) / 1000000.0;
|
||||
composition_->tick(t);
|
||||
|
||||
auto ctx = device_->immedidate_context();
|
||||
swap_chain_->bind(ctx);
|
||||
|
||||
const auto texture_size = browser_layer_->texture_size();
|
||||
|
||||
// Resize the composition and swap chain to match the texture if necessary.
|
||||
composition_->resize(!send_begin_frame(), texture_size.first,
|
||||
texture_size.second);
|
||||
swap_chain_->resize(texture_size.first, texture_size.second);
|
||||
|
||||
// Clear the render target.
|
||||
swap_chain_->clear(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
|
||||
// Render the scene.
|
||||
composition_->render(ctx);
|
||||
|
||||
// Present to window.
|
||||
swap_chain_->present(send_begin_frame() ? 0 : 1);
|
||||
}
|
||||
|
||||
} // namespace client
|
90
tests/cefclient/browser/osr_render_handler_win_d3d11.h
Normal file
90
tests/cefclient/browser/osr_render_handler_win_d3d11.h
Normal file
@ -0,0 +1,90 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_D3D11_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_D3D11_H_
|
||||
#pragma once
|
||||
|
||||
#include "tests/cefclient/browser/osr_d3d11_win.h"
|
||||
#include "tests/cefclient/browser/osr_render_handler_win.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
class BrowserLayer : public d3d11::Layer {
|
||||
public:
|
||||
explicit BrowserLayer(const std::shared_ptr<d3d11::Device>& device);
|
||||
|
||||
void render(const std::shared_ptr<d3d11::Context>& ctx) OVERRIDE;
|
||||
|
||||
void on_paint(void* share_handle);
|
||||
|
||||
// After calling on_paint() we can query the texture size.
|
||||
std::pair<uint32_t, uint32_t> texture_size() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<d3d11::FrameBuffer> frame_buffer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BrowserLayer);
|
||||
};
|
||||
|
||||
class PopupLayer : public BrowserLayer {
|
||||
public:
|
||||
explicit PopupLayer(const std::shared_ptr<d3d11::Device>& device);
|
||||
|
||||
void set_bounds(const CefRect& bounds);
|
||||
|
||||
bool contains(int x, int y) const { return bounds_.Contains(x, y); }
|
||||
int xoffset() const { return original_bounds_.x - bounds_.x; }
|
||||
int yoffset() const { return original_bounds_.y - bounds_.y; }
|
||||
|
||||
private:
|
||||
CefRect original_bounds_;
|
||||
CefRect bounds_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PopupLayer);
|
||||
};
|
||||
|
||||
class OsrRenderHandlerWinD3D11 : public OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWinD3D11(const OsrRendererSettings& settings, HWND hwnd);
|
||||
|
||||
// Must be called immediately after object creation.
|
||||
// May fail if D3D11 cannot be initialized.
|
||||
bool Initialize(CefRefPtr<CefBrowser> browser, int width, int height);
|
||||
|
||||
void SetSpin(float spinX, float spinY) OVERRIDE;
|
||||
void IncrementSpin(float spinDX, float spinDY) OVERRIDE;
|
||||
bool IsOverPopupWidget(int x, int y) const OVERRIDE;
|
||||
int GetPopupXOffset() const OVERRIDE;
|
||||
int GetPopupYOffset() const OVERRIDE;
|
||||
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
|
||||
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) OVERRIDE;
|
||||
void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) OVERRIDE;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) OVERRIDE;
|
||||
|
||||
private:
|
||||
void Render() OVERRIDE;
|
||||
|
||||
uint64_t start_time_;
|
||||
std::shared_ptr<d3d11::Device> device_;
|
||||
std::shared_ptr<d3d11::SwapChain> swap_chain_;
|
||||
std::shared_ptr<d3d11::Composition> composition_;
|
||||
std::shared_ptr<BrowserLayer> browser_layer_;
|
||||
std::shared_ptr<PopupLayer> popup_layer_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinD3D11);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_D3D11_H_
|
201
tests/cefclient/browser/osr_render_handler_win_gl.cc
Normal file
201
tests/cefclient/browser/osr_render_handler_win_gl.cc
Normal file
@ -0,0 +1,201 @@
|
||||
// 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_bind.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) {
|
||||
BOOL result = wglMakeCurrent(hdc, hglrc);
|
||||
ALLOW_UNUSED_LOCAL(result);
|
||||
DCHECK(result);
|
||||
}
|
||||
~ScopedGLContext() {
|
||||
BOOL result = wglMakeCurrent(NULL, NULL);
|
||||
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),
|
||||
hdc_(NULL),
|
||||
hrc_(NULL),
|
||||
painting_popup_(false) {}
|
||||
|
||||
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,
|
||||
void* share_handle) {
|
||||
// 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.
|
||||
BOOL result = wglDeleteContext(hrc_);
|
||||
ALLOW_UNUSED_LOCAL(result);
|
||||
DCHECK(result);
|
||||
ReleaseDC(hwnd(), hdc_);
|
||||
}
|
||||
|
||||
hdc_ = NULL;
|
||||
hrc_ = NULL;
|
||||
}
|
||||
|
||||
} // namespace client
|
57
tests/cefclient/browser/osr_render_handler_win_gl.h
Normal file
57
tests/cefclient/browser/osr_render_handler_win_gl.h
Normal file
@ -0,0 +1,57 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_GL_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_GL_H_
|
||||
#pragma once
|
||||
|
||||
#include "tests/cefclient/browser/osr_render_handler_win.h"
|
||||
#include "tests/cefclient/browser/osr_renderer.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
class OsrRenderHandlerWinGL : public OsrRenderHandlerWin {
|
||||
public:
|
||||
OsrRenderHandlerWinGL(const OsrRendererSettings& settings, HWND hwnd);
|
||||
virtual ~OsrRenderHandlerWinGL();
|
||||
|
||||
// Must be called immediately after object creation.
|
||||
void Initialize(CefRefPtr<CefBrowser> browser);
|
||||
|
||||
void SetSpin(float spinX, float spinY) OVERRIDE;
|
||||
void IncrementSpin(float spinDX, float spinDY) OVERRIDE;
|
||||
bool IsOverPopupWidget(int x, int y) const OVERRIDE;
|
||||
int GetPopupXOffset() const OVERRIDE;
|
||||
int GetPopupYOffset() const OVERRIDE;
|
||||
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
|
||||
void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) OVERRIDE;
|
||||
void OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) OVERRIDE;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) OVERRIDE;
|
||||
|
||||
private:
|
||||
void Render() OVERRIDE;
|
||||
|
||||
void EnableGL();
|
||||
void DisableGL();
|
||||
|
||||
// The below members are only accessed on the UI thread.
|
||||
OsrRenderer renderer_;
|
||||
HDC hdc_;
|
||||
HGLRC hrc_;
|
||||
bool painting_popup_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinGL);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_GL_H_
|
@ -40,7 +40,7 @@
|
||||
|
||||
namespace client {
|
||||
|
||||
OsrRenderer::OsrRenderer(const Settings& settings)
|
||||
OsrRenderer::OsrRenderer(const OsrRendererSettings& settings)
|
||||
: settings_(settings),
|
||||
initialized_(false),
|
||||
texture_id_(0),
|
||||
|
@ -8,20 +8,13 @@
|
||||
|
||||
#include "include/cef_browser.h"
|
||||
#include "include/cef_render_handler.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
class OsrRenderer {
|
||||
public:
|
||||
struct Settings {
|
||||
// If true draw a border around update rectangles.
|
||||
bool show_update_rect;
|
||||
|
||||
// Background color. Enables transparency if the alpha component is 0.
|
||||
cef_color_t background_color;
|
||||
};
|
||||
|
||||
explicit OsrRenderer(const Settings& settings);
|
||||
explicit OsrRenderer(const OsrRendererSettings& settings);
|
||||
~OsrRenderer();
|
||||
|
||||
// Initialize the OpenGL environment.
|
||||
@ -51,18 +44,19 @@ class OsrRenderer {
|
||||
int GetViewWidth() const { return view_width_; }
|
||||
int GetViewHeight() const { return view_height_; }
|
||||
|
||||
const CefRect& popup_rect() const { return popup_rect_; }
|
||||
const CefRect& original_popup_rect() const { return original_popup_rect_; }
|
||||
CefRect popup_rect() const { return popup_rect_; }
|
||||
CefRect original_popup_rect() const { return original_popup_rect_; }
|
||||
|
||||
CefRect GetPopupRectInWebView(const CefRect& original_rect);
|
||||
void ClearPopupRects();
|
||||
|
||||
private:
|
||||
CefRect GetPopupRectInWebView(const CefRect& original_rect);
|
||||
|
||||
inline bool IsTransparent() const {
|
||||
return CefColorGetA(settings_.background_color) == 0;
|
||||
};
|
||||
|
||||
const Settings settings_;
|
||||
const OsrRendererSettings settings_;
|
||||
bool initialized_;
|
||||
unsigned int texture_id_;
|
||||
int view_width_;
|
||||
|
38
tests/cefclient/browser/osr_renderer_settings.h
Normal file
38
tests/cefclient/browser/osr_renderer_settings.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2012 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_SETTINGS_H_
|
||||
#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_SETTINGS_H_
|
||||
#pragma once
|
||||
|
||||
#include "include/internal/cef_types.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
struct OsrRendererSettings {
|
||||
OsrRendererSettings()
|
||||
: show_update_rect(false),
|
||||
background_color(CefColorSetARGB(255, 255, 255, 255)),
|
||||
shared_texture_enabled(false),
|
||||
external_begin_frame_enabled(false),
|
||||
begin_frame_rate(0) {}
|
||||
|
||||
// If true draw a border around update rectangles.
|
||||
bool show_update_rect;
|
||||
|
||||
// Background color. Enables transparency if the alpha component is 0.
|
||||
cef_color_t background_color;
|
||||
|
||||
// Render using shared textures. Supported on Windows only via D3D11.
|
||||
bool shared_texture_enabled;
|
||||
|
||||
// Client implements a BeginFrame timer by calling
|
||||
// CefBrowserHost::SendExternalBeginFrame at the specified frame rate.
|
||||
bool external_begin_frame_enabled;
|
||||
int begin_frame_rate;
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_SETTINGS_H_
|
@ -14,6 +14,8 @@
|
||||
#include "tests/cefclient/browser/osr_accessibility_helper.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_node.h"
|
||||
#include "tests/cefclient/browser/osr_ime_handler_win.h"
|
||||
#include "tests/cefclient/browser/osr_render_handler_win_d3d11.h"
|
||||
#include "tests/cefclient/browser/osr_render_handler_win_gl.h"
|
||||
#include "tests/cefclient/browser/resource.h"
|
||||
#include "tests/shared/browser/geometry_util.h"
|
||||
#include "tests/shared/browser/main_message_loop.h"
|
||||
@ -25,44 +27,14 @@ namespace {
|
||||
|
||||
const wchar_t kWndClass[] = L"Client_OsrWindow";
|
||||
|
||||
// Render at 30fps during rotation.
|
||||
const int kRenderDelay = 1000 / 30;
|
||||
|
||||
// Helper that calls wglMakeCurrent.
|
||||
class ScopedGLContext {
|
||||
public:
|
||||
ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers)
|
||||
: hdc_(hdc), swap_buffers_(swap_buffers) {
|
||||
BOOL result = wglMakeCurrent(hdc, hglrc);
|
||||
ALLOW_UNUSED_LOCAL(result);
|
||||
DCHECK(result);
|
||||
}
|
||||
~ScopedGLContext() {
|
||||
BOOL result = wglMakeCurrent(NULL, NULL);
|
||||
DCHECK(result);
|
||||
if (swap_buffers_) {
|
||||
result = SwapBuffers(hdc_);
|
||||
DCHECK(result);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const HDC hdc_;
|
||||
const bool swap_buffers_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
OsrWindowWin::OsrWindowWin(Delegate* delegate,
|
||||
const OsrRenderer::Settings& settings)
|
||||
const OsrRendererSettings& settings)
|
||||
: delegate_(delegate),
|
||||
renderer_(settings),
|
||||
settings_(settings),
|
||||
hwnd_(NULL),
|
||||
hdc_(NULL),
|
||||
hrc_(NULL),
|
||||
device_scale_factor_(0),
|
||||
painting_popup_(false),
|
||||
render_task_pending_(false),
|
||||
hidden_(false),
|
||||
last_mouse_pos_(),
|
||||
current_mouse_pos_(),
|
||||
@ -80,7 +52,7 @@ OsrWindowWin::OsrWindowWin(Delegate* delegate,
|
||||
OsrWindowWin::~OsrWindowWin() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
// The native window should have already been destroyed.
|
||||
DCHECK(!hwnd_);
|
||||
DCHECK(!hwnd_ && !render_handler_.get());
|
||||
}
|
||||
|
||||
void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
|
||||
@ -103,6 +75,10 @@ void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
|
||||
CefWindowInfo window_info;
|
||||
window_info.SetAsWindowless(hwnd_);
|
||||
|
||||
window_info.shared_texture_enabled = settings_.shared_texture_enabled;
|
||||
window_info.external_begin_frame_enabled =
|
||||
settings_.external_begin_frame_enabled;
|
||||
|
||||
// Create the browser asynchronously.
|
||||
CefBrowserHost::CreateBrowser(window_info, handler, startup_url, settings,
|
||||
request_context);
|
||||
@ -127,6 +103,10 @@ void OsrWindowWin::ShowPopup(HWND parent_hwnd,
|
||||
y + static_cast<int>(height)};
|
||||
Create(parent_hwnd, rect);
|
||||
|
||||
// Create the render handler.
|
||||
EnsureRenderHandler();
|
||||
render_handler_->SetBrowser(browser_);
|
||||
|
||||
// Send resize notification so the compositor is assigned the correct
|
||||
// viewport size and begins rendering.
|
||||
browser_->GetHost()->WasResized();
|
||||
@ -226,7 +206,7 @@ void OsrWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
|
||||
|
||||
void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
DCHECK(!hwnd_ && !hdc_ && !hrc_);
|
||||
DCHECK(!hwnd_ && !render_handler_.get());
|
||||
DCHECK(parent_hwnd);
|
||||
DCHECK(!::IsRectEmpty(&rect));
|
||||
|
||||
@ -278,7 +258,7 @@ void OsrWindowWin::Destroy() {
|
||||
drop_target_ = NULL;
|
||||
#endif
|
||||
|
||||
DisableGL();
|
||||
render_handler_.reset();
|
||||
|
||||
// Destroy the native window.
|
||||
::DestroyWindow(hwnd_);
|
||||
@ -286,82 +266,6 @@ void OsrWindowWin::Destroy() {
|
||||
hwnd_ = NULL;
|
||||
}
|
||||
|
||||
void OsrWindowWin::EnableGL() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
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 OsrWindowWin::DisableGL() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
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.
|
||||
BOOL result = wglDeleteContext(hrc_);
|
||||
ALLOW_UNUSED_LOCAL(result);
|
||||
DCHECK(result);
|
||||
ReleaseDC(hwnd_, hdc_);
|
||||
}
|
||||
|
||||
hdc_ = NULL;
|
||||
hrc_ = NULL;
|
||||
}
|
||||
|
||||
void OsrWindowWin::Invalidate() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
// Don't post another task if the previous task is still pending.
|
||||
if (render_task_pending_)
|
||||
return;
|
||||
render_task_pending_ = true;
|
||||
|
||||
CefPostDelayedTask(TID_UI, base::Bind(&OsrWindowWin::Render, this),
|
||||
kRenderDelay);
|
||||
}
|
||||
|
||||
void OsrWindowWin::Render() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (render_task_pending_)
|
||||
render_task_pending_ = false;
|
||||
|
||||
if (!hdc_)
|
||||
EnableGL();
|
||||
|
||||
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
|
||||
renderer_.Render();
|
||||
}
|
||||
|
||||
void OsrWindowWin::NotifyNativeWindowCreated(HWND hwnd) {
|
||||
if (!CURRENTLY_ON_MAIN_THREAD()) {
|
||||
// Execute this method on the main thread.
|
||||
@ -647,8 +551,7 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (mouse_rotation_) {
|
||||
// End rotation effect.
|
||||
mouse_rotation_ = false;
|
||||
renderer_.SetSpin(0, 0);
|
||||
Invalidate();
|
||||
render_handler_->SetSpin(0, 0);
|
||||
} else {
|
||||
int x = GET_X_LPARAM(lParam);
|
||||
int y = GET_Y_LPARAM(lParam);
|
||||
@ -680,11 +583,11 @@ void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
// Apply rotation effect.
|
||||
current_mouse_pos_.x = x;
|
||||
current_mouse_pos_.y = y;
|
||||
renderer_.IncrementSpin(current_mouse_pos_.x - last_mouse_pos_.x,
|
||||
current_mouse_pos_.y - last_mouse_pos_.y);
|
||||
render_handler_->IncrementSpin(
|
||||
current_mouse_pos_.x - last_mouse_pos_.x,
|
||||
current_mouse_pos_.y - last_mouse_pos_.y);
|
||||
last_mouse_pos_.x = current_mouse_pos_.x;
|
||||
last_mouse_pos_.y = current_mouse_pos_.y;
|
||||
Invalidate();
|
||||
} else {
|
||||
if (!mouse_tracking_) {
|
||||
// Start tracking mouse leave. Required for the WM_MOUSELEAVE event to
|
||||
@ -819,21 +722,17 @@ bool OsrWindowWin::OnEraseBkgnd() {
|
||||
}
|
||||
|
||||
bool OsrWindowWin::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);
|
||||
if (!render_handler_)
|
||||
return false;
|
||||
return render_handler_->IsOverPopupWidget(x, y);
|
||||
}
|
||||
|
||||
int OsrWindowWin::GetPopupXOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
|
||||
return render_handler_->GetPopupXOffset();
|
||||
}
|
||||
|
||||
int OsrWindowWin::GetPopupYOffset() const {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
|
||||
return render_handler_->GetPopupYOffset();
|
||||
}
|
||||
|
||||
void OsrWindowWin::ApplyPopupOffset(int& x, int& y) const {
|
||||
@ -848,6 +747,12 @@ void OsrWindowWin::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
|
||||
DCHECK(!browser_);
|
||||
browser_ = browser;
|
||||
|
||||
if (hwnd_) {
|
||||
// The native window will already exist for non-popup browsers.
|
||||
EnsureRenderHandler();
|
||||
render_handler_->SetBrowser(browser);
|
||||
}
|
||||
|
||||
if (hwnd_) {
|
||||
// Show the browser window. Called asynchronously so that the browser has
|
||||
// time to create associated internal objects.
|
||||
@ -861,6 +766,7 @@ void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
|
||||
static_cast<ClientHandlerOsr*>(browser_->GetHost()->GetClient().get())
|
||||
->DetachOsrDelegate();
|
||||
browser_ = NULL;
|
||||
render_handler_->SetBrowser(NULL);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
@ -922,20 +828,13 @@ bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
if (!show) {
|
||||
renderer_.ClearPopupRects();
|
||||
browser->GetHost()->Invalidate(PET_VIEW);
|
||||
}
|
||||
renderer_.OnPopupShow(browser, show);
|
||||
render_handler_->OnPopupShow(browser, show);
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnPopupSize(CefRefPtr<CefBrowser> browser,
|
||||
const CefRect& rect) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
|
||||
renderer_.OnPopupSize(browser, LogicalToDevice(rect, device_scale_factor_));
|
||||
render_handler_->OnPopupSize(browser,
|
||||
LogicalToDevice(rect, device_scale_factor_));
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
@ -944,23 +843,17 @@ void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
EnsureRenderHandler();
|
||||
render_handler_->OnPaint(browser, type, dirtyRects, buffer, width, height);
|
||||
}
|
||||
|
||||
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 OsrWindowWin::OnAcceleratedPaint(
|
||||
CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) {
|
||||
EnsureRenderHandler();
|
||||
render_handler_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
|
||||
}
|
||||
|
||||
void OsrWindowWin::OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
@ -1093,6 +986,31 @@ CefBrowserHost::DragOperationsMask OsrWindowWin::OnDrop(
|
||||
return current_drag_op_;
|
||||
}
|
||||
|
||||
void OsrWindowWin::EnsureRenderHandler() {
|
||||
CEF_REQUIRE_UI_THREAD();
|
||||
if (!render_handler_) {
|
||||
if (settings_.shared_texture_enabled) {
|
||||
// Try to initialize D3D11 rendering.
|
||||
auto render_handler = new OsrRenderHandlerWinD3D11(settings_, hwnd_);
|
||||
if (render_handler->Initialize(browser_,
|
||||
client_rect_.right - client_rect_.left,
|
||||
client_rect_.bottom - client_rect_.top)) {
|
||||
render_handler_.reset(render_handler);
|
||||
} else {
|
||||
LOG(ERROR) << "Failed to initialize D3D11 rendering.";
|
||||
delete render_handler;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to GL rendering.
|
||||
if (!render_handler_) {
|
||||
auto render_handler = new OsrRenderHandlerWinGL(settings_, hwnd_);
|
||||
render_handler->Initialize(browser_);
|
||||
render_handler_.reset(render_handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(CEF_USE_ATL)
|
||||
|
||||
} // namespace client
|
||||
|
@ -13,7 +13,8 @@
|
||||
#include "tests/cefclient/browser/client_handler_osr.h"
|
||||
#include "tests/cefclient/browser/osr_accessibility_node.h"
|
||||
#include "tests/cefclient/browser/osr_dragdrop_win.h"
|
||||
#include "tests/cefclient/browser/osr_renderer.h"
|
||||
#include "tests/cefclient/browser/osr_render_handler_win.h"
|
||||
#include "tests/cefclient/browser/osr_renderer_settings.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
@ -44,7 +45,7 @@ class OsrWindowWin
|
||||
};
|
||||
|
||||
// |delegate| must outlive this object.
|
||||
OsrWindowWin(Delegate* delegate, const OsrRenderer::Settings& settings);
|
||||
OsrWindowWin(Delegate* delegate, const OsrRendererSettings& settings);
|
||||
|
||||
// Create a new browser and native window.
|
||||
void CreateBrowser(HWND parent_hwnd,
|
||||
@ -63,6 +64,8 @@ class OsrWindowWin
|
||||
void SetFocus();
|
||||
void SetDeviceScaleFactor(float device_scale_factor);
|
||||
|
||||
const OsrRendererSettings& settings() const { return settings_; }
|
||||
|
||||
private:
|
||||
// Only allow deletion via scoped_refptr.
|
||||
friend struct CefDeleteOnThread<TID_UI>;
|
||||
@ -74,14 +77,6 @@ class OsrWindowWin
|
||||
void Create(HWND parent_hwnd, const RECT& rect);
|
||||
void Destroy();
|
||||
|
||||
// Manage GL context lifespan.
|
||||
void EnableGL();
|
||||
void DisableGL();
|
||||
|
||||
// Redraw what is currently in the texture.
|
||||
void Invalidate();
|
||||
void Render();
|
||||
|
||||
void NotifyNativeWindowCreated(HWND hwnd);
|
||||
|
||||
static void RegisterOsrClass(HINSTANCE hInstance, HBRUSH background_brush);
|
||||
@ -130,6 +125,10 @@ class OsrWindowWin
|
||||
const void* buffer,
|
||||
int width,
|
||||
int height) OVERRIDE;
|
||||
void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
|
||||
CefRenderHandler::PaintElementType type,
|
||||
const CefRenderHandler::RectList& dirtyRects,
|
||||
void* share_handle) OVERRIDE;
|
||||
void OnCursorChange(CefRefPtr<CefBrowser> browser,
|
||||
CefCursorHandle cursor,
|
||||
CefRenderHandler::CursorType type,
|
||||
@ -163,14 +162,14 @@ class OsrWindowWin
|
||||
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
|
||||
#endif // defined(CEF_USE_ATL)
|
||||
|
||||
void EnsureRenderHandler();
|
||||
|
||||
// Only accessed on the main thread.
|
||||
Delegate* delegate_;
|
||||
|
||||
// The below members are only accessed on the UI thread.
|
||||
OsrRenderer renderer_;
|
||||
const OsrRendererSettings settings_;
|
||||
HWND hwnd_;
|
||||
HDC hdc_;
|
||||
HGLRC hrc_;
|
||||
std::unique_ptr<OsrRenderHandlerWin> render_handler_;
|
||||
|
||||
// Class that encapsulates IMM32 APIs and controls IMEs attached to a window.
|
||||
scoped_ptr<OsrImeHandlerWin> ime_handler_;
|
||||
@ -190,8 +189,6 @@ class OsrWindowWin
|
||||
IAccessible* accessibility_root_;
|
||||
#endif
|
||||
|
||||
bool painting_popup_;
|
||||
bool render_task_pending_;
|
||||
bool hidden_;
|
||||
|
||||
// Mouse state tracking.
|
||||
|
@ -243,7 +243,7 @@ bool RootWindowGtk::WithExtension() const {
|
||||
|
||||
void RootWindowGtk::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRenderer::Settings settings = {};
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
browser_window_.reset(new BrowserWindowOsrGtk(this, startup_url, settings));
|
||||
} else {
|
||||
|
@ -445,7 +445,7 @@ void RootWindowMac::WindowDestroyed() {
|
||||
|
||||
void RootWindowMac::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRenderer::Settings settings = {};
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
browser_window_.reset(new BrowserWindowOsrMac(this, startup_url, settings));
|
||||
} else {
|
||||
|
@ -301,7 +301,7 @@ bool RootWindowWin::WithExtension() const {
|
||||
|
||||
void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
|
||||
if (with_osr_) {
|
||||
OsrRenderer::Settings settings = {};
|
||||
OsrRendererSettings settings = {};
|
||||
MainContext::Get()->PopulateOsrSettings(&settings);
|
||||
browser_window_.reset(new BrowserWindowOsrWin(this, startup_url, settings));
|
||||
} else {
|
||||
|
@ -21,15 +21,8 @@ void ClientAppBrowser::OnBeforeCommandLineProcessing(
|
||||
// Pass additional command-line flags to the browser process.
|
||||
if (process_type.empty()) {
|
||||
// Pass additional command-line flags when off-screen rendering is enabled.
|
||||
if (command_line->HasSwitch(switches::kOffScreenRenderingEnabled)) {
|
||||
// If the PDF extension is enabled then cc Surfaces must be disabled for
|
||||
// PDFs to render correctly.
|
||||
// See https://bitbucket.org/chromiumembedded/cef/issues/1689 for details.
|
||||
if (!command_line->HasSwitch("disable-extensions") &&
|
||||
!command_line->HasSwitch("disable-pdf-extension")) {
|
||||
command_line->AppendSwitch("disable-surfaces");
|
||||
}
|
||||
|
||||
if (command_line->HasSwitch(switches::kOffScreenRenderingEnabled) &&
|
||||
!command_line->HasSwitch(switches::kSharedTextureEnabled)) {
|
||||
// Use software rendering and compositing (disable GPU) for increased FPS
|
||||
// and decreased CPU usage. This will also disable WebGL so remove these
|
||||
// switches if you need that capability.
|
||||
|
@ -8,6 +8,22 @@
|
||||
|
||||
namespace client {
|
||||
|
||||
namespace {
|
||||
|
||||
LARGE_INTEGER qi_freq_ = {};
|
||||
|
||||
} // namespace
|
||||
|
||||
uint64_t GetTimeNow() {
|
||||
if (!qi_freq_.HighPart && !qi_freq_.LowPart) {
|
||||
QueryPerformanceFrequency(&qi_freq_);
|
||||
}
|
||||
LARGE_INTEGER t = {};
|
||||
QueryPerformanceCounter(&t);
|
||||
return static_cast<uint64_t>((t.QuadPart / double(qi_freq_.QuadPart)) *
|
||||
1000000);
|
||||
}
|
||||
|
||||
void SetUserDataPtr(HWND hWnd, void* ptr) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
LONG_PTR result =
|
||||
|
@ -13,6 +13,9 @@
|
||||
|
||||
namespace client {
|
||||
|
||||
// Returns the current time in microseconds.
|
||||
uint64_t GetTimeNow();
|
||||
|
||||
// Set the window's user data pointer.
|
||||
void SetUserDataPtr(HWND hWnd, void* ptr);
|
||||
|
||||
|
@ -25,6 +25,8 @@ const char kOffScreenRenderingEnabled[] = "off-screen-rendering-enabled";
|
||||
const char kOffScreenFrameRate[] = "off-screen-frame-rate";
|
||||
const char kTransparentPaintingEnabled[] = "transparent-painting-enabled";
|
||||
const char kShowUpdateRect[] = "show-update-rect";
|
||||
const char kSharedTextureEnabled[] = "shared-texture-enabled";
|
||||
const char kExternalBeginFrameEnabled[] = "external-begin-frame-enabled";
|
||||
const char kMouseCursorChangeDisabled[] = "mouse-cursor-change-disabled";
|
||||
const char kRequestContextPerBrowser[] = "request-context-per-browser";
|
||||
const char kRequestContextSharedCache[] = "request-context-shared-cache";
|
||||
|
@ -19,6 +19,8 @@ extern const char kOffScreenRenderingEnabled[];
|
||||
extern const char kOffScreenFrameRate[];
|
||||
extern const char kTransparentPaintingEnabled[];
|
||||
extern const char kShowUpdateRect[];
|
||||
extern const char kSharedTextureEnabled[];
|
||||
extern const char kExternalBeginFrameEnabled[];
|
||||
extern const char kMouseCursorChangeDisabled[];
|
||||
extern const char kRequestContextPerBrowser[];
|
||||
extern const char kRequestContextSharedCache[];
|
||||
|
Loading…
x
Reference in New Issue
Block a user