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:
parent
52b88cc617
commit
9f37246d68
@ -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
46
gyp/vulkanviewer.gyp
Normal 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',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
20
tools/vulkan/Application.h
Normal file
20
tools/vulkan/Application.h
Normal 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
|
605
tools/vulkan/VulkanTestContext.cpp
Normal file
605
tools/vulkan/VulkanTestContext.cpp
Normal 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));
|
||||
|
||||
}
|
92
tools/vulkan/VulkanTestContext.h
Normal file
92
tools/vulkan/VulkanTestContext.h
Normal 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
52
tools/vulkan/Window.cpp
Normal 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
73
tools/vulkan/Window.h
Normal 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
|
48
tools/vulkan/viewer/InputHandler.cpp
Normal file
48
tools/vulkan/viewer/InputHandler.cpp
Normal 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;
|
||||
}
|
||||
}
|
84
tools/vulkan/viewer/InputHandler.h
Normal file
84
tools/vulkan/viewer/InputHandler.h
Normal 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
|
94
tools/vulkan/viewer/VulkanViewer.cpp
Normal file
94
tools/vulkan/viewer/VulkanViewer.cpp
Normal 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();
|
||||
}
|
37
tools/vulkan/viewer/VulkanViewer.h
Normal file
37
tools/vulkan/viewer/VulkanViewer.h
Normal 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
|
47
tools/vulkan/win/VulkanTestContext_win.cpp
Normal file
47
tools/vulkan/win/VulkanTestContext_win.cpp
Normal 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);
|
||||
}
|
24
tools/vulkan/win/VulkanTestContext_win.h
Normal file
24
tools/vulkan/win/VulkanTestContext_win.h
Normal 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
|
206
tools/vulkan/win/Window_win.cpp
Normal file
206
tools/vulkan/win/Window_win.cpp
Normal 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));
|
||||
}
|
37
tools/vulkan/win/Window_win.h
Normal file
37
tools/vulkan/win/Window_win.h
Normal 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
|
76
tools/vulkan/win/main_win.cpp
Normal file
76
tools/vulkan/win/main_win.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user