mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
[hud] Add HUD item to visualize memory chunk allocation
This commit is contained in:
parent
f679d7d90f
commit
266b99ad8d
10 changed files with 419 additions and 8 deletions
|
@ -56,6 +56,7 @@ The `DXVK_HUD` environment variable controls a HUD which can display the framera
|
||||||
- `pipelines`: Shows the total number of graphics and compute pipelines.
|
- `pipelines`: Shows the total number of graphics and compute pipelines.
|
||||||
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
|
- `descriptors`: Shows the number of descriptor pools and descriptor sets.
|
||||||
- `memory`: Shows the amount of device memory allocated and used.
|
- `memory`: Shows the amount of device memory allocated and used.
|
||||||
|
- `allocations`: Shows detailed memory chunk suballocation info.
|
||||||
- `gpuload`: Shows estimated GPU load. May be inaccurate.
|
- `gpuload`: Shows estimated GPU load. May be inaccurate.
|
||||||
- `version`: Shows DXVK version.
|
- `version`: Shows DXVK version.
|
||||||
- `api`: Shows the D3D feature level used by the application.
|
- `api`: Shows the D3D feature level used by the application.
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace dxvk::hud {
|
||||||
addItem<HudPipelineStatsItem>("pipelines", -1, device);
|
addItem<HudPipelineStatsItem>("pipelines", -1, device);
|
||||||
addItem<HudDescriptorStatsItem>("descriptors", -1, device);
|
addItem<HudDescriptorStatsItem>("descriptors", -1, device);
|
||||||
addItem<HudMemoryStatsItem>("memory", -1, device);
|
addItem<HudMemoryStatsItem>("memory", -1, device);
|
||||||
|
addItem<HudMemoryDetailsItem>("allocations", -1, device);
|
||||||
addItem<HudCsThreadItem>("cs", -1, device);
|
addItem<HudCsThreadItem>("cs", -1, device);
|
||||||
addItem<HudGpuLoadItem>("gpuload", -1, device);
|
addItem<HudGpuLoadItem>("gpuload", -1, device);
|
||||||
addItem<HudCompilerActivityItem>("compiler", -1, device);
|
addItem<HudCompilerActivityItem>("compiler", -1, device);
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "dxvk_hud_item.h"
|
#include "dxvk_hud_item.h"
|
||||||
|
|
||||||
|
#include <hud_chunk_frag_background.h>
|
||||||
|
#include <hud_chunk_frag_visualize.h>
|
||||||
|
#include <hud_chunk_vert.h>
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
|
|
||||||
|
@ -611,6 +615,235 @@ namespace dxvk::hud {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
HudMemoryDetailsItem::HudMemoryDetailsItem(const Rc<DxvkDevice>& device)
|
||||||
|
: m_device(device) {
|
||||||
|
DxvkShaderCreateInfo shaderInfo;
|
||||||
|
shaderInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
shaderInfo.pushConstStages = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
shaderInfo.pushConstSize = sizeof(ShaderArgs);
|
||||||
|
shaderInfo.outputMask = 0x1;
|
||||||
|
|
||||||
|
m_vs = new DxvkShader(shaderInfo, SpirvCodeBuffer(hud_chunk_vert));
|
||||||
|
|
||||||
|
shaderInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
shaderInfo.outputMask = 0x1;
|
||||||
|
|
||||||
|
m_fsBackground = new DxvkShader(shaderInfo, SpirvCodeBuffer(hud_chunk_frag_background));
|
||||||
|
|
||||||
|
DxvkBindingInfo pageMaskBinding = {
|
||||||
|
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 0, VK_IMAGE_VIEW_TYPE_MAX_ENUM,
|
||||||
|
VK_SHADER_STAGE_FRAGMENT_BIT, VK_ACCESS_SHADER_READ_BIT };
|
||||||
|
|
||||||
|
shaderInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
shaderInfo.bindingCount = 1;
|
||||||
|
shaderInfo.bindings = &pageMaskBinding;
|
||||||
|
shaderInfo.inputMask = 0x1;
|
||||||
|
shaderInfo.outputMask = 0x1;
|
||||||
|
|
||||||
|
m_fsVisualize = new DxvkShader(shaderInfo, SpirvCodeBuffer(hud_chunk_frag_visualize));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudMemoryDetailsItem::~HudMemoryDetailsItem() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HudMemoryDetailsItem::update(dxvk::high_resolution_clock::time_point time) {
|
||||||
|
m_device->getMemoryAllocationStats(m_stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HudPos HudMemoryDetailsItem::render(
|
||||||
|
HudRenderer& renderer,
|
||||||
|
HudPos position) {
|
||||||
|
uploadChunkData(renderer);
|
||||||
|
|
||||||
|
// Chunk memory per type, not including dedicated allocations
|
||||||
|
std::array<VkDeviceSize, VK_MAX_MEMORY_TYPES> chunkMemoryAllocated = { };
|
||||||
|
std::array<VkDeviceSize, VK_MAX_MEMORY_TYPES> chunkMemoryUsed = { };
|
||||||
|
|
||||||
|
// Compute layout, align the entire element to the bottom right.
|
||||||
|
float maxWidth = 556.0f;
|
||||||
|
|
||||||
|
HudPos pos = {
|
||||||
|
float(renderer.surfaceSize().width) / renderer.scale() - 8.0f - maxWidth,
|
||||||
|
float(renderer.surfaceSize().height) / renderer.scale() - 8.0f,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_stats.memoryTypes.size(); i++) {
|
||||||
|
const auto& type = m_stats.memoryTypes.at(i);
|
||||||
|
|
||||||
|
if (!type.allocated)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Reserve space for one line of text
|
||||||
|
pos.y -= 20.0f;
|
||||||
|
|
||||||
|
float width = 0.0f;
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < type.chunkCount; j++) {
|
||||||
|
const auto& chunk = m_stats.chunks.at(type.chunkIndex + j);
|
||||||
|
chunkMemoryAllocated.at(i) += chunk.capacity;
|
||||||
|
chunkMemoryUsed.at(i) += chunk.used;
|
||||||
|
|
||||||
|
float pixels = float((chunk.pageCount + 15u) / 16u);
|
||||||
|
|
||||||
|
if (width + pixels > maxWidth) {
|
||||||
|
pos.y -= 30.0f;
|
||||||
|
width = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
width += pixels + 6.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.y -= 30.0f + 4.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually render the thing
|
||||||
|
for (uint32_t i = 0; i < m_stats.memoryTypes.size(); i++) {
|
||||||
|
const auto& type = m_stats.memoryTypes.at(i);
|
||||||
|
|
||||||
|
if (!type.allocated)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VkDeviceSize dedicated = type.allocated - chunkMemoryAllocated.at(i);
|
||||||
|
VkDeviceSize allocated = chunkMemoryAllocated.at(i) + dedicated;
|
||||||
|
VkDeviceSize used = chunkMemoryUsed.at(i) + dedicated;
|
||||||
|
|
||||||
|
std::string headline = str::format("Mem type ", i, " [", type.properties.heapIndex, "]: ",
|
||||||
|
type.chunkCount, " chunk", type.chunkCount != 1u ? "s" : "", " (", (allocated >> 20u), " MB, ",
|
||||||
|
((used >= (1u << 20u)) ? used >> 20 : used >> 10),
|
||||||
|
(used >= (1u << 20u) ? " MB" : " kB"), " used)");
|
||||||
|
|
||||||
|
renderer.drawText(14.0f,
|
||||||
|
{ pos.x, pos.y },
|
||||||
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
|
headline);
|
||||||
|
|
||||||
|
pos.y += 8.0f;
|
||||||
|
|
||||||
|
float width = 0.0f;
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < type.chunkCount; j++) {
|
||||||
|
const auto& chunk = m_stats.chunks.at(type.chunkIndex + j);
|
||||||
|
float pixels = float((chunk.pageCount + 15u) / 16u);
|
||||||
|
|
||||||
|
if (width + pixels > maxWidth) {
|
||||||
|
pos.y += 30.0f;
|
||||||
|
width = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawChunk(renderer,
|
||||||
|
{ pos.x + width, pos.y },
|
||||||
|
{ pixels, 24.0f },
|
||||||
|
type.properties, chunk);
|
||||||
|
|
||||||
|
width += pixels + 6.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos.y += 46.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HudMemoryDetailsItem::uploadChunkData(HudRenderer& renderer) {
|
||||||
|
DxvkContext* context = renderer.getContext();
|
||||||
|
|
||||||
|
VkDeviceSize size = sizeof(uint32_t) * m_stats.pageMasks.size();
|
||||||
|
|
||||||
|
if (m_pageMaskBuffer == nullptr || m_pageMaskBuffer->info().size < size) {
|
||||||
|
DxvkBufferCreateInfo info = { };
|
||||||
|
info.size = std::max(VkDeviceSize(1u << 14),
|
||||||
|
(VkDeviceSize(-1) >> bit::lzcnt(size - 1u)) + 1u);
|
||||||
|
info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
|
info.access = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
info.stages = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
|
|
||||||
|
m_pageMaskBuffer = m_device->createBuffer(info,
|
||||||
|
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
|
|
||||||
|
DxvkBufferViewCreateInfo viewInfo = { };
|
||||||
|
viewInfo.format = VK_FORMAT_UNDEFINED;
|
||||||
|
viewInfo.rangeOffset = 0;
|
||||||
|
viewInfo.rangeLength = info.size;
|
||||||
|
viewInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
|
|
||||||
|
m_pageMaskView = m_device->createBufferView(m_pageMaskBuffer, viewInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_stats.pageMasks.empty()) {
|
||||||
|
context->invalidateBuffer(m_pageMaskBuffer, m_pageMaskBuffer->allocSlice());
|
||||||
|
std::memcpy(m_pageMaskBuffer->mapPtr(0), &m_stats.pageMasks.at(0), size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void HudMemoryDetailsItem::drawChunk(
|
||||||
|
HudRenderer& renderer,
|
||||||
|
HudPos pos,
|
||||||
|
HudPos size,
|
||||||
|
const VkMemoryType& memoryType,
|
||||||
|
const DxvkMemoryChunkStats& stats) const {
|
||||||
|
DxvkContext* context = renderer.getContext();
|
||||||
|
VkExtent2D surfaceSize = renderer.surfaceSize();
|
||||||
|
|
||||||
|
static const DxvkInputAssemblyState iaState = {
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
||||||
|
VK_FALSE, 0 };
|
||||||
|
|
||||||
|
context->setInputAssemblyState(iaState);
|
||||||
|
context->bindResourceBufferView(VK_SHADER_STAGE_FRAGMENT_BIT, 0, Rc<DxvkBufferView>(m_pageMaskView));
|
||||||
|
|
||||||
|
context->bindShader<VK_SHADER_STAGE_VERTEX_BIT>(Rc<DxvkShader>(m_vs));
|
||||||
|
context->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fsBackground));
|
||||||
|
|
||||||
|
ShaderArgs args = { };
|
||||||
|
args.pos.x = pos.x - 1.0f;
|
||||||
|
args.pos.y = pos.y - 1.0f;
|
||||||
|
args.size.x = size.x + 2.0f;
|
||||||
|
args.size.y = size.y + 2.0f;
|
||||||
|
args.scale.x = renderer.scale() / std::max(float(surfaceSize.width), 1.0f);
|
||||||
|
args.scale.y = renderer.scale() / std::max(float(surfaceSize.height), 1.0f);
|
||||||
|
args.opacity = renderer.opacity();
|
||||||
|
args.color = 0xc0000000u;
|
||||||
|
args.maskIndex = stats.pageMaskOffset;
|
||||||
|
args.pageCount = stats.pageCount;
|
||||||
|
|
||||||
|
context->pushConstants(0, sizeof(args), &args);
|
||||||
|
context->draw(4, 1, 0, 0);
|
||||||
|
|
||||||
|
context->bindShader<VK_SHADER_STAGE_FRAGMENT_BIT>(Rc<DxvkShader>(m_fsVisualize));
|
||||||
|
|
||||||
|
args.pos = pos;
|
||||||
|
args.size = size;
|
||||||
|
|
||||||
|
if (!(memoryType.propertyFlags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)) {
|
||||||
|
if (!(memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
|
||||||
|
args.color = 0xff202020u;
|
||||||
|
else if (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
|
||||||
|
args.color = 0xff208020u;
|
||||||
|
else
|
||||||
|
args.color = 0xff202080u;
|
||||||
|
} else if (memoryType.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
|
||||||
|
args.color = 0xff208080u;
|
||||||
|
} else {
|
||||||
|
args.color = 0xff804020u;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->pushConstants(0, sizeof(args), &args);
|
||||||
|
context->draw(4, 1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HudCsThreadItem::HudCsThreadItem(const Rc<DxvkDevice>& device)
|
HudCsThreadItem::HudCsThreadItem(const Rc<DxvkDevice>& device)
|
||||||
: m_device(device) {
|
: m_device(device) {
|
||||||
|
|
||||||
|
@ -799,7 +1032,7 @@ namespace dxvk::hud {
|
||||||
string = str::format(string, " (", computePercentage(), "%)");
|
string = str::format(string, " (", computePercentage(), "%)");
|
||||||
|
|
||||||
renderer.drawText(16.0f,
|
renderer.drawText(16.0f,
|
||||||
{ position.x, renderer.surfaceSize().height / renderer.scale() - 20.0f },
|
{ position.x, float(renderer.surfaceSize().height) / renderer.scale() - 20.0f },
|
||||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||||
string);
|
string);
|
||||||
}
|
}
|
||||||
|
|
|
@ -390,6 +390,58 @@ namespace dxvk::hud {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief HUD item to display detailed memory allocation info
|
||||||
|
*/
|
||||||
|
class HudMemoryDetailsItem : public HudItem {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HudMemoryDetailsItem(const Rc<DxvkDevice>& device);
|
||||||
|
|
||||||
|
~HudMemoryDetailsItem();
|
||||||
|
|
||||||
|
void update(dxvk::high_resolution_clock::time_point time);
|
||||||
|
|
||||||
|
HudPos render(
|
||||||
|
HudRenderer& renderer,
|
||||||
|
HudPos position);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct ShaderArgs {
|
||||||
|
HudPos pos;
|
||||||
|
HudPos size;
|
||||||
|
HudPos scale;
|
||||||
|
float opacity;
|
||||||
|
uint32_t color;
|
||||||
|
uint32_t maskIndex;
|
||||||
|
uint32_t pageCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
Rc<DxvkDevice> m_device;
|
||||||
|
DxvkMemoryAllocationStats m_stats;
|
||||||
|
|
||||||
|
Rc<DxvkShader> m_vs;
|
||||||
|
Rc<DxvkShader> m_fsBackground;
|
||||||
|
Rc<DxvkShader> m_fsVisualize;
|
||||||
|
|
||||||
|
Rc<DxvkBuffer> m_pageMaskBuffer;
|
||||||
|
Rc<DxvkBufferView> m_pageMaskView;
|
||||||
|
|
||||||
|
void uploadChunkData(
|
||||||
|
HudRenderer& renderer);
|
||||||
|
|
||||||
|
void drawChunk(
|
||||||
|
HudRenderer& renderer,
|
||||||
|
HudPos pos,
|
||||||
|
HudPos size,
|
||||||
|
const VkMemoryType& memoryType,
|
||||||
|
const DxvkMemoryChunkStats& stats) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief HUD item to display CS thread statistics
|
* \brief HUD item to display CS thread statistics
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -33,10 +33,10 @@ namespace dxvk::hud {
|
||||||
|
|
||||||
|
|
||||||
void HudRenderer::beginFrame(
|
void HudRenderer::beginFrame(
|
||||||
const Rc<DxvkContext>& context,
|
const Rc<DxvkContext>& context,
|
||||||
VkExtent2D surfaceSize,
|
VkExtent2D surfaceSize,
|
||||||
float scale,
|
float scale,
|
||||||
float opacity) {
|
float opacity) {
|
||||||
if (!m_initialized)
|
if (!m_initialized)
|
||||||
this->initFontTexture(context);
|
this->initFontTexture(context);
|
||||||
|
|
||||||
|
@ -128,7 +128,6 @@ namespace dxvk::hud {
|
||||||
VK_FALSE, 0 };
|
VK_FALSE, 0 };
|
||||||
|
|
||||||
m_context->setInputAssemblyState(iaState);
|
m_context->setInputAssemblyState(iaState);
|
||||||
m_context->setInputLayout(0, nullptr, 0, nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +146,6 @@ namespace dxvk::hud {
|
||||||
VK_FALSE, 0 };
|
VK_FALSE, 0 };
|
||||||
|
|
||||||
m_context->setInputAssemblyState(iaState);
|
m_context->setInputAssemblyState(iaState);
|
||||||
m_context->setInputLayout(0, nullptr, 0, nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,12 @@ namespace dxvk::hud {
|
||||||
HudPos size,
|
HudPos size,
|
||||||
size_t pointCount,
|
size_t pointCount,
|
||||||
const HudGraphPoint* pointData);
|
const HudGraphPoint* pointData);
|
||||||
|
|
||||||
|
DxvkContext* getContext() {
|
||||||
|
m_mode = Mode::RenderNone;
|
||||||
|
return m_context.ptr();
|
||||||
|
}
|
||||||
|
|
||||||
VkExtent2D surfaceSize() const {
|
VkExtent2D surfaceSize() const {
|
||||||
return m_surfaceSize;
|
return m_surfaceSize;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +134,10 @@ namespace dxvk::hud {
|
||||||
float scale() const {
|
float scale() const {
|
||||||
return m_scale;
|
return m_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float opacity() const {
|
||||||
|
return m_opacity;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
23
src/dxvk/hud/shaders/hud_chunk_frag_background.frag
Normal file
23
src/dxvk/hud/shaders/hud_chunk_frag_background.frag
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : require
|
||||||
|
|
||||||
|
#include "hud_frag_common.glsl"
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
|
layout(push_constant)
|
||||||
|
uniform push_data_t {
|
||||||
|
vec2 pos;
|
||||||
|
vec2 size;
|
||||||
|
vec2 scale;
|
||||||
|
float opacity;
|
||||||
|
uint color;
|
||||||
|
uint maskIndex;
|
||||||
|
uint pageCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 rgba = unpackUnorm4x8(color);
|
||||||
|
o_color = vec4(encodeOutput(rgba.rgb), rgba.a * opacity);
|
||||||
|
}
|
65
src/dxvk/hud/shaders/hud_chunk_frag_visualize.frag
Normal file
65
src/dxvk/hud/shaders/hud_chunk_frag_visualize.frag
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
#extension GL_GOOGLE_include_directive : require
|
||||||
|
|
||||||
|
#include "hud_frag_common.glsl"
|
||||||
|
|
||||||
|
layout(location = 0) in vec2 v_coord;
|
||||||
|
layout(location = 0) out vec4 o_color;
|
||||||
|
|
||||||
|
layout(binding = 0, std430)
|
||||||
|
readonly buffer mask_data_t {
|
||||||
|
uint masks[];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(push_constant)
|
||||||
|
uniform push_data_t {
|
||||||
|
vec2 pos;
|
||||||
|
vec2 size;
|
||||||
|
vec2 scale;
|
||||||
|
float opacity;
|
||||||
|
uint color;
|
||||||
|
uint maskIndex;
|
||||||
|
uint pageCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 rgba = unpackUnorm4x8(color);
|
||||||
|
|
||||||
|
float dx = dFdx(v_coord.x * float(pageCount)) / 2.0f - 0.5f;
|
||||||
|
|
||||||
|
uvec2 pageRange = uvec2(clamp(
|
||||||
|
(v_coord.xx * float(pageCount)) + vec2(-dx, dx),
|
||||||
|
vec2(0.0), vec2(float(pageCount - 1u))));
|
||||||
|
|
||||||
|
uint bitsTotal = max(pageRange.y - pageRange.x, 1u);
|
||||||
|
uint bitsSet = 0u;
|
||||||
|
|
||||||
|
uint index = pageRange.x / 32u;
|
||||||
|
uint shift = pageRange.x % 32u;
|
||||||
|
|
||||||
|
if (shift + bitsTotal <= 32u) {
|
||||||
|
bitsSet = bitCount(bitfieldExtract(
|
||||||
|
masks[maskIndex + index], int(shift), int(bitsTotal)));
|
||||||
|
} else {
|
||||||
|
bitsSet = bitCount(masks[maskIndex + (index++)] >> shift);
|
||||||
|
uint bitsCounted = 32u - shift;
|
||||||
|
|
||||||
|
while (bitsCounted + 32u <= bitsTotal) {
|
||||||
|
bitsSet += bitCount(masks[maskIndex + (index++)]);
|
||||||
|
bitsCounted += 32u;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitsCounted < bitsTotal) {
|
||||||
|
bitsSet += bitCount(bitfieldExtract(
|
||||||
|
masks[maskIndex + (index++)], 0, int(bitsTotal - bitsCounted)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bitsSet == 0u)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
float blendFactor = 0.5f * float(bitsSet) / max(float(bitsTotal), 1.0f);
|
||||||
|
o_color = vec4(mix(rgba.rgb, vec3(1.0f), blendFactor), rgba.a * opacity);
|
||||||
|
o_color.rgb = encodeOutput(o_color.rgb);
|
||||||
|
}
|
25
src/dxvk/hud/shaders/hud_chunk_vert.vert
Normal file
25
src/dxvk/hud/shaders/hud_chunk_vert.vert
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#version 450
|
||||||
|
|
||||||
|
layout(location = 0) out vec2 o_coord;
|
||||||
|
|
||||||
|
layout(push_constant)
|
||||||
|
uniform push_data_t {
|
||||||
|
vec2 pos;
|
||||||
|
vec2 size;
|
||||||
|
vec2 scale;
|
||||||
|
float opacity;
|
||||||
|
uint color;
|
||||||
|
uint maskIndex;
|
||||||
|
uint pageCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 coord = vec2(
|
||||||
|
float(gl_VertexIndex & 1),
|
||||||
|
float(gl_VertexIndex >> 1));
|
||||||
|
o_coord = coord;
|
||||||
|
|
||||||
|
vec2 pixel_pos = pos + size * coord;
|
||||||
|
vec2 scaled_pos = 2.0f * scale * pixel_pos - 1.0f;
|
||||||
|
gl_Position = vec4(scaled_pos, 0.0f, 1.0f);
|
||||||
|
}
|
|
@ -50,6 +50,10 @@ dxvk_shaders = files([
|
||||||
'shaders/dxvk_unpack_d24s8.comp',
|
'shaders/dxvk_unpack_d24s8.comp',
|
||||||
'shaders/dxvk_unpack_d32s8.comp',
|
'shaders/dxvk_unpack_d32s8.comp',
|
||||||
|
|
||||||
|
'hud/shaders/hud_chunk_frag_background.frag',
|
||||||
|
'hud/shaders/hud_chunk_frag_visualize.frag',
|
||||||
|
'hud/shaders/hud_chunk_vert.vert',
|
||||||
|
|
||||||
'hud/shaders/hud_graph_frag.frag',
|
'hud/shaders/hud_graph_frag.frag',
|
||||||
'hud/shaders/hud_graph_vert.vert',
|
'hud/shaders/hud_graph_vert.vert',
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue