Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add support for replaying to the surface on Windows and Linux #2124

Merged
merged 6 commits into from
Aug 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cmd/gapir/cc/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "core/cc/supported_abis.h"
#include "core/cc/target.h"

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -272,6 +273,11 @@ int main(int argc, const char* argv[]) {
}
}

#if TARGET_OS == GAPID_OS_LINUX
// Ignore SIGPIPE so we can log after gapis closes.
signal(SIGPIPE, SIG_IGN);
#endif

if (wait_for_debugger) {
GAPID_INFO("Waiting for debugger to attach");
core::Debugger::waitForAttach();
Expand Down Expand Up @@ -328,6 +334,8 @@ int main(int argc, const char* argv[]) {
fflush(stdout);

server->wait();

gapir::WaitForWindowClose();
return EXIT_SUCCESS;
}

Expand Down
7 changes: 6 additions & 1 deletion core/vulkan/vk_virtual_swapchain/cc/base_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device,
device_(device),
instance_functions_(instance_functions),
device_functions_(device_functions),
swapchain_info_(*swapchain_info) {
swapchain_info_(*swapchain_info),
valid_(false) {
if (platform_info == nullptr) {
return;
}
Expand Down Expand Up @@ -149,6 +150,8 @@ BaseSwapchain::BaseSwapchain(VkInstance instance, VkDevice device,
}

is_pending_.resize(num_images);

valid_ = true;
}

void BaseSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) {
Expand All @@ -172,6 +175,8 @@ void BaseSwapchain::Destroy(const VkAllocationCallbacks *pAllocator) {
command_buffers_.clear();
}

bool BaseSwapchain::Valid() const { return valid_; }

VkResult BaseSwapchain::PresentFrom(VkQueue queue, size_t index,
VkImage image) {
std::unique_lock<threading::mutex> guard(present_lock_);
Expand Down
4 changes: 4 additions & 0 deletions core/vulkan/vk_virtual_swapchain/cc/base_swapchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class BaseSwapchain {
const VkAllocationCallbacks *pAllocator,
const void *platform_info);
void Destroy(const VkAllocationCallbacks *pAllocator);
bool Valid() const;

VkResult PresentFrom(VkQueue queue, size_t index, VkImage image);
VkSemaphore BlitWaitSemaphore(size_t index);

Expand Down Expand Up @@ -65,6 +67,8 @@ class BaseSwapchain {
// The command buffers to use to blit. We need several in case someone
// submits while a previous one is still pending.
std::vector<VkCommandBuffer> command_buffers_;
// Whether we completed construction successfully
bool valid_;
};

} // namespace swapchain
Expand Down
8 changes: 7 additions & 1 deletion core/vulkan/vk_virtual_swapchain/cc/layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,14 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
GET_PROC(vkGetPhysicalDeviceProperties);
GET_PROC(vkGetPhysicalDeviceMemoryProperties);

#if defined(VK_USE_PLATFORM_ANDROID_KHR)
#ifdef VK_USE_PLATFORM_ANDROID_KHR
GET_PROC(vkCreateAndroidSurfaceKHR);
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
GET_PROC(vkCreateXcbSurfaceKHR);
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
GET_PROC(vkCreateWin32SurfaceKHR);
#endif
GET_PROC(vkDestroySurfaceKHR);

Expand Down
8 changes: 7 additions & 1 deletion core/vulkan/vk_virtual_swapchain/cc/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,14 @@ struct InstanceData {
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;

#if defined(VK_USE_PLATFORM_ANDROID_KHR)
#ifdef VK_USE_PLATFORM_ANDROID_KHR
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
#endif
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;

Expand Down
29 changes: 26 additions & 3 deletions core/vulkan/vk_virtual_swapchain/cc/platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ namespace swapchain {
void CreateSurface(const InstanceData* functions, VkInstance instance,
const void* data, const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface) {
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
*pSurface = 0;
#ifdef VK_USE_PLATFORM_ANDROID_KHR
{
auto pCreateInfo = static_cast<const VkAndroidSurfaceCreateInfoKHR*>(data);
if (pCreateInfo->sType ==
Expand All @@ -33,8 +34,30 @@ void CreateSurface(const InstanceData* functions, VkInstance instance,
}
}
}
#else
*pSurface = 0;
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
{
auto pCreateInfo = static_cast<const VkXcbSurfaceCreateInfoKHR*>(data);
if (pCreateInfo->sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR) {
// Attempt to create Xcb surface
if (functions->vkCreateXcbSurfaceKHR(instance, pCreateInfo, pAllocator,
pSurface) != VK_SUCCESS) {
*pSurface = 0;
}
}
}
#endif
#ifdef VK_USE_PLATFORM_WIN32_KHR
{
auto pCreateInfo = static_cast<const VkWin32SurfaceCreateInfoKHR*>(data);
if (pCreateInfo->sType == VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR) {
// Attempt to create Win32 surface
if (functions->vkCreateWin32SurfaceKHR(instance, pCreateInfo, pAllocator,
pSurface) != VK_SUCCESS) {
*pSurface = 0;
}
}
}
#endif
}

Expand Down
5 changes: 5 additions & 0 deletions core/vulkan/vk_virtual_swapchain/cc/virtual_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,5 +402,10 @@ void VirtualSwapchain::CreateBaseSwapchain(
base_swapchain_ = std::unique_ptr<BaseSwapchain>(new BaseSwapchain(
instance, device_, queue_, command_pool_, num_images_, instance_functions,
functions_, &swapchain_info_, pAllocator, platform_info));
if (!base_swapchain_->Valid()) {
// Failed to create some aspect of the base surface
base_swapchain_->Destroy(pAllocator);
base_swapchain_.reset();
}
}
} // namespace swapchain
4 changes: 3 additions & 1 deletion gapir/cc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ cc_library(
],
copts = cc_copts(),
linkopts = select({
"//tools/build:linux": [],
"//tools/build:linux": [
"-lxcb",
],
"//tools/build:darwin": [
"-framework Cocoa",
"-framework OpenGL",
Expand Down
196 changes: 191 additions & 5 deletions gapir/cc/surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,208 @@
* limitations under the License.
*/

#include <condition_variable>
#include <mutex>
#include <thread>

#include "core/cc/target.h"

#include "surface.h"

#if TARGET_OS == GAPID_OS_WINDOWS
#include <Windows.h>
#endif

namespace gapir {

namespace {
class Flag {
public:
Flag() : set_(false) {}

void Set() {
std::unique_lock<std::mutex> guard(mutex_);
set_ = true;
condition_.notify_all();
}

void Wait() {
std::unique_lock<std::mutex> guard(mutex_);
while (!set_) {
condition_.wait(guard);
}
}

private:
bool set_;
std::mutex mutex_;
std::condition_variable condition_;
};
} // namespace

#if TARGET_OS == GAPID_OS_ANDROID
ANativeWindow* android_window;
#elif TARGET_OS == GAPID_OS_LINUX
static XcbWindowInfo window_info;

static Flag window_create_flag;
static std::thread window_thread;

bool createWindow(uint32_t width, uint32_t height) {
window_info.connection = xcb_connect(nullptr, nullptr);
if (!window_info.connection) {
return false;
}

xcb_screen_t* screen =
xcb_setup_roots_iterator(xcb_get_setup(window_info.connection)).data;
if (!screen) {
return false;
}

window_info.window = xcb_generate_id(window_info.connection);

xcb_create_window(window_info.connection, XCB_COPY_FROM_PARENT,
window_info.window, screen->root, 0, 0, width, height, 1,
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, 0,
nullptr);
xcb_map_window(window_info.connection, window_info.window);
xcb_flush(window_info.connection);

return true;
}

void handleWindow(uint32_t width, uint32_t height) {
bool res = createWindow(width, height);
window_create_flag.Set();
if (!res) {
return;
}

xcb_intern_atom_cookie_t delete_cookie =
xcb_intern_atom(window_info.connection, 0, 16, "WM_DELETE_WINDOW");
xcb_intern_atom_reply_t* delete_reply =
xcb_intern_atom_reply(window_info.connection, delete_cookie, 0);

xcb_generic_event_t* event;
while ((event = xcb_wait_for_event(window_info.connection))) {
if ((event->response_type & 0x7f) == XCB_CLIENT_MESSAGE) {
auto message = (xcb_client_message_event_t*)event;
if (message->data.data32[0] == delete_reply->atom) {
break;
}
}
}
}

#endif // TARGET_OS == GAPID_OS_ANDROID
void* createXcbWindow(uint32_t width, uint32_t height) {
window_thread = std::thread(handleWindow, width, height);
window_create_flag.Wait();
return window_info.window ? (void*)&window_info : nullptr;
}
#elif TARGET_OS == GAPID_OS_WINDOWS
static Win32WindowInfo window_info;

static Flag window_create_flag;
static HANDLE window_thread;

LRESULT windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CLOSE:
PostQuitMessage(0);
return 0;
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

bool createWindow(uint32_t width, uint32_t height) {
window_info.instance = GetModuleHandle(nullptr);

WNDCLASS wndclass = {
CS_HREDRAW | CS_VREDRAW, // style
windowProc, // lpfnWindowProc
0, // cbClsExtra
0, // cbWndExtra
window_info.instance, // hInstance
LoadIcon(nullptr, IDI_APPLICATION), // hIcon
LoadCursor(nullptr, IDC_ARROW), // hCursor
(HBRUSH)(COLOR_BACKGROUND + 1), // hbrBackground
"", // lpszMenuName
"GAPID Replay", // lpszClassName
};
ATOM cls = RegisterClass(&wndclass);
if (cls == 0) {
// Class registration failed
return false;
}

window_info.window = CreateWindow(
MAKEINTATOM(cls), "GAPID Replay",
WS_BORDER | WS_CAPTION | WS_GROUP | WS_OVERLAPPED | WS_POPUP |
WS_SYSMENU | WS_TILED | WS_VISIBLE,
0, 0, width, height, nullptr, nullptr, window_info.instance, nullptr);
return (bool)window_info.window;
}

DWORD handleWindow(void* data) {
auto extent = (const uint32_t*)data;
bool res = createWindow(extent[0], extent[1]);
window_create_flag.Set();
if (!res) {
return 1;
}

void* SurfaceInfo() {
MSG msg;
while (GetMessage(&msg, window_info.window, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

void* createWin32Window(uint32_t width, uint32_t height) {
uint32_t extent[] = {width, height};
window_thread =
CreateThread(NULL, 0, handleWindow, (void*)extent, 0, nullptr);
window_create_flag.Wait();
return window_info.window ? (void*)&window_info : nullptr;
}
#endif

const void* CreateSurface(uint32_t width, uint32_t height, SurfaceType& type) {
switch (type) {
#if TARGET_OS == GAPID_OS_ANDROID
return (void*)android_window;
#else
return nullptr;
case SurfaceType::Android:
case SurfaceType::Unknown:
type = SurfaceType::Android;
return (void*)android_window;
#elif TARGET_OS == GAPID_OS_LINUX
case SurfaceType::Xcb:
case SurfaceType::Unknown:
type = SurfaceType::Xcb;
return createXcbWindow(width, height);
#elif TARGET_OS == GAPID_OS_WINDOWS
case SurfaceType::Win32:
case SurfaceType::Unknown:
type = SurfaceType::Win32;
return createWin32Window(width, height);
#endif
default:
return nullptr;
}
}

void WaitForWindowClose() {
#if TARGET_OS == GAPID_OS_WINDOWS
if (window_thread) {
WaitForSingleObject(window_thread, INFINITE);
}
#endif
#if TARGET_OS == GAPID_OS_LINUX
if (window_thread.joinable()) {
window_thread.join();
}
#endif
}

Expand Down
Loading