Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ if (CMAKE_SYSTEM_NAME MATCHES "Windows|Linux|BSD")
option(BUILD_APIDUMP "Build api_dump layer" ON)
option(BUILD_MONITOR "Build monitor layer" ON)
option(BUILD_SCREENSHOT "Build screenshot layer" ON)
if(NOT WIN32)
option(BUILD_CPUTIMING "Build CPUTiming layer" ON)
endif()
option(BUILD_LAYERMGR "Build Vulkan Configurator" ON)
set(SDK_VERSION "" CACHE STRING "Vulkan SDK version")

Expand All @@ -102,6 +105,7 @@ elseif(ANDROID)
# - libVkLayer_screenshot.so
option(BUILD_APIDUMP "Build api_dump layer" ON)
option(BUILD_SCREENSHOT "Build screenshot layer" ON)
option(BUILD_CPUTIMING "Build CPUTiming layer" ON)
set(BUILD_MONITOR OFF)
set(BUILD_LAYERMGR OFF)

Expand All @@ -121,7 +125,7 @@ if(BUILD_TESTS)
add_subdirectory(tests)
endif()

if(BUILD_APIDUMP OR BUILD_MONITOR OR BUILD_SCREENSHOT)
if(BUILD_APIDUMP OR BUILD_MONITOR OR BUILD_SCREENSHOT OR BUILD_CPUTIMING)
message(STATUS "INFO: Building Vulkan Layers")
add_subdirectory(layersvt)
endif()
Expand Down
41 changes: 39 additions & 2 deletions layersvt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ if(WIN32)
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN)
elseif(ANDROID)
add_compile_definitions(VK_USE_PLATFORM_ANDROID_KHR)

elseif(APPLE)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
add_compile_definitions(VK_USE_PLATFORM_MACOS_MVK)
Expand All @@ -18,6 +19,7 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|DragonFly|GNU")
option(BUILD_WSI_XCB_SUPPORT "Build XCB WSI support" ON)
option(BUILD_WSI_WAYLAND_SUPPORT "Build WAYLAND WSI support" ON)


find_package(PkgConfig REQUIRED)

if (BUILD_WSI_XCB_SUPPORT)
Expand Down Expand Up @@ -116,11 +118,46 @@ if(BUILD_SCREENSHOT)
)
endif()

if(BUILD_CPUTIMING)
add_library(VkLayer_CPUTiming MODULE)
set_target_properties(VkLayer_CPUTiming PROPERTIES FOLDER "layers/cputiming")
target_sources(VkLayer_CPUTiming PRIVATE
cputiming_handwritten_dispatch.cpp
generated/cputiming_dispatch.h
generated/cputiming_implementation.h
cputiming_handwritten_functions.h
cputiming.h
cputiming.cpp
perfetto/perfetto.cc
perfetto/perfetto_helpers.cpp
../scripts/generators/cputiming_generator.py
vk_layer_table.cpp
vk_layer_table.h
json/VkLayer_CPUTiming.json.in
)

if(CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|DragonFly|GNU")
if (BUILD_WSI_XCB_SUPPORT)
target_compile_definitions(VkLayer_CPUTiming PRIVATE VK_USE_PLATFORM_XLIB_KHR)
endif()

if (BUILD_WSI_WAYLAND_SUPPORT)
target_compile_definitions(VkLayer_CPUTiming PRIVATE VK_USE_PLATFORM_WAYLAND_KHR)
endif()
endif()

target_compile_definitions(VkLayer_CPUTiming PRIVATE VK_ENABLE_BETA_EXTENSIONS)

if (VT_CODEGEN)
add_dependencies(VkLayer_CPUTiming vt_codegen_as_needed)
endif()
endif()

if (BUILD_TESTS AND NOT RUN_ON_GITHUB)
add_subdirectory(test)
endif()

list(APPEND TOOL_LAYERS "VkLayer_api_dump" "VkLayer_screenshot" "VkLayer_monitor")
list(APPEND TOOL_LAYERS "VkLayer_api_dump" "VkLayer_screenshot" "VkLayer_monitor" "VkLayer_CPUTiming")
foreach(layer ${TOOL_LAYERS})
if (NOT TARGET "${layer}")
continue()
Expand All @@ -129,7 +166,7 @@ foreach(layer ${TOOL_LAYERS})
target_link_Libraries(${layer} PRIVATE Vulkan::Headers Vulkan::UtilityHeaders Vulkan::LayerSettings)

if (ANDROID)
target_link_Libraries(${layer} PRIVATE log android)
target_link_Libraries(${layer} PRIVATE log android atomic)
endif()

target_include_directories(${layer} PRIVATE .)
Expand Down
35 changes: 35 additions & 0 deletions layersvt/cputiming.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cputiming.h"

CpuTiming& CpuTiming::Get() {
static CpuTiming instance;
return instance;
}

void CpuTiming::SetVkInstance(VkPhysicalDevice phys_dev, VkInstance instance) {
std::lock_guard<std::mutex> lock(map_mutex_);
vk_instance_map_[phys_dev] = instance;
}

VkInstance CpuTiming::GetVkInstance(VkPhysicalDevice phys_dev) {
std::lock_guard<std::mutex> lock(map_mutex_);
auto it = vk_instance_map_.find(phys_dev);
if (it != vk_instance_map_.end()) return it->second;
return VK_NULL_HANDLE;
}
34 changes: 34 additions & 0 deletions layersvt/cputiming.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <vulkan/vulkan.h>
#include <mutex>
#include <unordered_map>

class CpuTiming {
public:
static CpuTiming& Get();

void SetVkInstance(VkPhysicalDevice phys_dev, VkInstance instance);
VkInstance GetVkInstance(VkPhysicalDevice phys_dev);

private:
std::mutex map_mutex_;
std::unordered_map<VkPhysicalDevice, VkInstance> vk_instance_map_;
};
51 changes: 51 additions & 0 deletions layersvt/cputiming_handwritten_dispatch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (C) 2015-2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

// Implementation file for specifically implemented functions

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

#include "generated/cputiming_dispatch.h"
#include "vk_layer_table.h"

extern "C" {

EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* pName) {
Timer timer(CPUTimingCategory::VkInstance, "vkGetInstanceProcAddr");
PFN_vkVoidFunction instance_func = cputiming_known_instance_functions(instance, pName);
if (instance_func) return instance_func;
PFN_vkVoidFunction device_func = cputiming_known_device_functions(NULL, pName);
// Make sure that device functions queried through GIPA works
if (device_func) return device_func;

// Haven't created an instance yet, exit now since there is no instance_dispatch_table
if (instance_dispatch_table(instance)->GetInstanceProcAddr == NULL) return nullptr;
return instance_dispatch_table(instance)->GetInstanceProcAddr(instance, pName);
}

EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* pName) {
Timer timer(CPUTimingCategory::VkDevice, "vkGetDeviceProcAddr");
PFN_vkVoidFunction device_func = cputiming_known_device_functions(device, pName);
if (device_func) return device_func;

// Haven't created a device yet, exit now since there is no device_dispatch_table
if (device_dispatch_table(device)->GetDeviceProcAddr == NULL) return nullptr;
return device_dispatch_table(device)->GetDeviceProcAddr(device, pName);
}
}
132 changes: 132 additions & 0 deletions layersvt/cputiming_handwritten_functions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* Copyright (c) 2015-2023 The Khronos Group Inc.
* Copyright (c) 2015-2023 Valve Corporation
* Copyright (c) 2015-2023 LunarG, Inc.
* Copyright (C) 2015-2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

// Implementation file for specifically implemented functions

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))

#include "generated/cputiming_implementation.h"
#include "timer.h"
#include "cputiming.h"
#include "perfetto/perfetto_helpers.h"
#include "vk_layer_table.h"

#if defined(__GNUC__) && __GNUC__ >= 4
#define EXPORT_FUNCTION __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define EXPORT_FUNCTION __attribute__((visibility("default")))
#else
#define EXPORT_FUNCTION
#endif

#include <mutex>

static std::once_flag g_perfetto_init_flag;

extern "C" {

VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance) {
std::call_once(g_perfetto_init_flag, []() { InitializePerfetto(); });
Timer timer(CPUTimingCategory::Other, "vkCreateInstance");



// Get the function pointer
VkLayerInstanceCreateInfo* chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
assert(chain_info->u.pLayerInfo != 0);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
assert(fpGetInstanceProcAddr != 0);
PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance");
if (fpCreateInstance == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}

// Call the function and create the dispatch table
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance);
if (result == VK_SUCCESS) {
initInstanceTable(*pInstance, fpGetInstanceProcAddr);
}

return result;
}
}

VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) {
Timer timer(CPUTimingCategory::VkPhysicalDevice, "vkCreateDevice");

// Get the function pointer
VkLayerDeviceCreateInfo* chain_info = get_chain_info(pCreateInfo, VK_LAYER_LINK_INFO);
assert(chain_info->u.pLayerInfo != 0);
PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr;
VkInstance vk_instance = CpuTiming::Get().GetVkInstance(physicalDevice);
PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(vk_instance, "vkCreateDevice");
if (fpCreateDevice == NULL) {
return VK_ERROR_INITIALIZATION_FAILED;
}

// Call the function and create the dispatch table
chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext;
VkResult result = fpCreateDevice(physicalDevice, pCreateInfo, pAllocator, pDevice);
if (result == VK_SUCCESS) {
initDeviceTable(*pDevice, fpGetDeviceProcAddr);
}

return result;
}

extern "C" {

EXPORT_FUNCTION VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceExtensionProperties(const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
Timer timer(CPUTimingCategory::Other, "vkEnumerateInstanceExtensionProperties");
return util_GetExtensionProperties(0, NULL, pPropertyCount, pProperties);
}

EXPORT_FUNCTION VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateInstanceLayerProperties(uint32_t* pPropertyCount,
VkLayerProperties* pProperties) {
Timer timer(CPUTimingCategory::Other, "vkEnumerateInstanceLayerProperties");
static const VkLayerProperties layerProperties[] = {{
"CPUTiming",
VK_MAKE_VERSION(1, 4, VK_HEADER_VERSION), // specVersion
VK_MAKE_VERSION(0, 2, 0), // implementationVersion
"layer: CPUTiming",
}};

return util_GetLayerProperties(ARRAY_SIZE(layerProperties), layerProperties, pPropertyCount, pProperties);
}

EXPORT_FUNCTION VKAPI_ATTR VkResult VKAPI_CALL vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice,
uint32_t* pPropertyCount,
VkLayerProperties* pProperties) {
Timer timer(CPUTimingCategory::VkPhysicalDevice, "vkEnumerateDeviceLayerProperties");
static const VkLayerProperties layerProperties[] = {{
"CPUTiming",
VK_MAKE_VERSION(1, 4, VK_HEADER_VERSION),
VK_MAKE_VERSION(0, 2, 0),
"layer: CPUTiming",
}};

return util_GetLayerProperties(ARRAY_SIZE(layerProperties), layerProperties, pPropertyCount, pProperties);
}
}
Loading
Loading