blob: 47a797967a0496409d9a0f9d4d271168aa052b7b [file] [log] [blame]
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// DisplayVkWin32.cpp:
// Implements the class methods for DisplayVkWin32.
//
#include "libANGLE/renderer/vulkan/win32/DisplayVkWin32.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include <vulkan/vulkan.h>
#include <windows.h>
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
#include "libANGLE/renderer/vulkan/win32/WindowSurfaceVkWin32.h"
namespace rx
{
DisplayVkWin32::DisplayVkWin32(const egl::DisplayState &state)
: DisplayVk(state), mWindowClass(NULL), mDummyWindow(nullptr)
{}
DisplayVkWin32::~DisplayVkWin32() {}
void DisplayVkWin32::terminate()
{
if (mDummyWindow)
{
DestroyWindow(mDummyWindow);
mDummyWindow = nullptr;
}
if (mWindowClass)
{
if (!UnregisterClassA(reinterpret_cast<const char *>(mWindowClass),
GetModuleHandle(nullptr)))
{
WARN() << "Failed to unregister ANGLE window class: " << gl::FmtHex(mWindowClass);
}
mWindowClass = NULL;
}
DisplayVk::terminate();
}
bool DisplayVkWin32::isValidNativeWindow(EGLNativeWindowType window) const
{
return (IsWindow(window) == TRUE);
}
SurfaceImpl *DisplayVkWin32::createWindowSurfaceVk(const egl::SurfaceState &state,
EGLNativeWindowType window)
{
return new WindowSurfaceVkWin32(state, window);
}
egl::Error DisplayVkWin32::initialize(egl::Display *display)
{
ANGLE_TRY(DisplayVk::initialize(display));
HINSTANCE hinstance = GetModuleHandle(nullptr);
std::ostringstream stream;
stream << "ANGLE DisplayVkWin32 " << gl::FmtHex(display) << " Intermediate Window Class";
const LPSTR idcArrow = MAKEINTRESOURCEA(32512);
std::string className = stream.str();
WNDCLASSA wndClass;
if (!GetClassInfoA(hinstance, className.c_str(), &wndClass))
{
WNDCLASSA intermediateClassDesc = {};
intermediateClassDesc.style = CS_OWNDC;
intermediateClassDesc.lpfnWndProc = DefWindowProcA;
intermediateClassDesc.cbClsExtra = 0;
intermediateClassDesc.cbWndExtra = 0;
intermediateClassDesc.hInstance = GetModuleHandle(nullptr);
intermediateClassDesc.hIcon = nullptr;
intermediateClassDesc.hCursor = LoadCursorA(nullptr, idcArrow);
intermediateClassDesc.hbrBackground = 0;
intermediateClassDesc.lpszMenuName = nullptr;
intermediateClassDesc.lpszClassName = className.c_str();
mWindowClass = RegisterClassA(&intermediateClassDesc);
if (!mWindowClass)
{
return egl::EglNotInitialized()
<< "Failed to register intermediate OpenGL window class \"" << className.c_str()
<< "\":" << gl::FmtErr(HRESULT_CODE(GetLastError()));
}
}
mDummyWindow =
CreateWindowExA(0, reinterpret_cast<const char *>(mWindowClass), "ANGLE Dummy Window",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
if (!mDummyWindow)
{
return egl::EglNotInitialized() << "Failed to create dummy OpenGL window.";
}
VkSurfaceKHR surfaceVk;
VkWin32SurfaceCreateInfoKHR info = {VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, nullptr, 0,
GetModuleHandle(nullptr), mDummyWindow};
VkInstance instance = mRenderer->getInstance();
VkPhysicalDevice physDevice = mRenderer->getPhysicalDevice();
if (vkCreateWin32SurfaceKHR(instance, &info, nullptr, &surfaceVk) != VK_SUCCESS)
{
return egl::EglNotInitialized() << "vkCreateWin32SurfaceKHR failed";
}
uint32_t surfaceFormatCount;
if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount, nullptr) !=
VK_SUCCESS)
{
return egl::EglNotInitialized() << "vkGetPhysicalDeviceSurfaceFormatsKHR failed";
}
mSurfaceFormats.resize(surfaceFormatCount);
if (vkGetPhysicalDeviceSurfaceFormatsKHR(physDevice, surfaceVk, &surfaceFormatCount,
mSurfaceFormats.data()) != VK_SUCCESS)
{
return egl::EglNotInitialized() << "vkGetPhysicalDeviceSurfaceFormatsKHR (2nd) failed";
}
vkDestroySurfaceKHR(instance, surfaceVk, nullptr);
DestroyWindow(mDummyWindow);
mDummyWindow = nullptr;
return egl::NoError();
}
egl::ConfigSet DisplayVkWin32::generateConfigs()
{
constexpr GLenum kColorFormats[] = {GL_RGB565, GL_BGRA8_EXT, GL_BGRX8_ANGLEX};
return egl_vk::GenerateConfigs(kColorFormats, egl_vk::kConfigDepthStencilFormats, this);
}
bool DisplayVkWin32::checkConfigSupport(egl::Config *config)
{
const vk::Format &formatVk = this->getRenderer()->getFormat(config->renderTargetFormat);
VkFormat nativeFormat = formatVk.vkImageFormat;
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
// the surface has no preferred format. Otherwise, at least one
// supported format will be returned.
if (mSurfaceFormats.size() == 1u && mSurfaceFormats[0].format == VK_FORMAT_UNDEFINED)
{
return true;
}
for (const VkSurfaceFormatKHR &surfaceFormat : mSurfaceFormats)
{
if (surfaceFormat.format == nativeFormat)
{
return true;
}
}
return false;
}
const char *DisplayVkWin32::getWSIExtension() const
{
return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
}
bool IsVulkanWin32DisplayAvailable()
{
return true;
}
DisplayImpl *CreateVulkanWin32Display(const egl::DisplayState &state)
{
return new DisplayVkWin32(state);
}
} // namespace rx