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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions code/client/launcher/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,9 @@ int RealMain()
loadSystemDll(L"\\d3d11.dll");

#ifdef IS_RDR3
// D3D12/RedM equivilant of the code above.
loadSystemDll(L"\\d3d12.dll");

// RedM attempts to load vulkan bundled with CEF first which on some systems leads to various issues
loadSystemDll(L"\\vulkan-1.dll");
#endif
Expand Down
2 changes: 0 additions & 2 deletions code/components/glue/src/ConnectToNative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -964,7 +964,6 @@ static InitFunction initFunction([] ()
{
static bool done = ([]
{
#ifdef GTA_FIVE
std::thread([]
{
UiDone();
Expand All @@ -977,7 +976,6 @@ static InitFunction initFunction([] ()
SetForegroundWindow(hWnd);
})
.detach();
#endif

MarkNuiLoaded();

Expand Down
89 changes: 12 additions & 77 deletions code/components/glue/src/GtaNui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,98 +628,33 @@ fwRefContainer<GITexture> GtaNuiInterface::CreateTextureFromShareHandle(HANDLE s
// meanwhile in Vulkan, this is infinitely annoying
return new GtaNuiTexture([shareHandle, width, height](GtaNuiTexture* texture)
{
std::vector<uint8_t> pixelData(size_t(width) * size_t(height) * 4);

rage::grcTextureReference reference;
memset(&reference, 0, sizeof(reference));
reference.width = width;
reference.height = height;
reference.depth = 1;
reference.stride = width * 4;
reference.format = 11;
reference.pixelData = (uint8_t*)pixelData.data();
rage::grcManualTextureDef textureDef;
memset(&textureDef, 0, sizeof(textureDef));
textureDef.isStaging = 0;
textureDef.arraySize = 1;

auto texRef = (rage::sga::TextureVK*)rage::grcTextureFactory::getInstance()->createImage(&reference, nullptr);
auto texRef = (rage::sga::TextureVK*)rage::grcTextureFactory::getInstance()->createManualTexture(width, height, 2, nullptr, true, &textureDef);

if (texRef)
{
rage::sga::Driver_Destroy_Texture(texRef);

// Vulkan API magic time (copy/pasted from samples on GH)
VkDevice device = (VkDevice)GetGraphicsDriverHandle();

VkExtent3D Extent = { width, height, 1 };

VkExternalMemoryImageCreateInfo ExternalMemoryImageCreateInfo = { VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO };
ExternalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
VkImageCreateInfo ImageCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
ImageCreateInfo.pNext = &ExternalMemoryImageCreateInfo;
ImageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
ImageCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
ImageCreateInfo.extent = Extent;
ImageCreateInfo.mipLevels = 1;
ImageCreateInfo.arrayLayers = 1;
ImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
ImageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
ImageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
ImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
ImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

VkPhysicalDevice physicalDevice = GetVulkanPhysicalHandle();

VkImage Image;
VkResult result = vkCreateImage(device, &ImageCreateInfo, nullptr, &Image);

if (result != VK_SUCCESS)
{
FatalError("Failed to create a Vulkan image. VkResult: %s", ResultToString(result));
}

VkMemoryRequirements MemoryRequirements;
vkGetImageMemoryRequirements(device, Image, &MemoryRequirements);

VkMemoryDedicatedAllocateInfo MemoryDedicatedAllocateInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO };
MemoryDedicatedAllocateInfo.image = Image;
VkImportMemoryWin32HandleInfoKHR ImportMemoryWin32HandleInfo = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR };
ImportMemoryWin32HandleInfo.pNext = &MemoryDedicatedAllocateInfo;
ImportMemoryWin32HandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
ImportMemoryWin32HandleInfo.handle = shareHandle;
VkMemoryAllocateInfo MemoryAllocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
MemoryAllocateInfo.pNext = &ImportMemoryWin32HandleInfo;
MemoryAllocateInfo.allocationSize = MemoryRequirements.size;

unsigned long typeIndex;
_BitScanForward(&typeIndex, MemoryRequirements.memoryTypeBits);
MemoryAllocateInfo.memoryTypeIndex = typeIndex;

static auto _vkBindImageMemory2 = (PFN_vkBindImageMemory2)vkGetDeviceProcAddr(device, "vkBindImageMemory2");

VkDeviceMemory ImageMemory;
result = vkAllocateMemory(device, &MemoryAllocateInfo, nullptr, &ImageMemory);

if (result != VK_SUCCESS)
{
FatalErrorNoReport("Failed to allocate memory for Vulkan. VkResult: %s", ResultToString(result));
}

VkBindImageMemoryInfo BindImageMemoryInfo = { VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO };
BindImageMemoryInfo.image = Image;
BindImageMemoryInfo.memory = ImageMemory;

result = _vkBindImageMemory2(device, 1, &BindImageMemoryInfo);

if (result != VK_SUCCESS)
{
FatalErrorNoReport("Failed to bind Vulkan image memory. VkResult: %s", ResultToString(result));
}
VkDeviceMemory DeviceMemory;
CreateVKImageFromShareHandle(device, shareHandle, width, height, Image, DeviceMemory);

auto newImage = new rage::sga::TextureVK::ImageData;
//memcpy(newImage, texRef->image, sizeof(*newImage));
memset(newImage, 0, sizeof(*newImage));
// these come from a fast allocator(?)
//delete texRef->image;
texRef->image = newImage;

texRef->image->image = Image;
texRef->image->memory = ImageMemory;
texRef->image->memory = DeviceMemory;
texRef->width = width;
texRef->height = height;

rage::sga::TextureViewDesc srvDesc;
srvDesc.mipLevels = 1;
Expand Down
4 changes: 4 additions & 0 deletions code/components/rage-graphics-five/src/ReShadeFixups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ void ScanForReshades()
L"d3d10.dll",
L"d3d10_1.dll",
L"d3d11.dll",
#ifdef IS_RDR3
L"d3d12.dll",
L"vulkan-1.dll"
#endif
L"dxgi.dll" };

// try loading all dll files *from plugins/*
Expand Down
15 changes: 14 additions & 1 deletion code/components/rage-graphics-rdr3/component.lua
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
includedirs { '../../../vendor/vulkan-headers/include/' }
includedirs {
'../../../vendor/vulkan-headers/include/',
'../rage-graphics-five/include'
}

return function()
filter {}

files {
'components/rage-graphics-five/include/dxerr.h',
'components/rage-graphics-five/src/dxerr.cpp',
'components/rage-graphics-five/src/ReShadeFixups.cpp'
}
end
7 changes: 6 additions & 1 deletion code/components/rage-graphics-rdr3/include/DrawCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ enum class GraphicsAPI
extern GFX_EXPORT GraphicsAPI GetCurrentGraphicsAPI();

// VK context or D3D12 device
extern GFX_EXPORT void* GetGraphicsDriverHandle();
extern GFX_EXPORT void* GetGraphicsDriverHandle();

// VK physicalDevice
extern GFX_EXPORT VkPhysicalDevice GetVulkanPhysicalHandle();

extern GFX_EXPORT VkInstance GetVulkanInstance();

namespace rage::sga
{
Expand Down
194 changes: 191 additions & 3 deletions code/components/rage-graphics-rdr3/include/VulkanHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

#if IS_RDR3
#include <string_view>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_win32.h>
#include <DrawCommands.h>

static PFN_vkBindImageMemory2 _vkBindImageMemory2 = nullptr;
static PFN_vkGetPhysicalDeviceMemoryProperties2 _vkGetPhysicalDeviceMemoryProperties2 = nullptr;
static PFN_vkGetImageMemoryRequirements2 _vkGetImageMemoryRequirements2 = nullptr;

inline std::string_view ResultToString(VkResult result)
inline std::string ResultToString(VkResult result)
{
switch (result)
{
Expand Down Expand Up @@ -69,7 +75,189 @@ inline std::string_view ResultToString(VkResult result)
case VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT A buffer creation failed because the requested address is not available.";
default:
return std::to_string(static_cast<uint32_t>(result));
return std::to_string(static_cast<int32_t>(result));
}
}

static uint32_t FindExternalMemoryType(VkDevice device, VkPhysicalDevice physicalDevice, HANDLE handle, uint32_t typeFilter, VkMemoryPropertyFlags properties)
{
static auto _vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)vkGetDeviceProcAddr(device, "vkGetMemoryWin32HandlePropertiesKHR");

VkPhysicalDeviceMemoryProperties memProps;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProps);

for (uint32_t i = 0; i < memProps.memoryTypeCount; i++)
{
if (!(typeFilter & (1 << i)))
{
continue;
}

if ((memProps.memoryTypes[i].propertyFlags & properties) != properties)
{
continue;
}

VkMemoryWin32HandlePropertiesKHR handleProps = {
VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR
};

// Finding the first 'VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT' memory type wasn't good enough on some system configurations.
// Check the handle properties against vkGetMemoryWin32HandlePropertiesKHR and 'VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT' if its good enough
static auto _vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR)vkGetDeviceProcAddr(device, "vkGetMemoryWin32HandlePropertiesKHR");
if (_vkGetMemoryWin32HandlePropertiesKHR(device, VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT, handle, &handleProps) != VK_SUCCESS)
{
continue;
}

if (handleProps.memoryTypeBits & (1 << i))
{
return i;
}
}

trace("Failed to find suitable Vulkan external memory type.\n");
return UINT32_MAX;
}

static void CreateVKImageFromShareHandle(VkDevice& device, HANDLE handle, unsigned int width, unsigned int height, VkImage& outImage, VkDeviceMemory& outMemory)
{
outImage = VK_NULL_HANDLE;
outMemory = VK_NULL_HANDLE;

if (!_vkBindImageMemory2)
{
_vkBindImageMemory2 = (PFN_vkBindImageMemory2)vkGetDeviceProcAddr(device, "vkBindImageMemory2");
if (!_vkBindImageMemory2)
{
FatalError("Unable to find 'vkBindImageMemory2' in vulkan.");
}
}

if (!_vkGetPhysicalDeviceMemoryProperties2)
{
_vkGetPhysicalDeviceMemoryProperties2 = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetInstanceProcAddr((VkInstance)GetVulkanInstance(), "vkGetPhysicalDeviceMemoryProperties2");
if (!_vkGetPhysicalDeviceMemoryProperties2)
{
FatalError("Unable to find 'vkGetPhysicalDeviceMemoryProperties2' in vulkan.");
}
}

if (!_vkGetImageMemoryRequirements2)
{
_vkGetImageMemoryRequirements2 = (PFN_vkGetImageMemoryRequirements2)vkGetDeviceProcAddr(device, "vkGetImageMemoryRequirements2");
if (!_vkGetImageMemoryRequirements2)
{
FatalError("Unable to find 'vkGetImageMemoryRequirements2' in vulkan.");
}
}

VkExternalMemoryImageCreateInfo externalMemoryInfo = {};
externalMemoryInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
externalMemoryInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;

VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.pNext = &externalMemoryInfo;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
imageInfo.extent = { width, height, 1 };
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;

VkResult result = vkCreateImage(device, &imageInfo, nullptr, &outImage);

if (result != VK_SUCCESS)
{
FatalError("Failed to create a Vulkan image. VkResult: %s", ResultToString(result));
outImage = VK_NULL_HANDLE;
outMemory = VK_NULL_HANDLE;
return;
}

VkMemoryDedicatedRequirements dedicatedReqs = {};
dedicatedReqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;

VkMemoryRequirements2 memReqs2 = {};
memReqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
memReqs2.pNext = &dedicatedReqs;

VkImageMemoryRequirementsInfo2 memReqsInfo = {};
memReqsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
memReqsInfo.image = outImage;

_vkGetImageMemoryRequirements2(device, &memReqsInfo, &memReqs2);

if (dedicatedReqs.requiresDedicatedAllocation == VK_FALSE && dedicatedReqs.prefersDedicatedAllocation == VK_FALSE)
{
// Dedicated allocation should either be required or preferred.
FatalError("Vulkan cannot allocate D3D11 Shared texture.");
vkDestroyImage(device, outImage, nullptr);
outImage = VK_NULL_HANDLE;
outMemory = VK_NULL_HANDLE;
return;
}

VkMemoryDedicatedAllocateInfo dedicatedInfo = {};
dedicatedInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
dedicatedInfo.image = outImage;

VkImportMemoryWin32HandleInfoKHR importInfo = {};
importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR;
importInfo.pNext = &dedicatedInfo;
importInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
importInfo.handle = handle;

uint32_t memTypeIndex = FindExternalMemoryType(
device,
(VkPhysicalDevice)GetVulkanPhysicalHandle(),
handle,
memReqs2.memoryRequirements.memoryTypeBits,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);

if (memTypeIndex == UINT32_MAX)
{
// Fallback to old behaviour.
unsigned long typeIndex;
_BitScanForward(&typeIndex, memReqs2.memoryRequirements.memoryTypeBits);
memTypeIndex = (uint32_t)typeIndex;
}

VkMemoryAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.pNext = &importInfo;
allocInfo.allocationSize = memReqs2.memoryRequirements.size;
allocInfo.memoryTypeIndex = memTypeIndex;

result = vkAllocateMemory(device, &allocInfo, nullptr, &outMemory);
if (result != VK_SUCCESS)
{
FatalError("Failed to allocate memory for Vulkan shared texture. VkResult: %s", ResultToString(result));
vkDestroyImage(device, outImage, nullptr);
outImage = VK_NULL_HANDLE;
outMemory = VK_NULL_HANDLE;
return;
}

VkBindImageMemoryInfo bindInfo = {};
bindInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
bindInfo.image = outImage;
bindInfo.memory = outMemory;
bindInfo.memoryOffset = 0;

result = _vkBindImageMemory2(device, 1, &bindInfo);
if (result != VK_SUCCESS)
{
FatalError("Failed to bind Vulkan image memory. VkResult: %s", ResultToString(result));
vkFreeMemory(device, outMemory, nullptr);
vkDestroyImage(device, outImage, nullptr);
outMemory = VK_NULL_HANDLE;
outImage = VK_NULL_HANDLE;
}
}
#endif
Loading
Loading