mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[dxvk] Added HUD
Experimental version of a HUD which displays information about the hardware, driver version, and frames per second.
This commit is contained in:
parent
672675ba78
commit
96a97aa0c4
@ -38,6 +38,7 @@ The behaviour of DXVK can be modified with environment variables.
|
||||
|
||||
- `DXVK_SHADER_DUMP_PATH=directory` Writes all DXBC and SPIR-V shaders to the given directory
|
||||
- `DXVK_DEBUG_LAYERS=1` Enables Vulkan debug layers. Highly recommended for troubleshooting and debugging purposes.
|
||||
- `DXVK_HUD=1` Enables the HUD
|
||||
|
||||
## Samples and executables
|
||||
In addition to the DLLs, the following standalone programs are included in the project:
|
||||
|
@ -18,5 +18,11 @@ lib_d3d11 = dxvk_compiler.find_library('d3d11')
|
||||
lib_dxgi = dxvk_compiler.find_library('dxgi')
|
||||
lib_d3dcompiler_47 = dxvk_compiler.find_library('d3dcompiler_47')
|
||||
|
||||
glsl_compiler = find_program('glslangValidator')
|
||||
glsl_generator = generator(glsl_compiler,
|
||||
output : [ '@BASENAME@.h' ],
|
||||
arguments : [ '-V', '--vn', '@BASENAME@', '@INPUT@', '-o', '@OUTPUT@' ])
|
||||
|
||||
|
||||
subdir('src')
|
||||
subdir('tests')
|
||||
|
@ -101,21 +101,17 @@ namespace dxvk {
|
||||
loState.logicOp = VK_LOGIC_OP_NO_OP;
|
||||
m_context->setLogicOpState(loState);
|
||||
|
||||
DxvkBlendMode blendMode;
|
||||
blendMode.enableBlending = VK_FALSE;
|
||||
blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendMode.colorDstFactor = VK_BLEND_FACTOR_ZERO;
|
||||
blendMode.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendMode.alphaDstFactor = VK_BLEND_FACTOR_ZERO;
|
||||
blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT
|
||||
| VK_COLOR_COMPONENT_G_BIT
|
||||
| VK_COLOR_COMPONENT_B_BIT
|
||||
| VK_COLOR_COMPONENT_A_BIT;
|
||||
|
||||
for (uint32_t i = 0; i < DxvkLimits::MaxNumRenderTargets; i++)
|
||||
m_context->setBlendMode(i, blendMode);
|
||||
m_blendMode.enableBlending = VK_FALSE;
|
||||
m_blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
m_blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
m_blendMode.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
m_blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
m_blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
m_blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
m_blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT
|
||||
| VK_COLOR_COMPONENT_G_BIT
|
||||
| VK_COLOR_COMPONENT_B_BIT
|
||||
| VK_COLOR_COMPONENT_A_BIT;
|
||||
|
||||
m_context->bindShader(
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
@ -124,6 +120,8 @@ namespace dxvk {
|
||||
m_context->bindShader(
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
this->createFragmentShader());
|
||||
|
||||
m_hud = hud::Hud::createHud(m_device);
|
||||
}
|
||||
|
||||
|
||||
@ -150,16 +148,11 @@ namespace dxvk {
|
||||
|
||||
|
||||
void DxgiPresenter::presentImage() {
|
||||
auto newTime = std::chrono::high_resolution_clock::now();
|
||||
auto us = std::chrono::duration_cast<std::chrono::microseconds>(newTime - m_oldTime).count();
|
||||
|
||||
m_frames += 1;
|
||||
|
||||
if (us >= 1'000'000) {
|
||||
std::cout << "FPS: " << (static_cast<double>(m_frames * 1'000'000)
|
||||
/ static_cast<double>(us)) << std::endl;
|
||||
m_frames = 0;
|
||||
m_oldTime = newTime;
|
||||
if (m_hud != nullptr) {
|
||||
m_hud->render({
|
||||
m_options.preferredBufferSize.width,
|
||||
m_options.preferredBufferSize.height,
|
||||
});
|
||||
}
|
||||
|
||||
const bool fitSize =
|
||||
@ -207,9 +200,20 @@ namespace dxvk {
|
||||
m_context->bindResourceSampler(BindingIds::Sampler,
|
||||
fitSize ? m_samplerFitting : m_samplerScaling);
|
||||
|
||||
m_blendMode.enableBlending = VK_FALSE;
|
||||
m_context->setBlendMode(0, m_blendMode);
|
||||
|
||||
m_context->bindResourceImage(BindingIds::Texture, m_backBufferView);
|
||||
m_context->draw(4, 1, 0, 0);
|
||||
|
||||
if (m_hud != nullptr) {
|
||||
m_blendMode.enableBlending = VK_TRUE;
|
||||
m_context->setBlendMode(0, m_blendMode);
|
||||
|
||||
m_context->bindResourceImage(BindingIds::Texture, m_hud->texture());
|
||||
m_context->draw(4, 1, 0, 0);
|
||||
}
|
||||
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
sem.acquireSync, sem.presentSync);
|
||||
|
@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
#include "../dxvk/dxvk_surface.h"
|
||||
#include "../dxvk/dxvk_swapchain.h"
|
||||
|
||||
#include <dxvk_device.h>
|
||||
#include <dxvk_surface.h>
|
||||
#include <dxvk_swapchain.h>
|
||||
|
||||
#include "dxgi_include.h"
|
||||
#include "../dxvk/hud/dxvk_hud.h"
|
||||
|
||||
#include "../spirv/spirv_module.h"
|
||||
|
||||
#include "dxgi_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
@ -100,14 +100,14 @@ namespace dxvk {
|
||||
Rc<DxvkImage> m_backBufferResolve;
|
||||
Rc<DxvkImageView> m_backBufferView;
|
||||
|
||||
Rc<hud::Hud> m_hud;
|
||||
|
||||
DxvkBlendMode m_blendMode;
|
||||
DxvkSwapchainProperties m_options;
|
||||
|
||||
Rc<DxvkShader> createVertexShader();
|
||||
Rc<DxvkShader> createFragmentShader();
|
||||
|
||||
std::chrono::high_resolution_clock::time_point m_oldTime;
|
||||
uint32_t m_frames = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ namespace dxvk::util {
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool operator == (VkExtent3D a, VkExtent3D b) {
|
||||
return a.width == b.width
|
||||
&& a.height == b.height
|
||||
@ -48,3 +49,15 @@ bool operator != (VkExtent3D a, VkExtent3D b) {
|
||||
|| a.height != b.height
|
||||
|| a.depth != b.depth;
|
||||
}
|
||||
|
||||
|
||||
bool operator == (VkExtent2D a, VkExtent2D b) {
|
||||
return a.width == b.width
|
||||
&& a.height == b.height;
|
||||
}
|
||||
|
||||
|
||||
bool operator != (VkExtent2D a, VkExtent2D b) {
|
||||
return a.width != b.width
|
||||
|| a.height != b.height;
|
||||
}
|
||||
|
@ -25,3 +25,6 @@ namespace dxvk::util {
|
||||
|
||||
bool operator == (VkExtent3D a, VkExtent3D b);
|
||||
bool operator != (VkExtent3D a, VkExtent3D b);
|
||||
|
||||
bool operator == (VkExtent2D a, VkExtent2D b);
|
||||
bool operator != (VkExtent2D a, VkExtent2D b);
|
||||
|
248
src/dxvk/hud/dxvk_hud.cpp
Normal file
248
src/dxvk/hud/dxvk_hud.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
#include "dxvk_hud.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
Hud::Hud(const Rc<DxvkDevice>& device)
|
||||
: m_device (device),
|
||||
m_context (m_device->createContext()),
|
||||
m_textRenderer (m_device, m_context),
|
||||
m_uniformBuffer (createUniformBuffer()),
|
||||
m_hudDeviceInfo (device) {
|
||||
this->setupConstantState();
|
||||
}
|
||||
|
||||
|
||||
Hud::~Hud() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Hud::render(VkExtent2D size) {
|
||||
bool recreateFbo = m_surfaceSize != size;
|
||||
|
||||
if (recreateFbo) {
|
||||
m_surfaceSize = size;
|
||||
this->setupFramebuffer(size);
|
||||
}
|
||||
|
||||
m_hudFps.update();
|
||||
|
||||
this->synchronize();
|
||||
this->updateUniformBuffer();
|
||||
this->beginRenderPass(recreateFbo);
|
||||
this->renderText();
|
||||
this->endRenderPass();
|
||||
}
|
||||
|
||||
|
||||
Rc<Hud> Hud::createHud(const Rc<DxvkDevice>& device) {
|
||||
const std::string hudConfig = env::getEnvVar(L"DXVK_HUD");
|
||||
|
||||
if (hudConfig.size() == 0)
|
||||
return nullptr;
|
||||
|
||||
// TODO implement configuration options for the HUD
|
||||
return new Hud(device);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkBuffer> Hud::createUniformBuffer() {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = sizeof(HudUniformData);
|
||||
info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
info.access = VK_ACCESS_UNIFORM_READ_BIT;
|
||||
|
||||
return m_device->createBuffer(info,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
}
|
||||
|
||||
|
||||
void Hud::renderText() {
|
||||
m_textRenderer.beginFrame(m_context);
|
||||
|
||||
HudPos position = { 8.0f, 24.0f };
|
||||
position = m_hudDeviceInfo.renderText(
|
||||
m_context, m_textRenderer, position);
|
||||
position = m_hudFps.renderText(
|
||||
m_context, m_textRenderer, position);
|
||||
}
|
||||
|
||||
|
||||
void Hud::synchronize() {
|
||||
// Wait for previous frame to complete so that we can
|
||||
// safely write to the uniform/vertex buffers. We could
|
||||
// actually avoid this by double-buffering the data, but
|
||||
// it is probably not worth the effort.
|
||||
if (m_syncFence != nullptr) {
|
||||
m_syncFence->wait(
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Hud::updateUniformBuffer() {
|
||||
HudUniformData uniformData;
|
||||
uniformData.surfaceSize = m_surfaceSize;
|
||||
|
||||
std::memcpy(m_uniformBuffer->mapPtr(0),
|
||||
&uniformData, sizeof(uniformData));
|
||||
}
|
||||
|
||||
|
||||
void Hud::beginRenderPass(bool initFbo) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
if (initFbo) {
|
||||
m_context->initImage(m_renderTarget,
|
||||
VkImageSubresourceRange {
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0, 1, 0, 1 });
|
||||
}
|
||||
|
||||
VkClearAttachment clearInfo;
|
||||
clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
clearInfo.colorAttachment = 0;
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
clearInfo.clearValue.color.float32[i] = 0.0f;
|
||||
|
||||
VkClearRect clearRect;
|
||||
clearRect.rect.offset = { 0, 0 };
|
||||
clearRect.rect.extent = m_surfaceSize;
|
||||
clearRect.baseArrayLayer = 0;
|
||||
clearRect.layerCount = 1;
|
||||
|
||||
m_context->bindFramebuffer(m_renderTargetFbo);
|
||||
m_context->clearRenderTarget(clearInfo, clearRect);
|
||||
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(m_surfaceSize.width);
|
||||
viewport.height = static_cast<float>(m_surfaceSize.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor;
|
||||
scissor.offset = { 0, 0 };
|
||||
scissor.extent = m_surfaceSize;
|
||||
|
||||
m_context->setViewports(1, &viewport, &scissor);
|
||||
m_context->bindResourceBuffer(0, DxvkBufferSlice(m_uniformBuffer));
|
||||
}
|
||||
|
||||
|
||||
void Hud::endRenderPass() {
|
||||
m_syncFence = m_device->submitCommandList(
|
||||
m_context->endRecording(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void Hud::setupFramebuffer(VkExtent2D size) {
|
||||
DxvkImageCreateInfo imageInfo;
|
||||
imageInfo.type = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.format = VK_FORMAT_R8G8B8A8_SRGB;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent = { size.width, size.height, 1 };
|
||||
imageInfo.numLayers = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
imageInfo.access = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
m_renderTarget = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = imageInfo.format;
|
||||
viewInfo.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.minLevel = 0;
|
||||
viewInfo.numLevels = 1;
|
||||
viewInfo.minLayer = 0;
|
||||
viewInfo.numLayers = 1;
|
||||
|
||||
m_renderTargetView = m_device->createImageView(m_renderTarget, viewInfo);
|
||||
|
||||
DxvkRenderTargets framebufferInfo;
|
||||
framebufferInfo.setColorTarget(0, m_renderTargetView);
|
||||
|
||||
m_renderTargetFbo = m_device->createFramebuffer(framebufferInfo);
|
||||
}
|
||||
|
||||
|
||||
void Hud::setupConstantState() {
|
||||
DxvkRasterizerState rsState;
|
||||
rsState.enableDepthClamp = VK_FALSE;
|
||||
rsState.enableDiscard = VK_FALSE;
|
||||
rsState.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rsState.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rsState.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
rsState.depthBiasEnable = VK_FALSE;
|
||||
rsState.depthBiasConstant = 0.0f;
|
||||
rsState.depthBiasClamp = 0.0f;
|
||||
rsState.depthBiasSlope = 0.0f;
|
||||
m_context->setRasterizerState(rsState);
|
||||
|
||||
DxvkMultisampleState msState;
|
||||
msState.sampleMask = 0xFFFFFFFF;
|
||||
msState.enableAlphaToCoverage = VK_FALSE;
|
||||
msState.enableAlphaToOne = VK_FALSE;
|
||||
msState.enableSampleShading = VK_FALSE;
|
||||
msState.minSampleShading = 1.0f;
|
||||
m_context->setMultisampleState(msState);
|
||||
|
||||
VkStencilOpState stencilOp;
|
||||
stencilOp.failOp = VK_STENCIL_OP_KEEP;
|
||||
stencilOp.passOp = VK_STENCIL_OP_KEEP;
|
||||
stencilOp.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||
stencilOp.compareOp = VK_COMPARE_OP_NEVER;
|
||||
stencilOp.compareMask = 0xFFFFFFFF;
|
||||
stencilOp.writeMask = 0xFFFFFFFF;
|
||||
stencilOp.reference = 0;
|
||||
|
||||
DxvkDepthStencilState dsState;
|
||||
dsState.enableDepthTest = VK_FALSE;
|
||||
dsState.enableDepthWrite = VK_FALSE;
|
||||
dsState.enableDepthBounds = VK_FALSE;
|
||||
dsState.enableStencilTest = VK_FALSE;
|
||||
dsState.depthCompareOp = VK_COMPARE_OP_NEVER;
|
||||
dsState.stencilOpFront = stencilOp;
|
||||
dsState.stencilOpBack = stencilOp;
|
||||
m_context->setDepthStencilState(dsState);
|
||||
|
||||
DxvkLogicOpState loState;
|
||||
loState.enableLogicOp = VK_FALSE;
|
||||
loState.logicOp = VK_LOGIC_OP_NO_OP;
|
||||
m_context->setLogicOpState(loState);
|
||||
|
||||
DxvkBlendMode blendMode;
|
||||
blendMode.enableBlending = VK_TRUE;
|
||||
blendMode.colorSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendMode.colorDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
blendMode.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
blendMode.alphaSrcFactor = VK_BLEND_FACTOR_ONE;
|
||||
blendMode.alphaDstFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
blendMode.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
blendMode.writeMask = VK_COLOR_COMPONENT_R_BIT
|
||||
| VK_COLOR_COMPONENT_G_BIT
|
||||
| VK_COLOR_COMPONENT_B_BIT
|
||||
| VK_COLOR_COMPONENT_A_BIT;
|
||||
|
||||
for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
|
||||
m_context->setBlendMode(i, blendMode);
|
||||
}
|
||||
|
||||
}
|
94
src/dxvk/hud/dxvk_hud.h
Normal file
94
src/dxvk/hud/dxvk_hud.h
Normal file
@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include "../dxvk_device.h"
|
||||
|
||||
#include "../util/util_env.h"
|
||||
|
||||
#include "dxvk_hud_devinfo.h"
|
||||
#include "dxvk_hud_fps.h"
|
||||
#include "dxvk_hud_text.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
struct HudUniformData {
|
||||
VkExtent2D surfaceSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DXVK HUD
|
||||
*
|
||||
* Can be used by the presentation backend to
|
||||
* display performance and driver information.
|
||||
*/
|
||||
class Hud : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
explicit Hud(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
~Hud();
|
||||
|
||||
/**
|
||||
* \brief Renders the HUD
|
||||
*
|
||||
* Recreates the render targets for the HUD
|
||||
* in case the surface size has changed.
|
||||
* \param [in] size Render target size
|
||||
*/
|
||||
void render(VkExtent2D size);
|
||||
|
||||
/**
|
||||
* \brief Rendered image
|
||||
*
|
||||
* Returns the rendered image from
|
||||
* the previous call to \ref render.
|
||||
* \returns The image view
|
||||
*/
|
||||
Rc<DxvkImageView> texture() const {
|
||||
return m_renderTargetView;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates the HUD
|
||||
*
|
||||
* Creates and initializes the HUD if the
|
||||
* \c DXVK_HUD environment variable is set.
|
||||
* \param [in] device The DXVK device
|
||||
* \returns HUD object, if it was created.
|
||||
*/
|
||||
static Rc<Hud> createHud(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
private:
|
||||
|
||||
const Rc<DxvkDevice> m_device;
|
||||
const Rc<DxvkContext> m_context;
|
||||
|
||||
HudTextRenderer m_textRenderer;
|
||||
VkExtent2D m_surfaceSize = { 0, 0 };
|
||||
|
||||
Rc<DxvkFence> m_syncFence;
|
||||
Rc<DxvkBuffer> m_uniformBuffer;
|
||||
Rc<DxvkImage> m_renderTarget;
|
||||
Rc<DxvkImageView> m_renderTargetView;
|
||||
Rc<DxvkFramebuffer> m_renderTargetFbo;
|
||||
|
||||
HudDeviceInfo m_hudDeviceInfo;
|
||||
HudFps m_hudFps;
|
||||
|
||||
void renderText();
|
||||
|
||||
Rc<DxvkBuffer> createUniformBuffer();
|
||||
|
||||
void synchronize();
|
||||
void updateUniformBuffer();
|
||||
void beginRenderPass(bool initFbo);
|
||||
void endRenderPass();
|
||||
|
||||
void setupFramebuffer(VkExtent2D size);
|
||||
void setupConstantState();
|
||||
|
||||
};
|
||||
|
||||
}
|
46
src/dxvk/hud/dxvk_hud_devinfo.cpp
Normal file
46
src/dxvk/hud/dxvk_hud_devinfo.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "dxvk_hud_devinfo.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
HudDeviceInfo::HudDeviceInfo(const Rc<DxvkDevice>& device) {
|
||||
VkPhysicalDeviceProperties props = device->adapter()->deviceProperties();
|
||||
m_deviceName = props.deviceName;
|
||||
m_driverVer = str::format("Driver: ",
|
||||
VK_VERSION_MAJOR(props.driverVersion), ".",
|
||||
VK_VERSION_MINOR(props.driverVersion), ".",
|
||||
VK_VERSION_PATCH(props.driverVersion));
|
||||
m_vulkanVer = str::format("Vulkan: ",
|
||||
VK_VERSION_MAJOR(props.apiVersion), ".",
|
||||
VK_VERSION_MINOR(props.apiVersion), ".",
|
||||
VK_VERSION_PATCH(props.apiVersion));
|
||||
}
|
||||
|
||||
|
||||
HudDeviceInfo::~HudDeviceInfo() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
HudPos HudDeviceInfo::renderText(
|
||||
const Rc<DxvkContext>& context,
|
||||
HudTextRenderer& renderer,
|
||||
HudPos position) {
|
||||
renderer.drawText(context, 16.0f,
|
||||
{ position.x, position.y },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF },
|
||||
m_deviceName);
|
||||
|
||||
renderer.drawText(context, 16.0f,
|
||||
{ position.x, position.y + 24 },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF },
|
||||
m_driverVer);
|
||||
|
||||
renderer.drawText(context, 16.0f,
|
||||
{ position.x, position.y + 44 },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF },
|
||||
m_vulkanVer);
|
||||
|
||||
return HudPos { position.x, position.y + 68 };
|
||||
}
|
||||
|
||||
}
|
33
src/dxvk/hud/dxvk_hud_devinfo.h
Normal file
33
src/dxvk/hud/dxvk_hud_devinfo.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "dxvk_hud_text.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
/**
|
||||
* \brief Device info display for the HUD
|
||||
*
|
||||
* Displays the name of the device, as well as
|
||||
* the driver version and Vulkan API version.
|
||||
*/
|
||||
class HudDeviceInfo {
|
||||
|
||||
public:
|
||||
|
||||
HudDeviceInfo(const Rc<DxvkDevice>& device);
|
||||
~HudDeviceInfo();
|
||||
|
||||
HudPos renderText(
|
||||
const Rc<DxvkContext>& context,
|
||||
HudTextRenderer& renderer,
|
||||
HudPos position);
|
||||
|
||||
private:
|
||||
|
||||
std::string m_deviceName;
|
||||
std::string m_driverVer;
|
||||
std::string m_vulkanVer;
|
||||
|
||||
};
|
||||
|
||||
}
|
1869
src/dxvk/hud/dxvk_hud_font.cpp
Normal file
1869
src/dxvk/hud/dxvk_hud_font.cpp
Normal file
File diff suppressed because it is too large
Load Diff
31
src/dxvk/hud/dxvk_hud_font.h
Normal file
31
src/dxvk/hud/dxvk_hud_font.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
struct HudGlyph {
|
||||
uint32_t codePoint;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t w;
|
||||
int32_t h;
|
||||
int32_t originX;
|
||||
int32_t originY;
|
||||
};
|
||||
|
||||
struct HudFont {
|
||||
int32_t size;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t falloff;
|
||||
uint32_t advance;
|
||||
uint32_t charCount;
|
||||
|
||||
const HudGlyph* glyphs;
|
||||
const uint8_t* texture;
|
||||
};
|
||||
|
||||
extern const HudFont g_hudFont;
|
||||
|
||||
}
|
47
src/dxvk/hud/dxvk_hud_fps.cpp
Normal file
47
src/dxvk/hud/dxvk_hud_fps.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "dxvk_hud_fps.h"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
HudFps::HudFps()
|
||||
: m_fpsString("FPS: "),
|
||||
m_prevUpdate(Clock::now()) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
HudFps::~HudFps() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void HudFps::update() {
|
||||
m_frameCount += 1;
|
||||
|
||||
const TimePoint now = Clock::now();
|
||||
const TimeDiff elapsed = std::chrono::duration_cast<TimeDiff>(now - m_prevUpdate);
|
||||
|
||||
if (elapsed.count() >= UpdateInterval) {
|
||||
const int64_t fps = (10'000'000ll * m_frameCount) / elapsed.count();
|
||||
m_fpsString = str::format("FPS: ", fps / 10, ".", fps % 10);
|
||||
|
||||
m_prevUpdate = now;
|
||||
m_frameCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HudPos HudFps::renderText(
|
||||
const Rc<DxvkContext>& context,
|
||||
HudTextRenderer& renderer,
|
||||
HudPos position) {
|
||||
renderer.drawText(context, 16.0f,
|
||||
{ position.x, position.y },
|
||||
{ 0xFF, 0xFF, 0xFF, 0xFF },
|
||||
m_fpsString);
|
||||
|
||||
return HudPos { position.x, position.y + 20 };
|
||||
}
|
||||
|
||||
}
|
42
src/dxvk/hud/dxvk_hud_fps.h
Normal file
42
src/dxvk/hud/dxvk_hud_fps.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include "dxvk_hud_text.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
/**
|
||||
* \brief FPS display for the HUD
|
||||
*
|
||||
* Displays the current frames per second.
|
||||
* TODO implement frame time info/graph.
|
||||
*/
|
||||
class HudFps {
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
using TimeDiff = std::chrono::microseconds;
|
||||
using TimePoint = typename Clock::time_point;
|
||||
|
||||
constexpr static int64_t UpdateInterval = 500'000;
|
||||
public:
|
||||
|
||||
HudFps();
|
||||
~HudFps();
|
||||
|
||||
void update();
|
||||
|
||||
HudPos renderText(
|
||||
const Rc<DxvkContext>& context,
|
||||
HudTextRenderer& renderer,
|
||||
HudPos position);
|
||||
|
||||
private:
|
||||
|
||||
std::string m_fpsString;
|
||||
|
||||
TimePoint m_prevUpdate;
|
||||
int64_t m_frameCount = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
278
src/dxvk/hud/dxvk_hud_text.cpp
Normal file
278
src/dxvk/hud/dxvk_hud_text.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
#include "dxvk_hud_text.h"
|
||||
|
||||
#include <hud_text_frag.h>
|
||||
#include <hud_text_vert.h>
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
HudTextRenderer::HudTextRenderer(
|
||||
const Rc<DxvkDevice>& device,
|
||||
const Rc<DxvkContext>& context)
|
||||
: m_vertShader (createVertexShader(device)),
|
||||
m_fragShader (createFragmentShader(device)),
|
||||
m_fontImage (createFontImage(device)),
|
||||
m_fontView (createFontView(device)),
|
||||
m_fontSampler (createFontSampler(device)),
|
||||
m_vertexBuffer (createVertexBuffer(device)) {
|
||||
this->initFontTexture(device, context);
|
||||
this->initCharMap();
|
||||
}
|
||||
|
||||
|
||||
HudTextRenderer::~HudTextRenderer() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void HudTextRenderer::beginFrame(const Rc<DxvkContext>& context) {
|
||||
context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vertShader);
|
||||
context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_fragShader);
|
||||
|
||||
DxvkInputAssemblyState iaState;
|
||||
iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
iaState.primitiveRestart = VK_FALSE;
|
||||
context->setInputAssemblyState(iaState);
|
||||
|
||||
const std::array<DxvkVertexAttribute, 3> ilAttributes = {{
|
||||
{ 0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(HudTextVertex, position) },
|
||||
{ 1, 0, VK_FORMAT_R16G16_UINT, offsetof(HudTextVertex, texcoord) },
|
||||
{ 2, 0, VK_FORMAT_R8G8B8A8_SRGB, offsetof(HudTextVertex, color) },
|
||||
}};
|
||||
|
||||
const std::array<DxvkVertexBinding, 1> ilBindings = {{
|
||||
{ 0, VK_VERTEX_INPUT_RATE_VERTEX },
|
||||
}};
|
||||
|
||||
context->setInputLayout(
|
||||
ilAttributes.size(),
|
||||
ilAttributes.data(),
|
||||
ilBindings.size(),
|
||||
ilBindings.data());
|
||||
|
||||
context->bindVertexBuffer(0,
|
||||
DxvkBufferSlice(m_vertexBuffer),
|
||||
sizeof(HudTextVertex));
|
||||
|
||||
context->bindResourceSampler(1, m_fontSampler);
|
||||
context->bindResourceImage (2, m_fontView);
|
||||
|
||||
m_vertexIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
void HudTextRenderer::drawText(
|
||||
const Rc<DxvkContext>& context,
|
||||
float size,
|
||||
HudPos pos,
|
||||
HudColor color,
|
||||
const std::string& text) {
|
||||
const size_t vertexIndex = m_vertexIndex;
|
||||
|
||||
HudTextVertex* vertexData = reinterpret_cast<HudTextVertex*>(
|
||||
m_vertexBuffer->mapPtr(vertexIndex * sizeof(HudTextVertex)));
|
||||
|
||||
const float sizeFactor = size / static_cast<float>(g_hudFont.size);
|
||||
|
||||
for (size_t i = 0; i < text.size(); i++) {
|
||||
const HudGlyph& glyph = g_hudFont.glyphs[
|
||||
m_charMap[static_cast<uint8_t>(text[i])]];
|
||||
|
||||
const HudPos size = {
|
||||
sizeFactor * static_cast<float>(glyph.w),
|
||||
sizeFactor * static_cast<float>(glyph.h) };
|
||||
|
||||
const HudPos origin = {
|
||||
pos.x + sizeFactor * static_cast<float>(glyph.originX),
|
||||
pos.y - sizeFactor * static_cast<float>(glyph.originY) };
|
||||
|
||||
const HudPos posTl = { origin.x, origin.y };
|
||||
const HudPos posBr = { origin.x + size.x, origin.y + size.y };
|
||||
|
||||
const HudTexCoord texTl = {
|
||||
static_cast<uint16_t>(glyph.x),
|
||||
static_cast<uint16_t>(glyph.y), };
|
||||
|
||||
const HudTexCoord texBr = {
|
||||
static_cast<uint16_t>(glyph.x + glyph.w),
|
||||
static_cast<uint16_t>(glyph.y + glyph.h) };
|
||||
|
||||
vertexData[6 * i + 0].position = { posTl.x, posTl.y };
|
||||
vertexData[6 * i + 0].texcoord = { texTl.u, texTl.v };
|
||||
vertexData[6 * i + 0].color = color;
|
||||
|
||||
vertexData[6 * i + 1].position = { posBr.x, posTl.y };
|
||||
vertexData[6 * i + 1].texcoord = { texBr.u, texTl.v };
|
||||
vertexData[6 * i + 1].color = color;
|
||||
|
||||
vertexData[6 * i + 2].position = { posTl.x, posBr.y };
|
||||
vertexData[6 * i + 2].texcoord = { texTl.u, texBr.v };
|
||||
vertexData[6 * i + 2].color = color;
|
||||
|
||||
vertexData[6 * i + 3].position = { posBr.x, posBr.y };
|
||||
vertexData[6 * i + 3].texcoord = { texBr.u, texBr.v };
|
||||
vertexData[6 * i + 3].color = color;
|
||||
|
||||
vertexData[6 * i + 4].position = { posTl.x, posBr.y };
|
||||
vertexData[6 * i + 4].texcoord = { texTl.u, texBr.v };
|
||||
vertexData[6 * i + 4].color = color;
|
||||
|
||||
vertexData[6 * i + 5].position = { posBr.x, posTl.y };
|
||||
vertexData[6 * i + 5].texcoord = { texBr.u, texTl.v };
|
||||
vertexData[6 * i + 5].color = color;
|
||||
|
||||
pos.x += sizeFactor * static_cast<float>(g_hudFont.advance);
|
||||
}
|
||||
|
||||
const uint32_t vertexCount = 6 * text.size();
|
||||
context->draw(vertexCount, 1, vertexIndex, 0);
|
||||
m_vertexIndex += vertexCount;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkShader> HudTextRenderer::createVertexShader(const Rc<DxvkDevice>& device) {
|
||||
const SpirvCodeBuffer codeBuffer(hud_text_vert);
|
||||
|
||||
// One shader resource: Global HUD uniform buffer
|
||||
const std::array<DxvkResourceSlot, 1> resourceSlots = {{
|
||||
{ 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_IMAGE_VIEW_TYPE_MAX_ENUM },
|
||||
}};
|
||||
|
||||
// 3 input registers, 2 output registers, tightly packed
|
||||
const DxvkInterfaceSlots interfaceSlots = { 0x7, 0x3 };
|
||||
|
||||
return new DxvkShader(
|
||||
VK_SHADER_STAGE_VERTEX_BIT,
|
||||
resourceSlots.size(),
|
||||
resourceSlots.data(),
|
||||
interfaceSlots,
|
||||
codeBuffer);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkShader> HudTextRenderer::createFragmentShader(const Rc<DxvkDevice>& device) {
|
||||
const SpirvCodeBuffer codeBuffer(hud_text_frag);
|
||||
|
||||
// One shader resource: Global HUD uniform buffer
|
||||
const std::array<DxvkResourceSlot, 2> resourceSlots = {{
|
||||
{ 1, VK_DESCRIPTOR_TYPE_SAMPLER, VK_IMAGE_VIEW_TYPE_MAX_ENUM },
|
||||
{ 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
|
||||
}};
|
||||
|
||||
// 2 input registers, 1 output register
|
||||
const DxvkInterfaceSlots interfaceSlots = { 0x3, 0x1 };
|
||||
|
||||
return new DxvkShader(
|
||||
VK_SHADER_STAGE_FRAGMENT_BIT,
|
||||
resourceSlots.size(),
|
||||
resourceSlots.data(),
|
||||
interfaceSlots,
|
||||
codeBuffer);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImage> HudTextRenderer::createFontImage(const Rc<DxvkDevice>& device) {
|
||||
DxvkImageCreateInfo info;
|
||||
info.type = VK_IMAGE_TYPE_2D;
|
||||
info.format = VK_FORMAT_R8_UNORM;
|
||||
info.flags = 0;
|
||||
info.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
info.extent = { g_hudFont.width, g_hudFont.height, 1 };
|
||||
info.numLayers = 1;
|
||||
info.mipLevels = 1;
|
||||
info.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
info.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
return device->createImage(info, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImageView> HudTextRenderer::createFontView(const Rc<DxvkDevice>& device) {
|
||||
DxvkImageViewCreateInfo info;
|
||||
info.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
info.format = m_fontImage->info().format;
|
||||
info.aspect = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
info.minLevel = 0;
|
||||
info.numLevels = 1;
|
||||
info.minLayer = 0;
|
||||
info.numLayers = 1;
|
||||
|
||||
return device->createImageView(m_fontImage, info);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkSampler> HudTextRenderer::createFontSampler(const Rc<DxvkDevice>& device) {
|
||||
DxvkSamplerCreateInfo info;
|
||||
info.magFilter = VK_FILTER_LINEAR;
|
||||
info.minFilter = VK_FILTER_LINEAR;
|
||||
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
info.mipmapLodBias = 0.0f;
|
||||
info.mipmapLodMin = 0.0f;
|
||||
info.mipmapLodMax = 0.0f;
|
||||
info.useAnisotropy = VK_FALSE;
|
||||
info.maxAnisotropy = 1.0f;
|
||||
info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
info.compareToDepth = VK_FALSE;
|
||||
info.compareOp = VK_COMPARE_OP_NEVER;
|
||||
info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||
info.usePixelCoord = VK_TRUE;
|
||||
|
||||
return device->createSampler(info);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkBuffer> HudTextRenderer::createVertexBuffer(const Rc<DxvkDevice>& device) {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = MaxVertexCount * sizeof(HudTextVertex);
|
||||
info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
info.access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
||||
|
||||
return device->createBuffer(info,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
}
|
||||
|
||||
|
||||
void HudTextRenderer::initFontTexture(
|
||||
const Rc<DxvkDevice>& device,
|
||||
const Rc<DxvkContext>& context) {
|
||||
context->beginRecording(
|
||||
device->createCommandList());
|
||||
|
||||
context->initImage(m_fontImage,
|
||||
VkImageSubresourceRange {
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0, 1, 0, 1 });
|
||||
|
||||
context->updateImage(m_fontImage,
|
||||
VkImageSubresourceLayers {
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
0, 0, 1 },
|
||||
VkOffset3D { 0, 0, 0 },
|
||||
VkExtent3D { g_hudFont.width, g_hudFont.height, 1 },
|
||||
g_hudFont.texture,
|
||||
g_hudFont.width,
|
||||
g_hudFont.width * g_hudFont.height);
|
||||
|
||||
device->submitCommandList(
|
||||
context->endRecording(),
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
void HudTextRenderer::initCharMap() {
|
||||
std::fill(m_charMap.begin(), m_charMap.end(), 0);
|
||||
|
||||
for (uint32_t i = 0; i < g_hudFont.charCount; i++)
|
||||
m_charMap.at(g_hudFont.glyphs[i].codePoint) = i;
|
||||
}
|
||||
|
||||
}
|
119
src/dxvk/hud/dxvk_hud_text.h
Normal file
119
src/dxvk/hud/dxvk_hud_text.h
Normal file
@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include "../dxvk_device.h"
|
||||
|
||||
#include "dxvk_hud_font.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
/**
|
||||
* \brief HUD coordinates
|
||||
*
|
||||
* Coordinates relative to the top-left
|
||||
* corner of the swap image, in pixels.
|
||||
*/
|
||||
struct HudPos {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Texture coordinates
|
||||
*
|
||||
* Absolute texture coordinates that are used
|
||||
* to pick letters in the font texture.
|
||||
*/
|
||||
struct HudTexCoord {
|
||||
uint16_t u;
|
||||
uint16_t v;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Color
|
||||
*
|
||||
* SRGB color with alpha channel. The text
|
||||
* will use this color for the most part.
|
||||
*/
|
||||
struct HudColor {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
uint8_t z;
|
||||
uint8_t w;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Text vertex
|
||||
*/
|
||||
struct HudTextVertex {
|
||||
HudPos position;
|
||||
HudTexCoord texcoord;
|
||||
HudColor color;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Text renderer for the HUD
|
||||
*
|
||||
* Can be used by the presentation backend to
|
||||
* display performance and driver information.
|
||||
*/
|
||||
class HudTextRenderer {
|
||||
constexpr static VkDeviceSize MaxVertexCount = 1 << 16;
|
||||
public:
|
||||
|
||||
HudTextRenderer(
|
||||
const Rc<DxvkDevice>& device,
|
||||
const Rc<DxvkContext>& context);
|
||||
|
||||
~HudTextRenderer();
|
||||
|
||||
void beginFrame(
|
||||
const Rc<DxvkContext>& context);
|
||||
|
||||
void drawText(
|
||||
const Rc<DxvkContext>& context,
|
||||
float size,
|
||||
HudPos pos,
|
||||
HudColor color,
|
||||
const std::string& text);
|
||||
|
||||
private:
|
||||
|
||||
std::array<uint8_t, 256> m_charMap;
|
||||
|
||||
Rc<DxvkShader> m_vertShader;
|
||||
Rc<DxvkShader> m_fragShader;
|
||||
|
||||
Rc<DxvkImage> m_fontImage;
|
||||
Rc<DxvkImageView> m_fontView;
|
||||
Rc<DxvkSampler> m_fontSampler;
|
||||
|
||||
Rc<DxvkBuffer> m_vertexBuffer;
|
||||
size_t m_vertexIndex = 0;
|
||||
|
||||
Rc<DxvkShader> createVertexShader(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
Rc<DxvkShader> createFragmentShader(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
Rc<DxvkImage> createFontImage(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
Rc<DxvkImageView> createFontView(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
Rc<DxvkSampler> createFontSampler(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
Rc<DxvkBuffer> createVertexBuffer(
|
||||
const Rc<DxvkDevice>& device);
|
||||
|
||||
void initFontTexture(
|
||||
const Rc<DxvkDevice>& device,
|
||||
const Rc<DxvkContext>& context);
|
||||
|
||||
void initCharMap();
|
||||
|
||||
};
|
||||
|
||||
}
|
26
src/dxvk/hud/shaders/hud_text_frag.frag
Normal file
26
src/dxvk/hud/shaders/hud_text_frag.frag
Normal file
@ -0,0 +1,26 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler s_font;
|
||||
layout(set = 0, binding = 2) uniform texture2D t_font;
|
||||
|
||||
layout(location = 0) in vec2 v_texcoord;
|
||||
layout(location = 1) in vec4 v_color;
|
||||
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
float sampleAlpha(float alpha_bias, float dist_range) {
|
||||
float value = texture(sampler2D(t_font, s_font), v_texcoord).r + alpha_bias - 0.5f;
|
||||
float dist = value * dot(vec2(dist_range, dist_range), 1.0f / fwidth(v_texcoord.xy));
|
||||
return clamp(dist + 0.5f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void main() {
|
||||
float r_alpha_center = sampleAlpha(0.0f, 5.0f);
|
||||
float r_alpha_shadow = sampleAlpha(0.3f, 5.0f);
|
||||
|
||||
vec4 r_center = vec4(v_color.rgb, v_color.a * r_alpha_center);
|
||||
vec4 r_shadow = vec4(0.0f, 0.0f, 0.0f, r_alpha_shadow);
|
||||
|
||||
o_color = mix(r_shadow, r_center, r_alpha_center);
|
||||
o_color.rgb *= o_color.a;
|
||||
}
|
21
src/dxvk/hud/shaders/hud_text_vert.vert
Normal file
21
src/dxvk/hud/shaders/hud_text_vert.vert
Normal file
@ -0,0 +1,21 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0, std140)
|
||||
uniform u_hud {
|
||||
uvec2 size;
|
||||
} g_hud;
|
||||
|
||||
layout(location = 0) in vec2 v_position;
|
||||
layout(location = 1) in uvec2 v_texcoord;
|
||||
layout(location = 2) in vec4 v_color;
|
||||
|
||||
layout(location = 0) out vec2 o_texcoord;
|
||||
layout(location = 1) out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
o_texcoord = vec2(v_texcoord);
|
||||
o_color = v_color;
|
||||
|
||||
vec2 pos = 2.0f * (v_position / vec2(g_hud.size)) - 1.0f;
|
||||
gl_Position = vec4(pos, 0.0f, 1.0f);
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
dxvk_hud_shaders = files([
|
||||
'hud/shaders/hud_text_frag.frag',
|
||||
'hud/shaders/hud_text_vert.vert',
|
||||
])
|
||||
|
||||
dxvk_src = files([
|
||||
'dxvk_adapter.cpp',
|
||||
'dxvk_barrier.cpp',
|
||||
@ -31,6 +36,12 @@ dxvk_src = files([
|
||||
'dxvk_sync.cpp',
|
||||
'dxvk_util.cpp',
|
||||
|
||||
'hud/dxvk_hud.cpp',
|
||||
'hud/dxvk_hud_devinfo.cpp',
|
||||
'hud/dxvk_hud_font.cpp',
|
||||
'hud/dxvk_hud_fps.cpp',
|
||||
'hud/dxvk_hud_text.cpp',
|
||||
|
||||
'vulkan/dxvk_vulkan_extensions.cpp',
|
||||
'vulkan/dxvk_vulkan_loader.cpp',
|
||||
'vulkan/dxvk_vulkan_names.cpp',
|
||||
@ -38,7 +49,7 @@ dxvk_src = files([
|
||||
|
||||
thread_dep = dependency('threads')
|
||||
|
||||
dxvk_lib = static_library('dxvk', dxvk_src,
|
||||
dxvk_lib = static_library('dxvk', dxvk_src, glsl_generator.process(dxvk_hud_shaders),
|
||||
link_with : [ util_lib, spirv_lib ],
|
||||
dependencies : [ thread_dep, lib_vulkan, lib_sdl2 ],
|
||||
include_directories : [ dxvk_include_path ])
|
||||
|
@ -23,6 +23,11 @@ namespace dxvk {
|
||||
SpirvCodeBuffer();
|
||||
SpirvCodeBuffer(uint32_t size, const uint32_t* data);
|
||||
SpirvCodeBuffer(std::istream&& stream);
|
||||
|
||||
template<size_t N>
|
||||
SpirvCodeBuffer(const uint32_t (&data)[N])
|
||||
: SpirvCodeBuffer(N, data) { }
|
||||
|
||||
~SpirvCodeBuffer();
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user