mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
4946: Better forced viewport handling r=def- a=Jupeyy For #4939 For the performance warnings refering `vkCmdClearAttachments` ignore them, because this function is only called when: - clear color is changed(open/close editor, switch between entities) to directly flush a clear with the new color - ~~a viewport is used that is "worse" than 5:4 (I don't really want to switch to non renderpass clear completly, since it *can* improve performance -- https://community.arm.com/arm-community-blogs/b/graphics-gaming-and-vr-blog/posts/vulkan-samples "Therefore, avoid using LOAD_OP_LOAD and vkCmdClearAttachments and use LOAD_OP_CLEAR or LOAD_OP_DONT_CARE whenever possible.")~~ thinking about it, maybe i can also drop this call now, since its dynamic viewport anyway ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) 4993: Unselect text after ctrl-u r=Jupeyy a=def- <!-- What is the motivation for the changes of this pull request --> ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) 4998: Refactor tooltips and add some more r=def- a=edg-l Refactored tooltips so they render last, otherwise stuff rendered after the call is overlapped. Also renamed "Alpha" to "Opacity" which is more clear to non-devs. ## Checklist - [x] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) 4999: Respect GPU type better r=def- a=Jupeyy fixes #4994 ## Checklist - [ ] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Jupeyy <jupjopjap@gmail.com> Co-authored-by: def <dennis@felsin9.de> Co-authored-by: Edgar Luque <git@edgarluque.com>
This commit is contained in:
commit
fdcb1576bd
|
@ -1958,6 +1958,8 @@ if(CLIENT)
|
|||
components/spectator.h
|
||||
components/statboard.cpp
|
||||
components/statboard.h
|
||||
components/tooltips.cpp
|
||||
components/tooltips.h
|
||||
components/voting.cpp
|
||||
components/voting.h
|
||||
gameclient.cpp
|
||||
|
|
|
@ -843,8 +843,25 @@ class CCommandProcessorFragment_Vulkan : public CCommandProcessorFragment_GLBase
|
|||
|
||||
struct SSwapImgViewportExtent
|
||||
{
|
||||
VkExtent2D m_SwapImg;
|
||||
VkExtent2D m_Viewport;
|
||||
VkExtent2D m_SwapImageViewport;
|
||||
bool m_HasForcedViewport = false;
|
||||
VkExtent2D m_ForcedViewport;
|
||||
|
||||
// the viewport of the resulting presented image on the screen
|
||||
// if there is a forced viewport the resulting image is smaller
|
||||
// than the full swap image size
|
||||
VkExtent2D GetPresentedImageViewport()
|
||||
{
|
||||
uint32_t ViewportWidth = m_SwapImageViewport.width;
|
||||
uint32_t ViewportHeight = m_SwapImageViewport.height;
|
||||
if(m_HasForcedViewport)
|
||||
{
|
||||
ViewportWidth = m_ForcedViewport.width;
|
||||
ViewportHeight = m_ForcedViewport.height;
|
||||
}
|
||||
|
||||
return {ViewportWidth, ViewportHeight};
|
||||
}
|
||||
};
|
||||
|
||||
struct SSwapChainMultiSampleImage
|
||||
|
@ -1228,14 +1245,7 @@ protected:
|
|||
m_aCommandCallbacks[CommandBufferCMDOff(CCommandBuffer::CMD_VSYNC)] = {false, [](SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand *pBaseCommand) {}, [this](const CCommandBuffer::SCommand *pBaseCommand, SRenderCommandExecuteBuffer &ExecBuffer) { Cmd_VSync(static_cast<const CCommandBuffer::SCommand_VSync *>(pBaseCommand)); return true; }};
|
||||
m_aCommandCallbacks[CommandBufferCMDOff(CCommandBuffer::CMD_TRY_SWAP_AND_SCREENSHOT)] = {false, [](SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand *pBaseCommand) {}, [this](const CCommandBuffer::SCommand *pBaseCommand, SRenderCommandExecuteBuffer &ExecBuffer) { Cmd_Screenshot(static_cast<const CCommandBuffer::SCommand_TrySwapAndScreenshot *>(pBaseCommand)); return true; }};
|
||||
|
||||
m_aCommandCallbacks[CommandBufferCMDOff(CCommandBuffer::CMD_UPDATE_VIEWPORT)] = {true, [this](SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand *pBaseCommand) {
|
||||
const auto* pCommand = static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand);
|
||||
if(pCommand->m_ByResize) {
|
||||
Cmd_Update_Viewport(pCommand, true);
|
||||
}
|
||||
else {
|
||||
Cmd_Update_Viewport_FillExecuteBuffer(ExecBuffer, pCommand);
|
||||
} }, [this](const CCommandBuffer::SCommand *pBaseCommand, SRenderCommandExecuteBuffer &ExecBuffer) { Cmd_Update_Viewport(static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand), false); return true; }};
|
||||
m_aCommandCallbacks[CommandBufferCMDOff(CCommandBuffer::CMD_UPDATE_VIEWPORT)] = {false, [this](SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand *pBaseCommand) { Cmd_Update_Viewport_FillExecuteBuffer(ExecBuffer, static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand)); }, [this](const CCommandBuffer::SCommand *pBaseCommand, SRenderCommandExecuteBuffer &ExecBuffer) { Cmd_Update_Viewport(static_cast<const CCommandBuffer::SCommand_Update_Viewport *>(pBaseCommand)); return true; }};
|
||||
|
||||
m_aCommandCallbacks[CommandBufferCMDOff(CCommandBuffer::CMD_WINDOW_CREATE_NTF)] = {false, [](SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand *pBaseCommand) {}, [this](const CCommandBuffer::SCommand *pBaseCommand, SRenderCommandExecuteBuffer &ExecBuffer) { Cmd_WindowCreateNtf(static_cast<const CCommandBuffer::SCommand_WindowCreateNtf *>(pBaseCommand)); return false; }};
|
||||
m_aCommandCallbacks[CommandBufferCMDOff(CCommandBuffer::CMD_WINDOW_DESTROY_NTF)] = {false, [](SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SCommand *pBaseCommand) {}, [this](const CCommandBuffer::SCommand *pBaseCommand, SRenderCommandExecuteBuffer &ExecBuffer) { Cmd_WindowDestroyNtf(static_cast<const CCommandBuffer::SCommand_WindowDestroyNtf *>(pBaseCommand)); return false; }};
|
||||
|
@ -1337,8 +1347,9 @@ protected:
|
|||
bool UsesRGBALikeFormat = m_VKSurfFormat.format == VK_FORMAT_R8G8B8A8_UNORM || IsB8G8R8A8;
|
||||
if(UsesRGBALikeFormat && m_LastPresentedSwapChainImageIndex != std::numeric_limits<decltype(m_LastPresentedSwapChainImageIndex)>::max())
|
||||
{
|
||||
Width = m_VKSwapImgAndViewportExtent.m_Viewport.width;
|
||||
Height = m_VKSwapImgAndViewportExtent.m_Viewport.height;
|
||||
auto Viewport = m_VKSwapImgAndViewportExtent.GetPresentedImageViewport();
|
||||
Width = Viewport.width;
|
||||
Height = Viewport.height;
|
||||
Format = CImageInfo::FORMAT_RGBA;
|
||||
|
||||
size_t ImageTotalSize = (size_t)Width * Height * 4;
|
||||
|
@ -1356,7 +1367,7 @@ protected:
|
|||
Region.imageSubresource.baseArrayLayer = 0;
|
||||
Region.imageSubresource.layerCount = 1;
|
||||
Region.imageOffset = {0, 0, 0};
|
||||
Region.imageExtent = {m_VKSwapImgAndViewportExtent.m_Viewport.width, m_VKSwapImgAndViewportExtent.m_Viewport.height, 1};
|
||||
Region.imageExtent = {Viewport.width, Viewport.height, 1};
|
||||
|
||||
auto &SwapImg = m_SwapChainImages[m_LastPresentedSwapChainImageIndex];
|
||||
|
||||
|
@ -2335,7 +2346,7 @@ protected:
|
|||
RenderPassInfo.renderPass = m_VKRenderPass;
|
||||
RenderPassInfo.framebuffer = m_FramebufferList[m_CurImageIndex];
|
||||
RenderPassInfo.renderArea.offset = {0, 0};
|
||||
RenderPassInfo.renderArea.extent = m_VKSwapImgAndViewportExtent.m_Viewport;
|
||||
RenderPassInfo.renderArea.extent = m_VKSwapImgAndViewportExtent.m_SwapImageViewport;
|
||||
|
||||
VkClearValue ClearColorVal = {{{m_aClearColor[0], m_aClearColor[1], m_aClearColor[2], m_aClearColor[3]}}};
|
||||
RenderPassInfo.clearValueCount = 1;
|
||||
|
@ -3021,9 +3032,14 @@ protected:
|
|||
return State.m_BlendMode == CCommandBuffer::BLEND_ADDITIVE ? VULKAN_BACKEND_BLEND_MODE_ADDITATIVE : (State.m_BlendMode == CCommandBuffer::BLEND_NONE ? VULKAN_BACKEND_BLEND_MODE_NONE : VULKAN_BACKEND_BLEND_MODE_ALPHA);
|
||||
}
|
||||
|
||||
size_t GetDynamicModeIndex(const CCommandBuffer::SState &State)
|
||||
size_t GetDynamicModeIndexFromState(const CCommandBuffer::SState &State)
|
||||
{
|
||||
return (State.m_ClipEnable || m_HasDynamicViewport) ? VULKAN_BACKEND_CLIP_MODE_DYNAMIC_SCISSOR_AND_VIEWPORT : VULKAN_BACKEND_CLIP_MODE_NONE;
|
||||
return (State.m_ClipEnable || m_HasDynamicViewport || m_VKSwapImgAndViewportExtent.m_HasForcedViewport) ? VULKAN_BACKEND_CLIP_MODE_DYNAMIC_SCISSOR_AND_VIEWPORT : VULKAN_BACKEND_CLIP_MODE_NONE;
|
||||
}
|
||||
|
||||
size_t GetDynamicModeIndexFromExecBuffer(const SRenderCommandExecuteBuffer &ExecBuffer)
|
||||
{
|
||||
return (ExecBuffer.m_HasDynamicState) ? VULKAN_BACKEND_CLIP_MODE_DYNAMIC_SCISSOR_AND_VIEWPORT : VULKAN_BACKEND_CLIP_MODE_NONE;
|
||||
}
|
||||
|
||||
VkPipeline &GetPipeline(SPipelineContainer &Container, bool IsTextured, size_t BlendModeIndex, size_t DynamicIndex)
|
||||
|
@ -3072,17 +3088,17 @@ protected:
|
|||
return GetPipeline(m_TileBorderLinePipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
}
|
||||
|
||||
void GetStateIndices(const CCommandBuffer::SState &State, bool &IsTextured, size_t &BlendModeIndex, size_t &DynamicIndex, size_t &AddressModeIndex)
|
||||
void GetStateIndices(const SRenderCommandExecuteBuffer &ExecBuffer, const CCommandBuffer::SState &State, bool &IsTextured, size_t &BlendModeIndex, size_t &DynamicIndex, size_t &AddressModeIndex)
|
||||
{
|
||||
IsTextured = GetIsTextured(State);
|
||||
AddressModeIndex = GetAddressModeIndex(State);
|
||||
BlendModeIndex = GetBlendModeIndex(State);
|
||||
DynamicIndex = GetDynamicModeIndex(State);
|
||||
DynamicIndex = GetDynamicModeIndexFromExecBuffer(ExecBuffer);
|
||||
}
|
||||
|
||||
void ExecBufferFillDynamicStates(const CCommandBuffer::SState &State, SRenderCommandExecuteBuffer &ExecBuffer)
|
||||
{
|
||||
size_t DynamicStateIndex = GetDynamicModeIndex(State);
|
||||
size_t DynamicStateIndex = GetDynamicModeIndexFromState(State);
|
||||
if(DynamicStateIndex == VULKAN_BACKEND_CLIP_MODE_DYNAMIC_SCISSOR_AND_VIEWPORT)
|
||||
{
|
||||
VkViewport Viewport;
|
||||
|
@ -3095,22 +3111,53 @@ protected:
|
|||
Viewport.minDepth = 0.0f;
|
||||
Viewport.maxDepth = 1.0f;
|
||||
}
|
||||
// else check if there is a forced viewport
|
||||
else if(m_VKSwapImgAndViewportExtent.m_HasForcedViewport)
|
||||
{
|
||||
Viewport.x = 0.0f;
|
||||
Viewport.y = 0.0f;
|
||||
Viewport.width = (float)m_VKSwapImgAndViewportExtent.m_ForcedViewport.width;
|
||||
Viewport.height = (float)m_VKSwapImgAndViewportExtent.m_ForcedViewport.height;
|
||||
Viewport.minDepth = 0.0f;
|
||||
Viewport.maxDepth = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Viewport.x = 0.0f;
|
||||
Viewport.y = 0.0f;
|
||||
Viewport.width = (float)m_VKSwapImgAndViewportExtent.m_Viewport.width;
|
||||
Viewport.height = (float)m_VKSwapImgAndViewportExtent.m_Viewport.height;
|
||||
Viewport.width = (float)m_VKSwapImgAndViewportExtent.m_SwapImageViewport.width;
|
||||
Viewport.height = (float)m_VKSwapImgAndViewportExtent.m_SwapImageViewport.height;
|
||||
Viewport.minDepth = 0.0f;
|
||||
Viewport.maxDepth = 1.0f;
|
||||
}
|
||||
|
||||
VkRect2D Scissor;
|
||||
// convert from OGL to vulkan clip
|
||||
int32_t ScissorY = (int32_t)m_VKSwapImgAndViewportExtent.m_Viewport.height - ((int32_t)State.m_ClipY + (int32_t)State.m_ClipH);
|
||||
|
||||
// the scissor always assumes the presented viewport, because the front-end keeps the calculation
|
||||
// for the forced viewport in sync
|
||||
auto ScissorViewport = m_VKSwapImgAndViewportExtent.GetPresentedImageViewport();
|
||||
if(State.m_ClipEnable)
|
||||
{
|
||||
int32_t ScissorY = (int32_t)ScissorViewport.height - ((int32_t)State.m_ClipY + (int32_t)State.m_ClipH);
|
||||
uint32_t ScissorH = (int32_t)State.m_ClipH;
|
||||
Scissor.offset = {(int32_t)State.m_ClipX, ScissorY};
|
||||
Scissor.extent = {(uint32_t)State.m_ClipW, ScissorH};
|
||||
}
|
||||
else
|
||||
{
|
||||
Scissor.offset = {0, 0};
|
||||
Scissor.extent = {(uint32_t)ScissorViewport.width, (uint32_t)ScissorViewport.height};
|
||||
}
|
||||
|
||||
// if there is a dynamic viewport make sure the scissor data is scaled down to that
|
||||
if(m_HasDynamicViewport)
|
||||
{
|
||||
Scissor.offset.x = (int32_t)(((float)Scissor.offset.x / (float)ScissorViewport.width) * (float)m_DynamicViewportSize.width) + m_DynamicViewportOffset.x;
|
||||
Scissor.offset.y = (int32_t)(((float)Scissor.offset.y / (float)ScissorViewport.height) * (float)m_DynamicViewportSize.height) + m_DynamicViewportOffset.y;
|
||||
Scissor.extent.width = (uint32_t)(((float)Scissor.extent.width / (float)ScissorViewport.width) * (float)m_DynamicViewportSize.width);
|
||||
Scissor.extent.height = (uint32_t)(((float)Scissor.extent.height / (float)ScissorViewport.height) * (float)m_DynamicViewportSize.height);
|
||||
}
|
||||
|
||||
Viewport.x = clamp(Viewport.x, 0.0f, std::numeric_limits<decltype(Viewport.x)>::max());
|
||||
Viewport.y = clamp(Viewport.y, 0.0f, std::numeric_limits<decltype(Viewport.y)>::max());
|
||||
|
@ -3136,7 +3183,7 @@ protected:
|
|||
m_vLastPipeline[RenderThreadIndex] = BindingPipe;
|
||||
}
|
||||
|
||||
size_t DynamicStateIndex = GetDynamicModeIndex(State);
|
||||
size_t DynamicStateIndex = GetDynamicModeIndexFromExecBuffer(ExecBuffer);
|
||||
if(DynamicStateIndex == VULKAN_BACKEND_CLIP_MODE_DYNAMIC_SCISSOR_AND_VIEWPORT)
|
||||
{
|
||||
vkCmdSetViewport(CommandBuffer, 0, 1, &ExecBuffer.m_Viewport);
|
||||
|
@ -3179,7 +3226,7 @@ protected:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
auto &PipeLayout = GetTileLayerPipeLayout(Type, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = GetTileLayerPipe(Type, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
||||
|
@ -3243,7 +3290,7 @@ protected:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
auto &PipeLayout = Is3DTextured ? GetPipeLayout(m_Standard3DPipeline, IsTextured, BlendModeIndex, DynamicIndex) : GetStandardPipeLayout(IsLineGeometry, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = Is3DTextured ? GetPipeline(m_Standard3DPipeline, IsTextured, BlendModeIndex, DynamicIndex) : GetStandardPipe(IsLineGeometry, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
||||
|
@ -3456,6 +3503,20 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
STWGraphicGPU::ETWGraphicsGPUType VKGPUTypeToGraphicsGPUType(VkPhysicalDeviceType VKGPUType)
|
||||
{
|
||||
if(VKGPUType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
|
||||
return STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_DISCRETE;
|
||||
else if(VKGPUType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU)
|
||||
return STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_INTEGRATED;
|
||||
else if(VKGPUType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU)
|
||||
return STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_VIRTUAL;
|
||||
else if(VKGPUType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU)
|
||||
return STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_CPU;
|
||||
|
||||
return STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_CPU;
|
||||
}
|
||||
|
||||
bool SelectGPU(char *pRendererName, char *pVendorName, char *pVersionName)
|
||||
{
|
||||
uint32_t DevicesCount = 0;
|
||||
|
@ -3474,7 +3535,9 @@ public:
|
|||
m_pGPUList->m_GPUs.reserve(DeviceList.size());
|
||||
|
||||
size_t FoundDeviceIndex = 0;
|
||||
size_t AutoGPUIndex = 0;
|
||||
size_t FoundGPUType = STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_INVALID;
|
||||
|
||||
STWGraphicGPU::ETWGraphicsGPUType AutoGPUType = STWGraphicGPU::ETWGraphicsGPUType::GRAPHICS_GPU_TYPE_INVALID;
|
||||
|
||||
bool IsAutoGPU = str_comp(g_Config.m_GfxGPUName, "auto") == 0;
|
||||
|
||||
|
@ -3484,9 +3547,11 @@ public:
|
|||
|
||||
auto &DeviceProp = DevicePropList[Index];
|
||||
|
||||
STWGraphicGPU::ETWGraphicsGPUType GPUType = VKGPUTypeToGraphicsGPUType(DeviceProp.deviceType);
|
||||
|
||||
STWGraphicGPU::STWGraphicGPUItem NewGPU;
|
||||
str_copy(NewGPU.m_Name, DeviceProp.deviceName, minimum(sizeof(DeviceProp.deviceName), sizeof(NewGPU.m_Name)));
|
||||
NewGPU.m_IsDiscreteGPU = DeviceProp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
|
||||
NewGPU.m_GPUType = GPUType;
|
||||
m_pGPUList->m_GPUs.push_back(NewGPU);
|
||||
|
||||
Index++;
|
||||
|
@ -3494,17 +3559,18 @@ public:
|
|||
int DevAPIMajor = (int)VK_API_VERSION_MAJOR(DeviceProp.apiVersion);
|
||||
int DevAPIMinor = (int)VK_API_VERSION_MINOR(DeviceProp.apiVersion);
|
||||
|
||||
if((AutoGPUIndex == 0 && DeviceProp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) && (DevAPIMajor > gs_BackendVulkanMajor || (DevAPIMajor == gs_BackendVulkanMajor && DevAPIMinor >= gs_BackendVulkanMinor)))
|
||||
if(GPUType < AutoGPUType && (DevAPIMajor > gs_BackendVulkanMajor || (DevAPIMajor == gs_BackendVulkanMajor && DevAPIMinor >= gs_BackendVulkanMinor)))
|
||||
{
|
||||
str_copy(m_pGPUList->m_AutoGPU.m_Name, DeviceProp.deviceName, minimum(sizeof(DeviceProp.deviceName), sizeof(m_pGPUList->m_AutoGPU.m_Name)));
|
||||
m_pGPUList->m_AutoGPU.m_IsDiscreteGPU = DeviceProp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
|
||||
m_pGPUList->m_AutoGPU.m_GPUType = GPUType;
|
||||
|
||||
AutoGPUIndex = Index;
|
||||
AutoGPUType = GPUType;
|
||||
}
|
||||
|
||||
if(((IsAutoGPU && FoundDeviceIndex == 0 && DeviceProp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || str_comp(DeviceProp.deviceName, g_Config.m_GfxGPUName) == 0) && (DevAPIMajor > gs_BackendVulkanMajor || (DevAPIMajor == gs_BackendVulkanMajor && DevAPIMinor >= gs_BackendVulkanMinor)))
|
||||
if(((IsAutoGPU && GPUType < FoundGPUType) || str_comp(DeviceProp.deviceName, g_Config.m_GfxGPUName) == 0) && (DevAPIMajor > gs_BackendVulkanMajor || (DevAPIMajor == gs_BackendVulkanMajor && DevAPIMinor >= gs_BackendVulkanMinor)))
|
||||
{
|
||||
FoundDeviceIndex = Index;
|
||||
FoundGPUType = GPUType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3769,11 +3835,20 @@ public:
|
|||
}
|
||||
|
||||
VkExtent2D AutoViewportExtent = RetSize;
|
||||
bool UsesForcedViewport = false;
|
||||
// keep this in sync with graphics_threaded AdjustViewport's check
|
||||
if(AutoViewportExtent.height > 4 * AutoViewportExtent.width / 5)
|
||||
{
|
||||
AutoViewportExtent.height = 4 * AutoViewportExtent.width / 5;
|
||||
UsesForcedViewport = true;
|
||||
}
|
||||
|
||||
return {RetSize, AutoViewportExtent};
|
||||
SSwapImgViewportExtent Ext;
|
||||
Ext.m_SwapImageViewport = RetSize;
|
||||
Ext.m_ForcedViewport = AutoViewportExtent;
|
||||
Ext.m_HasForcedViewport = UsesForcedViewport;
|
||||
|
||||
return Ext;
|
||||
}
|
||||
|
||||
bool GetImageUsage(const VkSurfaceCapabilitiesKHR &VKCapabilities, VkImageUsageFlags &VKOutUsage)
|
||||
|
@ -3892,7 +3967,7 @@ public:
|
|||
SwapInfo.minImageCount = SwapImgCount;
|
||||
SwapInfo.imageFormat = m_VKSurfFormat.format;
|
||||
SwapInfo.imageColorSpace = m_VKSurfFormat.colorSpace;
|
||||
SwapInfo.imageExtent = m_VKSwapImgAndViewportExtent.m_SwapImg;
|
||||
SwapInfo.imageExtent = m_VKSwapImgAndViewportExtent.m_SwapImageViewport;
|
||||
SwapInfo.imageArrayLayers = 1;
|
||||
SwapInfo.imageUsage = UsageFlags;
|
||||
SwapInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
@ -4075,7 +4150,7 @@ public:
|
|||
{
|
||||
for(size_t i = 0; i < m_SwapChainImageCount; ++i)
|
||||
{
|
||||
CreateImage(m_VKSwapImgAndViewportExtent.m_SwapImg.width, m_VKSwapImgAndViewportExtent.m_SwapImg.height, 1, 1, m_VKSurfFormat.format, VK_IMAGE_TILING_OPTIMAL, m_SwapChainMultiSamplingImages[i].m_Image, m_SwapChainMultiSamplingImages[i].m_ImgMem, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
CreateImage(m_VKSwapImgAndViewportExtent.m_SwapImageViewport.width, m_VKSwapImgAndViewportExtent.m_SwapImageViewport.height, 1, 1, m_VKSurfFormat.format, VK_IMAGE_TILING_OPTIMAL, m_SwapChainMultiSamplingImages[i].m_Image, m_SwapChainMultiSamplingImages[i].m_ImgMem, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
m_SwapChainMultiSamplingImages[i].m_ImgView = CreateImageView(m_SwapChainMultiSamplingImages[i].m_Image, m_VKSurfFormat.format, VK_IMAGE_VIEW_TYPE_2D, 1, 1);
|
||||
}
|
||||
}
|
||||
|
@ -4187,8 +4262,8 @@ public:
|
|||
FramebufferInfo.renderPass = m_VKRenderPass;
|
||||
FramebufferInfo.attachmentCount = HasMultiSamplingTargets ? aAttachments.size() : aAttachments.size() - 1;
|
||||
FramebufferInfo.pAttachments = HasMultiSamplingTargets ? aAttachments.data() : aAttachments.data() + 1;
|
||||
FramebufferInfo.width = m_VKSwapImgAndViewportExtent.m_SwapImg.width;
|
||||
FramebufferInfo.height = m_VKSwapImgAndViewportExtent.m_SwapImg.height;
|
||||
FramebufferInfo.width = m_VKSwapImgAndViewportExtent.m_SwapImageViewport.width;
|
||||
FramebufferInfo.height = m_VKSwapImgAndViewportExtent.m_SwapImageViewport.height;
|
||||
FramebufferInfo.layers = 1;
|
||||
|
||||
if(vkCreateFramebuffer(m_VKDevice, &FramebufferInfo, nullptr, &m_FramebufferList[i]) != VK_SUCCESS)
|
||||
|
@ -4342,13 +4417,13 @@ public:
|
|||
|
||||
Viewport.x = 0.0f;
|
||||
Viewport.y = 0.0f;
|
||||
Viewport.width = (float)m_VKSwapImgAndViewportExtent.m_Viewport.width;
|
||||
Viewport.height = (float)m_VKSwapImgAndViewportExtent.m_Viewport.height;
|
||||
Viewport.width = (float)m_VKSwapImgAndViewportExtent.m_SwapImageViewport.width;
|
||||
Viewport.height = (float)m_VKSwapImgAndViewportExtent.m_SwapImageViewport.height;
|
||||
Viewport.minDepth = 0.0f;
|
||||
Viewport.maxDepth = 1.0f;
|
||||
|
||||
Scissor.offset = {0, 0};
|
||||
Scissor.extent = m_VKSwapImgAndViewportExtent.m_Viewport;
|
||||
Scissor.extent = m_VKSwapImgAndViewportExtent.m_SwapImageViewport;
|
||||
|
||||
ViewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
ViewportState.viewportCount = 1;
|
||||
|
@ -6373,7 +6448,7 @@ public:
|
|||
if(ExecBuffer.m_ClearColorInRenderThread)
|
||||
{
|
||||
std::array<VkClearAttachment, 1> aAttachments = {VkClearAttachment{VK_IMAGE_ASPECT_COLOR_BIT, 0, VkClearValue{VkClearColorValue{{pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, pCommand->m_Color.a}}}}};
|
||||
std::array<VkClearRect, 1> aClearRects = {VkClearRect{{{0, 0}, m_VKSwapImgAndViewportExtent.m_SwapImg}, 0, 1}};
|
||||
std::array<VkClearRect, 1> aClearRects = {VkClearRect{{{0, 0}, m_VKSwapImgAndViewportExtent.m_SwapImageViewport}, 0, 1}};
|
||||
vkCmdClearAttachments(GetGraphicCommandBuffer(ExecBuffer.m_ThreadIndex), aAttachments.size(), aAttachments.data(), aClearRects.size(), aClearRects.data());
|
||||
}
|
||||
}
|
||||
|
@ -6449,9 +6524,9 @@ public:
|
|||
ExecBuffer.m_EstimatedRenderCallCount = 0;
|
||||
}
|
||||
|
||||
void Cmd_Update_Viewport(const CCommandBuffer::SCommand_Update_Viewport *pCommand, bool CalledByMainRenderThread)
|
||||
void Cmd_Update_Viewport(const CCommandBuffer::SCommand_Update_Viewport *pCommand)
|
||||
{
|
||||
if(pCommand->m_ByResize && CalledByMainRenderThread)
|
||||
if(pCommand->m_ByResize)
|
||||
{
|
||||
if(IsVerbose())
|
||||
{
|
||||
|
@ -6461,14 +6536,15 @@ public:
|
|||
m_CanvasHeight = (uint32_t)pCommand->m_Height;
|
||||
m_RecreateSwapChain = true;
|
||||
}
|
||||
else if(!pCommand->m_ByResize && !CalledByMainRenderThread)
|
||||
else if(!pCommand->m_ByResize)
|
||||
{
|
||||
if(pCommand->m_X != 0 || pCommand->m_Y != 0 || (uint32_t)pCommand->m_Width != m_VKSwapImgAndViewportExtent.m_Viewport.width || (uint32_t)pCommand->m_Height != m_VKSwapImgAndViewportExtent.m_Viewport.height)
|
||||
auto Viewport = m_VKSwapImgAndViewportExtent.GetPresentedImageViewport();
|
||||
if(pCommand->m_X != 0 || pCommand->m_Y != 0 || (uint32_t)pCommand->m_Width != Viewport.width || (uint32_t)pCommand->m_Height != Viewport.height)
|
||||
{
|
||||
m_HasDynamicViewport = true;
|
||||
|
||||
// convert viewport from OGL to vulkan
|
||||
int32_t ViewportY = (int32_t)m_VKSwapImgAndViewportExtent.m_Viewport.height - ((int32_t)pCommand->m_Y + (int32_t)pCommand->m_Height);
|
||||
int32_t ViewportY = (int32_t)Viewport.height - ((int32_t)pCommand->m_Y + (int32_t)pCommand->m_Height);
|
||||
uint32_t ViewportH = (int32_t)pCommand->m_Height;
|
||||
m_DynamicViewportOffset = {(int32_t)pCommand->m_X, ViewportY};
|
||||
m_DynamicViewportSize = {(uint32_t)pCommand->m_Width, ViewportH};
|
||||
|
@ -6687,7 +6763,7 @@ public:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
auto &PipeLayout = GetPipeLayout(CanBePushed ? m_QuadPushPipeline : m_QuadPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = GetPipeline(CanBePushed ? m_QuadPushPipeline : m_QuadPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
||||
|
@ -6783,7 +6859,7 @@ public:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
IsTextured = true; // text is always textured
|
||||
auto &PipeLayout = GetPipeLayout(m_TextPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = GetPipeline(m_TextPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
@ -6852,7 +6928,7 @@ public:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
auto &PipeLayout = GetStandardPipeLayout(false, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = GetStandardPipe(false, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
||||
|
@ -6893,7 +6969,7 @@ public:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
auto &PipeLayout = GetPipeLayout(IsRotationless ? m_PrimExRotationlessPipeline : m_PrimExPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = GetPipeline(IsRotationless ? m_PrimExRotationlessPipeline : m_PrimExPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
||||
|
@ -6954,7 +7030,7 @@ public:
|
|||
size_t BlendModeIndex;
|
||||
size_t DynamicIndex;
|
||||
size_t AddressModeIndex;
|
||||
GetStateIndices(pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
GetStateIndices(ExecBuffer, pCommand->m_State, IsTextured, BlendModeIndex, DynamicIndex, AddressModeIndex);
|
||||
auto &PipeLayout = GetPipeLayout(CanBePushed ? m_SpriteMultiPushPipeline : m_SpriteMultiPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
auto &PipeLine = GetPipeline(CanBePushed ? m_SpriteMultiPushPipeline : m_SpriteMultiPipeline, IsTextured, BlendModeIndex, DynamicIndex);
|
||||
|
||||
|
|
|
@ -845,7 +845,7 @@ void CGraphics_Threaded::Clear(float r, float g, float b, bool ForceClearNow)
|
|||
Cmd.m_Color.g = g;
|
||||
Cmd.m_Color.b = b;
|
||||
Cmd.m_Color.a = 0;
|
||||
Cmd.m_ForceClear = ForceClearNow || m_IsForcedViewport;
|
||||
Cmd.m_ForceClear = ForceClearNow;
|
||||
AddCmd(
|
||||
Cmd, [] { return true; }, "failed to clear graphics.");
|
||||
}
|
||||
|
@ -2270,18 +2270,7 @@ void CGraphics_Threaded::AdjustViewport(bool SendViewportChangeToBackend)
|
|||
|
||||
if(SendViewportChangeToBackend)
|
||||
{
|
||||
CCommandBuffer::SCommand_Update_Viewport Cmd;
|
||||
Cmd.m_X = 0;
|
||||
Cmd.m_Y = 0;
|
||||
Cmd.m_Width = m_ScreenWidth;
|
||||
Cmd.m_Height = m_ScreenHeight;
|
||||
Cmd.m_ByResize = true;
|
||||
|
||||
if(!AddCmd(
|
||||
Cmd, [] { return true; }, "failed to add resize command"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
UpdateViewport(0, 0, m_ScreenWidth, m_ScreenWidth, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2290,6 +2279,22 @@ void CGraphics_Threaded::AdjustViewport(bool SendViewportChangeToBackend)
|
|||
}
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::UpdateViewport(int X, int Y, int W, int H, bool ByResize)
|
||||
{
|
||||
CCommandBuffer::SCommand_Update_Viewport Cmd;
|
||||
Cmd.m_X = X;
|
||||
Cmd.m_Y = Y;
|
||||
Cmd.m_Width = W;
|
||||
Cmd.m_Height = H;
|
||||
Cmd.m_ByResize = ByResize;
|
||||
|
||||
if(!AddCmd(
|
||||
Cmd, [] { return true; }, "failed to add resize command"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CGraphics_Threaded::AddBackEndWarningIfExists()
|
||||
{
|
||||
const char *pErrStr = m_pBackend->GetErrorString();
|
||||
|
@ -2589,18 +2594,7 @@ void CGraphics_Threaded::GotResized(int w, int h, int RefreshRate)
|
|||
g_Config.m_GfxScreenRefreshRate = m_ScreenRefreshRate;
|
||||
m_ScreenHiDPIScale = m_ScreenWidth / (float)g_Config.m_GfxScreenWidth;
|
||||
|
||||
CCommandBuffer::SCommand_Update_Viewport Cmd;
|
||||
Cmd.m_X = 0;
|
||||
Cmd.m_Y = 0;
|
||||
Cmd.m_Width = m_ScreenWidth;
|
||||
Cmd.m_Height = m_ScreenHeight;
|
||||
Cmd.m_ByResize = true;
|
||||
|
||||
if(!AddCmd(
|
||||
Cmd, [] { return true; }, "failed to add resize command"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
UpdateViewport(0, 0, m_ScreenWidth, m_ScreenWidth, true);
|
||||
|
||||
// kick the command buffer and wait
|
||||
KickCommandBuffer();
|
||||
|
|
|
@ -1246,6 +1246,7 @@ public:
|
|||
void Move(int x, int y) override;
|
||||
void Resize(int w, int h, int RefreshRate) override;
|
||||
void GotResized(int w, int h, int RefreshRate) override;
|
||||
void UpdateViewport(int X, int Y, int W, int H, bool ByResize) override;
|
||||
void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) override;
|
||||
int GetWindowScreen() override;
|
||||
|
||||
|
|
|
@ -179,10 +179,21 @@ enum EBackendType
|
|||
|
||||
struct STWGraphicGPU
|
||||
{
|
||||
enum ETWGraphicsGPUType
|
||||
{
|
||||
GRAPHICS_GPU_TYPE_DISCRETE = 0,
|
||||
GRAPHICS_GPU_TYPE_INTEGRATED,
|
||||
GRAPHICS_GPU_TYPE_VIRTUAL,
|
||||
GRAPHICS_GPU_TYPE_CPU,
|
||||
|
||||
// should stay at last position in this enum
|
||||
GRAPHICS_GPU_TYPE_INVALID,
|
||||
};
|
||||
|
||||
struct STWGraphicGPUItem
|
||||
{
|
||||
char m_Name[256];
|
||||
bool m_IsDiscreteGPU;
|
||||
ETWGraphicsGPUType m_GPUType;
|
||||
};
|
||||
std::vector<STWGraphicGPUItem> m_GPUs;
|
||||
STWGraphicGPUItem m_AutoGPU;
|
||||
|
@ -249,6 +260,7 @@ public:
|
|||
virtual void Move(int x, int y) = 0;
|
||||
virtual void Resize(int w, int h, int RefreshRate) = 0;
|
||||
virtual void GotResized(int w, int h, int RefreshRate) = 0;
|
||||
virtual void UpdateViewport(int X, int Y, int W, int H, bool ByResize) = 0;
|
||||
virtual void AddWindowResizeListener(WINDOW_RESIZE_FUNC pFunc, void *pUser) = 0;
|
||||
|
||||
virtual void WindowDestroyNtf(uint32_t WindowID) = 0;
|
||||
|
|
|
@ -2833,63 +2833,3 @@ bool CMenus::HandleListInputs(const CUIRect &View, float &ScrollValue, const flo
|
|||
|
||||
return NewIndex != -1;
|
||||
}
|
||||
|
||||
void CMenus::DoToolTip(const void *pID, const CUIRect *pNearRect, const char *pText, float WidthHint)
|
||||
{
|
||||
static int64_t HoverTime = -1;
|
||||
|
||||
if(!UI()->MouseInside(pNearRect))
|
||||
{
|
||||
if(pID == UI()->ActiveTooltipItem())
|
||||
HoverTime = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
UI()->SetActiveTooltipItem(pID);
|
||||
|
||||
if(HoverTime == -1)
|
||||
HoverTime = time_get();
|
||||
|
||||
// Delay tooltip until 1 second passed.
|
||||
if(HoverTime > time_get() - time_freq())
|
||||
return;
|
||||
|
||||
const float MARGIN = 5.0f;
|
||||
|
||||
CUIRect Rect;
|
||||
Rect.w = WidthHint;
|
||||
if(WidthHint < 0.0f)
|
||||
Rect.w = TextRender()->TextWidth(0, 14.0f, pText, -1, -1.0f) + 4.0f;
|
||||
Rect.h = 30.0f;
|
||||
|
||||
CUIRect *pScreen = UI()->Screen();
|
||||
|
||||
// Try the top side.
|
||||
if(pNearRect->y - Rect.h - MARGIN > pScreen->y)
|
||||
{
|
||||
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
||||
Rect.y = pNearRect->y - Rect.h - MARGIN;
|
||||
}
|
||||
// Try the bottom side.
|
||||
else if(pNearRect->y + pNearRect->h + MARGIN < pScreen->h)
|
||||
{
|
||||
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
||||
Rect.y = pNearRect->y + pNearRect->h + MARGIN;
|
||||
}
|
||||
// Try the right side.
|
||||
else if(pNearRect->x + pNearRect->w + MARGIN + Rect.w < pScreen->w)
|
||||
{
|
||||
Rect.x = pNearRect->x + pNearRect->w + MARGIN;
|
||||
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
||||
}
|
||||
// Try the left side.
|
||||
else if(pNearRect->x - Rect.w - MARGIN > pScreen->x)
|
||||
{
|
||||
Rect.x = pNearRect->x - Rect.w - MARGIN;
|
||||
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
||||
}
|
||||
|
||||
RenderTools()->DrawUIRect(&Rect, ColorRGBA(0.2, 0.2, 0.2, 0.80f), CUI::CORNER_ALL, 5.0f);
|
||||
Rect.Margin(2.0f, &Rect);
|
||||
UI()->DoLabel(&Rect, pText, 14.0f, TEXTALIGN_LEFT);
|
||||
}
|
||||
|
|
|
@ -530,7 +530,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
{
|
||||
m_Dummy ^= 1;
|
||||
}
|
||||
DoToolTip(&m_Dummy, &DummyLabel, Localize("Toggle to edit your dummy settings."));
|
||||
GameClient()->m_Tooltips.DoToolTip(&m_Dummy, &DummyLabel, Localize("Toggle to edit your dummy settings."));
|
||||
|
||||
Dummy.HSplitTop(20.0f, &DummyLabel, &Dummy);
|
||||
|
||||
|
@ -1265,7 +1265,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
|||
MainView.HSplitTop(20.0f, &Button, &MainView);
|
||||
if(DoButton_CheckBox(&g_Config.m_GfxHighDetail, Localize("High Detail"), g_Config.m_GfxHighDetail, &Button))
|
||||
g_Config.m_GfxHighDetail ^= 1;
|
||||
DoToolTip(&g_Config.m_GfxHighDetail, &Button, Localize("Allows maps to render with more detail."));
|
||||
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_GfxHighDetail, &Button, Localize("Allows maps to render with more detail."));
|
||||
|
||||
MainView.HSplitTop(20.0f, &Button, &MainView);
|
||||
if(DoButton_CheckBox(&g_Config.m_GfxHighdpi, Localize("Use high DPI"), g_Config.m_GfxHighdpi, &Button))
|
||||
|
@ -2635,6 +2635,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
|||
{
|
||||
g_Config.m_ClRaceGhost ^= 1;
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClRaceGhost, &Button, Localize("When you cross the start line, show a ghost tee replicating the movements of your best time."));
|
||||
|
||||
if(g_Config.m_ClRaceGhost)
|
||||
{
|
||||
|
@ -2686,13 +2687,15 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
|||
Button.VSplitMid(&LeftLeft, &Button);
|
||||
|
||||
Button.VSplitLeft(50.0f, &Label, &Button);
|
||||
UI()->DoLabelScaled(&Label, Localize("Alpha"), 14.0f, TEXTALIGN_LEFT);
|
||||
UI()->DoLabelScaled(&Label, Localize("Opacity"), 14.0f, TEXTALIGN_LEFT);
|
||||
g_Config.m_ClShowOthersAlpha = (int)(UIEx()->DoScrollbarH(&g_Config.m_ClShowOthersAlpha, &Button, g_Config.m_ClShowOthersAlpha / 100.0f) * 100.0f);
|
||||
|
||||
if(DoButton_CheckBox(&g_Config.m_ClShowOthers, Localize("Show others"), g_Config.m_ClShowOthers == SHOW_OTHERS_ON, &LeftLeft))
|
||||
{
|
||||
g_Config.m_ClShowOthers = g_Config.m_ClShowOthers != SHOW_OTHERS_ON ? SHOW_OTHERS_ON : SHOW_OTHERS_OFF;
|
||||
}
|
||||
|
||||
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClShowOthersAlpha, &Button, "Adjust the opacity of entities belonging to other teams, such as tees and nameplates");
|
||||
}
|
||||
|
||||
Left.HSplitTop(20.0f, &Button, &Left);
|
||||
|
@ -2707,6 +2710,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
|||
{
|
||||
g_Config.m_ClShowQuads ^= 1;
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClShowQuads, &Button, Localize("Quads are used for background decoration"));
|
||||
|
||||
Right.HSplitTop(20.0f, &Label, &Right);
|
||||
Label.VSplitLeft(130.0f, &Label, &Button);
|
||||
|
@ -2720,6 +2724,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
|
|||
{
|
||||
g_Config.m_ClAntiPing ^= 1;
|
||||
}
|
||||
GameClient()->m_Tooltips.DoToolTip(&g_Config.m_ClAntiPing, &Button, Localize("Tries to predict other entities to give a feel of low latency."));
|
||||
|
||||
if(g_Config.m_ClAntiPing)
|
||||
{
|
||||
|
|
117
src/game/client/components/tooltips.cpp
Normal file
117
src/game/client/components/tooltips.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include "tooltips.h"
|
||||
|
||||
#include <game/client/render.h>
|
||||
|
||||
CTooltips::CTooltips()
|
||||
{
|
||||
OnReset();
|
||||
}
|
||||
|
||||
void CTooltips::OnReset()
|
||||
{
|
||||
HoverTime = -1;
|
||||
m_Tooltips.clear();
|
||||
}
|
||||
|
||||
void CTooltips::SetActiveTooltip(CTooltip &Tooltip)
|
||||
{
|
||||
if(m_ActiveTooltip.has_value())
|
||||
return;
|
||||
|
||||
m_ActiveTooltip.emplace(Tooltip);
|
||||
HoverTime = time_get();
|
||||
}
|
||||
|
||||
inline void CTooltips::ClearActiveTooltip()
|
||||
{
|
||||
m_ActiveTooltip.reset();
|
||||
}
|
||||
|
||||
void CTooltips::DoToolTip(const void *pID, const CUIRect *pNearRect, const char *pText, float WidthHint)
|
||||
{
|
||||
uintptr_t ID = reinterpret_cast<uintptr_t>(pID);
|
||||
|
||||
const auto &it = m_Tooltips.find(ID);
|
||||
|
||||
if(it == m_Tooltips.end())
|
||||
{
|
||||
CTooltip NewTooltip = {
|
||||
*pNearRect,
|
||||
pText,
|
||||
WidthHint,
|
||||
};
|
||||
|
||||
m_Tooltips[ID] = NewTooltip;
|
||||
|
||||
CTooltip &Tooltip = m_Tooltips[ID];
|
||||
|
||||
if(UI()->MouseInside(&Tooltip.m_Rect))
|
||||
{
|
||||
SetActiveTooltip(Tooltip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(UI()->MouseInside(&it->second.m_Rect))
|
||||
{
|
||||
SetActiveTooltip(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTooltips::OnRender()
|
||||
{
|
||||
if(m_ActiveTooltip.has_value())
|
||||
{
|
||||
CTooltip &Tooltip = m_ActiveTooltip.value();
|
||||
|
||||
if(!UI()->MouseInside(&Tooltip.m_Rect))
|
||||
{
|
||||
ClearActiveTooltip();
|
||||
return;
|
||||
}
|
||||
|
||||
// Delay tooltip until 1 second passed.
|
||||
if(HoverTime > time_get() - time_freq())
|
||||
return;
|
||||
|
||||
const float MARGIN = 5.0f;
|
||||
|
||||
CUIRect Rect;
|
||||
Rect.w = Tooltip.m_WidthHint;
|
||||
if(Tooltip.m_WidthHint < 0.0f)
|
||||
Rect.w = TextRender()->TextWidth(0, 14.0f, Tooltip.m_pText, -1, -1.0f) + 4.0f;
|
||||
Rect.h = 30.0f;
|
||||
|
||||
CUIRect *pScreen = UI()->Screen();
|
||||
|
||||
// Try the top side.
|
||||
if(Tooltip.m_Rect.y - Rect.h - MARGIN > pScreen->y)
|
||||
{
|
||||
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
||||
Rect.y = Tooltip.m_Rect.y - Rect.h - MARGIN;
|
||||
}
|
||||
// Try the bottom side.
|
||||
else if(Tooltip.m_Rect.y + Tooltip.m_Rect.h + MARGIN < pScreen->h)
|
||||
{
|
||||
Rect.x = clamp(UI()->MouseX() - Rect.w / 2.0f, MARGIN, pScreen->w - Rect.w - MARGIN);
|
||||
Rect.y = Tooltip.m_Rect.y + Tooltip.m_Rect.h + MARGIN;
|
||||
}
|
||||
// Try the right side.
|
||||
else if(Tooltip.m_Rect.x + Tooltip.m_Rect.w + MARGIN + Rect.w < pScreen->w)
|
||||
{
|
||||
Rect.x = Tooltip.m_Rect.x + Tooltip.m_Rect.w + MARGIN;
|
||||
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
||||
}
|
||||
// Try the left side.
|
||||
else if(Tooltip.m_Rect.x - Rect.w - MARGIN > pScreen->x)
|
||||
{
|
||||
Rect.x = Tooltip.m_Rect.x - Rect.w - MARGIN;
|
||||
Rect.y = clamp(UI()->MouseY() - Rect.h / 2.0f, MARGIN, pScreen->h - Rect.h - MARGIN);
|
||||
}
|
||||
|
||||
RenderTools()->DrawUIRect(&Rect, ColorRGBA(0.2, 0.2, 0.2, 0.80f), CUI::CORNER_ALL, 5.0f);
|
||||
Rect.Margin(2.0f, &Rect);
|
||||
UI()->DoLabel(&Rect, Tooltip.m_pText, 14.0f, TEXTALIGN_LEFT);
|
||||
}
|
||||
}
|
59
src/game/client/components/tooltips.h
Normal file
59
src/game/client/components/tooltips.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
#ifndef GAME_CLIENT_COMPONENTS_TOOLTIPS_H
|
||||
#define GAME_CLIENT_COMPONENTS_TOOLTIPS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <game/client/component.h>
|
||||
#include <game/client/ui.h>
|
||||
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
struct CTooltip
|
||||
{
|
||||
CUIRect m_Rect;
|
||||
const char *m_pText;
|
||||
float m_WidthHint;
|
||||
};
|
||||
|
||||
/**
|
||||
* A component that manages and renders UI tooltips.
|
||||
*
|
||||
* Should be among the last components to render.
|
||||
*/
|
||||
class CTooltips : public CComponent
|
||||
{
|
||||
std::unordered_map<uintptr_t, CTooltip> m_Tooltips;
|
||||
std::optional<std::reference_wrapper<CTooltip>> m_ActiveTooltip;
|
||||
int64_t HoverTime;
|
||||
|
||||
/**
|
||||
* The passed tooltip is only actually set if there is no currently active tooltip.
|
||||
*
|
||||
* @param Tooltip A reference to the tooltip that should be active.
|
||||
*/
|
||||
void SetActiveTooltip(CTooltip &Tooltip);
|
||||
|
||||
inline void ClearActiveTooltip();
|
||||
|
||||
public:
|
||||
CTooltips();
|
||||
virtual int Sizeof() const override { return sizeof(*this); }
|
||||
|
||||
/**
|
||||
* Adds the tooltip to a cache and renders it when active.
|
||||
*
|
||||
* On the first call to this function, the data passed is cached, afterwards the calls are used to detect if the tooltip should be activated.
|
||||
*
|
||||
* For now only works correctly with single line tooltips, since Text width calculation gets broken when there are multiple lines.
|
||||
*
|
||||
* @param pID The ID of the tooltip. Usually a reference to some g_Config value.
|
||||
* @param pNearTo Place the tooltip near this rect.
|
||||
* @param pText The text to display in the tooltip
|
||||
*/
|
||||
void DoToolTip(const void *pID, const CUIRect *pNearRect, const char *pText, float WidthHint = -1.0f);
|
||||
|
||||
virtual void OnReset() override;
|
||||
virtual void OnRender() override;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -137,6 +137,7 @@ void CGameClient::OnConsoleInit()
|
|||
m_All.Add(&m_Statboard);
|
||||
m_All.Add(&m_Motd);
|
||||
m_All.Add(&m_Menus);
|
||||
m_All.Add(&m_Tooltips);
|
||||
m_All.Add(&CMenus::m_Binder);
|
||||
m_All.Add(&m_GameConsole);
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "components/sounds.h"
|
||||
#include "components/spectator.h"
|
||||
#include "components/statboard.h"
|
||||
#include "components/tooltips.h"
|
||||
#include "components/voting.h"
|
||||
|
||||
class CGameInfo
|
||||
|
@ -144,6 +145,8 @@ public:
|
|||
CRaceDemo m_RaceDemo;
|
||||
CGhost m_Ghost;
|
||||
|
||||
CTooltips m_Tooltips;
|
||||
|
||||
private:
|
||||
class CStack
|
||||
{
|
||||
|
|
|
@ -339,6 +339,7 @@ bool CUIEx::DoEditBox(const void *pID, const CUIRect *pRect, char *pStr, unsigne
|
|||
{
|
||||
pStr[0] = '\0';
|
||||
m_CurCursor = 0;
|
||||
SetHasSelection(false);
|
||||
ReturnValue = true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue