mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-04 20:38:06 +02:00
radv: rework app workarounds implemented using internal layers
Just override the needed entrypoints. Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39549>
This commit is contained in:
parent
875b6ab951
commit
83fabf7d41
9 changed files with 177 additions and 168 deletions
123
src/amd/vulkan/layers/radv_app_workarounds.c
Normal file
123
src/amd/vulkan/layers/radv_app_workarounds.c
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright © 2026 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "vk_framebuffer.h"
|
||||
|
||||
#include "radv_cmd_buffer.h"
|
||||
#include "radv_device.h"
|
||||
#include "radv_entrypoints.h"
|
||||
#include "radv_image_view.h"
|
||||
|
||||
#include "layers/radv_app_workarounds.h"
|
||||
|
||||
/* This layer implements various application WAs that don't need to be in the core driver. */
|
||||
|
||||
/* Metro Exodus */
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
metro_exodus_GetSemaphoreCounterValue(VkDevice _device, VkSemaphore _semaphore, uint64_t *pValue)
|
||||
{
|
||||
/* See https://gitlab.freedesktop.org/mesa/mesa/-/issues/5119. */
|
||||
if (_semaphore == VK_NULL_HANDLE) {
|
||||
fprintf(stderr, "RADV: Ignoring vkGetSemaphoreCounterValue() with NULL semaphore (game bug)!\n");
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VK_FROM_HANDLE(radv_device, device, _device);
|
||||
return device->layer_dispatch.app.GetSemaphoreCounterValue(_device, _semaphore, pValue);
|
||||
}
|
||||
|
||||
/* No Man's Sky */
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
no_mans_sky_CreateImageView(VkDevice _device, const VkImageViewCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkImageView *pView)
|
||||
{
|
||||
VK_FROM_HANDLE(radv_device, device, _device);
|
||||
VkResult result;
|
||||
|
||||
result = device->layer_dispatch.app.CreateImageView(_device, pCreateInfo, pAllocator, pView);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
VK_FROM_HANDLE(radv_image_view, iview, *pView);
|
||||
|
||||
if ((iview->vk.aspects == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) &&
|
||||
(iview->vk.usage &
|
||||
(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) {
|
||||
/* No Man's Sky creates descriptors with depth/stencil aspects (only when Intel XESS is
|
||||
* enabled apparently). and this is illegal in Vulkan. Ignore them by using NULL descriptors
|
||||
* to workaroud GPU hangs.
|
||||
*/
|
||||
memset(&iview->descriptor, 0, sizeof(iview->descriptor));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Quantic Dream engine */
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
quantic_dream_UnmapMemory2(VkDevice _device, const VkMemoryUnmapInfo *pMemoryUnmapInfo)
|
||||
{
|
||||
/* Detroit: Become Human repeatedly calls vkMapMemory and vkUnmapMemory on the same buffer.
|
||||
* This creates high overhead in the kernel due to mapping operation and page fault costs.
|
||||
*
|
||||
* Simply skip the unmap call to workaround it. Mapping an already-mapped region is UB in Vulkan,
|
||||
* but will correctly return the mapped pointer on RADV.
|
||||
*/
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
/* RAGE2 */
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
rage2_CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
|
||||
VkSubpassContents contents)
|
||||
{
|
||||
VK_FROM_HANDLE(vk_framebuffer, framebuffer, pRenderPassBegin->framebuffer);
|
||||
VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
||||
|
||||
VkRenderPassBeginInfo render_pass_begin = {
|
||||
.sType = pRenderPassBegin->sType,
|
||||
.pNext = pRenderPassBegin->pNext,
|
||||
.renderPass = pRenderPassBegin->renderPass,
|
||||
.framebuffer = pRenderPassBegin->framebuffer,
|
||||
.clearValueCount = pRenderPassBegin->clearValueCount,
|
||||
.pClearValues = pRenderPassBegin->pClearValues,
|
||||
};
|
||||
|
||||
/* RAGE2 seems to incorrectly set the render area and with dynamic rendering the concept of
|
||||
* framebuffer dimensions goes away. Forcing the render area to be the framebuffer dimensions
|
||||
* restores previous logic and it fixes rendering issues.
|
||||
*/
|
||||
render_pass_begin.renderArea.offset.x = 0;
|
||||
render_pass_begin.renderArea.offset.y = 0;
|
||||
render_pass_begin.renderArea.extent.width = framebuffer->width;
|
||||
render_pass_begin.renderArea.extent.height = framebuffer->height;
|
||||
|
||||
device->layer_dispatch.app.CmdBeginRenderPass(commandBuffer, &render_pass_begin, contents);
|
||||
}
|
||||
|
||||
/* Strange Brigade (Vulkan) */
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
strange_brigade_CmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
||||
|
||||
for (uint32_t i = 0; i < pDependencyInfo->imageMemoryBarrierCount; i++) {
|
||||
VkImageMemoryBarrier2 *barrier = (VkImageMemoryBarrier2 *)&pDependencyInfo->pImageMemoryBarriers[i];
|
||||
|
||||
if (barrier->newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
|
||||
barrier->srcAccessMask == VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) {
|
||||
/* This game has a broken barrier right before present that causes rendering issues. Fix it
|
||||
* by modifying the src access mask.
|
||||
*/
|
||||
barrier->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device->layer_dispatch.app.CmdPipelineBarrier2(commandBuffer, pDependencyInfo);
|
||||
}
|
||||
27
src/amd/vulkan/layers/radv_app_workarounds.h
Normal file
27
src/amd/vulkan/layers/radv_app_workarounds.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright © 2026 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#ifndef RADV_APP_WORKAROUNDS_H
|
||||
#define RADV_APP_WORKAROUNDS_H
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL metro_exodus_GetSemaphoreCounterValue(VkDevice _device, VkSemaphore _semaphore,
|
||||
uint64_t *pValue);
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL no_mans_sky_CreateImageView(VkDevice _device, const VkImageViewCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkImageView *pView);
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL quantic_dream_UnmapMemory2(VkDevice _device, const VkMemoryUnmapInfo *pMemoryUnmapInfo);
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL rage2_CmdBeginRenderPass(VkCommandBuffer commandBuffer,
|
||||
const VkRenderPassBeginInfo *pRenderPassBegin,
|
||||
VkSubpassContents contents);
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL strange_brigade_CmdPipelineBarrier2(VkCommandBuffer commandBuffer,
|
||||
const VkDependencyInfo *pDependencyInfo);
|
||||
|
||||
#endif /* RADV_APP_WORKAROUNDS_H */
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2021 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "radv_device.h"
|
||||
#include "radv_entrypoints.h"
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
metro_exodus_GetSemaphoreCounterValue(VkDevice _device, VkSemaphore _semaphore, uint64_t *pValue)
|
||||
{
|
||||
/* See https://gitlab.freedesktop.org/mesa/mesa/-/issues/5119. */
|
||||
if (_semaphore == VK_NULL_HANDLE) {
|
||||
fprintf(stderr, "RADV: Ignoring vkGetSemaphoreCounterValue() with NULL semaphore (game bug)!\n");
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VK_FROM_HANDLE(radv_device, device, _device);
|
||||
return device->layer_dispatch.app.GetSemaphoreCounterValue(_device, _semaphore, pValue);
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2025 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "radv_device.h"
|
||||
#include "radv_entrypoints.h"
|
||||
#include "radv_image_view.h"
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
no_mans_sky_CreateImageView(VkDevice _device, const VkImageViewCreateInfo *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator, VkImageView *pView)
|
||||
{
|
||||
VK_FROM_HANDLE(radv_device, device, _device);
|
||||
VkResult result;
|
||||
|
||||
result = device->layer_dispatch.app.CreateImageView(_device, pCreateInfo, pAllocator, pView);
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
VK_FROM_HANDLE(radv_image_view, iview, *pView);
|
||||
|
||||
if ((iview->vk.aspects == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) &&
|
||||
(iview->vk.usage &
|
||||
(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) {
|
||||
/* No Man's Sky creates descriptors with depth/stencil aspects (only when Intel XESS is
|
||||
* enabled apparently). and this is illegal in Vulkan. Ignore them by using NULL descriptors
|
||||
* to workaroud GPU hangs.
|
||||
*/
|
||||
memset(&iview->descriptor, 0, sizeof(iview->descriptor));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2024 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "radv_entrypoints.h"
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL
|
||||
quantic_dream_UnmapMemory2(VkDevice _device, const VkMemoryUnmapInfo *pMemoryUnmapInfo)
|
||||
{
|
||||
/* Detroit: Become Human repeatedly calls vkMapMemory and vkUnmapMemory on the same buffer.
|
||||
* This creates high overhead in the kernel due to mapping operation and page fault costs.
|
||||
*
|
||||
* Simply skip the unmap call to workaround it. Mapping an already-mapped region is UB in Vulkan,
|
||||
* but will correctly return the mapped pointer on RADV.
|
||||
*/
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2023 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "radv_cmd_buffer.h"
|
||||
#include "radv_device.h"
|
||||
#include "radv_entrypoints.h"
|
||||
#include "vk_framebuffer.h"
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
rage2_CmdBeginRenderPass(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo *pRenderPassBegin,
|
||||
VkSubpassContents contents)
|
||||
{
|
||||
VK_FROM_HANDLE(vk_framebuffer, framebuffer, pRenderPassBegin->framebuffer);
|
||||
VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
||||
|
||||
VkRenderPassBeginInfo render_pass_begin = {
|
||||
.sType = pRenderPassBegin->sType,
|
||||
.pNext = pRenderPassBegin->pNext,
|
||||
.renderPass = pRenderPassBegin->renderPass,
|
||||
.framebuffer = pRenderPassBegin->framebuffer,
|
||||
.clearValueCount = pRenderPassBegin->clearValueCount,
|
||||
.pClearValues = pRenderPassBegin->pClearValues,
|
||||
};
|
||||
|
||||
/* RAGE2 seems to incorrectly set the render area and with dynamic rendering the concept of
|
||||
* framebuffer dimensions goes away. Forcing the render area to be the framebuffer dimensions
|
||||
* restores previous logic and it fixes rendering issues.
|
||||
*/
|
||||
render_pass_begin.renderArea.offset.x = 0;
|
||||
render_pass_begin.renderArea.offset.y = 0;
|
||||
render_pass_begin.renderArea.extent.width = framebuffer->width;
|
||||
render_pass_begin.renderArea.extent.height = framebuffer->height;
|
||||
|
||||
device->layer_dispatch.app.CmdBeginRenderPass(commandBuffer, &render_pass_begin, contents);
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2026 Valve Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "radv_cmd_buffer.h"
|
||||
#include "radv_device.h"
|
||||
#include "radv_entrypoints.h"
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
strange_brigade_CmdPipelineBarrier2(VkCommandBuffer commandBuffer, const VkDependencyInfo *pDependencyInfo)
|
||||
{
|
||||
VK_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
|
||||
struct radv_device *device = radv_cmd_buffer_device(cmd_buffer);
|
||||
|
||||
for (uint32_t i = 0; i < pDependencyInfo->imageMemoryBarrierCount; i++) {
|
||||
VkImageMemoryBarrier2 *barrier = (VkImageMemoryBarrier2 *)&pDependencyInfo->pImageMemoryBarriers[i];
|
||||
|
||||
if (barrier->newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
|
||||
barrier->srcAccessMask == VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) {
|
||||
/* This game has a broken barrier right before present that causes rendering issues. Fix it
|
||||
* by modifying the src access mask.
|
||||
*/
|
||||
barrier->srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device->layer_dispatch.app.CmdPipelineBarrier2(commandBuffer, pDependencyInfo);
|
||||
}
|
||||
|
|
@ -17,13 +17,6 @@ radv_entrypoints_gen_command += [
|
|||
'--device-prefix', 'rmv',
|
||||
'--device-prefix', 'ctx_roll',
|
||||
|
||||
# Application layer entrypoints
|
||||
'--device-prefix', 'metro_exodus',
|
||||
'--device-prefix', 'rage2',
|
||||
'--device-prefix', 'quantic_dream',
|
||||
'--device-prefix', 'no_mans_sky',
|
||||
'--device-prefix', 'strange_brigade',
|
||||
|
||||
# Command buffer annotation layer entrypoints
|
||||
'--device-prefix', 'annotate',
|
||||
]
|
||||
|
|
@ -38,12 +31,8 @@ radv_entrypoints = custom_target(
|
|||
|
||||
libradv_files = files(
|
||||
'bvh/bvh.h',
|
||||
'layers/radv_app_workarounds.c',
|
||||
'layers/radv_ctx_roll_layer.c',
|
||||
'layers/radv_metro_exodus.c',
|
||||
'layers/radv_rage2.c',
|
||||
'layers/radv_quantic_dream.c',
|
||||
'layers/radv_no_mans_sky.c',
|
||||
'layers/radv_strange_brigade.c',
|
||||
'layers/radv_rmv_layer.c',
|
||||
'layers/radv_rra_layer.c',
|
||||
'layers/radv_sqtt_layer.c',
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <sys/inotify.h>
|
||||
#endif
|
||||
|
||||
#include "layers/radv_app_workarounds.h"
|
||||
#include "meta/radv_meta.h"
|
||||
#include "util/disk_cache.h"
|
||||
#include "util/u_debug.h"
|
||||
|
|
@ -761,6 +762,30 @@ add_entrypoints(struct dispatch_table_builder *b, const struct vk_device_entrypo
|
|||
b->used[table] = true;
|
||||
}
|
||||
|
||||
static void
|
||||
init_app_workarounds_entrypoints(struct radv_device *device, struct dispatch_table_builder *b)
|
||||
{
|
||||
const struct radv_physical_device *pdev = radv_device_physical(device);
|
||||
const struct radv_instance *instance = radv_physical_device_instance(pdev);
|
||||
struct vk_device_entrypoint_table table = {0};
|
||||
|
||||
#define SET_ENTRYPOINT(app_layer, entrypoint) table.entrypoint = app_layer##_##entrypoint;
|
||||
if (!strcmp(instance->drirc.debug.app_layer, "metroexodus")) {
|
||||
SET_ENTRYPOINT(metro_exodus, GetSemaphoreCounterValue);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "rage2")) {
|
||||
SET_ENTRYPOINT(rage2, CmdBeginRenderPass);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "quanticdream")) {
|
||||
SET_ENTRYPOINT(quantic_dream, UnmapMemory2);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "no_mans_sky")) {
|
||||
SET_ENTRYPOINT(no_mans_sky, CreateImageView);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "strange_brigade")) {
|
||||
SET_ENTRYPOINT(strange_brigade, CmdPipelineBarrier2);
|
||||
}
|
||||
#undef SET_ENTRYPOINT
|
||||
|
||||
add_entrypoints(b, &table, RADV_APP_DISPATCH_TABLE);
|
||||
}
|
||||
|
||||
static void
|
||||
init_dispatch_tables(struct radv_device *device, struct radv_physical_device *pdev)
|
||||
{
|
||||
|
|
@ -778,17 +803,7 @@ init_dispatch_tables(struct radv_device *device, struct radv_physical_device *pd
|
|||
if (radv_device_fault_detection_enabled(device) || gather_ctx_rolls)
|
||||
add_entrypoints(&b, &annotate_device_entrypoints, RADV_ANNOTATE_DISPATCH_TABLE);
|
||||
|
||||
if (!strcmp(instance->drirc.debug.app_layer, "metroexodus")) {
|
||||
add_entrypoints(&b, &metro_exodus_device_entrypoints, RADV_APP_DISPATCH_TABLE);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "rage2")) {
|
||||
add_entrypoints(&b, &rage2_device_entrypoints, RADV_APP_DISPATCH_TABLE);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "quanticdream")) {
|
||||
add_entrypoints(&b, &quantic_dream_device_entrypoints, RADV_APP_DISPATCH_TABLE);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "no_mans_sky")) {
|
||||
add_entrypoints(&b, &no_mans_sky_device_entrypoints, RADV_APP_DISPATCH_TABLE);
|
||||
} else if (!strcmp(instance->drirc.debug.app_layer, "strange_brigade")) {
|
||||
add_entrypoints(&b, &strange_brigade_device_entrypoints, RADV_APP_DISPATCH_TABLE);
|
||||
}
|
||||
init_app_workarounds_entrypoints(device, &b);
|
||||
|
||||
if (instance->vk.trace_mode & RADV_TRACE_MODE_RGP)
|
||||
add_entrypoints(&b, &sqtt_device_entrypoints, RADV_RGP_DISPATCH_TABLE);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue