| Index: content/common/gpu/child_window_surface_win.cc
|
| diff --git a/content/common/gpu/child_window_surface_win.cc b/content/common/gpu/child_window_surface_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..14d423481a8704778206a2023cb5588148511cc3
|
| --- /dev/null
|
| +++ b/content/common/gpu/child_window_surface_win.cc
|
| @@ -0,0 +1,228 @@
|
| +// Copyright 2015 The Chromium 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 "content/common/gpu/child_window_surface_win.h"
|
| +
|
| +#include "base/compiler_specific.h"
|
| +#include "base/win/scoped_hdc.h"
|
| +#include "base/win/wrapped_window_proc.h"
|
| +#include "content/common/gpu/gpu_channel_manager.h"
|
| +#include "content/common/gpu/gpu_channel_manager_delegate.h"
|
| +#include "gpu/ipc/common/gpu_messages.h"
|
| +#include "ui/base/win/hidden_window.h"
|
| +#include "ui/gfx/native_widget_types.h"
|
| +#include "ui/gfx/win/hwnd_util.h"
|
| +#include "ui/gl/egl_util.h"
|
| +#include "ui/gl/gl_context.h"
|
| +#include "ui/gl/gl_surface_egl.h"
|
| +#include "ui/gl/scoped_make_current.h"
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +ATOM g_window_class;
|
| +
|
| +LRESULT CALLBACK IntermediateWindowProc(HWND window,
|
| + UINT message,
|
| + WPARAM w_param,
|
| + LPARAM l_param) {
|
| + switch (message) {
|
| + case WM_ERASEBKGND:
|
| + // Prevent windows from erasing the background.
|
| + return 1;
|
| + case WM_PAINT:
|
| + PAINTSTRUCT paint;
|
| + if (BeginPaint(window, &paint)) {
|
| + ChildWindowSurfaceWin* window_surface =
|
| + reinterpret_cast<ChildWindowSurfaceWin*>(
|
| + gfx::GetWindowUserData(window));
|
| + DCHECK(window_surface);
|
| +
|
| + // Wait to clear the contents until a GL draw occurs, as otherwise an
|
| + // unsightly black flash may happen if the GL contents are still
|
| + // transparent.
|
| + window_surface->InvalidateWindowRect(gfx::Rect(paint.rcPaint));
|
| + EndPaint(window, &paint);
|
| + }
|
| + return 0;
|
| + default:
|
| + return DefWindowProc(window, message, w_param, l_param);
|
| + }
|
| +}
|
| +
|
| +void InitializeWindowClass() {
|
| + if (g_window_class)
|
| + return;
|
| +
|
| + WNDCLASSEX intermediate_class;
|
| + base::win::InitializeWindowClass(
|
| + L"Intermediate D3D Window",
|
| + &base::win::WrappedWindowProc<IntermediateWindowProc>, CS_OWNDC, 0, 0,
|
| + nullptr, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), nullptr,
|
| + nullptr, nullptr, &intermediate_class);
|
| + g_window_class = RegisterClassEx(&intermediate_class);
|
| + if (!g_window_class) {
|
| + LOG(ERROR) << "RegisterClass failed.";
|
| + return;
|
| + }
|
| +}
|
| +}
|
| +
|
| +ChildWindowSurfaceWin::ChildWindowSurfaceWin(GpuChannelManager* manager,
|
| + HWND parent_window)
|
| + : gfx::NativeViewGLSurfaceEGL(0),
|
| + parent_window_(parent_window),
|
| + manager_(manager),
|
| + alpha_(true),
|
| + first_swap_(true) {
|
| + // Don't use EGL_ANGLE_window_fixed_size so that we can avoid recreating the
|
| + // window surface, which can cause flicker on DirectComposition.
|
| + enable_fixed_size_angle_ = false;
|
| +}
|
| +
|
| +EGLConfig ChildWindowSurfaceWin::GetConfig() {
|
| + if (!config_) {
|
| + int alpha_size = alpha_ ? 8 : EGL_DONT_CARE;
|
| +
|
| + EGLint config_attribs[] = {EGL_ALPHA_SIZE,
|
| + alpha_size,
|
| + EGL_BLUE_SIZE,
|
| + 8,
|
| + EGL_GREEN_SIZE,
|
| + 8,
|
| + EGL_RED_SIZE,
|
| + 8,
|
| + EGL_RENDERABLE_TYPE,
|
| + EGL_OPENGL_ES2_BIT,
|
| + EGL_SURFACE_TYPE,
|
| + EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
|
| + EGL_NONE};
|
| +
|
| + EGLDisplay display = GetHardwareDisplay();
|
| + EGLint num_configs;
|
| + if (!eglChooseConfig(display, config_attribs, &config_, 1, &num_configs)) {
|
| + LOG(ERROR) << "eglChooseConfig failed with error "
|
| + << ui::GetLastEGLErrorString();
|
| + return NULL;
|
| + }
|
| + }
|
| +
|
| + return config_;
|
| +}
|
| +
|
| +bool ChildWindowSurfaceWin::InitializeNativeWindow() {
|
| + if (window_)
|
| + return true;
|
| + InitializeWindowClass();
|
| + DCHECK(g_window_class);
|
| +
|
| + RECT windowRect;
|
| + GetClientRect(parent_window_, &windowRect);
|
| +
|
| + window_ = CreateWindowEx(
|
| + WS_EX_NOPARENTNOTIFY, reinterpret_cast<wchar_t*>(g_window_class), L"",
|
| + WS_CHILDWINDOW | WS_DISABLED | WS_VISIBLE, 0, 0,
|
| + windowRect.right - windowRect.left, windowRect.bottom - windowRect.top,
|
| + ui::GetHiddenWindow(), NULL, NULL, NULL);
|
| + gfx::SetWindowUserData(window_, this);
|
| + manager_->delegate()->SendAcceleratedSurfaceCreatedChildWindow(parent_window_,
|
| + window_);
|
| + return true;
|
| +}
|
| +
|
| +bool ChildWindowSurfaceWin::Resize(const gfx::Size& size,
|
| + float scale_factor,
|
| + bool has_alpha) {
|
| + if (!SupportsPostSubBuffer()) {
|
| + if (!MoveWindow(window_, 0, 0, size.width(), size.height(), FALSE)) {
|
| + return false;
|
| + }
|
| + alpha_ = has_alpha;
|
| + return gfx::NativeViewGLSurfaceEGL::Resize(size, scale_factor, has_alpha);
|
| + } else {
|
| + if (size == GetSize() && has_alpha == alpha_)
|
| + return true;
|
| +
|
| + // Force a resize and redraw (but not a move, activate, etc.).
|
| + if (!SetWindowPos(window_, nullptr, 0, 0, size.width(), size.height(),
|
| + SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS |
|
| + SWP_NOOWNERZORDER | SWP_NOZORDER)) {
|
| + return false;
|
| + }
|
| + size_ = size;
|
| + if (has_alpha == alpha_) {
|
| + // A 0-size PostSubBuffer doesn't swap but forces the swap chain to resize
|
| + // to match the window.
|
| + PostSubBuffer(0, 0, 0, 0);
|
| + } else {
|
| + alpha_ = has_alpha;
|
| + config_ = nullptr;
|
| +
|
| + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
|
| + gfx::GLContext* current_context = gfx::GLContext::GetCurrent();
|
| + bool was_current = current_context && current_context->IsCurrent(this);
|
| + if (was_current) {
|
| + scoped_make_current.reset(
|
| + new ui::ScopedMakeCurrent(current_context, this));
|
| + current_context->ReleaseCurrent(this);
|
| + }
|
| +
|
| + Destroy();
|
| +
|
| + if (!Initialize()) {
|
| + LOG(ERROR) << "Failed to resize window.";
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +gfx::SwapResult ChildWindowSurfaceWin::SwapBuffers() {
|
| + gfx::SwapResult result = NativeViewGLSurfaceEGL::SwapBuffers();
|
| + // Force the driver to finish drawing before clearing the contents to
|
| + // transparent, to reduce or eliminate the period of time where the contents
|
| + // have flashed black.
|
| + if (first_swap_) {
|
| + glFinish();
|
| + first_swap_ = false;
|
| + }
|
| + ClearInvalidContents();
|
| + return result;
|
| +}
|
| +
|
| +gfx::SwapResult ChildWindowSurfaceWin::PostSubBuffer(int x,
|
| + int y,
|
| + int width,
|
| + int height) {
|
| + gfx::SwapResult result =
|
| + NativeViewGLSurfaceEGL::PostSubBuffer(x, y, width, height);
|
| + ClearInvalidContents();
|
| + return result;
|
| +}
|
| +
|
| +void ChildWindowSurfaceWin::InvalidateWindowRect(const gfx::Rect& rect) {
|
| + rect_to_clear_.Union(rect);
|
| +}
|
| +
|
| +void ChildWindowSurfaceWin::ClearInvalidContents() {
|
| + if (!rect_to_clear_.IsEmpty()) {
|
| + base::win::ScopedGetDC dc(window_);
|
| +
|
| + RECT rect = rect_to_clear_.ToRECT();
|
| +
|
| + // DirectComposition composites with the contents under the SwapChain,
|
| + // so ensure that's cleared. GDI treats black as transparent.
|
| + FillRect(dc, &rect, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
|
| + rect_to_clear_ = gfx::Rect();
|
| + }
|
| +}
|
| +
|
| +ChildWindowSurfaceWin::~ChildWindowSurfaceWin() {
|
| + gfx::SetWindowUserData(window_, nullptr);
|
| + DestroyWindow(window_);
|
| +}
|
| +
|
| +} // namespace content
|
|
|