First pass at VulkanViewer

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1848833005

Review URL: https://codereview.chromium.org/1848833005
This commit is contained in:
jvanverth 2016-04-06 06:08:59 -07:00 committed by Commit bot
parent 52b88cc617
commit 9f37246d68
20 changed files with 1619 additions and 6 deletions

View File

@ -29,12 +29,14 @@
'visualbench.gyp:visualbench',
'fuzz.gyp:fuzz',
'kilobench.gyp:kilobench',
'vulkanviewer.gyp:vulkanviewer',
],
'conditions': [
[ 'skia_gpu == 0', {
'dependencies!': [
'visualbench.gyp:visualbench',
'kilobench.gyp:kilobench',
'vulkanviewer.gyp:vulkanviewer',
]
}],
[ 'skia_os != "android" and skia_os != "linux"', {
@ -73,6 +75,11 @@
'skiaserve.gyp:skiaserve',
],
}],
[ 'skia_vulkan == 0 or skia_os != "win"', {
'dependencies!': [
'vulkanviewer.gyp:vulkanviewer',
],
}],
[ 'skia_skip_gui',
{
'dependencies!': [

46
gyp/vulkanviewer.gyp Normal file
View File

@ -0,0 +1,46 @@
# Copyright 2016 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# GYP file to build performance testbench.
#
{
'includes': [
'apptype_console.gypi',
],
'targets': [
{
'target_name': 'vulkanviewer',
'type': 'executable',
'includes' : [
'gmslides.gypi',
],
'include_dirs': [
'../bench',
'../gm',
'../include/private',
'../src/core',
'../src/effects',
'../src/gpu',
'../src/images',
'../src/image',
],
'sources': [
'../gm/gm.cpp',
'<!@(python find.py ../tools/vulkan "*.cpp")',
],
'dependencies': [
'flags.gyp:flags',
'gputest.gyp:skgputest',
'jsoncpp.gyp:jsoncpp',
'skia_lib.gyp:skia_lib',
'tools.gyp:crash_handler',
'tools.gyp:proc_stats',
'tools.gyp:resources',
'tools.gyp:sk_tool_utils',
'tools.gyp:timer',
'tools.gyp:url_data_manager',
],
},
],
}

View File

@ -24,7 +24,7 @@ const char* kDebugLayerNames[] = {
"VK_LAYER_LUNARG_mem_tracker",
"VK_LAYER_LUNARG_draw_state",
"VK_LAYER_LUNARG_swapchain",
"VK_LAYER_GOOGLE_unique_objects",
//"VK_LAYER_GOOGLE_unique_objects",
// not included in standard_validation
//"VK_LAYER_LUNARG_api_dump",
//"VK_LAYER_LUNARG_vktrace",
@ -68,6 +68,8 @@ const GrVkBackendContext* GrVkBackendContext::Create() {
instanceExtensionNames.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
extensionFlags |= kEXT_debug_report_GrVkExtensionFlag;
}
#endif
if (extensions.hasInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME)) {
instanceExtensionNames.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
extensionFlags |= kKHR_surface_GrVkExtensionFlag;
@ -91,7 +93,6 @@ const GrVkBackendContext* GrVkBackendContext::Create() {
instanceExtensionNames.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
extensionFlags |= kKHR_xlib_surface_GrVkExtensionFlag;
}
#endif
#endif
const VkInstanceCreateInfo instance_create = {
@ -159,6 +160,10 @@ const GrVkBackendContext* GrVkBackendContext::Create() {
}
}
#endif
if (extensions.hasDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
deviceExtensionNames.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
extensionFlags |= kKHR_swapchain_GrVkExtensionFlag;
}
if (extensions.hasDeviceExtension("VK_NV_glsl_shader")) {
deviceExtensionNames.push_back("VK_NV_glsl_shader");
extensionFlags |= kNV_glsl_shader_GrVkExtensionFlag;

View File

@ -95,10 +95,10 @@ GrVkGpu::GrVkGpu(GrContext* context, const GrContextOptions& options,
callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
callbackCreateInfo.pNext = nullptr;
callbackCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
VK_DEBUG_REPORT_WARNING_BIT_EXT |
VK_DEBUG_REPORT_WARNING_BIT_EXT;// |
//VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
//VK_DEBUG_REPORT_DEBUG_BIT_EXT |
VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
//VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
callbackCreateInfo.pfnCallback = &DebugReportCallback;
callbackCreateInfo.pUserData = nullptr;

View File

@ -23,6 +23,9 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
case kSRGBA_8888_GrPixelConfig:
*format = VK_FORMAT_R8G8B8A8_SRGB;
break;
case kSBGRA_8888_GrPixelConfig:
*format = VK_FORMAT_B8G8R8A8_SRGB;
break;
case kRGB_565_GrPixelConfig:
*format = VK_FORMAT_R5G6B5_UNORM_PACK16;
break;
@ -30,7 +33,7 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
*format = VK_FORMAT_R4G4B4A4_UNORM_PACK16;
break;
case kIndex_8_GrPixelConfig:
// No current rad support for this config
// No current vulkan support for this config
return false;
case kAlpha_8_GrPixelConfig:
*format = VK_FORMAT_R8_UNORM;
@ -40,7 +43,7 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
*format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
break;
case kLATC_GrPixelConfig:
// No current rad support for this config
// No current vulkan support for this config
return false;
case kR11_EAC_GrPixelConfig:
*format = VK_FORMAT_EAC_R11_UNORM_BLOCK;
@ -63,6 +66,58 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) {
return true;
}
bool GrVkFormatToPixelConfig(VkFormat format, GrPixelConfig* config) {
GrPixelConfig dontCare;
if (!config) {
config = &dontCare;
}
switch (format) {
case VK_FORMAT_R8G8B8A8_UNORM:
*config = kRGBA_8888_GrPixelConfig;
break;
case VK_FORMAT_B8G8R8A8_UNORM:
*config = kBGRA_8888_GrPixelConfig;
break;
case VK_FORMAT_R8G8B8A8_SRGB:
*config = kSRGBA_8888_GrPixelConfig;
break;
case VK_FORMAT_B8G8R8A8_SRGB:
*config = kSBGRA_8888_GrPixelConfig;
break;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
*config = kRGB_565_GrPixelConfig;
break;
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
*config = kRGBA_4444_GrPixelConfig;
break;
case VK_FORMAT_R8_UNORM:
*config = kAlpha_8_GrPixelConfig;
break;
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
*config = kETC1_GrPixelConfig;
break;
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
*config = kR11_EAC_GrPixelConfig;
break;
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
*config = kASTC_12x12_GrPixelConfig;
break;
case VK_FORMAT_R32G32B32A32_SFLOAT:
*config = kRGBA_float_GrPixelConfig;
break;
case VK_FORMAT_R16G16B16A16_SFLOAT:
*config = kRGBA_half_GrPixelConfig;
break;
case VK_FORMAT_R16_SFLOAT:
*config = kAlpha_half_GrPixelConfig;
break;
default:
return false;
}
return true;
}
bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSamples) {
switch (samples) {
case 0: // fall through

View File

@ -30,6 +30,11 @@
*/
bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format);
/**
* Returns the GrPixelConfig for the given vulkan texture format
*/
bool GrVkFormatToPixelConfig(VkFormat format, GrPixelConfig* config);
bool GrSampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits* vkSamples);
#endif

View File

@ -0,0 +1,20 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef Application_DEFINED
#define Application_DEFINED
class Application {
public:
static Application* Create(int argc, char** argv, void* platformData);
virtual ~Application() {}
virtual void onIdle(float dt) = 0;
};
#endif

View File

@ -0,0 +1,605 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrContext.h"
#include "SkSurface.h"
#include "VulkanTestContext.h"
#include "vk/GrVkInterface.h"
#include "vk/GrVkUtil.h"
#include "vk/GrVkTypes.h"
#ifdef VK_USE_PLATFORM_WIN32_KHR
// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
#undef CreateSemaphore
#endif
VulkanTestContext::VulkanTestContext(void* platformData, int msaaSampleCount)
: fSurface(VK_NULL_HANDLE)
, fSwapchain(VK_NULL_HANDLE)
, fCommandPool(VK_NULL_HANDLE)
, fBackbuffers(nullptr) {
// any config code here (particularly for msaa)?
this->initializeContext(platformData);
}
void VulkanTestContext::initializeContext(void* platformData) {
fBackendContext.reset(GrVkBackendContext::Create());
fBackendContext->ref();
fContext = GrContext::Create(kVulkan_GrBackend, (GrBackendContext)fBackendContext.get());
fSurface = createVkSurface(platformData);
if (VK_NULL_HANDLE == fSurface) {
fBackendContext.reset(nullptr);
return;
}
// query to get the initial queue props size
uint32_t queueCount;
GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceQueueFamilyProperties(fBackendContext->fPhysicalDevice, &queueCount,
nullptr));
SkASSERT(queueCount >= 1);
SkAutoMalloc queuePropsAlloc(queueCount * sizeof(VkQueueFamilyProperties));
// now get the actual queue props
VkQueueFamilyProperties* queueProps = (VkQueueFamilyProperties*)queuePropsAlloc.get();
GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceQueueFamilyProperties(fBackendContext->fPhysicalDevice, &queueCount,
queueProps));
// iterate to find the present queue
fPresentQueueIndex = -1;
for (uint32_t i = 0; i < queueCount; i++) {
if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && canPresent(i)) {
fPresentQueueIndex = i;
break;
}
}
SkASSERT(0 <= fPresentQueueIndex && fPresentQueueIndex < queueCount);
VkBool32 supported;
VkResult res = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceSurfaceSupportKHR(fBackendContext->fPhysicalDevice,
fPresentQueueIndex,
fSurface,
&supported));
if (VK_SUCCESS != res) {
this->destroyContext();
return;
}
// get this info from somewhere?
if (!this->createSwapchain(1024, 768)) {
this->destroyContext();
return;
}
// create presentQueue
vkGetDeviceQueue(fBackendContext->fDevice, fPresentQueueIndex, 0, &fPresentQueue);
}
bool VulkanTestContext::createSwapchain(uint32_t width, uint32_t height)
{
// check for capabilities
VkSurfaceCapabilitiesKHR caps;
VkResult res = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice,
fSurface,
&caps));
if (VK_SUCCESS != res) {
return false;
}
uint32_t surfaceFormatCount;
res = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice,
fSurface,
&surfaceFormatCount,
nullptr));
if (VK_SUCCESS != res) {
return false;
}
SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
res = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice,
fSurface,
&surfaceFormatCount,
surfaceFormats));
if (VK_SUCCESS != res) {
return false;
}
uint32_t presentModeCount;
res = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice,
fSurface,
&presentModeCount,
nullptr));
if (VK_SUCCESS != res) {
return false;
}
SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
res = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice,
fSurface,
&presentModeCount,
presentModes));
if (VK_SUCCESS != res) {
return false;
}
VkExtent2D extent = caps.currentExtent;
// use the hints
if (extent.width == (uint32_t)-1) {
extent.width = width;
extent.height = height;
}
// clamp width; to protect us from broken hints?
if (extent.width < caps.minImageExtent.width) {
extent.width = caps.minImageExtent.width;
} else if (extent.width > caps.maxImageExtent.width) {
extent.width = caps.maxImageExtent.width;
}
// clamp height
if (extent.height < caps.minImageExtent.height) {
extent.height = caps.minImageExtent.height;
} else if (extent.height > caps.maxImageExtent.height) {
extent.height = caps.maxImageExtent.height;
}
fWidth = (int)extent.width;
fHeight = (int)extent.height;
uint32_t imageCount = caps.minImageCount + 2;
if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
// Application must settle for fewer images than desired:
imageCount = caps.maxImageCount;
}
VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
SkASSERT(caps.supportedTransforms & caps.currentTransform);
SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
VkCompositeAlphaFlagBitsKHR composite_alpha =
(caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
// FIFO is the only mode universally supported
VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
bool vsync = false;
for (uint32_t i = 0; i < presentModeCount; ++i) {
if ((vsync && VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) ||
(!vsync && VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i])) {
mode = presentModes[i];
}
}
VkSwapchainCreateInfoKHR swapchainCreateInfo;
memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainCreateInfo.surface = fSurface;
swapchainCreateInfo.minImageCount = imageCount;
swapchainCreateInfo.imageFormat = surfaceFormats[0].format; // for now, use the first one
swapchainCreateInfo.imageColorSpace = surfaceFormats[0].colorSpace;
swapchainCreateInfo.imageExtent = extent;
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = usageFlags;
uint32_t queueFamilies[] = { fBackendContext->fQueueFamilyIndex, fPresentQueueIndex };
if (fBackendContext->fQueueFamilyIndex != fPresentQueueIndex) {
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchainCreateInfo.queueFamilyIndexCount = 2;
swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
} else {
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainCreateInfo.queueFamilyIndexCount = 0;
swapchainCreateInfo.pQueueFamilyIndices = nullptr;
}
swapchainCreateInfo.preTransform = caps.currentTransform;;
swapchainCreateInfo.compositeAlpha = composite_alpha;
swapchainCreateInfo.presentMode = mode;
swapchainCreateInfo.clipped = true;
swapchainCreateInfo.oldSwapchain = fSwapchain;
res = GR_VK_CALL(fBackendContext->fInterface,
CreateSwapchainKHR(fBackendContext->fDevice,
&swapchainCreateInfo, nullptr, &fSwapchain));
if (VK_SUCCESS != res) {
return false;
}
// destroy the old swapchain
if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
this->destroyBuffers();
GR_VK_CALL(fBackendContext->fInterface, DestroySwapchainKHR(fBackendContext->fDevice,
swapchainCreateInfo.oldSwapchain,
nullptr));
}
GrVkFormatToPixelConfig(swapchainCreateInfo.imageFormat, &fPixelConfig);
this->createBuffers();
return true;
}
void VulkanTestContext::createBuffers() {
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, GetSwapchainImagesKHR(fBackendContext->fDevice,
fSwapchain,
&fImageCount,
nullptr));
SkASSERT(fImageCount);
fImages = new VkImage[fImageCount];
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, GetSwapchainImagesKHR(fBackendContext->fDevice,
fSwapchain,
&fImageCount,
fImages));
// set up initial image layouts and create surfaces
fImageLayouts = new VkImageLayout[fImageCount];
fSurfaces = new sk_sp<SkSurface>[fImageCount];
for (uint32_t i = 0; i < fImageCount; ++i) {
fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
GrBackendRenderTargetDesc desc;
GrVkTextureInfo info;
info.fImage = fImages[i];
info.fAlloc = nullptr;
info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
desc.fWidth = fWidth;
desc.fHeight = fHeight;
desc.fConfig = fPixelConfig;
desc.fOrigin = kTopLeft_GrSurfaceOrigin;
desc.fSampleCnt = 0;
desc.fStencilBits = 0;
desc.fRenderTargetHandle = (GrBackendObject) &info;
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(fContext, desc, &props);
}
// create the command pool for the command buffers
if (VK_NULL_HANDLE == fCommandPool) {
VkCommandPoolCreateInfo commandPoolInfo;
memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
// this needs to be on the render queue
commandPoolInfo.queueFamilyIndex = fBackendContext->fQueueFamilyIndex;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo,
nullptr, &fCommandPool));
}
// set up the backbuffers
VkSemaphoreCreateInfo semaphoreInfo;
memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreInfo.pNext = nullptr;
semaphoreInfo.flags = 0;
VkCommandBufferAllocateInfo commandBuffersInfo;
memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBuffersInfo.pNext = nullptr;
commandBuffersInfo.commandPool = fCommandPool;
commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
commandBuffersInfo.commandBufferCount = 2;
VkFenceCreateInfo fenceInfo;
memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.pNext = nullptr;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
// we create one additional backbuffer structure here, because we want to
// give the command buffers they contain a chance to finish before we cycle back
fBackbuffers = new BackbufferInfo[fImageCount + 1];
for (uint32_t i = 0; i < fImageCount + 1; ++i) {
fBackbuffers[i].fImageIndex = -1;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
nullptr, &fBackbuffers[i].fAcquireSemaphore));
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
nullptr, &fBackbuffers[i].fRenderSemaphore));
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo,
fBackbuffers[i].fTransitionCmdBuffers));
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
&fBackbuffers[i].fUsageFences[0]));
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
&fBackbuffers[i].fUsageFences[1]));
}
fCurrentBackbufferIndex = fImageCount;
}
void VulkanTestContext::destroyBuffers() {
if (fBackbuffers) {
for (uint32_t i = 0; i < fImageCount + 1; ++i) {
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
WaitForFences(fBackendContext->fDevice, 2,
fBackbuffers[i].fUsageFences,
true, UINT64_MAX));
fBackbuffers[i].fImageIndex = -1;
GR_VK_CALL(fBackendContext->fInterface,
DestroySemaphore(fBackendContext->fDevice,
fBackbuffers[i].fAcquireSemaphore,
nullptr));
GR_VK_CALL(fBackendContext->fInterface,
DestroySemaphore(fBackendContext->fDevice,
fBackbuffers[i].fRenderSemaphore,
nullptr));
GR_VK_CALL(fBackendContext->fInterface,
FreeCommandBuffers(fBackendContext->fDevice, fCommandPool, 2,
fBackbuffers[i].fTransitionCmdBuffers));
GR_VK_CALL(fBackendContext->fInterface,
DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[0], 0));
GR_VK_CALL(fBackendContext->fInterface,
DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[1], 0));
}
}
delete[] fBackbuffers;
fBackbuffers = nullptr;
delete[] fSurfaces;
fSurfaces = nullptr;
delete[] fImageLayouts;
fImageLayouts = nullptr;
delete[] fImages;
fImages = nullptr;
}
VulkanTestContext::~VulkanTestContext() {
this->destroyContext();
}
void VulkanTestContext::destroyContext() {
if (!fBackendContext.get()) {
return;
}
GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
this->destroyBuffers();
if (VK_NULL_HANDLE != fCommandPool) {
GR_VK_CALL(fBackendContext->fInterface, DestroyCommandPool(fBackendContext->fDevice,
fCommandPool, nullptr));
fCommandPool = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != fSwapchain) {
GR_VK_CALL(fBackendContext->fInterface, DestroySwapchainKHR(fBackendContext->fDevice,
fSwapchain, nullptr));
fSwapchain = VK_NULL_HANDLE;
}
if (VK_NULL_HANDLE != fSurface) {
GR_VK_CALL(fBackendContext->fInterface, DestroySurfaceKHR(fBackendContext->fInstance,
fSurface, nullptr));
fSurface = VK_NULL_HANDLE;
}
delete fContext;
fBackendContext.reset(nullptr);
}
VulkanTestContext::BackbufferInfo* VulkanTestContext::getAvailableBackbuffer() {
SkASSERT(fBackbuffers);
++fCurrentBackbufferIndex;
if (fCurrentBackbufferIndex > fImageCount) {
fCurrentBackbufferIndex = 0;
}
BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
WaitForFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences,
true, UINT64_MAX));
return backbuffer;
}
SkSurface* VulkanTestContext::getBackbufferSurface() {
BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
SkASSERT(backbuffer);
// reset the fence
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
// semaphores should be in unsignaled state
// acquire the image
VkResult res = GR_VK_CALL(fBackendContext->fInterface,
AcquireNextImageKHR(fBackendContext->fDevice,
fSwapchain,
UINT64_MAX,
backbuffer->fAcquireSemaphore,
VK_NULL_HANDLE,
&backbuffer->fImageIndex));
if (VK_ERROR_SURFACE_LOST_KHR == res) {
// need to figure out how to create a new vkSurface without the platformData*
return nullptr;
}
if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_ERROR_SURFACE_LOST_KHR == res) {
// tear swapchain down and try again
if (!this->createSwapchain(0, 0)) {
return nullptr;
}
// acquire the image
res = GR_VK_CALL(fBackendContext->fInterface,
AcquireNextImageKHR(fBackendContext->fDevice,
fSwapchain,
UINT64_MAX,
backbuffer->fAcquireSemaphore,
VK_NULL_HANDLE,
&backbuffer->fImageIndex));
if (VK_SUCCESS != res) {
return nullptr;
}
}
// set up layout transfer from initial to color attachment
VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex];
VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
0 : VK_ACCESS_MEMORY_READ_BIT;
VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkImageMemoryBarrier imageMemoryBarrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
NULL, // pNext
srcAccessMask, // outputMask
dstAccessMask, // inputMask
layout, // oldLayout
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
fPresentQueueIndex, // srcQueueFamilyIndex
fBackendContext->fQueueFamilyIndex, // dstQueueFamilyIndex
fImages[backbuffer->fImageIndex], // image
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
};
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
VkCommandBufferBeginInfo info;
memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = 0;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
GR_VK_CALL(fBackendContext->fInterface,
CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
srcStageMask, dstStageMask, 0,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier));
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
// insert the layout transfer into the queue and wait on the acquire
VkSubmitInfo submitInfo;
memset(&submitInfo, 0, sizeof(VkSubmitInfo));
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore;
submitInfo.pWaitDstStageMask = 0;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
submitInfo.signalSemaphoreCount = 0;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
backbuffer->fUsageFences[0]));
return fSurfaces[backbuffer->fImageIndex].get();
}
void VulkanTestContext::swapBuffers() {
BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
VkImageLayout layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
VkAccessFlags srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
VkImageMemoryBarrier imageMemoryBarrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
NULL, // pNext
srcAccessMask, // outputMask
dstAccessMask, // inputMask
layout, // oldLayout
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
fBackendContext->fQueueFamilyIndex, // srcQueueFamilyIndex
fPresentQueueIndex, // dstQueueFamilyIndex
fImages[backbuffer->fImageIndex], // image
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
};
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
VkCommandBufferBeginInfo info;
memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = 0;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
GR_VK_CALL(fBackendContext->fInterface,
CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
srcStageMask, dstStageMask, 0,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier));
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// insert the layout transfer into the queue and wait on the acquire
VkSubmitInfo submitInfo;
memset(&submitInfo, 0, sizeof(VkSubmitInfo));
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pWaitDstStageMask = 0;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
backbuffer->fUsageFences[1]));
// Submit present operation to present queue
const VkPresentInfoKHR presentInfo =
{
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
NULL, // pNext
1, // waitSemaphoreCount
&backbuffer->fRenderSemaphore, // pWaitSemaphores
1, // swapchainCount
&fSwapchain, // pSwapchains
&backbuffer->fImageIndex, // pImageIndices
NULL // pResults
};
GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
QueuePresentKHR(fPresentQueue, &presentInfo));
}

View File

@ -0,0 +1,92 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VulkanTestContext_DEFINED
#define VulkanTestContext_DEFINED
#ifdef SK_VULKAN
#include "GrTypes.h"
#include "vk/GrVkBackendContext.h"
class SkSurface;
class GrContext;
class VulkanTestContext {
public:
~VulkanTestContext();
// each platform will have to implement these in its CPP file
VkSurfaceKHR createVkSurface(void* platformData);
bool canPresent(uint32_t queueFamilyIndex);
static VulkanTestContext* Create(void* platformData, int msaaSampleCount) {
VulkanTestContext* ctx = new VulkanTestContext(platformData, msaaSampleCount);
if (!ctx->isValid()) {
delete ctx;
return nullptr;
}
return ctx;
}
SkSurface* getBackbufferSurface();
void swapBuffers();
bool makeCurrent() { return true; }
int getStencilBits() { return 0; }
int getSampleCount() { return 0; }
bool isValid() { return SkToBool(fBackendContext.get()); }
void resize() {
this->createSwapchain(0, 0);
}
GrBackendContext getBackendContext() { return (GrBackendContext)fBackendContext.get(); }
private:
VulkanTestContext();
VulkanTestContext(void*, int msaaSampleCount);
void initializeContext(void*);
void destroyContext();
struct BackbufferInfo {
uint32_t fImageIndex; // image this is associated with
VkSemaphore fAcquireSemaphore; // we signal on this for acquisition of image
VkSemaphore fRenderSemaphore; // we wait on this for rendering to be done
VkCommandBuffer fTransitionCmdBuffers[2]; // to transition layout between present and render
VkFence fUsageFences[2]; // used to ensure this data is no longer used on GPU
};
BackbufferInfo* getAvailableBackbuffer();
bool createSwapchain(uint32_t width, uint32_t height);
void createBuffers();
void destroyBuffers();
SkAutoTUnref<const GrVkBackendContext> fBackendContext;
GrContext* fContext;
VkSurfaceKHR fSurface;
VkSwapchainKHR fSwapchain;
uint32_t fPresentQueueIndex;
VkQueue fPresentQueue;
int fWidth;
int fHeight;
GrPixelConfig fPixelConfig;
uint32_t fImageCount;
VkImage* fImages; // images in the swapchain
VkImageLayout* fImageLayouts; // layouts of these images when not color attachment
sk_sp<SkSurface>* fSurfaces; // wrapped surface for those images
VkCommandPool fCommandPool;
BackbufferInfo* fBackbuffers;
uint32_t fCurrentBackbufferIndex;
};
#endif // SK_VULKAN
#endif

52
tools/vulkan/Window.cpp Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Window.h"
#include "SkSurface.h"
#include "SkCanvas.h"
#include "VulkanTestContext.h"
static bool default_key_func(int key, bool down, void* userData) {
return false;
}
static bool default_mouse_func(int x, int y, bool down, void* userData) {
return false;
}
static void default_paint_func(SkCanvas*, void* userData) {}
Window::Window() : fKeyFunc(default_key_func)
, fMouseFunc(default_mouse_func)
, fPaintFunc(default_paint_func) {
}
void Window::detach() {
delete fTestContext;
fTestContext = nullptr;
}
void Window::onPaint() {
SkSurface* backbuffer = fTestContext->getBackbufferSurface();
if (backbuffer) {
// draw into the canvas of this surface
SkCanvas* canvas = backbuffer->getCanvas();
fPaintFunc(canvas, fPaintUserData);
canvas->flush();
fTestContext->swapBuffers();
}
}
void Window::onSize() {
fTestContext->resize();
}

73
tools/vulkan/Window.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef Window_DEFINED
#define Window_DEFINED
class SkCanvas;
class VulkanTestContext;
class Window {
public:
static Window* CreateNativeWindow(void* platformData);
virtual ~Window() {};
virtual void setTitle(const char*) = 0;
virtual void show() = 0;
struct AttachmentInfo {
int fSampleCount;
int fStencilBits;
};
enum BackEndTypes {
kNativeGL_BackendType,
kVulkan_BackendType
};
virtual bool attach(BackEndTypes attachType, int msaaSampleCount, AttachmentInfo*) = 0;
void detach();
// input handling
typedef bool(*OnKeyFunc)(int key, bool down, void* userData);
typedef bool(*OnMouseFunc)(int x, int y, bool down, void* userData);
typedef void(*OnPaintFunc)(SkCanvas*, void* userData);
void registerKeyFunc(OnKeyFunc func, void* userData) {
fKeyFunc = func;
fKeyUserData = userData;
}
void registerMouseFunc(OnMouseFunc func, void* userData) {
fMouseFunc = func;
fMouseUserData = userData;
}
void registerPaintFunc(OnPaintFunc func, void* userData) {
fPaintFunc = func;
fPaintUserData = userData;
}
void onPaint();
void onSize();
protected:
Window();
OnKeyFunc fKeyFunc;
void* fKeyUserData;
OnMouseFunc fMouseFunc;
void* fMouseUserData;
OnPaintFunc fPaintFunc;
void* fPaintUserData;
VulkanTestContext* fTestContext;
};
#endif

View File

@ -0,0 +1,48 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "InputHandler.h"
#include <ctype.h>
InputHandler::InputHandler() : fMouseDown(false), fMousePressed(false), fMouseReleased(false)
, fMouseX(0), fMouseY(0) {
// clear key states
memset(fKeys, 0, sizeof(bool) * 256);
memset(fKeyPressed, 0, sizeof(bool) * 256);
memset(fKeyReleased, 0, sizeof(bool) * 256);
}
void InputHandler::onKeyDown(unsigned char key) {
if (!fKeys[key]) {
fKeys[key] = true;
fKeyPressed[key] = true;
}
}
void InputHandler::onKeyUp(unsigned char key) {
if (fKeys[key]) {
fKeys[key] = false;
fKeyReleased[key] = true;
}
}
void InputHandler::onMouseDown(unsigned int h, unsigned int v) {
if (!fMouseDown) {
fMouseDown = true;
fMousePressed = true;
}
fMouseX = h;
fMouseY = v;
}
void InputHandler::onMouseUp() {
if (fMouseDown) {
fMouseDown = false;
fMouseReleased = true;
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef InputHandler_DEFINED
#define InputHandler_DEFINED
#include <string.h>
class InputHandler
{
public:
InputHandler();
void onKeyDown(unsigned char key); // Handle key down event
void onKeyUp(unsigned char key); // Handle key up event
void onMouseDown(unsigned int h, unsigned int v); // Handle mouse down event
void onMouseUp(); // Handle mouse up event
bool isKeyDown(unsigned char key) const {
return fKeys[key];
}
bool isKeyUp(unsigned char key) const {
return !fKeys[key];
}
bool isKeyPressed(unsigned char key) const {
return fKeyPressed[key];
}
bool isKeyReleased(unsigned char key) const {
return fKeyReleased[key];
}
bool isMouseDown(unsigned int* h, unsigned int* v) const {
if (fMouseDown)
{
*h = fMouseX;
*v = fMouseY;
return true;
}
return false;
}
bool isMousePressed(unsigned int* h, unsigned int* v) const {
if (fMousePressed)
{
*h = fMouseX;
*v = fMouseY;
return true;
}
return false;
}
bool IsMouseReleased() const {
return fMouseReleased;
}
inline void Update() {
memset(fKeyPressed, 0, sizeof(bool) * 256);
memset(fKeyReleased, 0, sizeof(bool) * 256);
fMousePressed = false;
fMouseReleased = false;
}
private:
// assumes ASCII keystrokes only
bool fKeys[256];
bool fKeyPressed[256];
bool fKeyReleased[256];
bool fMouseDown;
bool fMousePressed;
bool fMouseReleased;
unsigned int fMouseX;
unsigned int fMouseY;
InputHandler(const InputHandler& other);
InputHandler& operator=(const InputHandler& other);
};
#endif

View File

@ -0,0 +1,94 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "VulkanViewer.h"
#include "SkCanvas.h"
#include "SkRandom.h"
#include "SkCommonFlags.h"
DEFINE_string(key, "",
"Space-separated key/value pairs to add to JSON identifying this builder.");
Application* Application::Create(int argc, char** argv, void* platformData) {
return new VulkanViewer(argc, argv, platformData);
}
static bool on_key_handler(int key, bool keyDown, void* userData) {
VulkanViewer* vv = reinterpret_cast<VulkanViewer*>(userData);
return vv->onKey(key, keyDown);
}
static bool on_mouse_handler(int x, int y, bool mouseDown, void* userData) {
VulkanViewer* vv = reinterpret_cast<VulkanViewer*>(userData);
return vv->onMouse(x, y, mouseDown);
}
static void on_paint_handler(SkCanvas* canvas, void* userData) {
VulkanViewer* vv = reinterpret_cast<VulkanViewer*>(userData);
return vv->onPaint(canvas);
}
VulkanViewer::VulkanViewer(int argc, char** argv, void* platformData) :
fGMs(skiagm::GMRegistry::Head()){
fWindow = Window::CreateNativeWindow(platformData);
fWindow->attach(Window::kVulkan_BackendType, 0, nullptr);
// register callbacks
fWindow->registerKeyFunc(on_key_handler, this);
fWindow->registerMouseFunc(on_mouse_handler, this);
fWindow->registerPaintFunc(on_paint_handler, this);
fWindow->setTitle("VulkanViewer");
fWindow->show();
}
VulkanViewer::~VulkanViewer() {
fWindow->detach();
delete fWindow;
}
bool VulkanViewer::onKey(int key, bool keyDown) {
if (keyDown) {
fInputHandler.onKeyDown(key);
} else {
fInputHandler.onKeyUp(key);
}
return true;
}
bool VulkanViewer::onMouse(int x, int y, bool mouseDown) {
if (mouseDown) {
fInputHandler.onMouseDown(x, y);
} else {
fInputHandler.onMouseUp();
}
return true;
}
void VulkanViewer::onPaint(SkCanvas* canvas) {
SkAutoTDelete<skiagm::GM> gm(fGMs->factory()(nullptr));
canvas->save();
gm->draw(canvas);
canvas->restore();
}
void VulkanViewer::onIdle(float dt) {
if (fInputHandler.isKeyPressed('l') || fInputHandler.isKeyPressed('L')) {
fGMs = fGMs->next();
}
fWindow->onPaint();
fInputHandler.Update();
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VulkanViewer_DEFINED
#define VulkanViewer_DEFINED
#include "../Application.h"
#include "InputHandler.h"
#include "../Window.h"
#include "gm.h"
class SkCanvas;
class VulkanViewer : public Application {
public:
VulkanViewer(int argc, char** argv, void* platformData);
~VulkanViewer() override;
bool onKey(int key, bool keyDown);
bool onMouse(int x, int y, bool mouseDown);
void onPaint(SkCanvas* canvas);
void onIdle(float dt) override;
private:
Window* fWindow;
InputHandler fInputHandler;
const skiagm::GMRegistry* fGMs;
};
#endif

View File

@ -0,0 +1,47 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "VulkanTestContext_win.h"
#include "vk/GrVkInterface.h"
#include "../../src/gpu/vk/GrVkUtil.h"
// Platform dependant call
VkSurfaceKHR VulkanTestContext::createVkSurface(void* platformData) {
// need better error handling here
SkASSERT(platformData);
ContextPlatformData_win* winPlatformData =
reinterpret_cast<ContextPlatformData_win*>(platformData);
VkSurfaceKHR surface;
VkWin32SurfaceCreateInfoKHR surfaceCreateInfo;
memset(&surfaceCreateInfo, 0, sizeof(VkWin32SurfaceCreateInfoKHR));
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.pNext = nullptr;
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.hinstance = winPlatformData->fHInstance;
surfaceCreateInfo.hwnd = winPlatformData->fHWnd;
VkResult res = GR_VK_CALL(fBackendContext->fInterface,
CreateWin32SurfaceKHR(fBackendContext->fInstance, &surfaceCreateInfo,
nullptr, &surface));
if (VK_SUCCESS != res) {
return VK_NULL_HANDLE;
}
return surface;
}
// Platform dependant call
bool VulkanTestContext::canPresent(uint32_t queueFamilyIndex) {
VkBool32 check = GR_VK_CALL(fBackendContext->fInterface,
GetPhysicalDeviceWin32PresentationSupportKHR(
fBackendContext->fPhysicalDevice,
queueFamilyIndex));
return (VK_FALSE != check);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef VULKANTESTCONTEXT_WIN_DEFINED
#define VULKANTESTCONTEXT_WIN_DEFINED
#ifdef SK_VULKAN
#include <windows.h>
#include "../VulkanTestContext.h"
// for Windows
struct ContextPlatformData_win {
HINSTANCE fHInstance;
HWND fHWnd;
};
#endif // SK_VULKAN
#endif

View File

@ -0,0 +1,206 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Window_win.h"
#include <tchar.h>
#include <windows.h>
#include <windowsx.h>
#include "VulkanTestContext_win.h"
Window* Window::CreateNativeWindow(void* platformData) {
HINSTANCE hInstance = (HINSTANCE)platformData;
Window_win* window = new Window_win();
if (!window->init(hInstance)) {
delete window;
return nullptr;
}
return window;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
bool Window_win::init(HINSTANCE hInstance) {
fHInstance = hInstance ? hInstance : GetModuleHandle(nullptr);
WNDCLASSEX wcex;
// The main window class name
static const TCHAR gSZWindowClass[] = _T("SkiaApp");
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = fHInstance;
wcex.hIcon = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr;
wcex.lpszClassName = gSZWindowClass;
wcex.hIconSm = LoadIcon(fHInstance, (LPCTSTR)IDI_WINLOGO);;
if (!RegisterClassEx(&wcex)) {
return false;
}
/*
if (fullscreen)
{
DEVMODE dmScreenSettings;
// If full screen set the screen to maximum size of the users desktop and 32bit.
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)width;
dmScreenSettings.dmPelsHeight = (unsigned long)height;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Change the display settings to full screen.
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
// Set the position of the window to the top left corner.
posX = posY = 0;
}
*/
// gIsFullscreen = fullscreen;
fHWnd = CreateWindow(gSZWindowClass, nullptr, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, fHInstance, nullptr);
if (!fHWnd)
{
return false;
}
SetWindowLongPtr(fHWnd, GWLP_USERDATA, (LONG_PTR)this);
return true;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
Window_win* window = (Window_win*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
window->onPaint();
EndPaint(hWnd, &ps);
break;
case WM_CLOSE:
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_ACTIVATE:
// disable/enable rendering here, depending on wParam != WA_INACTIVE
break;
case WM_SIZE:
window->onSize();
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
DWORD dwMask = (1 << 29);
bool bAltDown = ((lParam & dwMask) != 0);
UINT theChar = MapVirtualKey((UINT)wParam, 2);
// Handle Extended ASCII only
if (theChar < 256) {
return window->onKeyboard(theChar, true, bAltDown);
}
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
{
DWORD dwMask = (1 << 29);
bool bAltDown = ((lParam & dwMask) != 0);
UINT theChar = MapVirtualKey((UINT)wParam, 2);
// Handle Extended ASCII only
if (theChar < 256) {
return window->onKeyboard(theChar, false, bAltDown);
}
}
break;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
{
bool bLeftDown = ((wParam & MK_LBUTTON) != 0);
bool bRightDown = ((wParam & MK_RBUTTON) != 0);
bool bMiddleDown = ((wParam & MK_MBUTTON) != 0);
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
//if (!gIsFullscreen)
//{
// RECT rc = { 0, 0, 640, 480 };
// AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
// xPos -= rc.left;
// yPos -= rc.top;
//}
return window->onMouse(bLeftDown, bRightDown, bMiddleDown, false, false, 0, xPos, yPos);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
bool Window_win::onKeyboard(UINT nChar, bool bKeyDown, bool bAltDown) {
return fKeyFunc(nChar, bKeyDown, fKeyUserData);
}
bool Window_win::onMouse(bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown,
bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta,
int xPos, int yPos) {
return fMouseFunc(xPos, yPos, bLeftButtonDown, fMouseUserData);
}
void Window_win::setTitle(const char* title) {
SetWindowTextA(fHWnd, title);
}
void Window_win::show() {
ShowWindow(fHWnd, SW_SHOW);
}
bool Window_win::attach(BackEndTypes attachType, int msaaSampleCount, AttachmentInfo*) {
if (kVulkan_BackendType != attachType) {
return false;
}
ContextPlatformData_win platformData;
platformData.fHInstance = fHInstance;
platformData.fHWnd = fHWnd;
fTestContext = VulkanTestContext::Create((void*)&platformData, msaaSampleCount);
return (SkToBool(fTestContext));
}

View File

@ -0,0 +1,37 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef Window_win_DEFINED
#define Window_win_DEFINED
#include <windows.h>
#include "../Window.h"
class Window_win : public Window {
public:
Window_win() : Window() {}
~Window_win() override {}
bool init(HINSTANCE instance);
void setTitle(const char*) override;
void show() override;
// event callbacks
bool onKeyboard(UINT nChar, bool bKeyDown, bool bAltDown);
bool onMouse(bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown,
bool bSideButton1Down, bool bSideButton2Down, int nMouseWheelDelta,
int xPos, int yPos);
bool attach(BackEndTypes attachType, int msaaSampleCount, AttachmentInfo*) override;
private:
HINSTANCE fHInstance;
HWND fHWnd;
};
#endif

View File

@ -0,0 +1,76 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <windows.h>
#include <tchar.h>
#include "SkTypes.h"
#include "Window_win.h"
#include "../Application.h"
static char* tchar_to_utf8(const TCHAR* str) {
#ifdef _UNICODE
int size = WideCharToMultiByte(CP_UTF8, 0, str, wcslen(str), NULL, 0, NULL, NULL);
char* str8 = (char*)sk_malloc_throw(size + 1);
WideCharToMultiByte(CP_UTF8, 0, str, wcslen(str), str8, size, NULL, NULL);
str8[size] = '\0';
return str8;
#else
return _strdup(str);
#endif
}
// This file can work with GUI or CONSOLE subsystem types since we define _tWinMain and main().
static int main_common(HINSTANCE hInstance, int show, int argc, char**argv);
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,
int nCmdShow) {
// convert from lpCmdLine to argc, argv.
char* argv[4096];
int argc = 0;
TCHAR exename[1024], *next;
int exenameLen = GetModuleFileName(NULL, exename, SK_ARRAY_COUNT(exename));
// we're ignoring the possibility that the exe name exceeds the exename buffer
(void)exenameLen;
argv[argc++] = tchar_to_utf8(exename);
TCHAR* arg = _tcstok_s(lpCmdLine, _T(" "), &next);
while (arg != NULL) {
argv[argc++] = tchar_to_utf8(arg);
arg = _tcstok_s(NULL, _T(" "), &next);
}
int result = main_common(hInstance, nCmdShow, argc, argv);
for (int i = 0; i < argc; ++i) {
sk_free(argv[i]);
}
return result;
}
int main(int argc, char**argv) {
return main_common(GetModuleHandle(NULL), SW_SHOW, argc, argv);
}
static int main_common(HINSTANCE hInstance, int show, int argc, char**argv) {
Application* app = Application::Create(argc, argv, (void*)hInstance);
MSG msg = { 0 };
// Main message loop
while (WM_QUIT != msg.message) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
app->onIdle(0.0f);
}
delete app;
return (int)msg.wParam;
}