diff --git a/src/dxvk/hud/dxvk_hud_fps.cpp b/src/dxvk/hud/dxvk_hud_fps.cpp index d01a8ba4b..f8cb6e7dc 100644 --- a/src/dxvk/hud/dxvk_hud_fps.cpp +++ b/src/dxvk/hud/dxvk_hud_fps.cpp @@ -77,7 +77,7 @@ namespace dxvk::hud { const Rc& context, HudRenderer& renderer, HudPos position) { - std::array vData; + std::array vData; // 60 FPS = optimal, 10 FPS = worst const float targetUs = 16'666.6f; @@ -100,8 +100,10 @@ namespace dxvk::hud { float g = std::min(std::max( 3.0f - us / targetUs, 0.0f), 1.0f); float l = std::sqrt(r * r + g * g); - HudTexCoord tc = { 0u, 0u }; - HudColor color = { r / l, g / l, 0.0f, 1.0f }; + HudNormColor color = { + uint8_t(255.0f * (r / l)), + uint8_t(255.0f * (g / l)), + uint8_t(0), uint8_t(255) }; float x = position.x + float(i); float y = position.y + 24.0f; @@ -110,8 +112,8 @@ namespace dxvk::hud { / std::log2((maxUs - minUs) / targetUs); float h = std::min(std::max(40.0f * hVal, 2.0f), 40.0f); - vData[2 * i + 0] = HudVertex { { x, y }, tc, color }; - vData[2 * i + 1] = HudVertex { { x, y - h }, tc, color }; + vData[2 * i + 0] = HudLineVertex { { x, y }, color }; + vData[2 * i + 1] = HudLineVertex { { x, y - h }, color }; } renderer.drawLines(context, vData.size(), vData.data()); diff --git a/src/dxvk/hud/dxvk_hud_renderer.cpp b/src/dxvk/hud/dxvk_hud_renderer.cpp index 4964fb997..ad99ddc42 100644 --- a/src/dxvk/hud/dxvk_hud_renderer.cpp +++ b/src/dxvk/hud/dxvk_hud_renderer.cpp @@ -1,17 +1,18 @@ #include "dxvk_hud_renderer.h" -#include -#include -#include +#include +#include + +#include +#include namespace dxvk::hud { HudRenderer::HudRenderer(const Rc& device) : m_mode (Mode::RenderNone), m_surfaceSize { 0, 0 }, - m_vertShader (createVertexShader(device)), - m_textShader (createTextShader(device)), - m_lineShader (createLineShader(device)), + m_textShaders (createTextShaders(device)), + m_lineShaders (createLineShaders(device)), m_fontImage (createFontImage(device)), m_fontView (createFontView(device)), m_fontSampler (createFontSampler(device)), @@ -30,32 +31,11 @@ namespace dxvk::hud { auto vertexSlice = m_vertexBuffer->allocSlice(); context->invalidateBuffer(m_vertexBuffer, vertexSlice); - const std::array ilAttributes = {{ - { 0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(HudVertex, position) }, - { 1, 0, VK_FORMAT_R32G32_UINT, offsetof(HudVertex, texcoord) }, - { 2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(HudVertex, color) }, - }}; - - const std::array ilBindings = {{ - { 0, VK_VERTEX_INPUT_RATE_VERTEX }, - }}; - - context->setInputLayout( - ilAttributes.size(), - ilAttributes.data(), - ilBindings.size(), - ilBindings.data()); - - context->bindVertexBuffer(0, - DxvkBufferSlice(m_vertexBuffer), - sizeof(HudVertex)); - context->bindResourceSampler(1, m_fontSampler); context->bindResourceView (1, m_fontView, nullptr); m_mode = Mode::RenderNone; m_surfaceSize = surfaceSize; - m_vertexIndex = 0; } @@ -65,12 +45,19 @@ namespace dxvk::hud { HudPos pos, HudColor color, const std::string& text) { - this->setRenderMode(context, Mode::RenderText); + beginTextRendering(context); + + uint32_t vertexCount = 6 * text.size(); + + auto vertexSlice = allocVertexBuffer(context, + vertexCount * sizeof(HudTextVertex)); - const size_t vertexIndex = m_vertexIndex; - - HudVertex* vertexData = reinterpret_cast( - m_vertexBuffer->mapPtr(vertexIndex * sizeof(HudVertex))); + context->bindVertexBuffer(0, vertexSlice, sizeof(HudTextVertex)); + context->pushConstants(0, sizeof(color), &color); + context->draw(vertexCount, 1, 0, 0); + + auto vertexData = reinterpret_cast( + vertexSlice.getSliceHandle().mapPtr); const float sizeFactor = size / static_cast(g_hudFont.size); @@ -99,132 +86,183 @@ namespace dxvk::hud { 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(g_hudFont.advance); } - - const uint32_t vertexCount = 6 * text.size(); - context->draw(vertexCount, 1, vertexIndex, 0); - m_vertexIndex += vertexCount; } void HudRenderer::drawLines( const Rc& context, size_t vertexCount, - const HudVertex* vertexData) { - this->setRenderMode(context, Mode::RenderLines); - const size_t vertexIndex = m_vertexIndex; + const HudLineVertex* vertexData) { + beginLineRendering(context); + + auto vertexSlice = allocVertexBuffer(context, + vertexCount * sizeof(HudLineVertex)); - HudVertex* dstVertexData = reinterpret_cast( - m_vertexBuffer->mapPtr(vertexIndex * sizeof(HudVertex))); + context->bindVertexBuffer(0, vertexSlice, sizeof(HudLineVertex)); + context->draw(vertexCount, 1, 0, 0); + + auto dstVertexData = reinterpret_cast( + vertexSlice.getSliceHandle().mapPtr); for (size_t i = 0; i < vertexCount; i++) dstVertexData[i] = vertexData[i]; - - context->draw(vertexCount, 1, vertexIndex, 0); - m_vertexIndex += vertexCount; } - void HudRenderer::setRenderMode( + DxvkBufferSlice HudRenderer::allocVertexBuffer( const Rc& context, - Mode mode) { - if (m_mode != mode) { - m_mode = mode; - - switch (mode) { - case Mode::RenderNone: - break; - - case Mode::RenderText: { - context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vertShader); - context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_textShader); - - DxvkInputAssemblyState iaState; - iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - iaState.primitiveRestart = VK_FALSE; - iaState.patchVertexCount = 0; - context->setInputAssemblyState(iaState); - } break; - - case Mode::RenderLines: { - context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_vertShader); - context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_lineShader); - - DxvkInputAssemblyState iaState; - iaState.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - iaState.primitiveRestart = VK_FALSE; - iaState.patchVertexCount = 0; - context->setInputAssemblyState(iaState); - } break; - } + VkDeviceSize dataSize) { + dataSize = align(dataSize, 64); + + if (m_vertexOffset + dataSize > m_vertexBuffer->info().size) { + context->invalidateBuffer(m_vertexBuffer, m_vertexBuffer->allocSlice()); + m_vertexOffset = 0; + } + + DxvkBufferSlice slice(m_vertexBuffer, m_vertexOffset, dataSize); + m_vertexOffset += dataSize; + return slice; + } + + + void HudRenderer::beginTextRendering( + const Rc& context) { + if (m_mode != Mode::RenderText) { + m_mode = Mode::RenderText; + + context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_textShaders.vert); + context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_textShaders.frag); + + static const DxvkInputAssemblyState iaState = { + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + VK_FALSE, 0 }; + + static const std::array ilAttributes = {{ + { 0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(HudTextVertex, position) }, + { 1, 0, VK_FORMAT_R32G32_UINT, offsetof(HudTextVertex, texcoord) }, + }}; + + static const std::array ilBindings = {{ + { 0, VK_VERTEX_INPUT_RATE_VERTEX }, + }}; + + context->setInputAssemblyState(iaState); + context->setInputLayout( + ilAttributes.size(), + ilAttributes.data(), + ilBindings.size(), + ilBindings.data()); + } + } + + + void HudRenderer::beginLineRendering( + const Rc& context) { + if (m_mode != Mode::RenderLines) { + m_mode = Mode::RenderLines; + + context->bindShader(VK_SHADER_STAGE_VERTEX_BIT, m_lineShaders.vert); + context->bindShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_lineShaders.frag); + + static const DxvkInputAssemblyState iaState = { + VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + VK_FALSE, 0 }; + + static const std::array ilAttributes = {{ + { 0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(HudLineVertex, position) }, + { 1, 0, VK_FORMAT_R8G8B8A8_UNORM, offsetof(HudLineVertex, color) }, + }}; + + static const std::array ilBindings = {{ + { 0, VK_VERTEX_INPUT_RATE_VERTEX }, + }}; + + context->setInputAssemblyState(iaState); + context->setInputLayout( + ilAttributes.size(), + ilAttributes.data(), + ilBindings.size(), + ilBindings.data()); } } - - Rc HudRenderer::createVertexShader(const Rc& device) { - const SpirvCodeBuffer codeBuffer(hud_vert); + + HudRenderer::ShaderPair HudRenderer::createTextShaders(const Rc& device) { + ShaderPair result; + + const SpirvCodeBuffer vsCode(hud_text_vert); + const SpirvCodeBuffer fsCode(hud_text_frag); // One shader resource: Global HUD uniform buffer - const std::array resourceSlots = {{ + const std::array vsResources = {{ { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_IMAGE_VIEW_TYPE_MAX_ENUM }, }}; - - return device->createShader( - VK_SHADER_STAGE_VERTEX_BIT, - resourceSlots.size(), - resourceSlots.data(), - { 0x7, 0x3 }, - codeBuffer); - } - - - Rc HudRenderer::createTextShader(const Rc& device) { - const SpirvCodeBuffer codeBuffer(hud_text); - + // Two shader resources: Font texture and sampler - const std::array resourceSlots = {{ + const std::array fsResources = {{ { 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_IMAGE_VIEW_TYPE_2D }, }}; - return device->createShader( - VK_SHADER_STAGE_FRAGMENT_BIT, - resourceSlots.size(), - resourceSlots.data(), + result.vert = device->createShader( + VK_SHADER_STAGE_VERTEX_BIT, + vsResources.size(), + vsResources.data(), { 0x3, 0x1 }, - codeBuffer); + vsCode); + + result.frag = device->createShader( + VK_SHADER_STAGE_FRAGMENT_BIT, + fsResources.size(), + fsResources.data(), + { 0x1, 0x1, 0, sizeof(HudColor) }, + fsCode); + + return result; } - Rc HudRenderer::createLineShader(const Rc& device) { - const SpirvCodeBuffer codeBuffer(hud_line); + HudRenderer::ShaderPair HudRenderer::createLineShaders(const Rc& device) { + ShaderPair result; + + const SpirvCodeBuffer vsCode(hud_line_vert); + const SpirvCodeBuffer fsCode(hud_line_frag); - return device->createShader( + // One shader resource: Global HUD uniform buffer + const std::array vsResources = {{ + { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_IMAGE_VIEW_TYPE_MAX_ENUM }, + }}; + + result.vert = device->createShader( + VK_SHADER_STAGE_VERTEX_BIT, + vsResources.size(), + vsResources.data(), + { 0x3, 0x1 }, + vsCode); + + result.frag = device->createShader( VK_SHADER_STAGE_FRAGMENT_BIT, - 0, nullptr, { 0x2, 0x1 }, - codeBuffer); + 0, nullptr, { 0x1, 0x1 }, + fsCode); + + return result; } @@ -289,7 +327,7 @@ namespace dxvk::hud { Rc HudRenderer::createVertexBuffer(const Rc& device) { DxvkBufferCreateInfo info; - info.size = MaxVertexCount * sizeof(HudVertex); + info.size = 1 << 16; info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; info.stages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; info.access = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; diff --git a/src/dxvk/hud/dxvk_hud_renderer.h b/src/dxvk/hud/dxvk_hud_renderer.h index 41a7fa001..8d30091aa 100644 --- a/src/dxvk/hud/dxvk_hud_renderer.h +++ b/src/dxvk/hud/dxvk_hud_renderer.h @@ -40,14 +40,32 @@ namespace dxvk::hud { float b; float a; }; + + /** + * \brief Normalized color + * SRGB color with alpha channel. + */ + struct HudNormColor { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; /** - * \brief Vertex + * \brief Text vertex and texture coordinates */ - struct HudVertex { - HudPos position; - HudTexCoord texcoord; - HudColor color; + struct HudTextVertex { + HudPos position; + HudTexCoord texcoord; + }; + + /** + * \brief Line vertex and color + */ + struct HudLineVertex { + HudPos position; + HudNormColor color; }; /** @@ -57,7 +75,7 @@ namespace dxvk::hud { * display performance and driver information. */ class HudRenderer { - constexpr static VkDeviceSize MaxVertexCount = 1 << 16; + public: HudRenderer( @@ -79,7 +97,7 @@ namespace dxvk::hud { void drawLines( const Rc& context, size_t vertexCount, - const HudVertex* vertexData); + const HudLineVertex* vertexData); VkExtent2D surfaceSize() const { return m_surfaceSize; @@ -92,34 +110,41 @@ namespace dxvk::hud { RenderText, RenderLines, }; + + struct ShaderPair { + Rc vert; + Rc frag; + }; std::array m_charMap; Mode m_mode; VkExtent2D m_surfaceSize; - Rc m_vertShader; - Rc m_textShader; - Rc m_lineShader; + ShaderPair m_textShaders; + ShaderPair m_lineShaders; Rc m_fontImage; Rc m_fontView; Rc m_fontSampler; Rc m_vertexBuffer; - size_t m_vertexIndex = 0; + VkDeviceSize m_vertexOffset = 0; - void setRenderMode( + DxvkBufferSlice allocVertexBuffer( const Rc& context, - Mode mode); + VkDeviceSize dataSize); + + void beginTextRendering( + const Rc& context); - Rc createVertexShader( + void beginLineRendering( + const Rc& context); + + ShaderPair createTextShaders( const Rc& device); - Rc createTextShader( - const Rc& device); - - Rc createLineShader( + ShaderPair createLineShaders( const Rc& device); Rc createFontImage( diff --git a/src/dxvk/hud/shaders/hud_line.frag b/src/dxvk/hud/shaders/hud_line_frag.frag similarity index 76% rename from src/dxvk/hud/shaders/hud_line.frag rename to src/dxvk/hud/shaders/hud_line_frag.frag index 2612605aa..7e4843ab6 100644 --- a/src/dxvk/hud/shaders/hud_line.frag +++ b/src/dxvk/hud/shaders/hud_line_frag.frag @@ -1,6 +1,6 @@ #version 450 -layout(location = 1) in vec4 v_color; +layout(location = 0) in vec4 v_color; layout(location = 0) out vec4 o_color; void main() { diff --git a/src/dxvk/hud/shaders/hud_line_vert.vert b/src/dxvk/hud/shaders/hud_line_vert.vert new file mode 100644 index 000000000..091391581 --- /dev/null +++ b/src/dxvk/hud/shaders/hud_line_vert.vert @@ -0,0 +1,18 @@ +#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 vec4 v_color; + +layout(location = 0) out vec4 o_color; + +void main() { + o_color = v_color; + + vec2 pos = 2.0f * (v_position / vec2(g_hud.size)) - 1.0f; + gl_Position = vec4(pos, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/src/dxvk/hud/shaders/hud_text.frag b/src/dxvk/hud/shaders/hud_text_frag.frag similarity index 84% rename from src/dxvk/hud/shaders/hud_text.frag rename to src/dxvk/hud/shaders/hud_text_frag.frag index 573f014d6..875474f11 100644 --- a/src/dxvk/hud/shaders/hud_text.frag +++ b/src/dxvk/hud/shaders/hud_text_frag.frag @@ -3,10 +3,13 @@ layout(set = 0, binding = 1) uniform sampler2D s_font; layout(location = 0) in vec2 v_texcoord; -layout(location = 1) in vec4 v_color; - layout(location = 0) out vec4 o_color; +layout(push_constant) +uniform push_data { + vec4 color; +}; + float sampleAlpha(float alpha_bias, float dist_range) { float value = texture(s_font, v_texcoord).r + alpha_bias - 0.5f; float dist = value * dot(vec2(dist_range, dist_range), 1.0f / fwidth(v_texcoord.xy)); @@ -17,7 +20,7 @@ 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_center = vec4(color.rgb, 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); diff --git a/src/dxvk/hud/shaders/hud_vert.vert b/src/dxvk/hud/shaders/hud_text_vert.vert similarity index 78% rename from src/dxvk/hud/shaders/hud_vert.vert rename to src/dxvk/hud/shaders/hud_text_vert.vert index 4c1d6ce56..3011664ee 100644 --- a/src/dxvk/hud/shaders/hud_vert.vert +++ b/src/dxvk/hud/shaders/hud_text_vert.vert @@ -7,14 +7,11 @@ uniform u_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); diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 0ccdbff59..64f20998c 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -39,9 +39,11 @@ dxvk_shaders = files([ 'shaders/dxvk_unpack_d24s8.comp', 'shaders/dxvk_unpack_d32s8.comp', - 'hud/shaders/hud_line.frag', - 'hud/shaders/hud_text.frag', - 'hud/shaders/hud_vert.vert', + 'hud/shaders/hud_line_frag.frag', + 'hud/shaders/hud_line_vert.vert', + + 'hud/shaders/hud_text_frag.frag', + 'hud/shaders/hud_text_vert.vert', ]) dxvk_src = files([