mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
Initial commit
This commit is contained in:
commit
00e63d71a9
16
build-win64.txt
Normal file
16
build-win64.txt
Normal file
@ -0,0 +1,16 @@
|
||||
[binaries]
|
||||
c = '/usr/bin/x86_64-w64-mingw32-gcc'
|
||||
cpp = '/usr/bin/x86_64-w64-mingw32-g++'
|
||||
ar = '/usr/bin/x86_64-w64-mingw32-ar'
|
||||
strip = '/usr/bin/x86_64-w64-mingw32-strip'
|
||||
exe_wrapper = 'wine'
|
||||
|
||||
[properties]
|
||||
cpp_args = ['-std=c++17']
|
||||
cpp_link_args = ['-static', '-static-libgcc', '-static-libstdc++']
|
||||
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
152
include/vulkan/vk_icd.h
Normal file
152
include/vulkan/vk_icd.h
Normal file
@ -0,0 +1,152 @@
|
||||
//
|
||||
// File: vk_icd.h
|
||||
//
|
||||
/*
|
||||
* Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
* Copyright (c) 2015-2016 Valve Corporation
|
||||
* Copyright (c) 2015-2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VKICD_H
|
||||
#define VKICD_H
|
||||
|
||||
#include "vulkan.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
// Loader-ICD version negotiation API. Versions add the following features:
|
||||
// Version 0 - Initial. Doesn't support vk_icdGetInstanceProcAddr
|
||||
// or vk_icdNegotiateLoaderICDInterfaceVersion.
|
||||
// Version 1 - Add support for vk_icdGetInstanceProcAddr.
|
||||
// Version 2 - Add Loader/ICD Interface version negotiation
|
||||
// via vk_icdNegotiateLoaderICDInterfaceVersion.
|
||||
// Version 3 - Add ICD creation/destruction of KHR_surface objects.
|
||||
// Version 4 - Add unknown physical device extension qyering via
|
||||
// vk_icdGetPhysicalDeviceProcAddr.
|
||||
// Version 5 - Tells ICDs that the loader is now paying attention to the
|
||||
// application version of Vulkan passed into the ApplicationInfo
|
||||
// structure during vkCreateInstance. This will tell the ICD
|
||||
// that if the loader is older, it should automatically fail a
|
||||
// call for any API version > 1.0. Otherwise, the loader will
|
||||
// manually determine if it can support the expected version.
|
||||
#define CURRENT_LOADER_ICD_INTERFACE_VERSION 5
|
||||
#define MIN_SUPPORTED_LOADER_ICD_INTERFACE_VERSION 0
|
||||
#define MIN_PHYS_DEV_EXTENSION_ICD_INTERFACE_VERSION 4
|
||||
typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderICDInterfaceVersion)(uint32_t *pVersion);
|
||||
|
||||
// This is defined in vk_layer.h which will be found by the loader, but if an ICD is building against this
|
||||
// flie directly, it won't be found.
|
||||
#ifndef PFN_GetPhysicalDeviceProcAddr
|
||||
typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_GetPhysicalDeviceProcAddr)(VkInstance instance, const char* pName);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The ICD must reserve space for a pointer for the loader's dispatch
|
||||
* table, at the start of <each object>.
|
||||
* The ICD must initialize this variable using the SET_LOADER_MAGIC_VALUE macro.
|
||||
*/
|
||||
|
||||
#define ICD_LOADER_MAGIC 0x01CDC0DE
|
||||
|
||||
typedef union {
|
||||
uintptr_t loaderMagic;
|
||||
void *loaderData;
|
||||
} VK_LOADER_DATA;
|
||||
|
||||
static inline void set_loader_magic_value(void *pNewObject) {
|
||||
VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;
|
||||
loader_info->loaderMagic = ICD_LOADER_MAGIC;
|
||||
}
|
||||
|
||||
static inline bool valid_loader_magic_value(void *pNewObject) {
|
||||
const VK_LOADER_DATA *loader_info = (VK_LOADER_DATA *)pNewObject;
|
||||
return (loader_info->loaderMagic & 0xffffffff) == ICD_LOADER_MAGIC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Windows and Linux ICDs will treat VkSurfaceKHR as a pointer to a struct that
|
||||
* contains the platform-specific connection and surface information.
|
||||
*/
|
||||
typedef enum {
|
||||
VK_ICD_WSI_PLATFORM_MIR,
|
||||
VK_ICD_WSI_PLATFORM_WAYLAND,
|
||||
VK_ICD_WSI_PLATFORM_WIN32,
|
||||
VK_ICD_WSI_PLATFORM_XCB,
|
||||
VK_ICD_WSI_PLATFORM_XLIB,
|
||||
VK_ICD_WSI_PLATFORM_DISPLAY
|
||||
} VkIcdWsiPlatform;
|
||||
|
||||
typedef struct {
|
||||
VkIcdWsiPlatform platform;
|
||||
} VkIcdSurfaceBase;
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
typedef struct {
|
||||
VkIcdSurfaceBase base;
|
||||
MirConnection *connection;
|
||||
MirSurface *mirSurface;
|
||||
} VkIcdSurfaceMir;
|
||||
#endif // VK_USE_PLATFORM_MIR_KHR
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
typedef struct {
|
||||
VkIcdSurfaceBase base;
|
||||
struct wl_display *display;
|
||||
struct wl_surface *surface;
|
||||
} VkIcdSurfaceWayland;
|
||||
#endif // VK_USE_PLATFORM_WAYLAND_KHR
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
typedef struct {
|
||||
VkIcdSurfaceBase base;
|
||||
HINSTANCE hinstance;
|
||||
HWND hwnd;
|
||||
} VkIcdSurfaceWin32;
|
||||
#endif // VK_USE_PLATFORM_WIN32_KHR
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
typedef struct {
|
||||
VkIcdSurfaceBase base;
|
||||
xcb_connection_t *connection;
|
||||
xcb_window_t window;
|
||||
} VkIcdSurfaceXcb;
|
||||
#endif // VK_USE_PLATFORM_XCB_KHR
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
typedef struct {
|
||||
VkIcdSurfaceBase base;
|
||||
Display *dpy;
|
||||
Window window;
|
||||
} VkIcdSurfaceXlib;
|
||||
#endif // VK_USE_PLATFORM_XLIB_KHR
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
typedef struct {
|
||||
ANativeWindow* window;
|
||||
} VkIcdSurfaceAndroid;
|
||||
#endif //VK_USE_PLATFORM_ANDROID_KHR
|
||||
|
||||
typedef struct {
|
||||
VkIcdSurfaceBase base;
|
||||
VkDisplayModeKHR displayMode;
|
||||
uint32_t planeIndex;
|
||||
uint32_t planeStackIndex;
|
||||
VkSurfaceTransformFlagBitsKHR transform;
|
||||
float globalAlpha;
|
||||
VkDisplayPlaneAlphaFlagBitsKHR alphaMode;
|
||||
VkExtent2D imageExtent;
|
||||
} VkIcdSurfaceDisplay;
|
||||
|
||||
#endif // VKICD_H
|
143
include/vulkan/vk_layer.h
Normal file
143
include/vulkan/vk_layer.h
Normal file
@ -0,0 +1,143 @@
|
||||
//
|
||||
// File: vk_layer.h
|
||||
//
|
||||
/*
|
||||
* Copyright (c) 2015-2017 The Khronos Group Inc.
|
||||
* Copyright (c) 2015-2017 Valve Corporation
|
||||
* Copyright (c) 2015-2017 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Need to define dispatch table
|
||||
* Core struct can then have ptr to dispatch table at the top
|
||||
* Along with object ptrs for current and next OBJ
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "vulkan.h"
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define VK_LAYER_EXPORT __attribute__((visibility("default")))
|
||||
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
|
||||
#define VK_LAYER_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define VK_LAYER_EXPORT
|
||||
#endif
|
||||
|
||||
// Definition for VkLayerDispatchTable and VkLayerInstanceDispatchTable now appear in externally generated header
|
||||
#include "vk_layer_dispatch_table.h"
|
||||
|
||||
#define MAX_NUM_UNKNOWN_EXTS 250
|
||||
|
||||
// Loader-Layer version negotiation API. Versions add the following features:
|
||||
// Versions 0/1 - Initial. Doesn't support vk_layerGetPhysicalDeviceProcAddr
|
||||
// or vk_icdNegotiateLoaderLayerInterfaceVersion.
|
||||
// Version 2 - Add support for vk_layerGetPhysicalDeviceProcAddr and
|
||||
// vk_icdNegotiateLoaderLayerInterfaceVersion.
|
||||
#define CURRENT_LOADER_LAYER_INTERFACE_VERSION 2
|
||||
#define MIN_SUPPORTED_LOADER_LAYER_INTERFACE_VERSION 1
|
||||
|
||||
// Version negotiation values
|
||||
typedef enum VkNegotiateLayerStructType {
|
||||
LAYER_NEGOTIATE_UNINTIALIZED = 0,
|
||||
LAYER_NEGOTIATE_INTERFACE_STRUCT = 1,
|
||||
} VkNegotiateLayerStructType;
|
||||
|
||||
// Version negotiation structures
|
||||
typedef struct VkNegotiateLayerInterface {
|
||||
VkNegotiateLayerStructType sType;
|
||||
void *pNext;
|
||||
uint32_t loaderLayerInterfaceVersion;
|
||||
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
|
||||
PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr;
|
||||
PFN_GetPhysicalDeviceProcAddr pfnGetPhysicalDeviceProcAddr;
|
||||
} VkNegotiateLayerInterface;
|
||||
|
||||
// Version negotiation functions
|
||||
typedef VkResult (VKAPI_PTR *PFN_vkNegotiateLoaderLayerInterfaceVersion)(VkNegotiateLayerInterface *pVersionStruct);
|
||||
|
||||
// Function prototype for unknown physical device extension command
|
||||
typedef VkResult(VKAPI_PTR *PFN_PhysDevExt)(VkPhysicalDevice phys_device);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// CreateInstance and CreateDevice support structures
|
||||
|
||||
/* Sub type of structure for instance and device loader ext of CreateInfo.
|
||||
* When sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
||||
* or sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
|
||||
* then VkLayerFunction indicates struct type pointed to by pNext
|
||||
*/
|
||||
typedef enum VkLayerFunction_ {
|
||||
VK_LAYER_LINK_INFO = 0,
|
||||
VK_LOADER_DATA_CALLBACK = 1
|
||||
} VkLayerFunction;
|
||||
|
||||
typedef struct VkLayerInstanceLink_ {
|
||||
struct VkLayerInstanceLink_ *pNext;
|
||||
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
|
||||
PFN_GetPhysicalDeviceProcAddr pfnNextGetPhysicalDeviceProcAddr;
|
||||
} VkLayerInstanceLink;
|
||||
|
||||
/*
|
||||
* When creating the device chain the loader needs to pass
|
||||
* down information about it's device structure needed at
|
||||
* the end of the chain. Passing the data via the
|
||||
* VkLayerDeviceInfo avoids issues with finding the
|
||||
* exact instance being used.
|
||||
*/
|
||||
typedef struct VkLayerDeviceInfo_ {
|
||||
void *device_info;
|
||||
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
|
||||
} VkLayerDeviceInfo;
|
||||
|
||||
typedef VkResult (VKAPI_PTR *PFN_vkSetInstanceLoaderData)(VkInstance instance,
|
||||
void *object);
|
||||
typedef VkResult (VKAPI_PTR *PFN_vkSetDeviceLoaderData)(VkDevice device,
|
||||
void *object);
|
||||
|
||||
typedef struct {
|
||||
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
|
||||
const void *pNext;
|
||||
VkLayerFunction function;
|
||||
union {
|
||||
VkLayerInstanceLink *pLayerInfo;
|
||||
PFN_vkSetInstanceLoaderData pfnSetInstanceLoaderData;
|
||||
} u;
|
||||
} VkLayerInstanceCreateInfo;
|
||||
|
||||
typedef struct VkLayerDeviceLink_ {
|
||||
struct VkLayerDeviceLink_ *pNext;
|
||||
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
|
||||
PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr;
|
||||
} VkLayerDeviceLink;
|
||||
|
||||
typedef struct {
|
||||
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
|
||||
const void *pNext;
|
||||
VkLayerFunction function;
|
||||
union {
|
||||
VkLayerDeviceLink *pLayerInfo;
|
||||
PFN_vkSetDeviceLoaderData pfnSetDeviceLoaderData;
|
||||
} u;
|
||||
} VkLayerDeviceCreateInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface *pVersionStruct);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
120
include/vulkan/vk_platform.h
Normal file
120
include/vulkan/vk_platform.h
Normal file
@ -0,0 +1,120 @@
|
||||
//
|
||||
// File: vk_platform.h
|
||||
//
|
||||
/*
|
||||
** Copyright (c) 2014-2017 The Khronos Group 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef VK_PLATFORM_H_
|
||||
#define VK_PLATFORM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
/*
|
||||
***************************************************************************************************
|
||||
* Platform-specific directives and type declarations
|
||||
***************************************************************************************************
|
||||
*/
|
||||
|
||||
/* Platform-specific calling convention macros.
|
||||
*
|
||||
* Platforms should define these so that Vulkan clients call Vulkan commands
|
||||
* with the same calling conventions that the Vulkan implementation expects.
|
||||
*
|
||||
* VKAPI_ATTR - Placed before the return type in function declarations.
|
||||
* Useful for C++11 and GCC/Clang-style function attribute syntax.
|
||||
* VKAPI_CALL - Placed after the return type in function declarations.
|
||||
* Useful for MSVC-style calling convention syntax.
|
||||
* VKAPI_PTR - Placed between the '(' and '*' in function pointer types.
|
||||
*
|
||||
* Function declaration: VKAPI_ATTR void VKAPI_CALL vkCommand(void);
|
||||
* Function pointer type: typedef void (VKAPI_PTR *PFN_vkCommand)(void);
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
// On Windows, Vulkan commands use the stdcall convention
|
||||
#define VKAPI_ATTR
|
||||
#define VKAPI_CALL __stdcall
|
||||
#define VKAPI_PTR VKAPI_CALL
|
||||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
|
||||
#error "Vulkan isn't supported for the 'armeabi' NDK ABI"
|
||||
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
|
||||
// On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
|
||||
// calling convention, i.e. float parameters are passed in registers. This
|
||||
// is true even if the rest of the application passes floats on the stack,
|
||||
// as it does by default when compiling for the armeabi-v7a NDK ABI.
|
||||
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
|
||||
#define VKAPI_CALL
|
||||
#define VKAPI_PTR VKAPI_ATTR
|
||||
#else
|
||||
// On other platforms, use the default calling convention
|
||||
#define VKAPI_ATTR
|
||||
#define VKAPI_CALL
|
||||
#define VKAPI_PTR
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if !defined(VK_NO_STDINT_H)
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1600)
|
||||
typedef signed __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#endif // !defined(VK_NO_STDINT_H)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
// Platform-specific headers required by platform window system extensions.
|
||||
// These are enabled prior to #including "vulkan.h". The same enable then
|
||||
// controls inclusion of the extension interfaces in vulkan.h.
|
||||
|
||||
#ifdef VK_USE_PLATFORM_ANDROID_KHR
|
||||
#include <android/native_window.h>
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_MIR_KHR
|
||||
#include <mir_toolkit/client_types.h>
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
#include <wayland-client.h>
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
#include <xcb/xcb.h>
|
||||
#endif
|
||||
|
||||
#endif
|
46
include/vulkan/vk_sdk_platform.h
Normal file
46
include/vulkan/vk_sdk_platform.h
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// File: vk_sdk_platform.h
|
||||
//
|
||||
/*
|
||||
* Copyright (c) 2015-2016 The Khronos Group Inc.
|
||||
* Copyright (c) 2015-2016 Valve Corporation
|
||||
* Copyright (c) 2015-2016 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.
|
||||
*/
|
||||
|
||||
#ifndef VK_SDK_PLATFORM_H
|
||||
#define VK_SDK_PLATFORM_H
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define NOMINMAX
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#define inline __inline
|
||||
#endif // __cplusplus
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/)
|
||||
// C99:
|
||||
// Microsoft didn't implement C99 in Visual Studio; but started adding it with
|
||||
// VS2013. However, VS2013 still didn't have snprintf(). The following is a
|
||||
// work-around (Note: The _CRT_SECURE_NO_WARNINGS macro must be set in the
|
||||
// "CMakeLists.txt" file).
|
||||
// NOTE: This is fixed in Visual Studio 2015.
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#define strdup _strdup
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // VK_SDK_PLATFORM_H
|
6429
include/vulkan/vulkan.h
Normal file
6429
include/vulkan/vulkan.h
Normal file
File diff suppressed because it is too large
Load Diff
32807
include/vulkan/vulkan.hpp
Normal file
32807
include/vulkan/vulkan.hpp
Normal file
File diff suppressed because it is too large
Load Diff
BIN
lib/SDL2.lib
Executable file
BIN
lib/SDL2.lib
Executable file
Binary file not shown.
BIN
lib/vulkan-1.lib
Executable file
BIN
lib/vulkan-1.lib
Executable file
Binary file not shown.
11
meson.build
Normal file
11
meson.build
Normal file
@ -0,0 +1,11 @@
|
||||
project('dxvk', ['cpp'])
|
||||
|
||||
dxvk_compiler = meson.get_compiler('cpp')
|
||||
dxvk_library_path = meson.source_root() + '/lib'
|
||||
dxvk_include_path = include_directories('./include')
|
||||
|
||||
lib_vulkan = dxvk_compiler.find_library('vulkan-1', dirs : dxvk_library_path)
|
||||
lib_sdl2 = dxvk_compiler.find_library('SDL2', dirs : dxvk_library_path)
|
||||
|
||||
subdir('src')
|
||||
subdir('tests')
|
177
src/dxvk/dxvk_adapter.cpp
Normal file
177
src/dxvk/dxvk_adapter.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "dxvk_adapter.h"
|
||||
#include "dxvk_device.h"
|
||||
#include "dxvk_instance.h"
|
||||
#include "dxvk_surface.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkAdapter::DxvkAdapter(
|
||||
const Rc<DxvkInstance>& instance,
|
||||
VkPhysicalDevice handle)
|
||||
: m_instance (instance),
|
||||
m_vki (instance->vki()),
|
||||
m_handle (handle) {
|
||||
uint32_t numQueueFamilies = 0;
|
||||
m_vki->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
m_handle, &numQueueFamilies, nullptr);
|
||||
|
||||
m_queueFamilies.resize(numQueueFamilies);
|
||||
m_vki->vkGetPhysicalDeviceQueueFamilyProperties(
|
||||
m_handle, &numQueueFamilies, m_queueFamilies.data());
|
||||
}
|
||||
|
||||
|
||||
DxvkAdapter::~DxvkAdapter() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
VkPhysicalDeviceProperties DxvkAdapter::deviceProperties() const {
|
||||
VkPhysicalDeviceProperties properties;
|
||||
m_vki->vkGetPhysicalDeviceProperties(m_handle, &properties);
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
||||
VkPhysicalDeviceMemoryProperties DxvkAdapter::memoryProperties() const {
|
||||
VkPhysicalDeviceMemoryProperties memoryProperties;
|
||||
m_vki->vkGetPhysicalDeviceMemoryProperties(m_handle, &memoryProperties);
|
||||
return memoryProperties;
|
||||
}
|
||||
|
||||
|
||||
VkPhysicalDeviceFeatures DxvkAdapter::features() const {
|
||||
VkPhysicalDeviceFeatures features;
|
||||
m_vki->vkGetPhysicalDeviceFeatures(m_handle, &features);
|
||||
return features;
|
||||
}
|
||||
|
||||
|
||||
VkFormatProperties DxvkAdapter::formatProperties(VkFormat format) const {
|
||||
VkFormatProperties formatProperties;
|
||||
m_vki->vkGetPhysicalDeviceFormatProperties(m_handle, format, &formatProperties);
|
||||
return formatProperties;
|
||||
}
|
||||
|
||||
|
||||
std::optional<VkImageFormatProperties> DxvkAdapter::imageFormatProperties(
|
||||
VkFormat format,
|
||||
VkImageType type,
|
||||
VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkImageCreateFlags flags) const {
|
||||
VkImageFormatProperties formatProperties;
|
||||
|
||||
VkResult status = m_vki->vkGetPhysicalDeviceImageFormatProperties(
|
||||
m_handle, format, type, tiling, usage, flags, &formatProperties);
|
||||
|
||||
switch (status) {
|
||||
case VK_SUCCESS: return formatProperties;
|
||||
case VK_ERROR_FORMAT_NOT_SUPPORTED: return { };
|
||||
|
||||
default:
|
||||
throw DxvkError("DxvkAdapter::imageFormatProperties: Failed to query format properties");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkAdapter::graphicsQueueFamily() const {
|
||||
for (uint32_t i = 0; i < m_queueFamilies.size(); i++) {
|
||||
if (m_queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
return i;
|
||||
}
|
||||
|
||||
throw DxvkError("DxvkAdapter::graphicsQueueFamily: No graphics queue found");
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkAdapter::presentQueueFamily() const {
|
||||
// TODO Implement properly
|
||||
return this->graphicsQueueFamily();
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkDevice> DxvkAdapter::createDevice() {
|
||||
auto enabledExtensions = this->enableExtensions();
|
||||
auto enabledFeatures = this->enableFeatures();
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
std::vector<VkDeviceQueueCreateInfo> queueInfos;
|
||||
|
||||
const uint32_t gIndex = this->graphicsQueueFamily();
|
||||
const uint32_t pIndex = this->presentQueueFamily();
|
||||
|
||||
VkDeviceQueueCreateInfo graphicsQueue;
|
||||
graphicsQueue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
graphicsQueue.pNext = nullptr;
|
||||
graphicsQueue.flags = 0;
|
||||
graphicsQueue.queueFamilyIndex = gIndex;
|
||||
graphicsQueue.queueCount = 1;
|
||||
graphicsQueue.pQueuePriorities = &queuePriority;
|
||||
queueInfos.push_back(graphicsQueue);
|
||||
|
||||
if (pIndex != gIndex) {
|
||||
VkDeviceQueueCreateInfo presentQueue = graphicsQueue;
|
||||
presentQueue.queueFamilyIndex = pIndex;
|
||||
queueInfos.push_back(presentQueue);
|
||||
}
|
||||
|
||||
VkDeviceCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.queueCreateInfoCount = queueInfos.size();
|
||||
info.pQueueCreateInfos = queueInfos.data();
|
||||
info.enabledLayerCount = 0;
|
||||
info.ppEnabledLayerNames = nullptr;
|
||||
info.enabledExtensionCount = enabledExtensions.count();
|
||||
info.ppEnabledExtensionNames = enabledExtensions.names();
|
||||
info.pEnabledFeatures = &enabledFeatures;
|
||||
|
||||
VkDevice device = VK_NULL_HANDLE;
|
||||
|
||||
if (m_vki->vkCreateDevice(m_handle, &info, nullptr, &device) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkDevice::createDevice: Failed to create device");
|
||||
return new DxvkDevice(this, new vk::DeviceFn(m_vki->instance(), device));
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkSurface> DxvkAdapter::createSurface(HINSTANCE instance, HWND window) {
|
||||
return new DxvkSurface(this, instance, window);
|
||||
}
|
||||
|
||||
|
||||
vk::NameList DxvkAdapter::enableExtensions() {
|
||||
std::vector<const char*> extOptional = { };
|
||||
std::vector<const char*> extRequired = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
const vk::NameSet extensionsAvailable
|
||||
= vk::NameSet::enumerateDeviceExtensions(*m_vki, m_handle);
|
||||
vk::NameList extensionsEnabled;
|
||||
|
||||
for (auto e : extOptional) {
|
||||
if (extensionsAvailable.supports(e))
|
||||
extensionsEnabled.add(e);
|
||||
}
|
||||
|
||||
for (auto e : extRequired) {
|
||||
if (!extensionsAvailable.supports(e))
|
||||
throw DxvkError(str::format("DxvkDevice::getExtensions: Extension ", e, " not supported"));
|
||||
extensionsEnabled.add(e);
|
||||
}
|
||||
|
||||
return extensionsEnabled;
|
||||
}
|
||||
|
||||
|
||||
VkPhysicalDeviceFeatures DxvkAdapter::enableFeatures() {
|
||||
VkPhysicalDeviceFeatures features;
|
||||
std::memset(&features, 0, sizeof(features));
|
||||
return features;
|
||||
}
|
||||
|
||||
}
|
143
src/dxvk/dxvk_adapter.h
Normal file
143
src/dxvk/dxvk_adapter.h
Normal file
@ -0,0 +1,143 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "./vulkan/dxvk_vulkan_extensions.h"
|
||||
|
||||
#include "dxvk_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkDevice;
|
||||
class DxvkInstance;
|
||||
class DxvkSurface;
|
||||
|
||||
/**
|
||||
* \brief DXVK adapter
|
||||
*
|
||||
* Corresponds to a physical device in Vulkan. Provides
|
||||
* all kinds of information about the device itself and
|
||||
* the supported feature set.
|
||||
*/
|
||||
class DxvkAdapter : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkAdapter(
|
||||
const Rc<DxvkInstance>& instance,
|
||||
VkPhysicalDevice handle);
|
||||
~DxvkAdapter();
|
||||
|
||||
/**
|
||||
* \brief Vulkan instance functions
|
||||
* \returns Vulkan instance functions
|
||||
*/
|
||||
Rc<vk::InstanceFn> vki() const {
|
||||
return m_vki;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Physical device handle
|
||||
* \returns The adapter handle
|
||||
*/
|
||||
VkPhysicalDevice handle() const {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Physical device properties
|
||||
*
|
||||
* Retrieves information about the device itself.
|
||||
* \returns Physical device properties
|
||||
*/
|
||||
VkPhysicalDeviceProperties deviceProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Memory properties
|
||||
*
|
||||
* Queries the memory types and memory heaps of
|
||||
* the device. This is useful for memory allocators.
|
||||
* \returns Device memory properties
|
||||
*/
|
||||
VkPhysicalDeviceMemoryProperties memoryProperties() const;
|
||||
|
||||
/**
|
||||
* \brief Supportred device features
|
||||
*
|
||||
* Queries the supported device features.
|
||||
* \returns Device features
|
||||
*/
|
||||
VkPhysicalDeviceFeatures features() const;
|
||||
|
||||
/**
|
||||
* \brief Queries format support
|
||||
*
|
||||
* \param [in] format The format to query
|
||||
* \returns Format support info
|
||||
*/
|
||||
VkFormatProperties formatProperties(
|
||||
VkFormat format) const;
|
||||
|
||||
/**
|
||||
* \brief Queries image format support
|
||||
*
|
||||
* \param [in] format Format to query
|
||||
* \param [in] type Image type
|
||||
* \param [in] tiling Image tiling
|
||||
* \param [in] usage Image usage flags
|
||||
* \param [in] flags Image create flags
|
||||
* \returns Image format support info
|
||||
*/
|
||||
std::optional<VkImageFormatProperties> imageFormatProperties(
|
||||
VkFormat format,
|
||||
VkImageType type,
|
||||
VkImageTiling tiling,
|
||||
VkImageUsageFlags usage,
|
||||
VkImageCreateFlags flags) const;
|
||||
|
||||
/**
|
||||
* \brief Graphics queue family index
|
||||
* \returns Graphics queue family index
|
||||
*/
|
||||
uint32_t graphicsQueueFamily() const;
|
||||
|
||||
/**
|
||||
* \brief Presentation queue family index
|
||||
* \returns Presentation queue family index
|
||||
*/
|
||||
uint32_t presentQueueFamily() const;
|
||||
|
||||
/**
|
||||
* \brief Creates a DXVK device
|
||||
*
|
||||
* Creates a logical device for this adapter.
|
||||
* \returns Device handle
|
||||
*/
|
||||
Rc<DxvkDevice> createDevice();
|
||||
|
||||
/**
|
||||
* \brief Creates a surface
|
||||
*
|
||||
* \param [in] instance Module instance
|
||||
* \param [in] window Application window
|
||||
* \returns Surface handle
|
||||
*/
|
||||
Rc<DxvkSurface> createSurface(
|
||||
HINSTANCE instance,
|
||||
HWND window);
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkInstance> m_instance;
|
||||
Rc<vk::InstanceFn> m_vki;
|
||||
VkPhysicalDevice m_handle;
|
||||
|
||||
std::vector<VkQueueFamilyProperties> m_queueFamilies;
|
||||
|
||||
vk::NameList enableExtensions();
|
||||
|
||||
VkPhysicalDeviceFeatures enableFeatures();
|
||||
|
||||
};
|
||||
|
||||
}
|
0
src/dxvk/dxvk_buffer.cpp
Normal file
0
src/dxvk/dxvk_buffer.cpp
Normal file
38
src/dxvk/dxvk_buffer.h
Normal file
38
src/dxvk/dxvk_buffer.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Buffer create info
|
||||
*
|
||||
* The properties of a buffer that are
|
||||
* passed to \ref DxvkDevice::createBuffer
|
||||
*/
|
||||
struct DxvkBufferCreateInfo {
|
||||
|
||||
/// Size of the buffer, in bytes
|
||||
VkDeviceSize bufferSize;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK buffer
|
||||
*
|
||||
* A simple buffer resource that stores linear data.
|
||||
*/
|
||||
class DxvkBuffer : public DxvkResource {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
68
src/dxvk/dxvk_cmdlist.cpp
Normal file
68
src/dxvk/dxvk_cmdlist.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include "dxvk_cmdlist.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkCommandList::DxvkCommandList(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
uint32_t queueFamily)
|
||||
: m_vkd(vkd) {
|
||||
VkCommandPoolCreateInfo poolInfo;
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.pNext = nullptr;
|
||||
poolInfo.flags = 0;
|
||||
poolInfo.queueFamilyIndex = queueFamily;
|
||||
|
||||
if (m_vkd->vkCreateCommandPool(m_vkd->device(), &poolInfo, nullptr, &m_pool) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkCommandList::DxvkCommandList: Failed to create command pool");
|
||||
|
||||
VkCommandBufferAllocateInfo cmdInfo;
|
||||
cmdInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
cmdInfo.pNext = nullptr;
|
||||
cmdInfo.commandPool = m_pool;
|
||||
cmdInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
cmdInfo.commandBufferCount = 1;
|
||||
|
||||
if (m_vkd->vkAllocateCommandBuffers(m_vkd->device(), &cmdInfo, &m_buffer) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkCommandList::DxvkCommandList: Failed to allocate command buffer");
|
||||
}
|
||||
|
||||
|
||||
DxvkCommandList::~DxvkCommandList() {
|
||||
m_resources.reset();
|
||||
|
||||
m_vkd->vkDestroyCommandPool(
|
||||
m_vkd->device(), m_pool, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::beginRecording() {
|
||||
VkCommandBufferBeginInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
info.pInheritanceInfo = nullptr;
|
||||
|
||||
if (m_vkd->vkResetCommandPool(m_vkd->device(), m_pool, 0) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkCommandList::beginRecording: Failed to reset command pool");
|
||||
|
||||
if (m_vkd->vkBeginCommandBuffer(m_buffer, &info) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkCommandList::beginRecording: Failed to begin command buffer recording");
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::endRecording() {
|
||||
if (m_vkd->vkEndCommandBuffer(m_buffer) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkCommandList::endRecording: Failed to record command buffer");
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::trackResource(const Rc<DxvkResource>& rc) {
|
||||
m_resources.trackResource(rc);
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::reset() {
|
||||
m_resources.reset();
|
||||
}
|
||||
|
||||
}
|
70
src/dxvk/dxvk_cmdlist.h
Normal file
70
src/dxvk/dxvk_cmdlist.h
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "dxvk_lifetime.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVK command list
|
||||
*
|
||||
* Stores a command buffer that a context can use to record Vulkan
|
||||
* commands. The command list shall also reference the resources
|
||||
* used by the recorded commands for automatic lifetime tracking.
|
||||
* When the command list has completed execution, resources that
|
||||
* are no longer used may get destroyed.
|
||||
*/
|
||||
class DxvkCommandList : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkCommandList(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
uint32_t queueFamily);
|
||||
~DxvkCommandList();
|
||||
|
||||
/**
|
||||
* \brief Command buffer handle
|
||||
* \returns Command buffer handle
|
||||
*/
|
||||
VkCommandBuffer handle() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
void beginRecording();
|
||||
void endRecording();
|
||||
|
||||
/**
|
||||
* \brief Adds a resource to track
|
||||
*
|
||||
* Adds a resource to the internal resource tracker.
|
||||
* Resources will be kept alive and "in use" until
|
||||
* the device can guarantee that the submission has
|
||||
* completed.
|
||||
*/
|
||||
void trackResource(
|
||||
const Rc<DxvkResource>& rc);
|
||||
|
||||
/**
|
||||
* \brief Resets the command list
|
||||
*
|
||||
* Resets the internal command buffer of the command list and
|
||||
* marks all tracked resources as unused. When submitting the
|
||||
* command list to the device, this method will be called once
|
||||
* the command list completes execution.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
VkCommandPool m_pool;
|
||||
VkCommandBuffer m_buffer;
|
||||
|
||||
DxvkLifetimeTracker m_resources;
|
||||
|
||||
};
|
||||
|
||||
}
|
73
src/dxvk/dxvk_context.cpp
Normal file
73
src/dxvk/dxvk_context.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include "dxvk_context.h"
|
||||
#include "dxvk_main.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkContext::DxvkContext(const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd) { }
|
||||
|
||||
|
||||
DxvkContext::~DxvkContext() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::beginRecording(
|
||||
const Rc<DxvkCommandList>& cmdList) {
|
||||
m_commandList = cmdList;
|
||||
m_commandList->beginRecording();
|
||||
}
|
||||
|
||||
|
||||
bool DxvkContext::endRecording() {
|
||||
m_commandList->endRecording();
|
||||
m_commandList = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void DxvkContext::setFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& fb) {
|
||||
const DxvkFramebufferSize fbSize = fb->size();
|
||||
// TODO implement properly
|
||||
VkRect2D renderArea;
|
||||
renderArea.offset.x = 0;
|
||||
renderArea.offset.y = 0;
|
||||
renderArea.extent.width = fbSize.width;
|
||||
renderArea.extent.height = fbSize.height;
|
||||
|
||||
VkRenderPassBeginInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.renderPass = fb->renderPass();
|
||||
info.framebuffer = fb->handle();
|
||||
info.renderArea = renderArea;
|
||||
info.clearValueCount = 0;
|
||||
info.pClearValues = nullptr;
|
||||
|
||||
// This is for testing purposes only.
|
||||
VkClearAttachment attachment;
|
||||
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
attachment.colorAttachment = 0;
|
||||
attachment.clearValue.color.float32[0] = 1.0f;
|
||||
attachment.clearValue.color.float32[1] = 1.0f;
|
||||
attachment.clearValue.color.float32[2] = 1.0f;
|
||||
attachment.clearValue.color.float32[3] = 1.0f;
|
||||
|
||||
VkClearRect clearRect;
|
||||
clearRect.rect = renderArea;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = fbSize.layers;
|
||||
|
||||
m_vkd->vkCmdBeginRenderPass(
|
||||
m_commandList->handle(), &info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
m_vkd->vkCmdClearAttachments(
|
||||
m_commandList->handle(),
|
||||
1, &attachment,
|
||||
1, &clearRect);
|
||||
m_vkd->vkCmdEndRenderPass(
|
||||
m_commandList->handle());
|
||||
}
|
||||
|
||||
}
|
66
src/dxvk/dxvk_context.h
Normal file
66
src/dxvk/dxvk_context.h
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_cmdlist.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVk context
|
||||
*
|
||||
* Tracks pipeline state and records command lists.
|
||||
* This is where the actual rendering commands are
|
||||
* recorded.
|
||||
*/
|
||||
class DxvkContext : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkContext(const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkContext();
|
||||
|
||||
/**
|
||||
* \brief Begins command buffer recording
|
||||
*
|
||||
* Begins recording a command list. This does
|
||||
* not alter any context state other than the
|
||||
* active command list.
|
||||
* \param [in] cmdList Target command list
|
||||
*/
|
||||
void beginRecording(
|
||||
const Rc<DxvkCommandList>& cmdList);
|
||||
|
||||
/**
|
||||
* \brief Ends command buffer recording
|
||||
*
|
||||
* Finishes recording the active command list.
|
||||
* The command list can then be submitted to
|
||||
* the device.
|
||||
*
|
||||
* The return value of this method can be used to
|
||||
* determine whether the command list needs to be
|
||||
* submitted. In case the command list is empty,
|
||||
* \c false will be returned and it shall not be
|
||||
* submitted to the device.
|
||||
*
|
||||
* This will not change any context state
|
||||
* other than the active command list.
|
||||
* \returns \c true if any commands were recorded
|
||||
*/
|
||||
bool endRecording();
|
||||
|
||||
/**
|
||||
* \brief Sets framebuffer
|
||||
* \param [in] fb Framebuffer
|
||||
*/
|
||||
void setFramebuffer(
|
||||
const Rc<DxvkFramebuffer>& fb);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
Rc<DxvkCommandList> m_commandList;
|
||||
|
||||
};
|
||||
|
||||
}
|
0
src/dxvk/dxvk_context_state.cpp
Normal file
0
src/dxvk/dxvk_context_state.cpp
Normal file
9
src/dxvk/dxvk_context_state.h
Normal file
9
src/dxvk/dxvk_context_state.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_cmdlist.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
|
||||
|
||||
}
|
119
src/dxvk/dxvk_device.cpp
Normal file
119
src/dxvk/dxvk_device.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "dxvk_device.h"
|
||||
#include "dxvk_instance.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkDevice::DxvkDevice(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const Rc<vk::DeviceFn>& vkd)
|
||||
: m_adapter (adapter),
|
||||
m_vkd (vkd),
|
||||
m_memory (adapter, vkd),
|
||||
m_renderPassPool(vkd) {
|
||||
m_vkd->vkGetDeviceQueue(m_vkd->device(),
|
||||
m_adapter->graphicsQueueFamily(), 0,
|
||||
&m_graphicsQueue);
|
||||
m_vkd->vkGetDeviceQueue(m_vkd->device(),
|
||||
m_adapter->presentQueueFamily(), 0,
|
||||
&m_presentQueue);
|
||||
}
|
||||
|
||||
|
||||
DxvkDevice::~DxvkDevice() {
|
||||
m_vkd->vkDeviceWaitIdle(m_vkd->device());
|
||||
m_vkd->vkDestroyDevice(m_vkd->device(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkCommandList> DxvkDevice::createCommandList() {
|
||||
return new DxvkCommandList(m_vkd,
|
||||
m_adapter->graphicsQueueFamily());
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkContext> DxvkDevice::createContext() {
|
||||
return new DxvkContext(m_vkd);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
|
||||
const DxvkRenderTargets& renderTargets) {
|
||||
auto format = renderTargets.renderPassFormat();
|
||||
auto renderPass = m_renderPassPool.getRenderPass(format);
|
||||
return new DxvkFramebuffer(m_vkd, renderPass, renderTargets);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImage> DxvkDevice::createImage(
|
||||
const DxvkImageCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImageView> DxvkDevice::createImageView(
|
||||
const Rc<DxvkImage>& image,
|
||||
const DxvkImageViewCreateInfo& createInfo) {
|
||||
return new DxvkImageView(m_vkd, image, createInfo);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkSemaphore> DxvkDevice::createSemaphore() {
|
||||
return new DxvkSemaphore(m_vkd);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkSwapchain> DxvkDevice::createSwapchain(
|
||||
const Rc<DxvkSurface>& surface,
|
||||
const DxvkSwapchainProperties& properties) {
|
||||
return new DxvkSwapchain(this, surface, properties, m_presentQueue);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkFence> DxvkDevice::submitCommandList(
|
||||
const Rc<DxvkCommandList>& commandList,
|
||||
const Rc<DxvkSemaphore>& waitSync,
|
||||
const Rc<DxvkSemaphore>& wakeSync) {
|
||||
Rc<DxvkFence> fence = new DxvkFence(m_vkd);
|
||||
|
||||
VkCommandBuffer commandBuffer = commandList->handle();
|
||||
VkSemaphore waitSemaphore = VK_NULL_HANDLE;
|
||||
VkSemaphore wakeSemaphore = VK_NULL_HANDLE;
|
||||
|
||||
if (waitSync != nullptr) {
|
||||
waitSemaphore = waitSync->handle();
|
||||
commandList->trackResource(waitSync);
|
||||
}
|
||||
|
||||
if (wakeSync != nullptr) {
|
||||
wakeSemaphore = wakeSync->handle();
|
||||
commandList->trackResource(wakeSync);
|
||||
}
|
||||
|
||||
const VkPipelineStageFlags waitStageMask
|
||||
= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
|
||||
|
||||
VkSubmitInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.waitSemaphoreCount = waitSemaphore == VK_NULL_HANDLE ? 0 : 1;
|
||||
info.pWaitSemaphores = &waitSemaphore;
|
||||
info.pWaitDstStageMask = &waitStageMask;
|
||||
info.commandBufferCount = commandBuffer == VK_NULL_HANDLE ? 0 : 1;
|
||||
info.pCommandBuffers = &commandBuffer;
|
||||
info.signalSemaphoreCount = wakeSemaphore == VK_NULL_HANDLE ? 0 : 1;
|
||||
info.pSignalSemaphores = &wakeSemaphore;
|
||||
|
||||
if (m_vkd->vkQueueSubmit(m_graphicsQueue, 1, &info, fence->handle()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkDevice::submitCommandList: Command submission failed");
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
|
||||
void DxvkDevice::waitForIdle() const {
|
||||
if (m_vkd->vkDeviceWaitIdle(m_vkd->device()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkDevice::waitForIdle: Operation failed");
|
||||
}
|
||||
|
||||
}
|
152
src/dxvk/dxvk_device.h
Normal file
152
src/dxvk/dxvk_device.h
Normal file
@ -0,0 +1,152 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_adapter.h"
|
||||
#include "dxvk_buffer.h"
|
||||
#include "dxvk_context.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_memory.h"
|
||||
#include "dxvk_renderpass.h"
|
||||
#include "dxvk_swapchain.h"
|
||||
#include "dxvk_sync.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkInstance;
|
||||
|
||||
/**
|
||||
* \brief DXVK device
|
||||
*
|
||||
* Device object. This is responsible for resource creation,
|
||||
* memory allocation, command submission and state tracking.
|
||||
* Rendering commands are recorded into command lists using
|
||||
* contexts. Multiple contexts can be created for a device.
|
||||
*/
|
||||
class DxvkDevice : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkDevice(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkDevice();
|
||||
|
||||
/**
|
||||
* \brief Vulkan device functions
|
||||
* \returns Vulkan device functions
|
||||
*/
|
||||
Rc<vk::DeviceFn> vkd() const {
|
||||
return m_vkd;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Logical device handle
|
||||
* \returns The device handle
|
||||
*/
|
||||
VkDevice handle() const {
|
||||
return m_vkd->device();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates a command list
|
||||
* \returns The command list
|
||||
*/
|
||||
Rc<DxvkCommandList> createCommandList();
|
||||
|
||||
/**
|
||||
* \brief Creates a context
|
||||
*
|
||||
* Creates a context object that can
|
||||
* be used to record command buffers.
|
||||
* \returns The context object
|
||||
*/
|
||||
Rc<DxvkContext> createContext();
|
||||
|
||||
/**
|
||||
* \brief Creates framebuffer for a set of render targets
|
||||
*
|
||||
* Automatically deduces framebuffer dimensions
|
||||
* from the supplied render target views.
|
||||
* \param [in] renderTargets Render targets
|
||||
* \returns The framebuffer object
|
||||
*/
|
||||
Rc<DxvkFramebuffer> createFramebuffer(
|
||||
const DxvkRenderTargets& renderTargets);
|
||||
|
||||
/**
|
||||
* \brief Creates an image object
|
||||
*
|
||||
* \param [in] createInfo Image create info
|
||||
* \param [in] memoryType Memory type flags
|
||||
* \returns The image object
|
||||
*/
|
||||
Rc<DxvkImage> createImage(
|
||||
const DxvkImageCreateInfo& createInfo,
|
||||
VkMemoryPropertyFlags memoryType);
|
||||
|
||||
/**
|
||||
* \brief Creates an image view
|
||||
*
|
||||
* \param [in] image The image to create a view for
|
||||
* \param [in] createInfo Image view create info
|
||||
* \returns The image view
|
||||
*/
|
||||
Rc<DxvkImageView> createImageView(
|
||||
const Rc<DxvkImage>& image,
|
||||
const DxvkImageViewCreateInfo& createInfo);
|
||||
|
||||
/**
|
||||
* \brief Creates a semaphore object
|
||||
* \returns Newly created semaphore
|
||||
*/
|
||||
Rc<DxvkSemaphore> createSemaphore();
|
||||
|
||||
/**
|
||||
* \brief Creates a swap chain
|
||||
*
|
||||
* \param [in] surface The target surface
|
||||
* \param [in] properties Swapchain properties
|
||||
* \returns The swapchain object
|
||||
*/
|
||||
Rc<DxvkSwapchain> createSwapchain(
|
||||
const Rc<DxvkSurface>& surface,
|
||||
const DxvkSwapchainProperties& properties);
|
||||
|
||||
/**
|
||||
* \brief Submits a command list
|
||||
*
|
||||
* Synchronization arguments are optional.
|
||||
* \param [in] commandList The command list to submit
|
||||
* \param [in] waitSync (Optional) Semaphore to wait on
|
||||
* \param [in] wakeSync (Optional) Semaphore to notify
|
||||
* \returns Synchronization fence
|
||||
*/
|
||||
Rc<DxvkFence> submitCommandList(
|
||||
const Rc<DxvkCommandList>& commandList,
|
||||
const Rc<DxvkSemaphore>& waitSync,
|
||||
const Rc<DxvkSemaphore>& wakeSync);
|
||||
|
||||
/**
|
||||
* \brief Waits until the device becomes idle
|
||||
*
|
||||
* Waits for the GPU to complete the execution of all
|
||||
* previously submitted command buffers. This may be
|
||||
* used to ensure that resources that were previously
|
||||
* used by the GPU can be safely destroyed.
|
||||
*/
|
||||
void waitForIdle() const;
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkAdapter> m_adapter;
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
DxvkMemoryAllocator m_memory;
|
||||
DxvkRenderPassPool m_renderPassPool;
|
||||
|
||||
VkQueue m_graphicsQueue;
|
||||
VkQueue m_presentQueue;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
95
src/dxvk/dxvk_framebuffer.cpp
Normal file
95
src/dxvk/dxvk_framebuffer.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "dxvk_framebuffer.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkRenderTargets:: DxvkRenderTargets() { }
|
||||
DxvkRenderTargets::~DxvkRenderTargets() { }
|
||||
|
||||
|
||||
DxvkRenderPassFormat DxvkRenderTargets::renderPassFormat() const {
|
||||
DxvkRenderPassFormat result;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets; i++) {
|
||||
if (m_colorTargets.at(i) != nullptr) {
|
||||
result.setColorFormat(i, m_colorTargets.at(i)->info().format);
|
||||
result.setSampleCount(m_colorTargets.at(i)->imageInfo().sampleCount);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_depthTarget != nullptr) {
|
||||
result.setDepthFormat(m_depthTarget->info().format);
|
||||
result.setSampleCount(m_depthTarget->imageInfo().sampleCount);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::vector<VkImageView> DxvkRenderTargets::getAttachments() const {
|
||||
std::vector<VkImageView> result;
|
||||
|
||||
if (m_depthTarget != nullptr)
|
||||
result.push_back(m_depthTarget->handle());
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets; i++) {
|
||||
if (m_colorTargets.at(i) != nullptr)
|
||||
result.push_back(m_colorTargets.at(i)->handle());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkRenderTargets::getImageSize() const {
|
||||
if (m_depthTarget != nullptr)
|
||||
return this->renderTargetSize(m_depthTarget);
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets; i++) {
|
||||
if (m_colorTargets.at(i) != nullptr)
|
||||
return this->renderTargetSize(m_colorTargets.at(i));
|
||||
}
|
||||
|
||||
return DxvkFramebufferSize { 0, 0, 0 };
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebufferSize DxvkRenderTargets::renderTargetSize(
|
||||
const Rc<DxvkImageView>& renderTarget) const {
|
||||
auto extent = renderTarget->imageInfo().extent;
|
||||
auto layers = renderTarget->info().numLayers;
|
||||
return DxvkFramebufferSize { extent.width, extent.height, layers };
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebuffer::DxvkFramebuffer(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const Rc<DxvkRenderPass>& renderPass,
|
||||
const DxvkRenderTargets& renderTargets)
|
||||
: m_vkd (vkd),
|
||||
m_renderPass (renderPass),
|
||||
m_renderTargets (renderTargets),
|
||||
m_framebufferSize (renderTargets.getImageSize()) {
|
||||
auto views = renderTargets.getAttachments();
|
||||
|
||||
VkFramebufferCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.renderPass = renderPass->handle();
|
||||
info.attachmentCount = views.size();
|
||||
info.pAttachments = views.data();
|
||||
info.width = m_framebufferSize.width;
|
||||
info.height = m_framebufferSize.height;
|
||||
info.layers = m_framebufferSize.layers;
|
||||
|
||||
if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_framebuffer) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkFramebuffer::DxvkFramebuffer: Failed to create framebuffer object");
|
||||
}
|
||||
|
||||
|
||||
DxvkFramebuffer::~DxvkFramebuffer() {
|
||||
m_vkd->vkDestroyFramebuffer(
|
||||
m_vkd->device(), m_framebuffer, nullptr);
|
||||
}
|
||||
|
||||
}
|
160
src/dxvk/dxvk_framebuffer.h
Normal file
160
src/dxvk/dxvk_framebuffer.h
Normal file
@ -0,0 +1,160 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_image.h"
|
||||
#include "dxvk_renderpass.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Framebuffer size
|
||||
*
|
||||
* Stores the width, height and number of layers
|
||||
* of a framebuffer. This can be used in case a
|
||||
* framebuffer does not have any attachments.
|
||||
*/
|
||||
struct DxvkFramebufferSize {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t layers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Render target description
|
||||
*
|
||||
* Stores render targets for a framebuffer object
|
||||
* and provides methods to query the render pass
|
||||
* format. Note that all render target views must
|
||||
* have the same size and number of array layers.
|
||||
*/
|
||||
class DxvkRenderTargets {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderTargets();
|
||||
~DxvkRenderTargets();
|
||||
|
||||
/**
|
||||
* \brief Retrieves color target
|
||||
*
|
||||
* \param [in] id Color attachment ID
|
||||
* \returns Render target view
|
||||
*/
|
||||
Rc<DxvkImageView> getColorTarget(uint32_t id) const {
|
||||
return m_colorTargets.at(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves depth-stencil target
|
||||
* \returns Depth-stencil target view
|
||||
*/
|
||||
Rc<DxvkImageView> getDepthTarget() const {
|
||||
return m_depthTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets color target
|
||||
*
|
||||
* \param [in] id Color attachment ID
|
||||
* \param [in] view Render target view
|
||||
*/
|
||||
void setColorTarget(uint32_t id, const Rc<DxvkImageView>& view) {
|
||||
m_colorTargets.at(id) = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets depth-stencil target
|
||||
* \param [in] view Depth-stencil target view
|
||||
*/
|
||||
void setDepthTarget(const Rc<DxvkImageView>& view) {
|
||||
m_depthTarget = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render pass format
|
||||
*
|
||||
* Computes the render pass format based on
|
||||
* the color and depth-stencil attachments.
|
||||
* \returns Render pass format
|
||||
*/
|
||||
DxvkRenderPassFormat renderPassFormat() const;
|
||||
|
||||
/**
|
||||
* \brief Creates attachment list
|
||||
* \returns Framebuffer attachment list
|
||||
*/
|
||||
std::vector<VkImageView> getAttachments() const;
|
||||
|
||||
/**
|
||||
* \brief Framebuffer size
|
||||
*
|
||||
* The width, height and layers
|
||||
* of the attached render targets.
|
||||
* \returns Framebuffer size
|
||||
*/
|
||||
DxvkFramebufferSize getImageSize() const;
|
||||
|
||||
private:
|
||||
|
||||
std::array<Rc<DxvkImageView>, MaxNumColorTargets> m_colorTargets;
|
||||
Rc<DxvkImageView> m_depthTarget;
|
||||
|
||||
DxvkFramebufferSize renderTargetSize(
|
||||
const Rc<DxvkImageView>& renderTarget) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK framebuffer
|
||||
*
|
||||
* A framebuffer either stores a set of image views
|
||||
* that will be used as render targets, or in case
|
||||
* no render targets are being used, fixed viewport
|
||||
* dimensions.
|
||||
*/
|
||||
class DxvkFramebuffer : public DxvkResource {
|
||||
|
||||
public:
|
||||
|
||||
DxvkFramebuffer(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const Rc<DxvkRenderPass>& renderPass,
|
||||
const DxvkRenderTargets& renderTargets);
|
||||
~DxvkFramebuffer();
|
||||
|
||||
/**
|
||||
* \brief Framebuffer handle
|
||||
* \returns Framebuffer handle
|
||||
*/
|
||||
VkFramebuffer handle() const {
|
||||
return m_framebuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render pass handle
|
||||
* \returns Render pass handle
|
||||
*/
|
||||
VkRenderPass renderPass() const {
|
||||
return m_renderPass->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Framebuffer size
|
||||
* \returns Framebuffer size
|
||||
*/
|
||||
DxvkFramebufferSize size() const {
|
||||
return m_framebufferSize;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
Rc<DxvkRenderPass> m_renderPass;
|
||||
DxvkRenderTargets m_renderTargets;
|
||||
DxvkFramebufferSize m_framebufferSize;
|
||||
VkFramebuffer m_framebuffer;
|
||||
|
||||
};
|
||||
|
||||
}
|
34
src/dxvk/dxvk_hash.h
Normal file
34
src/dxvk/dxvk_hash.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct DxvkHash {
|
||||
template<typename T>
|
||||
size_t operator () (const T& object) const {
|
||||
return object.hash();
|
||||
}
|
||||
};
|
||||
|
||||
class DxvkHashState {
|
||||
|
||||
public:
|
||||
|
||||
void add(size_t hash) {
|
||||
m_value ^= hash + 0x9e3779b9
|
||||
+ (m_value << 6)
|
||||
+ (m_value >> 2);
|
||||
}
|
||||
|
||||
operator size_t () const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
size_t m_value = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
66
src/dxvk/dxvk_image.cpp
Normal file
66
src/dxvk/dxvk_image.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "dxvk_image.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// DxvkImage::DxvkImage(
|
||||
// const Rc<vk::DeviceFn>& vkd,
|
||||
// const DxvkImageCreateInfo& info,
|
||||
// DxvkMemory&& memory)
|
||||
// : m_vkd(vkd), m_info(info), m_memory(std::move(memory)) {
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
DxvkImage::DxvkImage(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkImageCreateInfo& info,
|
||||
VkImage image)
|
||||
: m_vkd(vkd), m_info(info), m_image(image) { }
|
||||
|
||||
|
||||
DxvkImage::~DxvkImage() {
|
||||
// This is a bit of a hack to determine whether
|
||||
// the image is implementation-handled or not
|
||||
if (m_memory.memory() != VK_NULL_HANDLE)
|
||||
m_vkd->vkDestroyImage(m_vkd->device(), m_image, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DxvkImageView::DxvkImageView(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const Rc<DxvkImage>& image,
|
||||
const DxvkImageViewCreateInfo& info)
|
||||
: m_vkd(vkd), m_image(image), m_info(info) {
|
||||
VkComponentMapping componentMapping;
|
||||
componentMapping.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
componentMapping.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
componentMapping.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
componentMapping.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
|
||||
VkImageSubresourceRange subresourceRange;
|
||||
subresourceRange.aspectMask = info.aspect;
|
||||
subresourceRange.baseMipLevel = info.minLevel;
|
||||
subresourceRange.levelCount = info.numLevels;
|
||||
subresourceRange.baseArrayLayer = info.minLayer;
|
||||
subresourceRange.layerCount = info.numLayers;
|
||||
|
||||
VkImageViewCreateInfo viewInfo;
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.pNext = nullptr;
|
||||
viewInfo.flags = 0;
|
||||
viewInfo.image = image->handle();
|
||||
viewInfo.viewType = info.type;
|
||||
viewInfo.format = info.format;
|
||||
viewInfo.components = componentMapping;
|
||||
viewInfo.subresourceRange = subresourceRange;
|
||||
|
||||
if (m_vkd->vkCreateImageView(m_vkd->device(), &viewInfo, nullptr, &m_view) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkImageView::DxvkImageView: Failed to create image view");
|
||||
}
|
||||
|
||||
|
||||
DxvkImageView::~DxvkImageView() {
|
||||
m_vkd->vkDestroyImageView(m_vkd->device(), m_view, nullptr);
|
||||
}
|
||||
|
||||
}
|
151
src/dxvk/dxvk_image.h
Normal file
151
src/dxvk/dxvk_image.h
Normal file
@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_memory.h"
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct DxvkImageCreateInfo {
|
||||
VkImageType type;
|
||||
VkFormat format;
|
||||
VkSampleCountFlagBits sampleCount;
|
||||
VkExtent3D extent;
|
||||
uint32_t numLayers;
|
||||
uint32_t mipLevels;
|
||||
VkImageUsageFlags usage;
|
||||
VkImageTiling tiling;
|
||||
};
|
||||
|
||||
struct DxvkImageViewCreateInfo {
|
||||
VkImageViewType type;
|
||||
VkFormat format;
|
||||
VkImageAspectFlags aspect;
|
||||
uint32_t minLevel;
|
||||
uint32_t numLevels;
|
||||
uint32_t minLayer;
|
||||
uint32_t numLayers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK image
|
||||
*/
|
||||
class DxvkImage : public DxvkResource {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Creates a new image
|
||||
*
|
||||
* \param [in] vkd Vulkan device functions
|
||||
* \param [in] info Image properties
|
||||
* \param [in] memory Image memory
|
||||
*/
|
||||
// DxvkImage(
|
||||
// const Rc<vk::DeviceFn>& vkd,
|
||||
// const DxvkImageCreateInfo& info,
|
||||
// DxvkMemory&& memory);
|
||||
|
||||
/**
|
||||
* \brief Creates image object from existing image
|
||||
*
|
||||
* This can be used to create an image object for
|
||||
* an implementation-managed image. Make sure to
|
||||
* provide the correct image properties, since
|
||||
* otherwise some image operations may fail.
|
||||
*/
|
||||
DxvkImage(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkImageCreateInfo& info,
|
||||
VkImage image);
|
||||
|
||||
/**
|
||||
* \brief Destroys image
|
||||
*
|
||||
* If this is an implementation-managed image,
|
||||
* this will not destroy the Vulkan image.
|
||||
*/
|
||||
~DxvkImage();
|
||||
|
||||
/**
|
||||
* \brief Image handle
|
||||
*
|
||||
* Internal use only.
|
||||
* \returns Image handle
|
||||
*/
|
||||
VkImage handle() const {
|
||||
return m_image;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Image properties
|
||||
*
|
||||
* The image create info structure.
|
||||
* \returns Image properties
|
||||
*/
|
||||
const DxvkImageCreateInfo& info() const {
|
||||
return m_info;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
DxvkImageCreateInfo m_info;
|
||||
DxvkMemory m_memory;
|
||||
VkImage m_image;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK image view
|
||||
*/
|
||||
class DxvkImageView : public DxvkResource {
|
||||
|
||||
public:
|
||||
|
||||
DxvkImageView(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const Rc<DxvkImage>& image,
|
||||
const DxvkImageViewCreateInfo& info);
|
||||
|
||||
~DxvkImageView();
|
||||
|
||||
/**
|
||||
* \brief Image view handle
|
||||
*
|
||||
* Internal use only.
|
||||
* \returns Image view handle
|
||||
*/
|
||||
VkImageView handle() const {
|
||||
return m_view;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Image view properties
|
||||
* \returns Image view properties
|
||||
*/
|
||||
const DxvkImageViewCreateInfo& info() const {
|
||||
return m_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Image properties
|
||||
* \returns Image properties
|
||||
*/
|
||||
const DxvkImageCreateInfo& imageInfo() const {
|
||||
return m_image->info();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
Rc<DxvkImage> m_image;
|
||||
|
||||
DxvkImageViewCreateInfo m_info;
|
||||
VkImageView m_view;
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
10
src/dxvk/dxvk_include.h
Normal file
10
src/dxvk/dxvk_include.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "../util/util_error.h"
|
||||
#include "../util/util_string.h"
|
||||
|
||||
#include "../util/rc/util_rc.h"
|
||||
#include "../util/rc/util_rc_ptr.h"
|
||||
|
||||
#include "./vulkan/dxvk_vulkan_extensions.h"
|
||||
#include "./vulkan/dxvk_vulkan_loader.h"
|
108
src/dxvk/dxvk_instance.cpp
Normal file
108
src/dxvk/dxvk_instance.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "dxvk_instance.h"
|
||||
#include "dxvk_main.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkInstance::DxvkInstance()
|
||||
: m_vkl(new vk::LibraryFn()),
|
||||
m_vki(new vk::InstanceFn(this->createInstance())) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkInstance::~DxvkInstance() {
|
||||
m_vki->vkDestroyInstance(
|
||||
m_vki->instance(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
std::vector<Rc<DxvkAdapter>> DxvkInstance::enumAdapters() {
|
||||
uint32_t numAdapters = 0;
|
||||
if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkInstance::enumAdapters: Failed to enumerate adapters");
|
||||
|
||||
std::vector<VkPhysicalDevice> adapters(numAdapters);
|
||||
if (m_vki->vkEnumeratePhysicalDevices(m_vki->instance(), &numAdapters, adapters.data()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkInstance::enumAdapters: Failed to enumerate adapters");
|
||||
|
||||
std::vector<Rc<DxvkAdapter>> result;
|
||||
for (uint32_t i = 0; i < numAdapters; i++)
|
||||
result.push_back(new DxvkAdapter(this, adapters[i]));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
VkInstance DxvkInstance::createInstance() {
|
||||
auto enabledLayers = this->getLayers();
|
||||
auto enabledExtensions = this->getExtensions(enabledLayers);
|
||||
|
||||
VkApplicationInfo appInfo;
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pNext = nullptr;
|
||||
appInfo.pApplicationName = nullptr;
|
||||
appInfo.applicationVersion = 0;
|
||||
appInfo.pEngineName = "DXVK";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(0, 0, 1);
|
||||
appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 47);
|
||||
|
||||
VkInstanceCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.pApplicationInfo = &appInfo;
|
||||
info.enabledLayerCount = enabledLayers.count();
|
||||
info.ppEnabledLayerNames = enabledLayers.names();
|
||||
info.enabledExtensionCount = enabledExtensions.count();
|
||||
info.ppEnabledExtensionNames = enabledExtensions.names();
|
||||
|
||||
VkInstance result = VK_NULL_HANDLE;
|
||||
if (m_vkl->vkCreateInstance(&info, nullptr, &result) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkInstance::createInstance: Failed to create Vulkan instance");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
vk::NameList DxvkInstance::getLayers() {
|
||||
std::vector<const char*> layers = {
|
||||
"VK_LAYER_LUNARG_standard_validation"
|
||||
};
|
||||
|
||||
const vk::NameSet layersAvailable
|
||||
= vk::NameSet::enumerateInstanceLayers(*m_vkl);
|
||||
|
||||
vk::NameList layersEnabled;
|
||||
for (auto l : layers) {
|
||||
if (layersAvailable.supports(l))
|
||||
layersEnabled.add(l);
|
||||
}
|
||||
|
||||
return layersEnabled;
|
||||
}
|
||||
|
||||
|
||||
vk::NameList DxvkInstance::getExtensions(const vk::NameList& layers) {
|
||||
std::vector<const char*> extOptional = { };
|
||||
std::vector<const char*> extRequired = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
const vk::NameSet extensionsAvailable
|
||||
= vk::NameSet::enumerateInstanceExtensions(*m_vkl, layers);
|
||||
vk::NameList extensionsEnabled;
|
||||
|
||||
for (auto e : extOptional) {
|
||||
if (extensionsAvailable.supports(e))
|
||||
extensionsEnabled.add(e);
|
||||
}
|
||||
|
||||
for (auto e : extRequired) {
|
||||
if (!extensionsAvailable.supports(e))
|
||||
throw DxvkError(str::format("DxvkInstance::getExtensions: Extension ", e, " not supported"));
|
||||
extensionsEnabled.add(e);
|
||||
}
|
||||
|
||||
return extensionsEnabled;
|
||||
}
|
||||
|
||||
}
|
56
src/dxvk/dxvk_instance.h
Normal file
56
src/dxvk/dxvk_instance.h
Normal file
@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_adapter.h"
|
||||
#include "dxvk_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVK instance
|
||||
*
|
||||
* Manages a Vulkan instance and stores a list
|
||||
* of adapters. This also provides methods for
|
||||
* device creation.
|
||||
*/
|
||||
class DxvkInstance : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkInstance();
|
||||
~DxvkInstance();
|
||||
|
||||
/**
|
||||
* \brief Vulkan instance functions
|
||||
* \returns Vulkan instance functions
|
||||
*/
|
||||
Rc<vk::InstanceFn> vki() const {
|
||||
return m_vki;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Vulkan instance handle
|
||||
* \returns The instance handle
|
||||
*/
|
||||
VkInstance handle() {
|
||||
return m_vki->instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves a list of adapters
|
||||
* \returns List of adapter objects
|
||||
*/
|
||||
std::vector<Rc<DxvkAdapter>> enumAdapters();
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::LibraryFn> m_vkl;
|
||||
Rc<vk::InstanceFn> m_vki;
|
||||
|
||||
VkInstance createInstance();
|
||||
|
||||
vk::NameList getLayers();
|
||||
vk::NameList getExtensions(const vk::NameList& layers);
|
||||
|
||||
};
|
||||
|
||||
}
|
21
src/dxvk/dxvk_lifetime.cpp
Normal file
21
src/dxvk/dxvk_lifetime.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include "dxvk_lifetime.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkLifetimeTracker:: DxvkLifetimeTracker() { }
|
||||
DxvkLifetimeTracker::~DxvkLifetimeTracker() { }
|
||||
|
||||
|
||||
void DxvkLifetimeTracker::trackResource(const Rc<DxvkResource>& rc) {
|
||||
if (m_resources.insert(rc).second)
|
||||
rc->incUseCount();
|
||||
}
|
||||
|
||||
|
||||
void DxvkLifetimeTracker::reset() {
|
||||
for (auto i = m_resources.cbegin(); i != m_resources.cend(); i++)
|
||||
(*i)->decUseCount();
|
||||
m_resources.clear();
|
||||
}
|
||||
|
||||
}
|
45
src/dxvk/dxvk_lifetime.h
Normal file
45
src/dxvk/dxvk_lifetime.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVK lifetime tracker
|
||||
*
|
||||
* Maintains references to a set of resources. This is
|
||||
* used to guarantee that resources are not destroyed
|
||||
* or otherwise accessed in an unsafe manner until the
|
||||
* device has finished using them.
|
||||
*/
|
||||
class DxvkLifetimeTracker {
|
||||
|
||||
public:
|
||||
|
||||
DxvkLifetimeTracker();
|
||||
~DxvkLifetimeTracker();
|
||||
|
||||
/**
|
||||
* \brief Adds a resource to track
|
||||
* \param [in] rc The resource to track
|
||||
*/
|
||||
void trackResource(
|
||||
const Rc<DxvkResource>& rc);
|
||||
|
||||
/**
|
||||
* \brief Resets the command list
|
||||
*
|
||||
* Called automatically by the device when
|
||||
* the command list has completed execution.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_set<Rc<DxvkResource>, RcHash<DxvkResource>> m_resources;
|
||||
|
||||
};
|
||||
|
||||
}
|
11
src/dxvk/dxvk_main.cpp
Normal file
11
src/dxvk/dxvk_main.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "dxvk_main.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
Log g_logger("dxvk.log");
|
||||
|
||||
void log(const std::string& message) {
|
||||
g_logger.log(message);
|
||||
}
|
||||
|
||||
}
|
14
src/dxvk/dxvk_main.h
Normal file
14
src/dxvk/dxvk_main.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "../util/log/log.h"
|
||||
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Adds a message to the global DXVK log
|
||||
* \param [in] message Log message
|
||||
*/
|
||||
void log(const std::string& message);
|
||||
|
||||
}
|
112
src/dxvk/dxvk_memory.cpp
Normal file
112
src/dxvk/dxvk_memory.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include "dxvk_memory.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkMemory::DxvkMemory() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkMemory::DxvkMemory(
|
||||
DxvkMemoryAllocator* alloc,
|
||||
VkDeviceMemory memory,
|
||||
void* mapPtr)
|
||||
: m_alloc (alloc),
|
||||
m_memory(memory),
|
||||
m_mapPtr(mapPtr) { }
|
||||
|
||||
|
||||
DxvkMemory::DxvkMemory(DxvkMemory&& other)
|
||||
: m_alloc (other.m_alloc),
|
||||
m_memory(other.m_memory),
|
||||
m_mapPtr(other.m_mapPtr) {
|
||||
other.m_alloc = nullptr;
|
||||
other.m_memory = VK_NULL_HANDLE;
|
||||
other.m_mapPtr = nullptr;
|
||||
}
|
||||
|
||||
|
||||
DxvkMemory& DxvkMemory::operator = (DxvkMemory&& other) {
|
||||
this->m_alloc = other.m_alloc;
|
||||
this->m_memory = other.m_memory;
|
||||
this->m_mapPtr = other.m_mapPtr;
|
||||
other.m_alloc = nullptr;
|
||||
other.m_memory = VK_NULL_HANDLE;
|
||||
other.m_mapPtr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
DxvkMemory::~DxvkMemory() {
|
||||
if (m_memory != VK_NULL_HANDLE)
|
||||
m_alloc->freeMemory(m_memory);
|
||||
}
|
||||
|
||||
|
||||
DxvkMemoryAllocator::DxvkMemoryAllocator(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd), m_memProps(adapter->memoryProperties()) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkMemoryAllocator::~DxvkMemoryAllocator() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkMemory DxvkMemoryAllocator::alloc(
|
||||
const VkMemoryRequirements& req,
|
||||
const VkMemoryPropertyFlags flags) {
|
||||
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
void* mapPtr = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < m_memProps.memoryTypeCount; i++) {
|
||||
const bool supported = (req.memoryTypeBits & (1u << i)) != 0;
|
||||
const bool adequate = (m_memProps.memoryTypes[i].propertyFlags & flags) == flags;
|
||||
|
||||
if (supported && adequate) {
|
||||
memory = this->allocMemory(req.size, i);
|
||||
|
||||
if (memory != VK_NULL_HANDLE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (memory == VK_NULL_HANDLE)
|
||||
throw DxvkError("DxvkMemoryAllocator::alloc: Failed to allocate memory");
|
||||
|
||||
if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
||||
if (m_vkd->vkMapMemory(m_vkd->device(), memory,
|
||||
0, VK_WHOLE_SIZE, 0, &mapPtr) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkMemoryAllocator::alloc: Failed to map memory");
|
||||
}
|
||||
|
||||
return DxvkMemory(this, memory, mapPtr);
|
||||
}
|
||||
|
||||
|
||||
VkDeviceMemory DxvkMemoryAllocator::allocMemory(
|
||||
VkDeviceSize blockSize, uint32_t memoryType) {
|
||||
|
||||
VkMemoryAllocateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.allocationSize = blockSize;
|
||||
info.memoryTypeIndex = memoryType;
|
||||
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
if (m_vkd->vkAllocateMemory(m_vkd->device(),
|
||||
&info, nullptr, &memory) != VK_SUCCESS)
|
||||
return VK_NULL_HANDLE;
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
void DxvkMemoryAllocator::freeMemory(VkDeviceMemory memory) {
|
||||
m_vkd->vkFreeMemory(m_vkd->device(), memory, nullptr);
|
||||
}
|
||||
|
||||
}
|
105
src/dxvk/dxvk_memory.h
Normal file
105
src/dxvk/dxvk_memory.h
Normal file
@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_adapter.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkMemoryAllocator;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Memory slice
|
||||
*/
|
||||
class DxvkMemory {
|
||||
|
||||
public:
|
||||
|
||||
DxvkMemory();
|
||||
DxvkMemory(
|
||||
DxvkMemoryAllocator* alloc,
|
||||
VkDeviceMemory memory,
|
||||
void* mapPtr);
|
||||
DxvkMemory (DxvkMemory&& other);
|
||||
DxvkMemory& operator = (DxvkMemory&& other);
|
||||
~DxvkMemory();
|
||||
|
||||
/**
|
||||
* \brief Memory object
|
||||
*
|
||||
* This information is required when
|
||||
* binding memory to Vulkan objects.
|
||||
* \returns Memory object
|
||||
*/
|
||||
VkDeviceMemory memory() const {
|
||||
return m_memory;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Offset from memory object
|
||||
*
|
||||
* This information is required when
|
||||
* binding memory to Vulkan objects.
|
||||
* \returns Offset from memory object
|
||||
*/
|
||||
VkDeviceSize offset() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Pointer to mapped data
|
||||
* \returns Pointer to mapped data
|
||||
*/
|
||||
void* mapPtr() const {
|
||||
return m_mapPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxvkMemoryAllocator* m_alloc = nullptr;
|
||||
VkDeviceMemory m_memory = VK_NULL_HANDLE;
|
||||
void* m_mapPtr = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Memory allocator
|
||||
*
|
||||
* Allocates device memory for Vulkan resources.
|
||||
* Memory objects will be destroyed automatically.
|
||||
*/
|
||||
class DxvkMemoryAllocator {
|
||||
friend class DxvkMemory;
|
||||
public:
|
||||
|
||||
DxvkMemoryAllocator(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkMemoryAllocator();
|
||||
|
||||
/**
|
||||
* \brief Allocates device memory
|
||||
*
|
||||
* \param [in] req Memory requirements
|
||||
* \param [in] flats Memory type flags
|
||||
* \returns Allocated memory slice
|
||||
*/
|
||||
DxvkMemory alloc(
|
||||
const VkMemoryRequirements& req,
|
||||
const VkMemoryPropertyFlags flags);
|
||||
|
||||
private:
|
||||
|
||||
const Rc<vk::DeviceFn> m_vkd;
|
||||
const VkPhysicalDeviceMemoryProperties m_memProps;
|
||||
|
||||
VkDeviceMemory allocMemory(
|
||||
VkDeviceSize blockSize,
|
||||
uint32_t memoryType);
|
||||
|
||||
void freeMemory(
|
||||
VkDeviceMemory memory);
|
||||
|
||||
};
|
||||
|
||||
}
|
166
src/dxvk/dxvk_renderpass.cpp
Normal file
166
src/dxvk/dxvk_renderpass.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#include "dxvk_renderpass.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkRenderPassFormat::DxvkRenderPassFormat() {
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets; i++)
|
||||
m_color.at(i) = VK_FORMAT_UNDEFINED;
|
||||
m_depth = VK_FORMAT_UNDEFINED;
|
||||
m_samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
|
||||
|
||||
size_t DxvkRenderPassFormat::hash() const {
|
||||
DxvkHashState result;
|
||||
std::hash<VkFormat> fhash;
|
||||
std::hash<VkSampleCountFlagBits> shash;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets; i++)
|
||||
result.add(fhash(m_color.at(i)));
|
||||
|
||||
result.add(fhash(m_depth));
|
||||
result.add(shash(m_samples));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool DxvkRenderPassFormat::operator == (const DxvkRenderPassFormat& other) const {
|
||||
bool equal = m_depth == other.m_depth
|
||||
&& m_samples == other.m_samples;
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets && !equal; i++)
|
||||
equal = m_color.at(i) == other.m_color.at(i);
|
||||
return equal;
|
||||
}
|
||||
|
||||
|
||||
bool DxvkRenderPassFormat::operator != (const DxvkRenderPassFormat& other) const {
|
||||
return !this->operator == (other);
|
||||
}
|
||||
|
||||
|
||||
DxvkRenderPass::DxvkRenderPass(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkRenderPassFormat& fmt,
|
||||
VkImageLayout initialLayout,
|
||||
VkImageLayout finalLayout)
|
||||
: m_vkd(vkd), m_format(fmt) {
|
||||
std::vector<VkAttachmentDescription> attachments;
|
||||
|
||||
VkAttachmentReference depthRef;
|
||||
std::array<VkAttachmentReference, MaxNumColorTargets> colorRef;
|
||||
|
||||
// Render passes may not require the previous
|
||||
// contents of the attachments to be preserved.
|
||||
VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
if (initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
|
||||
loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
|
||||
if (fmt.getDepthFormat() != VK_FORMAT_UNDEFINED) {
|
||||
VkAttachmentDescription desc;
|
||||
desc.flags = 0;
|
||||
desc.format = fmt.getDepthFormat();
|
||||
desc.samples = fmt.getSampleCount();
|
||||
desc.loadOp = loadOp;
|
||||
desc.storeOp = storeOp;
|
||||
desc.stencilLoadOp = loadOp;
|
||||
desc.stencilStoreOp = storeOp;
|
||||
desc.initialLayout = initialLayout;
|
||||
desc.finalLayout = finalLayout;
|
||||
|
||||
depthRef.attachment = attachments.size();
|
||||
depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
attachments.push_back(desc);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumColorTargets; i++) {
|
||||
colorRef.at(i).attachment = VK_ATTACHMENT_UNUSED;
|
||||
colorRef.at(i).layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
|
||||
if (fmt.getColorFormat(i) != VK_FORMAT_UNDEFINED) {
|
||||
VkAttachmentDescription desc;
|
||||
desc.flags = 0;
|
||||
desc.format = fmt.getColorFormat(i);
|
||||
desc.samples = fmt.getSampleCount();
|
||||
desc.loadOp = loadOp;
|
||||
desc.storeOp = storeOp;
|
||||
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
desc.initialLayout = initialLayout;
|
||||
desc.finalLayout = finalLayout;
|
||||
|
||||
colorRef.at(i).attachment = attachments.size();
|
||||
colorRef.at(i).layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
attachments.push_back(desc);
|
||||
}
|
||||
}
|
||||
|
||||
VkSubpassDescription subpass;
|
||||
subpass.flags = 0;
|
||||
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass.inputAttachmentCount = 0;
|
||||
subpass.pInputAttachments = nullptr;
|
||||
subpass.colorAttachmentCount = colorRef.size();
|
||||
subpass.pColorAttachments = colorRef.data();
|
||||
subpass.pResolveAttachments = nullptr;
|
||||
subpass.pDepthStencilAttachment = fmt.getDepthFormat() != VK_FORMAT_UNDEFINED ? &depthRef : nullptr;
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = nullptr;
|
||||
|
||||
VkRenderPassCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.attachmentCount = attachments.size();
|
||||
info.pAttachments = attachments.data();
|
||||
info.subpassCount = 1;
|
||||
info.pSubpasses = &subpass;
|
||||
info.dependencyCount = 0;
|
||||
info.pDependencies = nullptr;
|
||||
|
||||
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &m_renderPass) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkRenderPass::DxvkRenderPass: Failed to create render pass object");
|
||||
}
|
||||
|
||||
|
||||
DxvkRenderPass::~DxvkRenderPass() {
|
||||
m_vkd->vkDestroyRenderPass(
|
||||
m_vkd->device(), m_renderPass, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DxvkRenderPassPool::DxvkRenderPassPool(const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd) { }
|
||||
|
||||
|
||||
DxvkRenderPassPool::~DxvkRenderPassPool() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkRenderPass> DxvkRenderPassPool::getRenderPass(
|
||||
const DxvkRenderPassFormat& fmt) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
auto rp = m_renderPasses.find(fmt);
|
||||
|
||||
if (rp != m_renderPasses.end())
|
||||
return rp->second;
|
||||
|
||||
auto result = this->createRenderPass(fmt);
|
||||
m_renderPasses.insert(std::make_pair(fmt, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkRenderPass> DxvkRenderPassPool::createRenderPass(
|
||||
const DxvkRenderPassFormat& fmt) {
|
||||
return new DxvkRenderPass(m_vkd, fmt,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_IMAGE_LAYOUT_GENERAL);
|
||||
}
|
||||
|
||||
}
|
175
src/dxvk/dxvk_renderpass.h
Normal file
175
src/dxvk/dxvk_renderpass.h
Normal file
@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "dxvk_hash.h"
|
||||
#include "dxvk_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr uint32_t MaxNumColorTargets = 8;
|
||||
|
||||
/**
|
||||
* \brief Render pass format
|
||||
*
|
||||
* Stores the formats of all render targets
|
||||
* that are used by a framebuffer object.
|
||||
*/
|
||||
class DxvkRenderPassFormat {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderPassFormat();
|
||||
|
||||
/**
|
||||
* \brief Retrieves color target format
|
||||
*
|
||||
* If the color target has not been defined,
|
||||
* this will return \c VK_FORMAT_UNDEFINED.
|
||||
* \param [in] id Color target index
|
||||
* \returns Color target format
|
||||
*/
|
||||
VkFormat getColorFormat(uint32_t id) const {
|
||||
return m_color.at(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves depth-stencil format
|
||||
*
|
||||
* If the color target has not been defined,
|
||||
* this will return \c VK_FORMAT_UNDEFINED.
|
||||
*/
|
||||
VkFormat getDepthFormat() const {
|
||||
return m_depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Retrieves sample count
|
||||
*
|
||||
* If no sample count has been explicitly specitied,
|
||||
* this will return \c VK_SAMPLE_COUNT_1_BIT.
|
||||
* \returns Sample count
|
||||
*/
|
||||
VkSampleCountFlagBits getSampleCount() const {
|
||||
return m_samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets color target format
|
||||
*
|
||||
* \param [in] id Color target index
|
||||
* \param [in] fmt Color target format
|
||||
*/
|
||||
void setColorFormat(uint32_t id, VkFormat fmt) {
|
||||
m_color.at(id) = fmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets depth-stencil format
|
||||
* \param [in] fmt Depth-stencil format
|
||||
*/
|
||||
void setDepthFormat(VkFormat fmt) {
|
||||
m_depth = fmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets sample count
|
||||
* \param [in] samples Sample count
|
||||
*/
|
||||
void setSampleCount(VkSampleCountFlagBits samples) {
|
||||
m_samples = samples;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Computes the hash
|
||||
* \returns Resulting hash
|
||||
*/
|
||||
size_t hash() const;
|
||||
|
||||
bool operator == (const DxvkRenderPassFormat& other) const;
|
||||
bool operator != (const DxvkRenderPassFormat& other) const;
|
||||
|
||||
private:
|
||||
|
||||
std::array<VkFormat, MaxNumColorTargets> m_color;
|
||||
VkFormat m_depth;
|
||||
VkSampleCountFlagBits m_samples;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK render pass
|
||||
*
|
||||
* Render pass objects are used internally to identify render
|
||||
* target formats and
|
||||
*/
|
||||
class DxvkRenderPass : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderPass(
|
||||
const Rc<vk::DeviceFn>& vkd,
|
||||
const DxvkRenderPassFormat& fmt,
|
||||
VkImageLayout initialLayout,
|
||||
VkImageLayout finalLayout);
|
||||
~DxvkRenderPass();
|
||||
|
||||
/**
|
||||
* \brief Render pass handle
|
||||
*
|
||||
* Internal use only.
|
||||
* \returns Render pass handle
|
||||
*/
|
||||
VkRenderPass handle() const {
|
||||
return m_renderPass;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
DxvkRenderPassFormat m_format;
|
||||
VkRenderPass m_renderPass;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Render pass pool
|
||||
*
|
||||
* Thread-safe class that manages the render pass
|
||||
* objects that are used within an application.
|
||||
*/
|
||||
class DxvkRenderPassPool {
|
||||
|
||||
public:
|
||||
|
||||
DxvkRenderPassPool(const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkRenderPassPool();
|
||||
|
||||
/**
|
||||
* \brief Retrieves a render pass object
|
||||
*
|
||||
* \param [in] fmt Render target formats
|
||||
* \returns Compatible render pass object
|
||||
*/
|
||||
Rc<DxvkRenderPass> getRenderPass(
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::unordered_map<
|
||||
DxvkRenderPassFormat,
|
||||
Rc<DxvkRenderPass>,
|
||||
DxvkHash> m_renderPasses;
|
||||
|
||||
Rc<DxvkRenderPass> createRenderPass(
|
||||
const DxvkRenderPassFormat& fmt);
|
||||
|
||||
};
|
||||
|
||||
}
|
9
src/dxvk/dxvk_resource.cpp
Normal file
9
src/dxvk/dxvk_resource.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkResource::~DxvkResource() {
|
||||
|
||||
}
|
||||
|
||||
}
|
33
src/dxvk/dxvk_resource.h
Normal file
33
src/dxvk/dxvk_resource.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVK resource
|
||||
*
|
||||
* Keeps track of whether the resource is currently in use
|
||||
* by the GPU. As soon as a command that uses the resource
|
||||
* is recorded, it will be marked as 'in use'.
|
||||
*/
|
||||
class DxvkResource : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~DxvkResource();
|
||||
|
||||
bool isInUse() const {
|
||||
return m_useCount != 0;
|
||||
}
|
||||
|
||||
void incUseCount() { m_useCount += 1; }
|
||||
void decUseCount() { m_useCount -= 1; }
|
||||
|
||||
private:
|
||||
|
||||
std::atomic<uint32_t> m_useCount = { 0u };
|
||||
|
||||
};
|
||||
|
||||
}
|
150
src/dxvk/dxvk_surface.cpp
Normal file
150
src/dxvk/dxvk_surface.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
#include "dxvk_surface.h"
|
||||
|
||||
#include "../util/util_math.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkSurface::DxvkSurface(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
HINSTANCE instance,
|
||||
HWND window)
|
||||
: m_adapter (adapter),
|
||||
m_vki (adapter->vki()),
|
||||
m_handle (createSurface(instance, window)),
|
||||
m_surfaceFormats (getSurfaceFormats()),
|
||||
m_presentModes (getPresentModes()) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
DxvkSurface::~DxvkSurface() {
|
||||
m_vki->vkDestroySurfaceKHR(
|
||||
m_vki->instance(), m_handle, nullptr);
|
||||
}
|
||||
|
||||
|
||||
VkSurfaceCapabilitiesKHR DxvkSurface::getSurfaceCapabilities() const {
|
||||
VkSurfaceCapabilitiesKHR surfaceCaps;
|
||||
if (m_vki->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
||||
m_adapter->handle(), m_handle, &surfaceCaps) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSurface::getSurfaceCapabilities: Failed to query surface capabilities");
|
||||
return surfaceCaps;
|
||||
}
|
||||
|
||||
|
||||
VkSurfaceFormatKHR DxvkSurface::pickSurfaceFormat(VkSurfaceFormatKHR preferred) const {
|
||||
// If the implementation allows us to freely choose
|
||||
// the format, we'll just use the preferred format.
|
||||
if (m_surfaceFormats.size() == 1 && m_surfaceFormats.at(0).format == VK_FORMAT_UNDEFINED)
|
||||
return preferred;
|
||||
|
||||
// If the preferred format is explicitly listed in
|
||||
// the array of supported surface formats, use it
|
||||
for (auto fmt : m_surfaceFormats) {
|
||||
if (fmt.format == preferred.format
|
||||
&& fmt.colorSpace == preferred.colorSpace)
|
||||
return fmt;
|
||||
}
|
||||
|
||||
// Otherwise, fall back to the first format
|
||||
return m_surfaceFormats.at(0);
|
||||
}
|
||||
|
||||
|
||||
VkPresentModeKHR DxvkSurface::pickPresentMode(VkPresentModeKHR preferred) const {
|
||||
for (auto mode : m_presentModes) {
|
||||
if (mode == preferred)
|
||||
return mode;
|
||||
}
|
||||
|
||||
// This mode is guaranteed to be available
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxvkSurface::pickImageCount(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkPresentModeKHR mode) const {
|
||||
uint32_t count = caps.minImageCount;
|
||||
|
||||
if (mode == VK_PRESENT_MODE_MAILBOX_KHR
|
||||
|| mode == VK_PRESENT_MODE_FIFO_KHR)
|
||||
count += 1;
|
||||
|
||||
if (count > caps.maxImageCount && caps.maxImageCount != 0)
|
||||
count = caps.maxImageCount;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
VkExtent2D DxvkSurface::pickImageExtent(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkExtent2D preferred) const {
|
||||
if (caps.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
||||
return caps.currentExtent;
|
||||
|
||||
VkExtent2D actual;
|
||||
actual.width = clamp(preferred.width, caps.minImageExtent.width, caps.maxImageExtent.width);
|
||||
actual.height = clamp(preferred.height, caps.minImageExtent.height, caps.maxImageExtent.height);
|
||||
return actual;
|
||||
}
|
||||
|
||||
|
||||
VkSurfaceKHR DxvkSurface::createSurface(HINSTANCE instance, HWND window) {
|
||||
VkWin32SurfaceCreateInfoKHR info;
|
||||
info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.hinstance = instance;
|
||||
info.hwnd = window;
|
||||
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
if (m_vki->vkCreateWin32SurfaceKHR(m_vki->instance(), &info, nullptr, &surface) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSurface::createSurface: Failed to create win32 surface");
|
||||
|
||||
VkBool32 supportStatus = VK_FALSE;
|
||||
|
||||
if (m_vki->vkGetPhysicalDeviceSurfaceSupportKHR(m_adapter->handle(),
|
||||
m_adapter->presentQueueFamily(), surface, &supportStatus) != VK_SUCCESS) {
|
||||
m_vki->vkDestroySurfaceKHR(m_vki->instance(), surface, nullptr);
|
||||
throw DxvkError("DxvkSurface::createSurface: Failed to query surface support");
|
||||
}
|
||||
|
||||
if (!supportStatus) {
|
||||
m_vki->vkDestroySurfaceKHR(m_vki->instance(), surface, nullptr);
|
||||
throw DxvkError("DxvkSurface::createSurface: Surface not supported by device");
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> DxvkSurface::getSurfaceFormats() {
|
||||
uint32_t numFormats = 0;
|
||||
if (m_vki->vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
m_adapter->handle(), m_handle, &numFormats, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSurface::getSurfaceFormats: Failed to query surface formats");
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> formats(numFormats);
|
||||
if (m_vki->vkGetPhysicalDeviceSurfaceFormatsKHR(
|
||||
m_adapter->handle(), m_handle, &numFormats, formats.data()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSurface::getSurfaceFormats: Failed to query surface formats");
|
||||
return formats;
|
||||
}
|
||||
|
||||
|
||||
std::vector<VkPresentModeKHR> DxvkSurface::getPresentModes() {
|
||||
uint32_t numModes = 0;
|
||||
if (m_vki->vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
m_adapter->handle(), m_handle, &numModes, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSurface::getPresentModes: Failed to query present modes");
|
||||
|
||||
std::vector<VkPresentModeKHR> modes(numModes);
|
||||
if (m_vki->vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
m_adapter->handle(), m_handle, &numModes, modes.data()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSurface::getPresentModes: Failed to query present modes");
|
||||
return modes;
|
||||
}
|
||||
|
||||
}
|
98
src/dxvk/dxvk_surface.h
Normal file
98
src/dxvk/dxvk_surface.h
Normal file
@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_adapter.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVK surface
|
||||
*
|
||||
* Vulkan representation of a drawable window surface. This
|
||||
* class provides methods to query the current dimension of
|
||||
* the surface as well as format support queries.
|
||||
*/
|
||||
class DxvkSurface : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkSurface(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
HINSTANCE instance,
|
||||
HWND window);
|
||||
~DxvkSurface();
|
||||
|
||||
/**
|
||||
* \brief Vulkan surface handle
|
||||
* \returns The surface handle
|
||||
*/
|
||||
VkSurfaceKHR handle() const {
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Queries surface capabilities
|
||||
*
|
||||
* Retrieves up-to-date information about the surface,
|
||||
* such as the bounds of the swapchain images.
|
||||
* \returns Current surface properties
|
||||
*/
|
||||
VkSurfaceCapabilitiesKHR getSurfaceCapabilities() const;
|
||||
|
||||
/**
|
||||
* \brief Picks a suitable surface format
|
||||
*
|
||||
* \param [in] preferred Preferred surface format
|
||||
* \returns The actual surface format
|
||||
*/
|
||||
VkSurfaceFormatKHR pickSurfaceFormat(
|
||||
VkSurfaceFormatKHR preferred) const;
|
||||
|
||||
/**
|
||||
* \brief Picks a supported present mode
|
||||
*
|
||||
* \param [in] preferred The preferred present mode
|
||||
* \returns The actual present mode
|
||||
*/
|
||||
VkPresentModeKHR pickPresentMode(
|
||||
VkPresentModeKHR preferred) const;
|
||||
|
||||
/**
|
||||
* \brief Picks a suitable image count for a swap chain
|
||||
*
|
||||
* \param [in] caps Surface capabilities
|
||||
* \param [in] mode The present mode
|
||||
* \returns Suitable image count
|
||||
*/
|
||||
uint32_t pickImageCount(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkPresentModeKHR mode) const;
|
||||
|
||||
/**
|
||||
* \brief Picks a suitable image size for a swap chain
|
||||
*
|
||||
* \param [in] caps Surface capabilities
|
||||
* \param [in] preferred Preferred image size
|
||||
* \returns Selected image size
|
||||
*/
|
||||
VkExtent2D pickImageExtent(
|
||||
const VkSurfaceCapabilitiesKHR& caps,
|
||||
VkExtent2D preferred) const;
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkAdapter> m_adapter;
|
||||
Rc<vk::InstanceFn> m_vki;
|
||||
|
||||
VkSurfaceKHR m_handle;
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> m_surfaceFormats;
|
||||
std::vector<VkPresentModeKHR> m_presentModes;
|
||||
|
||||
VkSurfaceKHR createSurface(HINSTANCE instance, HWND window);
|
||||
|
||||
std::vector<VkSurfaceFormatKHR> getSurfaceFormats();
|
||||
std::vector<VkPresentModeKHR> getPresentModes();
|
||||
|
||||
};
|
||||
|
||||
}
|
185
src/dxvk/dxvk_swapchain.cpp
Normal file
185
src/dxvk/dxvk_swapchain.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include "dxvk_main.h"
|
||||
|
||||
#include "dxvk_device.h"
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_surface.h"
|
||||
#include "dxvk_swapchain.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkSwapchain::DxvkSwapchain(
|
||||
const Rc<DxvkDevice>& device,
|
||||
const Rc<DxvkSurface>& surface,
|
||||
const DxvkSwapchainProperties& properties,
|
||||
VkQueue queue)
|
||||
: m_device (device),
|
||||
m_vkd (device->vkd()),
|
||||
m_surface (surface),
|
||||
m_queue (queue),
|
||||
m_properties(properties) {
|
||||
this->recreateSwapchain();
|
||||
}
|
||||
|
||||
|
||||
DxvkSwapchain::~DxvkSwapchain() {
|
||||
m_device->waitForIdle();
|
||||
m_vkd->vkDestroySwapchainKHR(
|
||||
m_vkd->device(), m_handle, nullptr);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkFramebuffer> DxvkSwapchain::getFramebuffer(
|
||||
const Rc<DxvkSemaphore>& wakeSync) {
|
||||
VkResult status = this->acquireNextImage(wakeSync);
|
||||
|
||||
if (status == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
this->recreateSwapchain();
|
||||
status = this->acquireNextImage(wakeSync);
|
||||
}
|
||||
|
||||
if (status != VK_SUCCESS
|
||||
&& status != VK_SUBOPTIMAL_KHR)
|
||||
throw DxvkError("DxvkSwapchain::getFramebuffer: Failed to acquire image");
|
||||
|
||||
return m_framebuffers.at(m_imageIndex);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchain::present(const Rc<DxvkSemaphore>& waitSync) {
|
||||
const VkSemaphore waitSemaphore = waitSync->handle();
|
||||
|
||||
VkPresentInfoKHR info;
|
||||
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
info.pNext = nullptr;
|
||||
info.waitSemaphoreCount = 1;
|
||||
info.pWaitSemaphores = &waitSemaphore;
|
||||
info.swapchainCount = 1;
|
||||
info.pSwapchains = &m_handle;
|
||||
info.pImageIndices = &m_imageIndex;
|
||||
info.pResults = nullptr;
|
||||
|
||||
VkResult status = m_vkd->vkQueuePresentKHR(m_queue, &info);
|
||||
|
||||
if (status != VK_SUCCESS
|
||||
&& status != VK_SUBOPTIMAL_KHR
|
||||
&& status != VK_ERROR_OUT_OF_DATE_KHR)
|
||||
throw DxvkError("DxvkSwapchain::present: Failed to present image");
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchain::changeProperties(
|
||||
const DxvkSwapchainProperties& props) {
|
||||
m_properties = props;
|
||||
this->recreateSwapchain();
|
||||
}
|
||||
|
||||
|
||||
VkResult DxvkSwapchain::acquireNextImage(
|
||||
const Rc<DxvkSemaphore>& wakeSync) {
|
||||
return m_vkd->vkAcquireNextImageKHR(
|
||||
m_vkd->device(), m_handle,
|
||||
std::numeric_limits<uint64_t>::max(),
|
||||
wakeSync->handle(),
|
||||
VK_NULL_HANDLE,
|
||||
&m_imageIndex);
|
||||
}
|
||||
|
||||
|
||||
void DxvkSwapchain::recreateSwapchain() {
|
||||
VkSwapchainKHR oldSwapchain = m_handle;
|
||||
|
||||
// Wait until we can be certain that none of our
|
||||
// resources are still in use by the device.
|
||||
m_device->waitForIdle();
|
||||
|
||||
// Recreate the actual swapchain object
|
||||
auto caps = m_surface->getSurfaceCapabilities();
|
||||
auto fmt = m_surface->pickSurfaceFormat(m_properties.preferredSurfaceFormat);
|
||||
auto mode = m_surface->pickPresentMode (m_properties.preferredPresentMode);
|
||||
|
||||
VkSwapchainCreateInfoKHR swapInfo;
|
||||
swapInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapInfo.pNext = nullptr;
|
||||
swapInfo.flags = 0;
|
||||
swapInfo.surface = m_surface->handle();
|
||||
swapInfo.minImageCount = m_surface->pickImageCount(caps, mode);
|
||||
swapInfo.imageFormat = fmt.format;
|
||||
swapInfo.imageColorSpace = fmt.colorSpace;
|
||||
swapInfo.imageExtent = m_surface->pickImageExtent(caps, m_properties.preferredBufferSize);
|
||||
swapInfo.imageArrayLayers = 1;
|
||||
swapInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapInfo.queueFamilyIndexCount = 0;
|
||||
swapInfo.pQueueFamilyIndices = nullptr;
|
||||
swapInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
swapInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
swapInfo.presentMode = mode;
|
||||
swapInfo.clipped = VK_TRUE;
|
||||
swapInfo.oldSwapchain = oldSwapchain;
|
||||
|
||||
if (m_vkd->vkCreateSwapchainKHR(m_vkd->device(), &swapInfo, nullptr, &m_handle) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSwapchain::recreateSwapchain: Failed to recreate swap chain");
|
||||
|
||||
// Destroy previous swapchain object
|
||||
m_vkd->vkDestroySwapchainKHR(
|
||||
m_vkd->device(), oldSwapchain, nullptr);
|
||||
|
||||
// Create the render pass object
|
||||
DxvkRenderPassFormat renderTargetFormat;
|
||||
renderTargetFormat.setColorFormat(0, fmt.format);
|
||||
|
||||
m_renderPass = new DxvkRenderPass(
|
||||
m_vkd, renderTargetFormat,
|
||||
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
|
||||
// Retrieve swap images
|
||||
auto swapImages = this->retrieveSwapImages();
|
||||
m_framebuffers.resize(swapImages.size());
|
||||
|
||||
for (size_t i = 0; i < swapImages.size(); i++) {
|
||||
DxvkImageCreateInfo imageInfo;
|
||||
imageInfo.type = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = fmt.format;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent.width = swapInfo.imageExtent.width;
|
||||
imageInfo.extent.height = swapInfo.imageExtent.height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.numLayers = swapInfo.imageArrayLayers;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = fmt.format;
|
||||
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = swapInfo.imageArrayLayers;
|
||||
|
||||
Rc<DxvkImage> image = new DxvkImage(m_vkd, imageInfo, swapImages.at(i));
|
||||
Rc<DxvkImageView> iview = m_device->createImageView(image, viewInfo);
|
||||
|
||||
DxvkRenderTargets renderTargets;
|
||||
renderTargets.setColorTarget(0, iview);
|
||||
|
||||
m_framebuffers.at(i) = new DxvkFramebuffer(
|
||||
m_vkd, m_renderPass, renderTargets);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<VkImage> DxvkSwapchain::retrieveSwapImages() {
|
||||
uint32_t imageCount = 0;
|
||||
if (m_vkd->vkGetSwapchainImagesKHR(m_vkd->device(), m_handle, &imageCount, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSwapchain::recreateSwapchain: Failed to retrieve swap chain images");
|
||||
|
||||
std::vector<VkImage> images(imageCount);
|
||||
if (m_vkd->vkGetSwapchainImagesKHR(m_vkd->device(), m_handle, &imageCount, images.data()) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSwapchain::recreateSwapchain: Failed to retrieve swap chain images");
|
||||
return images;
|
||||
}
|
||||
|
||||
}
|
96
src/dxvk/dxvk_swapchain.h
Normal file
96
src/dxvk/dxvk_swapchain.h
Normal file
@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_framebuffer.h"
|
||||
#include "dxvk_sync.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkDevice;
|
||||
class DxvkFramebuffer;
|
||||
class DxvkSurface;
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
struct DxvkSwapchainProperties {
|
||||
VkSurfaceFormatKHR preferredSurfaceFormat;
|
||||
VkPresentModeKHR preferredPresentMode;
|
||||
VkExtent2D preferredBufferSize;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief DXVK swapchain
|
||||
*
|
||||
* Manages a Vulkan swapchain object.
|
||||
*/
|
||||
class DxvkSwapchain : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkSwapchain(
|
||||
const Rc<DxvkDevice>& device,
|
||||
const Rc<DxvkSurface>& surface,
|
||||
const DxvkSwapchainProperties& properties,
|
||||
VkQueue queue);
|
||||
~DxvkSwapchain();
|
||||
|
||||
/**
|
||||
* \brief Retrieves the framebuffer for the current frame
|
||||
*
|
||||
* If necessary, this will automatically recreate the
|
||||
* underlying swapchain object and framebuffer objects.
|
||||
* \param [in] wakeSync Semaphore to signal
|
||||
* \returns The framebuffer object
|
||||
*/
|
||||
Rc<DxvkFramebuffer> getFramebuffer(
|
||||
const Rc<DxvkSemaphore>& wakeSync);
|
||||
|
||||
/**
|
||||
* \brief Presents the current framebuffer
|
||||
*
|
||||
* This may actually fail to present an image. If that is the
|
||||
* case, the surface contents will be undefined for this frame
|
||||
* and the swapchain object will be recreated.
|
||||
* \param [in] waitSync Semaphore to wait on
|
||||
*/
|
||||
void present(
|
||||
const Rc<DxvkSemaphore>& waitSync);
|
||||
|
||||
/**
|
||||
* \brief Changes swapchain properties
|
||||
*
|
||||
* This must not be called between \ref getFramebuffer
|
||||
* and \ref present as this method may recreate the swap
|
||||
* chain and framebuffer objects immediately.
|
||||
* \param [in] props New swapchain properties
|
||||
*/
|
||||
void changeProperties(
|
||||
const DxvkSwapchainProperties& props);
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
Rc<DxvkSurface> m_surface;
|
||||
|
||||
VkQueue m_queue;
|
||||
|
||||
DxvkSwapchainProperties m_properties;
|
||||
VkSwapchainKHR m_handle = VK_NULL_HANDLE;
|
||||
uint32_t m_imageIndex = 0;
|
||||
uint32_t m_frameIndex = 0;
|
||||
|
||||
Rc<DxvkRenderPass> m_renderPass;
|
||||
std::vector<Rc<DxvkFramebuffer>> m_framebuffers;
|
||||
|
||||
VkResult acquireNextImage(
|
||||
const Rc<DxvkSemaphore>& wakeSync);
|
||||
|
||||
void recreateSwapchain();
|
||||
|
||||
std::vector<VkImage> retrieveSwapImages();
|
||||
|
||||
};
|
||||
|
||||
}
|
57
src/dxvk/dxvk_sync.cpp
Normal file
57
src/dxvk/dxvk_sync.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "dxvk_sync.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxvkSemaphore::DxvkSemaphore(
|
||||
const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd) {
|
||||
VkSemaphoreCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
|
||||
if (m_vkd->vkCreateSemaphore(m_vkd->device(), &info, nullptr, &m_semaphore) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkSemaphore::DxvkSemaphore: Failed to create semaphore");
|
||||
}
|
||||
|
||||
|
||||
DxvkSemaphore::~DxvkSemaphore() {
|
||||
m_vkd->vkDestroySemaphore(
|
||||
m_vkd->device(), m_semaphore, nullptr);
|
||||
}
|
||||
|
||||
|
||||
DxvkFence::DxvkFence(const Rc<vk::DeviceFn>& vkd)
|
||||
: m_vkd(vkd) {
|
||||
VkFenceCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
|
||||
if (m_vkd->vkCreateFence(m_vkd->device(), &info, nullptr, &m_fence) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkFence::DxvkFence: Failed to create fence");
|
||||
}
|
||||
|
||||
|
||||
DxvkFence::~DxvkFence() {
|
||||
m_vkd->vkDestroyFence(
|
||||
m_vkd->device(), m_fence, nullptr);
|
||||
}
|
||||
|
||||
|
||||
bool DxvkFence::wait(uint64_t timeout) const {
|
||||
VkResult status = m_vkd->vkWaitForFences(
|
||||
m_vkd->device(), 1, &m_fence, VK_FALSE, timeout);
|
||||
|
||||
if (status == VK_SUCCESS) return true;
|
||||
if (status == VK_TIMEOUT) return false;
|
||||
throw DxvkError("DxvkFence::wait: Failed to wait for fence");
|
||||
}
|
||||
|
||||
|
||||
void DxvkFence::reset() {
|
||||
if (m_vkd->vkResetFences(m_vkd->device(), 1, &m_fence) != VK_SUCCESS)
|
||||
throw DxvkError("DxvkFence::reset: Failed to reset fence");
|
||||
}
|
||||
|
||||
}
|
89
src/dxvk/dxvk_sync.h
Normal file
89
src/dxvk/dxvk_sync.h
Normal file
@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_resource.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Semaphore object
|
||||
*
|
||||
* This is merely an abstraction of Vulkan's semaphores.
|
||||
* They are only used internally by \ref DxvkSwapchain
|
||||
* in order to synchronize the presentation engine with
|
||||
* command buffer submissions.
|
||||
*/
|
||||
class DxvkSemaphore : public DxvkResource {
|
||||
|
||||
public:
|
||||
|
||||
DxvkSemaphore(const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkSemaphore();
|
||||
|
||||
/**
|
||||
* \brief Semaphore handle
|
||||
*
|
||||
* Internal use only.
|
||||
* \returns Semaphore handle
|
||||
*/
|
||||
VkSemaphore handle() const {
|
||||
return m_semaphore;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
VkSemaphore m_semaphore;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Fence object
|
||||
*
|
||||
* This is merely an abstraction of Vulkan's fences. Client
|
||||
* APIs that support fence operations may use them directly.
|
||||
* Other than that, they are used internally to keep track
|
||||
* of GPU resource usage.
|
||||
*/
|
||||
class DxvkFence : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxvkFence(const Rc<vk::DeviceFn>& vkd);
|
||||
~DxvkFence();
|
||||
|
||||
/**
|
||||
* \brief Fence handle
|
||||
*
|
||||
* Internal use only.
|
||||
* \returns Fence handle
|
||||
*/
|
||||
VkFence handle() const {
|
||||
return m_fence;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Waits for fence to be signaled
|
||||
*
|
||||
* \param [in] timeout Amount of time to wait
|
||||
* \returns \c true if the fence has been signaled,
|
||||
* \c false if a timeout occured.
|
||||
*/
|
||||
bool wait(uint64_t timeout) const;
|
||||
|
||||
/**
|
||||
* \brief Resets the fence
|
||||
*
|
||||
* Transitions the fence into the unsignaled state,
|
||||
* which means that the fence may be submitted again.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
|
||||
Rc<vk::DeviceFn> m_vkd;
|
||||
VkFence m_fence;
|
||||
|
||||
};
|
||||
|
||||
}
|
32
src/dxvk/meson.build
Normal file
32
src/dxvk/meson.build
Normal file
@ -0,0 +1,32 @@
|
||||
dxvk_src = files([
|
||||
'dxvk_adapter.cpp',
|
||||
'dxvk_cmdlist.cpp',
|
||||
'dxvk_context.cpp',
|
||||
'dxvk_context_state.cpp',
|
||||
'dxvk_device.cpp',
|
||||
'dxvk_framebuffer.cpp',
|
||||
'dxvk_image.cpp',
|
||||
'dxvk_instance.cpp',
|
||||
'dxvk_lifetime.cpp',
|
||||
'dxvk_main.cpp',
|
||||
'dxvk_memory.cpp',
|
||||
'dxvk_renderpass.cpp',
|
||||
'dxvk_resource.cpp',
|
||||
'dxvk_surface.cpp',
|
||||
'dxvk_swapchain.cpp',
|
||||
'dxvk_sync.cpp',
|
||||
|
||||
'vulkan/dxvk_vulkan_extensions.cpp',
|
||||
'vulkan/dxvk_vulkan_loader.cpp',
|
||||
])
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
|
||||
dxvk_lib = static_library('dxvk', dxvk_src,
|
||||
link_with : [ util_lib ],
|
||||
dependencies : [ thread_dep, lib_vulkan, lib_sdl2 ],
|
||||
include_directories : [ dxvk_include_path ])
|
||||
|
||||
dxvk_dep = declare_dependency(
|
||||
link_with : [ dxvk_lib ],
|
||||
include_directories : [ dxvk_include_path, include_directories('.') ])
|
71
src/dxvk/vulkan/dxvk_vulkan_extensions.cpp
Normal file
71
src/dxvk/vulkan/dxvk_vulkan_extensions.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "dxvk_vulkan_extensions.h"
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
bool NameSet::supports(const char* name) const {
|
||||
return m_names.find(name) != m_names.end();
|
||||
}
|
||||
|
||||
|
||||
NameSet NameSet::enumerateInstanceLayers(const LibraryFn& vkl) {
|
||||
uint32_t layerCount = 0;
|
||||
if (vkl.vkEnumerateInstanceLayerProperties(&layerCount, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError(str::format("LayerSet::enumerateInstanceLayers: Failed to query instance layers"));
|
||||
|
||||
std::vector<VkLayerProperties> layers(layerCount);
|
||||
if (vkl.vkEnumerateInstanceLayerProperties(&layerCount, layers.data()) != VK_SUCCESS)
|
||||
throw DxvkError(str::format("LayerSet::enumerateInstanceLayers: Failed to query instance layers"));
|
||||
|
||||
NameSet result;
|
||||
for (const auto& layer : layers)
|
||||
result.m_names.insert(layer.layerName);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
NameSet NameSet::enumerateInstanceExtensions(
|
||||
const LibraryFn& vkl,
|
||||
const NameList& layers) {
|
||||
NameSet result;
|
||||
result.addInstanceLayerExtensions(vkl, nullptr);
|
||||
|
||||
for (size_t i = 0; i < layers.count(); i++)
|
||||
result.addInstanceLayerExtensions(vkl, layers.name(i));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
NameSet NameSet::enumerateDeviceExtensions(
|
||||
const InstanceFn& vki,
|
||||
VkPhysicalDevice device) {
|
||||
uint32_t extCount = 0;
|
||||
if (vki.vkEnumerateDeviceExtensionProperties(device, nullptr, &extCount, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError("ExtensionSet::addDeviceExtensions: Failed to query device extensions");
|
||||
|
||||
std::vector<VkExtensionProperties> extensions(extCount);
|
||||
if (vki.vkEnumerateDeviceExtensionProperties(device, nullptr, &extCount, extensions.data()) != VK_SUCCESS)
|
||||
throw DxvkError("ExtensionSet::addDeviceExtensions: Failed to query device extensions");
|
||||
|
||||
NameSet result;
|
||||
for (const auto& ext : extensions)
|
||||
result.m_names.insert(ext.extensionName);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void NameSet::addInstanceLayerExtensions(
|
||||
const LibraryFn& vkl,
|
||||
const char* layer) {
|
||||
uint32_t extCount = 0;
|
||||
if (vkl.vkEnumerateInstanceExtensionProperties(layer, &extCount, nullptr) != VK_SUCCESS)
|
||||
throw DxvkError("ExtensionSet::addInstanceExtensions: Failed to query instance extensions");
|
||||
|
||||
std::vector<VkExtensionProperties> extensions(extCount);
|
||||
if (vkl.vkEnumerateInstanceExtensionProperties(layer, &extCount, extensions.data()) != VK_SUCCESS)
|
||||
throw DxvkError("ExtensionSet::addInstanceExtensions: Failed to query instance extensions");
|
||||
|
||||
for (const auto& ext : extensions)
|
||||
m_names.insert(ext.extensionName);
|
||||
}
|
||||
|
||||
}
|
103
src/dxvk/vulkan/dxvk_vulkan_extensions.h
Normal file
103
src/dxvk/vulkan/dxvk_vulkan_extensions.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "dxvk_vulkan_loader.h"
|
||||
|
||||
#include "../../util/util_error.h"
|
||||
#include "../../util/util_string.h"
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
/**
|
||||
* \brief Name list
|
||||
*
|
||||
* Stores a list of extension or layer names.
|
||||
* Note that only name constants may be added
|
||||
* to a name list. Adding dynamically allocated
|
||||
* strings will result in udefined behaviour.
|
||||
*/
|
||||
class NameList {
|
||||
|
||||
public:
|
||||
|
||||
void add(const char* name) {
|
||||
m_list.push_back(name);
|
||||
}
|
||||
|
||||
auto name(size_t i) const {
|
||||
return m_list[i];
|
||||
}
|
||||
|
||||
auto names() const { return m_list.data(); }
|
||||
auto count() const { return m_list.size(); }
|
||||
|
||||
private:
|
||||
|
||||
std::vector<const char*> m_list;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Name set
|
||||
*
|
||||
* Stores a set of supported layers or extensions and
|
||||
* provides methods to query their support status.
|
||||
*/
|
||||
class NameSet {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Checks whether an extension or layer is supported
|
||||
*
|
||||
* \param [in] name The layer or extension name
|
||||
* \returns \c true if the entity is supported
|
||||
*/
|
||||
bool supports(const char* name) const;
|
||||
|
||||
/**
|
||||
* \brief Enumerates instance layers
|
||||
*
|
||||
* \param [in] vkl Vulkan library functions
|
||||
* \returns Available instance layers
|
||||
*/
|
||||
static NameSet enumerateInstanceLayers(
|
||||
const LibraryFn& vkl);
|
||||
|
||||
/**
|
||||
* \brief Enumerates instance extensions
|
||||
*
|
||||
* \param [in] vkl Vulkan library functions
|
||||
* \param [in] layers Enabled instance layers
|
||||
* \returns Available instance extensions
|
||||
*/
|
||||
static NameSet enumerateInstanceExtensions(
|
||||
const LibraryFn& vkl,
|
||||
const NameList& layers);
|
||||
|
||||
/**
|
||||
* \brief Enumerates device extensions
|
||||
*
|
||||
* \param [in] vki Vulkan instance functions
|
||||
* \param [in] device The physical device
|
||||
* \returns Available device extensions
|
||||
*/
|
||||
static NameSet enumerateDeviceExtensions(
|
||||
const InstanceFn& vki,
|
||||
VkPhysicalDevice device);
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_set<std::string> m_names;
|
||||
|
||||
void addInstanceLayerExtensions(
|
||||
const LibraryFn& vkl,
|
||||
const char* layer);
|
||||
|
||||
};
|
||||
|
||||
}
|
43
src/dxvk/vulkan/dxvk_vulkan_loader.cpp
Normal file
43
src/dxvk/vulkan/dxvk_vulkan_loader.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "dxvk_vulkan_loader.h"
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
PFN_vkVoidFunction LibraryLoader::sym(const char* name) const {
|
||||
return ::vkGetInstanceProcAddr(nullptr, name);
|
||||
}
|
||||
|
||||
|
||||
InstanceLoader::InstanceLoader(VkInstance instance)
|
||||
: m_instance(instance) { }
|
||||
|
||||
|
||||
PFN_vkVoidFunction InstanceLoader::sym(const char* name) const {
|
||||
return ::vkGetInstanceProcAddr(m_instance, name);
|
||||
}
|
||||
|
||||
|
||||
DeviceLoader::DeviceLoader(VkInstance instance, VkDevice device)
|
||||
: m_getDeviceProcAddr(reinterpret_cast<PFN_vkGetDeviceProcAddr>(
|
||||
::vkGetInstanceProcAddr(instance, "vkGetDeviceProcAddr"))),
|
||||
m_device(device) { }
|
||||
|
||||
|
||||
PFN_vkVoidFunction DeviceLoader::sym(const char* name) const {
|
||||
return m_getDeviceProcAddr(m_device, name);
|
||||
}
|
||||
|
||||
|
||||
LibraryFn::LibraryFn() { }
|
||||
LibraryFn::~LibraryFn() { }
|
||||
|
||||
|
||||
InstanceFn::InstanceFn(VkInstance instance)
|
||||
: InstanceLoader(instance) { }
|
||||
InstanceFn::~InstanceFn() { }
|
||||
|
||||
|
||||
DeviceFn::DeviceFn(VkInstance instance, VkDevice device)
|
||||
: DeviceLoader(instance, device) { }
|
||||
DeviceFn::~DeviceFn() { }
|
||||
|
||||
}
|
267
src/dxvk/vulkan/dxvk_vulkan_loader.h
Normal file
267
src/dxvk/vulkan/dxvk_vulkan_loader.h
Normal file
@ -0,0 +1,267 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../util/rc/util_rc.h"
|
||||
#include "../../util/rc/util_rc_ptr.h"
|
||||
|
||||
#include "dxvk_vulkan_loader_fn.h"
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
/**
|
||||
* \brief Vulkan library loader
|
||||
*
|
||||
* Provides methods to load Vulkan functions that
|
||||
* can be called before creating a instance.
|
||||
*/
|
||||
struct LibraryLoader : public RcObject {
|
||||
PFN_vkVoidFunction sym(const char* name) const;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Vulkan instance loader
|
||||
*
|
||||
* Loads Vulkan functions that can be
|
||||
* called for a specific instance.
|
||||
*/
|
||||
struct InstanceLoader : public RcObject {
|
||||
InstanceLoader(VkInstance instance);
|
||||
PFN_vkVoidFunction sym(const char* name) const;
|
||||
VkInstance instance() const { return m_instance; }
|
||||
private:
|
||||
const VkInstance m_instance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Vulkan device loader
|
||||
*
|
||||
* Loads Vulkan functions for a
|
||||
* specific device.
|
||||
*/
|
||||
struct DeviceLoader : public RcObject {
|
||||
DeviceLoader(VkInstance instance, VkDevice device);
|
||||
PFN_vkVoidFunction sym(const char* name) const;
|
||||
VkDevice device() const { return m_device; }
|
||||
private:
|
||||
const PFN_vkGetDeviceProcAddr m_getDeviceProcAddr;
|
||||
const VkDevice m_device;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Vulkan library functions
|
||||
*
|
||||
* Vulkan functions that are called before
|
||||
* creating an actual Vulkan instance.
|
||||
*/
|
||||
struct LibraryFn : LibraryLoader {
|
||||
LibraryFn();
|
||||
~LibraryFn();
|
||||
|
||||
VULKAN_FN(vkCreateInstance);
|
||||
VULKAN_FN(vkEnumerateInstanceLayerProperties);
|
||||
VULKAN_FN(vkEnumerateInstanceExtensionProperties);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Vulkan instance functions
|
||||
*
|
||||
* Vulkan functions for a given instance that
|
||||
* are independent of any Vulkan devices.
|
||||
*/
|
||||
struct InstanceFn : InstanceLoader {
|
||||
InstanceFn(VkInstance instance);
|
||||
~InstanceFn();
|
||||
|
||||
VULKAN_FN(vkCreateDevice);
|
||||
VULKAN_FN(vkDestroyInstance);
|
||||
VULKAN_FN(vkEnumerateDeviceExtensionProperties);
|
||||
VULKAN_FN(vkEnumeratePhysicalDevices);
|
||||
VULKAN_FN(vkGetPhysicalDeviceFeatures);
|
||||
VULKAN_FN(vkGetPhysicalDeviceFormatProperties);
|
||||
VULKAN_FN(vkGetPhysicalDeviceImageFormatProperties);
|
||||
VULKAN_FN(vkGetPhysicalDeviceMemoryProperties);
|
||||
VULKAN_FN(vkGetPhysicalDeviceProperties);
|
||||
VULKAN_FN(vkGetPhysicalDeviceQueueFamilyProperties);
|
||||
VULKAN_FN(vkGetPhysicalDeviceSparseImageFormatProperties);
|
||||
|
||||
#ifdef VK_KHR_surface
|
||||
#ifdef VK_USE_PLATFORM_XCB_KHR
|
||||
VULKAN_FN(vkCreateXcbSurfaceKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceXcbPresentationSupportKHR);
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_XLIB_KHR
|
||||
VULKAN_FN(vkCreateXlibSurfaceKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceXlibPresentationSupportKHR);
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
|
||||
VULKAN_FN(vkCreateWaylandSurfaceKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceWaylandPresentationSupportKHR);
|
||||
#endif
|
||||
|
||||
#ifdef VK_USE_PLATFORM_WIN32_KHR
|
||||
VULKAN_FN(vkCreateWin32SurfaceKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceWin32PresentationSupportKHR);
|
||||
#endif
|
||||
|
||||
VULKAN_FN(vkDestroySurfaceKHR);
|
||||
|
||||
VULKAN_FN(vkGetPhysicalDeviceSurfaceSupportKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceSurfaceFormatsKHR);
|
||||
VULKAN_FN(vkGetPhysicalDeviceSurfacePresentModesKHR);
|
||||
#endif
|
||||
|
||||
#ifdef VK_EXT_debug_report
|
||||
VULKAN_FN(vkCreateDebugReportCallbackEXT);
|
||||
VULKAN_FN(vkDestroyDebugReportCallbackEXT);
|
||||
VULKAN_FN(vkDebugReportMessageEXT);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Vulkan device functions
|
||||
*
|
||||
* Vulkan functions for a specific Vulkan device.
|
||||
* This ensures that no slow dispatch code is executed.
|
||||
*/
|
||||
struct DeviceFn : DeviceLoader {
|
||||
DeviceFn(VkInstance instance, VkDevice device);
|
||||
~DeviceFn();
|
||||
|
||||
VULKAN_FN(vkDestroyDevice);
|
||||
VULKAN_FN(vkGetDeviceQueue);
|
||||
VULKAN_FN(vkQueueSubmit);
|
||||
VULKAN_FN(vkQueueWaitIdle);
|
||||
VULKAN_FN(vkDeviceWaitIdle);
|
||||
VULKAN_FN(vkAllocateMemory);
|
||||
VULKAN_FN(vkFreeMemory);
|
||||
VULKAN_FN(vkMapMemory);
|
||||
VULKAN_FN(vkUnmapMemory);
|
||||
VULKAN_FN(vkFlushMappedMemoryRanges);
|
||||
VULKAN_FN(vkInvalidateMappedMemoryRanges);
|
||||
VULKAN_FN(vkGetDeviceMemoryCommitment);
|
||||
VULKAN_FN(vkBindBufferMemory);
|
||||
VULKAN_FN(vkBindImageMemory);
|
||||
VULKAN_FN(vkGetBufferMemoryRequirements);
|
||||
VULKAN_FN(vkGetImageMemoryRequirements);
|
||||
VULKAN_FN(vkGetImageSparseMemoryRequirements);
|
||||
VULKAN_FN(vkQueueBindSparse);
|
||||
VULKAN_FN(vkCreateFence);
|
||||
VULKAN_FN(vkDestroyFence);
|
||||
VULKAN_FN(vkResetFences);
|
||||
VULKAN_FN(vkGetFenceStatus);
|
||||
VULKAN_FN(vkWaitForFences);
|
||||
VULKAN_FN(vkCreateSemaphore);
|
||||
VULKAN_FN(vkDestroySemaphore);
|
||||
VULKAN_FN(vkCreateEvent);
|
||||
VULKAN_FN(vkDestroyEvent);
|
||||
VULKAN_FN(vkGetEventStatus);
|
||||
VULKAN_FN(vkSetEvent);
|
||||
VULKAN_FN(vkResetEvent);
|
||||
VULKAN_FN(vkCreateQueryPool);
|
||||
VULKAN_FN(vkDestroyQueryPool);
|
||||
VULKAN_FN(vkGetQueryPoolResults);
|
||||
VULKAN_FN(vkCreateBuffer);
|
||||
VULKAN_FN(vkDestroyBuffer);
|
||||
VULKAN_FN(vkCreateBufferView);
|
||||
VULKAN_FN(vkDestroyBufferView);
|
||||
VULKAN_FN(vkCreateImage);
|
||||
VULKAN_FN(vkDestroyImage);
|
||||
VULKAN_FN(vkGetImageSubresourceLayout);
|
||||
VULKAN_FN(vkCreateImageView);
|
||||
VULKAN_FN(vkDestroyImageView);
|
||||
VULKAN_FN(vkCreateShaderModule);
|
||||
VULKAN_FN(vkDestroyShaderModule);
|
||||
VULKAN_FN(vkCreatePipelineCache);
|
||||
VULKAN_FN(vkDestroyPipelineCache);
|
||||
VULKAN_FN(vkGetPipelineCacheData);
|
||||
VULKAN_FN(vkMergePipelineCaches);
|
||||
VULKAN_FN(vkCreateGraphicsPipelines);
|
||||
VULKAN_FN(vkCreateComputePipelines);
|
||||
VULKAN_FN(vkDestroyPipeline);
|
||||
VULKAN_FN(vkCreatePipelineLayout);
|
||||
VULKAN_FN(vkDestroyPipelineLayout);
|
||||
VULKAN_FN(vkCreateSampler);
|
||||
VULKAN_FN(vkDestroySampler);
|
||||
VULKAN_FN(vkCreateDescriptorSetLayout);
|
||||
VULKAN_FN(vkDestroyDescriptorSetLayout);
|
||||
VULKAN_FN(vkCreateDescriptorPool);
|
||||
VULKAN_FN(vkDestroyDescriptorPool);
|
||||
VULKAN_FN(vkResetDescriptorPool);
|
||||
VULKAN_FN(vkAllocateDescriptorSets);
|
||||
VULKAN_FN(vkFreeDescriptorSets);
|
||||
VULKAN_FN(vkUpdateDescriptorSets);
|
||||
VULKAN_FN(vkCreateFramebuffer);
|
||||
VULKAN_FN(vkDestroyFramebuffer);
|
||||
VULKAN_FN(vkCreateRenderPass);
|
||||
VULKAN_FN(vkDestroyRenderPass);
|
||||
VULKAN_FN(vkGetRenderAreaGranularity);
|
||||
VULKAN_FN(vkCreateCommandPool);
|
||||
VULKAN_FN(vkDestroyCommandPool);
|
||||
VULKAN_FN(vkResetCommandPool);
|
||||
VULKAN_FN(vkAllocateCommandBuffers);
|
||||
VULKAN_FN(vkFreeCommandBuffers);
|
||||
VULKAN_FN(vkBeginCommandBuffer);
|
||||
VULKAN_FN(vkEndCommandBuffer);
|
||||
VULKAN_FN(vkResetCommandBuffer);
|
||||
VULKAN_FN(vkCmdBindPipeline);
|
||||
VULKAN_FN(vkCmdSetViewport);
|
||||
VULKAN_FN(vkCmdSetScissor);
|
||||
VULKAN_FN(vkCmdSetLineWidth);
|
||||
VULKAN_FN(vkCmdSetDepthBias);
|
||||
VULKAN_FN(vkCmdSetBlendConstants);
|
||||
VULKAN_FN(vkCmdSetDepthBounds);
|
||||
VULKAN_FN(vkCmdSetStencilCompareMask);
|
||||
VULKAN_FN(vkCmdSetStencilWriteMask);
|
||||
VULKAN_FN(vkCmdSetStencilReference);
|
||||
VULKAN_FN(vkCmdBindDescriptorSets);
|
||||
VULKAN_FN(vkCmdBindIndexBuffer);
|
||||
VULKAN_FN(vkCmdBindVertexBuffers);
|
||||
VULKAN_FN(vkCmdDraw);
|
||||
VULKAN_FN(vkCmdDrawIndexed);
|
||||
VULKAN_FN(vkCmdDrawIndirect);
|
||||
VULKAN_FN(vkCmdDrawIndexedIndirect);
|
||||
VULKAN_FN(vkCmdDispatch);
|
||||
VULKAN_FN(vkCmdDispatchIndirect);
|
||||
VULKAN_FN(vkCmdCopyBuffer);
|
||||
VULKAN_FN(vkCmdCopyImage);
|
||||
VULKAN_FN(vkCmdBlitImage);
|
||||
VULKAN_FN(vkCmdCopyBufferToImage);
|
||||
VULKAN_FN(vkCmdCopyImageToBuffer);
|
||||
VULKAN_FN(vkCmdUpdateBuffer);
|
||||
VULKAN_FN(vkCmdFillBuffer);
|
||||
VULKAN_FN(vkCmdClearColorImage);
|
||||
VULKAN_FN(vkCmdClearDepthStencilImage);
|
||||
VULKAN_FN(vkCmdClearAttachments);
|
||||
VULKAN_FN(vkCmdResolveImage);
|
||||
VULKAN_FN(vkCmdSetEvent);
|
||||
VULKAN_FN(vkCmdResetEvent);
|
||||
VULKAN_FN(vkCmdWaitEvents);
|
||||
VULKAN_FN(vkCmdPipelineBarrier);
|
||||
VULKAN_FN(vkCmdBeginQuery);
|
||||
VULKAN_FN(vkCmdEndQuery);
|
||||
VULKAN_FN(vkCmdResetQueryPool);
|
||||
VULKAN_FN(vkCmdWriteTimestamp);
|
||||
VULKAN_FN(vkCmdCopyQueryPoolResults);
|
||||
VULKAN_FN(vkCmdPushConstants);
|
||||
VULKAN_FN(vkCmdBeginRenderPass);
|
||||
VULKAN_FN(vkCmdNextSubpass);
|
||||
VULKAN_FN(vkCmdEndRenderPass);
|
||||
VULKAN_FN(vkCmdExecuteCommands);
|
||||
|
||||
#ifdef VK_KHR_swapchain
|
||||
VULKAN_FN(vkCreateSwapchainKHR);
|
||||
VULKAN_FN(vkDestroySwapchainKHR);
|
||||
VULKAN_FN(vkGetSwapchainImagesKHR);
|
||||
VULKAN_FN(vkAcquireNextImageKHR);
|
||||
VULKAN_FN(vkQueuePresentKHR);
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
48
src/dxvk/vulkan/dxvk_vulkan_loader_fn.h
Normal file
48
src/dxvk/vulkan/dxvk_vulkan_loader_fn.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#define VULKAN_FN(name) \
|
||||
VulkanFn<::PFN_ ## name> name = sym(#name)
|
||||
|
||||
namespace dxvk::vk {
|
||||
|
||||
template<typename Fn>
|
||||
class VulkanFn;
|
||||
|
||||
/**
|
||||
* \brief Vulkan function
|
||||
*
|
||||
* Wraps an Vulkan function pointer and provides
|
||||
* a call operator using the correct types.
|
||||
*/
|
||||
template<typename Ret, typename... Args>
|
||||
class VulkanFn<Ret (VKAPI_PTR*)(Args...)> {
|
||||
using Fn = Ret (VKAPI_PTR*)(Args...);
|
||||
public:
|
||||
|
||||
VulkanFn() { }
|
||||
VulkanFn(Fn ptr)
|
||||
: m_fn(ptr) { }
|
||||
|
||||
VulkanFn(PFN_vkVoidFunction ptr)
|
||||
: m_fn(reinterpret_cast<Fn>(ptr)) { }
|
||||
|
||||
/**
|
||||
* \brief Invokes Vulkan function
|
||||
*
|
||||
* \param [in] args Arguments
|
||||
* \returns Function return value
|
||||
*/
|
||||
Ret operator () (Args... args) const {
|
||||
return (*m_fn)(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Fn m_fn = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
2
src/meson.build
Normal file
2
src/meson.build
Normal file
@ -0,0 +1,2 @@
|
||||
subdir('util')
|
||||
subdir('dxvk')
|
26
src/util/log/log.cpp
Normal file
26
src/util/log/log.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "log.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
Log::Log(const std::string& filename)
|
||||
: m_stream(filename, std::ios_base::out | std::ios_base::trunc) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Log::~Log() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Log::log(const std::string& message) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
std::cerr << message << std::endl;
|
||||
std::cerr.flush();
|
||||
|
||||
m_stream << message << std::endl;
|
||||
m_stream.flush();
|
||||
}
|
||||
|
||||
}
|
40
src/util/log/log.h
Normal file
40
src/util/log/log.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "../rc/util_rc.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Logger
|
||||
*
|
||||
* Logs messages generated by DXVK and
|
||||
* the client APIs using DXVK.
|
||||
*/
|
||||
class Log : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
Log(const std::string& filename);
|
||||
~Log();
|
||||
|
||||
/**
|
||||
* \brief Adds a message to the log
|
||||
*
|
||||
* Prints the message to stderr and appends
|
||||
* it to the log file at the same time.
|
||||
*/
|
||||
void log(const std::string& message);
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::fstream m_stream;
|
||||
|
||||
};
|
||||
|
||||
}
|
6
src/util/meson.build
Normal file
6
src/util/meson.build
Normal file
@ -0,0 +1,6 @@
|
||||
util_src = files([
|
||||
'log/log.cpp',
|
||||
])
|
||||
|
||||
util_lib = static_library('util', util_src,
|
||||
include_directories : [ dxvk_include_path ])
|
36
src/util/rc/util_rc.h
Normal file
36
src/util/rc/util_rc.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Reference-counted object
|
||||
*/
|
||||
class RcObject {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Increments reference count
|
||||
* \returns New reference count
|
||||
*/
|
||||
uint32_t incRef() {
|
||||
return ++m_refCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Decrements reference count
|
||||
* \returns New reference count
|
||||
*/
|
||||
uint32_t decRef() {
|
||||
return --m_refCount;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::atomic<uint32_t> m_refCount = { 0u };
|
||||
|
||||
};
|
||||
|
||||
}
|
126
src/util/rc/util_rc_ptr.h
Normal file
126
src/util/rc/util_rc_ptr.h
Normal file
@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Pointer for reference-counted objects
|
||||
*
|
||||
* This only requires the given type to implement \c incRef
|
||||
* and \c decRef methods that adjust the reference count.
|
||||
* \tparam T Object type
|
||||
*/
|
||||
template<typename T>
|
||||
class Rc {
|
||||
template<typename Tx>
|
||||
friend class Rc;
|
||||
public:
|
||||
|
||||
Rc() { }
|
||||
Rc(std::nullptr_t) { }
|
||||
|
||||
Rc(T* object)
|
||||
: m_object(object) {
|
||||
this->incRef();
|
||||
}
|
||||
|
||||
Rc(const Rc& other)
|
||||
: m_object(other.m_object) {
|
||||
this->incRef();
|
||||
}
|
||||
|
||||
template<typename Tx>
|
||||
Rc(const Rc<Tx>& other)
|
||||
: m_object(other.m_object) {
|
||||
this->incRef();
|
||||
}
|
||||
|
||||
Rc(Rc&& other)
|
||||
: m_object(other.m_object) {
|
||||
other.m_object = nullptr;
|
||||
}
|
||||
|
||||
template<typename Tx>
|
||||
Rc(Rc<Tx>&& other)
|
||||
: m_object(other.m_object) {
|
||||
other.m_object = nullptr;
|
||||
}
|
||||
|
||||
Rc& operator = (std::nullptr_t) {
|
||||
this->decRef();
|
||||
m_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rc& operator = (const Rc& other) {
|
||||
other.incRef();
|
||||
this->decRef();
|
||||
m_object = other.m_object;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Tx>
|
||||
Rc& operator = (const Rc<Tx>& other) {
|
||||
other.incRef();
|
||||
this->decRef();
|
||||
m_object = other.m_object;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rc& operator = (Rc&& other) {
|
||||
this->decRef();
|
||||
this->m_object = other.m_object;
|
||||
other.m_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Tx>
|
||||
Rc& operator = (Rc<Tx>&& other) {
|
||||
this->decRef();
|
||||
this->m_object = other.m_object;
|
||||
other.m_object = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Rc() {
|
||||
this->decRef();
|
||||
}
|
||||
|
||||
T& operator * () const { return *m_object; }
|
||||
T* operator -> () const { return m_object; }
|
||||
T* ptr() const { return m_object; }
|
||||
|
||||
bool operator == (const Rc& other) const { return m_object == other.m_object; }
|
||||
bool operator != (const Rc& other) const { return m_object != other.m_object; }
|
||||
|
||||
bool operator == (std::nullptr_t) const { return m_object == nullptr; }
|
||||
bool operator != (std::nullptr_t) const { return m_object != nullptr; }
|
||||
|
||||
private:
|
||||
|
||||
T* m_object = nullptr;
|
||||
|
||||
void incRef() const {
|
||||
if (m_object != nullptr)
|
||||
m_object->incRef();
|
||||
}
|
||||
|
||||
void decRef() const {
|
||||
if (m_object != nullptr) {
|
||||
if (m_object->decRef() == 0)
|
||||
delete m_object;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct RcHash {
|
||||
size_t operator () (const Rc<T>& rc) const {
|
||||
return std::hash<T*>()(rc.ptr());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
31
src/util/util_error.h
Normal file
31
src/util/util_error.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXVK error
|
||||
*
|
||||
* A generic exception class that stores a
|
||||
* message. Exceptions should be logged.
|
||||
*/
|
||||
class DxvkError {
|
||||
|
||||
public:
|
||||
|
||||
DxvkError() { }
|
||||
DxvkError(std::string&& message)
|
||||
: m_message(std::move(message)) { }
|
||||
|
||||
const std::string& message() const {
|
||||
return m_message;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::string m_message;
|
||||
|
||||
};
|
||||
|
||||
}
|
12
src/util/util_math.h
Normal file
12
src/util/util_math.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template<typename T>
|
||||
T clamp(T n, T lo, T hi) {
|
||||
if (n < lo) return lo;
|
||||
if (n > hi) return hi;
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
23
src/util/util_string.h
Normal file
23
src/util/util_string.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
namespace dxvk::str {
|
||||
|
||||
inline void format1(std::stringstream&) { }
|
||||
|
||||
template<typename T, typename... Tx>
|
||||
void format1(std::stringstream& str, const T& arg, const Tx&... args) {
|
||||
str << arg;
|
||||
format1(str, args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string format(const Args&... args) {
|
||||
std::stringstream stream;
|
||||
format1(stream, args...);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
}
|
3
tests/dxvk/meson.build
Normal file
3
tests/dxvk/meson.build
Normal file
@ -0,0 +1,3 @@
|
||||
test_dxvk_deps = [ dxvk_dep ]
|
||||
|
||||
executable('dxvk-triangle', files('test_dxvk_triangle.cpp'), dependencies: test_dxvk_deps)
|
128
tests/dxvk/test_dxvk_triangle.cpp
Normal file
128
tests/dxvk/test_dxvk_triangle.cpp
Normal file
@ -0,0 +1,128 @@
|
||||
#include <dxvk_framebuffer.h>
|
||||
#include <dxvk_instance.h>
|
||||
#include <dxvk_main.h>
|
||||
#include <dxvk_surface.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
using namespace dxvk;
|
||||
|
||||
class TriangleApp {
|
||||
|
||||
public:
|
||||
|
||||
TriangleApp(HINSTANCE instance, HWND window)
|
||||
: m_dxvkInstance (new DxvkInstance()),
|
||||
m_dxvkAdapter (m_dxvkInstance->enumAdapters().at(0)),
|
||||
m_dxvkDevice (m_dxvkAdapter->createDevice()),
|
||||
m_dxvkSurface (m_dxvkAdapter->createSurface(instance, window)),
|
||||
m_dxvkSwapchain (m_dxvkDevice->createSwapchain(m_dxvkSurface,
|
||||
DxvkSwapchainProperties {
|
||||
VkSurfaceFormatKHR { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
|
||||
VK_PRESENT_MODE_FIFO_KHR,
|
||||
VkExtent2D { 640, 480 },
|
||||
})),
|
||||
m_dxvkContext (m_dxvkDevice->createContext()),
|
||||
m_dxvkCommandList (m_dxvkDevice->createCommandList()) {
|
||||
|
||||
}
|
||||
|
||||
~TriangleApp() {
|
||||
|
||||
}
|
||||
|
||||
void run() {
|
||||
auto sync1 = m_dxvkDevice->createSemaphore();
|
||||
auto sync2 = m_dxvkDevice->createSemaphore();
|
||||
|
||||
m_dxvkContext->beginRecording(m_dxvkCommandList);
|
||||
m_dxvkContext->setFramebuffer(
|
||||
m_dxvkSwapchain->getFramebuffer(sync1));
|
||||
m_dxvkContext->endRecording();
|
||||
|
||||
auto fence = m_dxvkDevice->submitCommandList(
|
||||
m_dxvkCommandList, sync1, sync2);
|
||||
m_dxvkSwapchain->present(sync2);
|
||||
m_dxvkDevice->waitForIdle();
|
||||
m_dxvkCommandList->reset();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkInstance> m_dxvkInstance;
|
||||
Rc<DxvkAdapter> m_dxvkAdapter;
|
||||
Rc<DxvkDevice> m_dxvkDevice;
|
||||
Rc<DxvkSurface> m_dxvkSurface;
|
||||
Rc<DxvkSwapchain> m_dxvkSwapchain;
|
||||
Rc<DxvkContext> m_dxvkContext;
|
||||
Rc<DxvkCommandList> m_dxvkCommandList;
|
||||
|
||||
Rc<DxvkBuffer> m_vertexBuffer;
|
||||
|
||||
};
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND hWnd,
|
||||
UINT message,
|
||||
WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine,
|
||||
int nCmdShow) {
|
||||
HWND hWnd;
|
||||
WNDCLASSEXW wc;
|
||||
ZeroMemory(&wc, sizeof(WNDCLASSEX));
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = WindowProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
|
||||
wc.lpszClassName = L"WindowClass1";
|
||||
RegisterClassExW(&wc);
|
||||
|
||||
hWnd = CreateWindowExW(0,
|
||||
L"WindowClass1",
|
||||
L"Our First Windowed Program",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
300, 300,
|
||||
640, 480,
|
||||
nullptr,
|
||||
nullptr,
|
||||
hInstance,
|
||||
nullptr);
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
|
||||
MSG msg;
|
||||
|
||||
TriangleApp app(hInstance, hWnd);
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
|
||||
if (msg.message == WM_QUIT)
|
||||
return msg.wParam;
|
||||
} else {
|
||||
app.run();
|
||||
}
|
||||
}
|
||||
} catch (const dxvk::DxvkError& e) {
|
||||
dxvk::log(e.message());
|
||||
return msg.wParam;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_CLOSE:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
1
tests/meson.build
Normal file
1
tests/meson.build
Normal file
@ -0,0 +1 @@
|
||||
subdir('dxvk')
|
Loading…
x
Reference in New Issue
Block a user