options: image <path> / image_max_width (int) / image_background (path)

image : to display an image component (only one component of type image can be rendered)
        note that the texture is never cleared, nor reloaded (in case of configuration modification).

image_max_width: by default, the width of the image is the one of the pannel (value is 0). with this
                 option, you can reduce it.

image_background: global background image to display

Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
pr-642
Nicolas Adenis-Lamarre 3 years ago committed by jackun
parent 882f44f5ee
commit 1756e8d852
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

@ -346,6 +346,9 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `show_fps_limit` | Display the current fps limit |
| `custom_text_center` | Display a custom text centered useful for a header e.g `custom_text_center=FlightLessMango Benchmarks` |
| `custom_text` | Display a custom text e.g `custom_text=Fsync enabled` |
| `background_image` | Display a background image from argument path on the whole screen (eventually transparent) |
| `image` | Display an image from argument path |
| `image_max_width` | Maximize the image by a max number of pixel for the width |
| `exec` | Display output of bash command in next column, e.g `custom_text=/home` , `exec=df -h /home \| tail -n 1`. Only works with legacy_layout=false |
| `round_corners` | Change the amount of roundness of the corners have e.g `round_corners=10.0` |
| `vkbasalt` | Shows if vkbasalt is on |

@ -117,6 +117,13 @@ frame_timing
### Display output of Bash command in next column
# exec=
### Display a background image from argument path on the whole screen (eventually transparent)
# background_image=
### Display an image from argument path
# image=
### Maximize the image by a max number of pixel for the width
# image_max_width=
### Display media player metadata
# media_player
# media_player_name=spotify

@ -251,7 +251,7 @@ static bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"varying vec4 Frag_Color;\n"
"void main()\n"
"{\n"
" gl_FragColor = Frag_Color * vec4(1, 1, 1, texture2D(Texture, Frag_UV.st).r);\n"
" gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
"}\n";
const GLchar* fragment_shader_glsl_130 =

@ -5,6 +5,7 @@
#include <chrono>
#include <iomanip>
#include <spdlog/spdlog.h>
#include <glad/glad.h>
#include "real_dlsym.h"
#include "mesa/util/macros.h"
#include "mesa/util/os_time.h"
@ -25,6 +26,10 @@ void* get_egl_proc_address(const char* name) {
SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libEGL.so.1: {}", dlerror());
} else {
pfn_eglGetProcAddress = reinterpret_cast<decltype(pfn_eglGetProcAddress)>(real_dlsym(handle, "eglGetProcAddress"));
if(gladLoadGLES2Loader((GLADloadproc)pfn_eglGetProcAddress) == 0) {
pfn_eglGetProcAddress = nullptr;
}
}
}

@ -17,6 +17,7 @@
#include "string_utils.h"
#include "app/mangoapp.h"
#include <IconsForkAwesome.h>
#include "load_textures.h"
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
@ -672,6 +673,72 @@ void HudElements::custom_text_center(){
ImGui::PopFont();
}
void HudElements::image(){
const std::string& value = HUDElements.ordered_functions[HUDElements.place].second;
// load the image if needed
if (HUDElements.image_infos.loaded == false) {
unsigned maxwidth = HUDElements.params->width;
if (HUDElements.params->image_max_width != 0 && HUDElements.params->image_max_width < maxwidth) {
maxwidth = HUDElements.params->image_max_width;
}
HUDElements.image_infos.loaded = true;
if (HUDElements.is_vulkan) {
if ((HUDElements.image_infos.texture = add_texture(HUDElements.sw_stats, value, &(HUDElements.image_infos.width), &(HUDElements.image_infos.height), maxwidth)))
HUDElements.image_infos.valid = true;
} else {
HUDElements.image_infos.valid = GL_LoadTextureFromFile(value.c_str(),
reinterpret_cast<unsigned int*>(&(HUDElements.image_infos.texture)),
&(HUDElements.image_infos.width),
&(HUDElements.image_infos.height),
maxwidth);
}
if (HUDElements.image_infos.valid)
SPDLOG_INFO("Image {} loaded ({}x{})", value, HUDElements.image_infos.width, HUDElements.image_infos.height);
else
SPDLOG_WARN("Failed to load image: {}", value);
}
// render the image
if (HUDElements.image_infos.valid) {
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::Image(HUDElements.image_infos.texture, ImVec2(HUDElements.image_infos.width, HUDElements.image_infos.height));
}
}
void HudElements::background_image(){
const std::string& value = HUDElements.params->background_image;
// load the image if needed
if (HUDElements.background_image_infos.loaded == false) {
HUDElements.background_image_infos.loaded = true;
if (HUDElements.is_vulkan) {
if ((HUDElements.background_image_infos.texture = add_texture(HUDElements.sw_stats, value, &(HUDElements.background_image_infos.width), &(HUDElements.background_image_infos.height), 0)))
HUDElements.background_image_infos.valid = true;
} else {
HUDElements.background_image_infos.valid = GL_LoadTextureFromFile(value.c_str(),
reinterpret_cast<unsigned int*>(&(HUDElements.background_image_infos.texture)),
&(HUDElements.background_image_infos.width),
&(HUDElements.background_image_infos.height),
0);
}
if (HUDElements.background_image_infos.valid)
SPDLOG_INFO("Image {} loaded ({}x{})", value, HUDElements.background_image_infos.width, HUDElements.background_image_infos.height);
else
SPDLOG_WARN("Failed to load image: {}", value);
}
// render the image
if (HUDElements.background_image_infos.valid) {
ImGui::GetBackgroundDrawList()->AddImage(HUDElements.background_image_infos.texture,
ImVec2(0, 0),
ImVec2(HUDElements.background_image_infos.width, HUDElements.background_image_infos.height));
}
}
void HudElements::custom_text(){
ImGui::TableNextRow(); ImGui::TableNextColumn();
ImGui::PushFont(HUDElements.sw_stats->font1);
@ -1109,6 +1176,8 @@ void HudElements::sort_elements(const std::pair<std::string, std::string>& optio
if (param == "frame_timing") { ordered_functions.push_back({frame_timing, value}); }
if (param == "media_player") { ordered_functions.push_back({media_player, value}); }
if (param == "custom_text") { ordered_functions.push_back({custom_text, value}); }
if (param == "background_image") { ordered_functions.push_back({background_image, value}); }
if (param == "image") { ordered_functions.push_back({image, value}); }
if (param == "custom_text_center") { ordered_functions.push_back({custom_text_center, value}); }
if (param == "exec") { ordered_functions.push_back({_exec, value});
exec_list.push_back({int(ordered_functions.size() - 1), value}); }

@ -5,9 +5,29 @@
#include <imgui.h>
#include "timing.hpp"
struct image_infos {
std::string path;
int width;
int height;
bool loaded;
bool valid;
ImTextureID texture;
image_infos() {
loaded = false;
valid = false;
}
~image_infos() {
}
};
struct overlay_params;
class HudElements{
public:
struct image_infos image_infos;
struct image_infos background_image_infos;
struct swapchain_stats *sw_stats;
struct overlay_params *params;
struct exec_entry {
@ -54,6 +74,8 @@ class HudElements{
static void show_fps_limit();
static void custom_text_center();
static void custom_text();
static void image();
static void background_image();
static void vkbasalt();
static void gamemode();
static void graphs();

@ -1,4 +1,4 @@
#include <glad/glad.h>
#include "load_textures.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_RESIZE_IMPLEMENTATION
@ -22,17 +22,22 @@ bool GL_LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_
int image_width_resized = image_width * ratio;
int image_height_resized = image_height * ratio;
unsigned char* image_data_resized = (unsigned char*)malloc(image_width_resized * image_height_resized * 4);
if (!image_data_resized) {
if (ratio != 1)
{
unsigned char* image_data_resized = (unsigned char*)stbi__malloc(image_width_resized * image_height_resized * 4);
if (!image_data_resized) {
stbi_image_free(image_data);
return false;
}
stbir_resize_uint8(image_data, image_width, image_height, 0,
image_data_resized, image_width_resized, image_height_resized, 0,
4);
stbi_image_free(image_data);
return false;
image_data = image_data_resized;
}
stbir_resize_uint8(image_data, image_width, image_height, 0,
image_data_resized, image_width_resized, image_height_resized, 0,
4);
stbi_image_free(image_data);
// Create a OpenGL texture identifier
GLuint image_texture;
glGenTextures(1, &image_texture);
@ -48,8 +53,8 @@ bool GL_LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_
#if defined(GL_UNPACK_ROW_LENGTH) && !defined(__EMSCRIPTEN__)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width_resized, image_height_resized, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data_resized);
stbi_image_free(image_data_resized);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width_resized, image_height_resized, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
stbi_image_free(image_data);
*out_texture = image_texture;
*out_width = image_width_resized;

@ -0,0 +1,4 @@
#pragma once
#include <glad/glad.h>
bool GL_LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_width, int* out_height, int maxwidth);

@ -55,6 +55,7 @@ vklayer_files = files(
'blacklist.cpp',
'file_utils.cpp',
'amdgpu.cpp',
'load_textures.cpp',
)
opengl_files = []
if ['windows', 'mingw'].contains(host_machine.system())

@ -114,6 +114,7 @@ float get_time_stat(void *_data, int _idx);
void stop_hw_updater();
extern void control_client_check(int control, int& control_client, const std::string& deviceName);
extern void process_control_socket(int& control_client, overlay_params &params);
ImTextureID add_texture(swapchain_stats* stats, const std::string& filename, int* width, int* height, int maxwidth);
#ifdef HAVE_DBUS
void render_mpris_metadata(const overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);
#endif

@ -429,6 +429,9 @@ parse_gl_size_query(const char *str)
#define parse_blacklist(s) parse_str_tokenize(s)
#define parse_custom_text_center(s) parse_str(s)
#define parse_custom_text(s) parse_str(s)
#define parse_background_image(s) parse_str(s)
#define parse_image(s) parse_str(s)
#define parse_image_max_width(s) parse_unsigned(s)
#define parse_fps_value(s) parse_load_value(s)
#define parse_fps_color(s) parse_load_color(s)
#define parse_battery_color(s) parse_color(s)
@ -629,6 +632,7 @@ parse_overlay_config(struct overlay_params *params,
params->round_corners = 0;
params->battery_color =0xff9078;
params->fsr_steam_sharpness = -1;
params->image_max_width = 0;
#ifdef HAVE_X11
params->toggle_hud = { XK_Shift_R, XK_F12 };

@ -69,6 +69,9 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(fps_color_change) \
OVERLAY_PARAM_BOOL(custom_text_center) \
OVERLAY_PARAM_BOOL(custom_text) \
OVERLAY_PARAM_CUSTOM(background_image) \
OVERLAY_PARAM_CUSTOM(image) \
OVERLAY_PARAM_CUSTOM(image_max_width) \
OVERLAY_PARAM_BOOL(exec) \
OVERLAY_PARAM_BOOL(vkbasalt) \
OVERLAY_PARAM_BOOL(gamemode) \
@ -251,6 +254,9 @@ struct overlay_params {
uint32_t font_glyph_ranges;
std::string custom_text_center;
std::string custom_text;
std::string background_image;
std::string image;
unsigned image_max_width;
std::string config_file_path;
std::unordered_map<std::string,std::string> options;
int permit_upload;

@ -50,6 +50,9 @@
#include "blacklist.h"
#include "pci_ids.h"
#include "stb_image.h"
#include "stb_image_resize.h"
using namespace std;
float offset_x, offset_y, hudSpacing;
@ -71,6 +74,13 @@ struct vk_image {
bool uploaded;
};
struct texture_info {
vk_image image;
VkDescriptorSet descset;
std::string filename;
int maxwidth;
};
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
struct vk_instance_dispatch_table vtable;
@ -113,6 +123,8 @@ struct device_data {
ImFont *font_alt, *font_text;
struct vk_image font_img;
size_t font_params_hash = 0;
std::vector<struct texture_info> textures;
};
/* Mapped from VkCommandBuffer */
@ -344,10 +356,10 @@ static void setup_device_pipeline(struct device_data *device_data)
/* Descriptor pool */
VkDescriptorPoolSize sampler_pool_size = {};
sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
sampler_pool_size.descriptorCount = 1;
sampler_pool_size.descriptorCount = 3;
VkDescriptorPoolCreateInfo desc_pool_info = {};
desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
desc_pool_info.maxSets = 1;
desc_pool_info.maxSets = 3;
desc_pool_info.poolSizeCount = 1;
desc_pool_info.pPoolSizes = &sampler_pool_size;
VK_CHECK(device_data->vtable.CreateDescriptorPool(device_data->device,
@ -859,6 +871,36 @@ static void check_fonts(struct swapchain_data* data)
}
}
ImTextureID add_texture(swapchain_stats *stats, const std::string& filename, int* width, int* height, int maxwidth) {
// FIXME hacks
struct swapchain_data *data = reinterpret_cast<swapchain_data *>((char*)stats - ((char*)&((swapchain_data*)0)->sw_stats));
struct texture_info ti {};
int original_width, original_height, channels;
// load
int ret = stbi_info(filename.c_str(), &original_width, &original_height, &channels);
if (!ret)
return nullptr;
// reduce the image
float ratio = 1.0;
if (original_width > maxwidth && maxwidth != 0) {
ratio = maxwidth / static_cast<float> (original_width);
}
*width = original_width * ratio;
*height = original_height * ratio;
ti.descset = alloc_descriptor_set(data->device);
create_image(data->device, *width, *height, VK_FORMAT_R8G8B8A8_UNORM, ti.image);
update_image_descriptor(data->device, ti.image.image_view, ti.descset);
ti.filename = filename;
ti.maxwidth = maxwidth;
data->device->textures.push_back(ti);
return (ImTextureID) ti.descset;
}
static void CreateOrResizeBuffer(struct device_data *data,
VkBuffer *buffer,
VkDeviceMemory *buffer_memory,
@ -929,6 +971,39 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
// ensure_swapchain_fonts(data->device, draw->command_buffer);
/* ensure_textures */
for (auto& tex : data->device->textures) {
if (!tex.descset)
continue;
if (!tex.image.uploaded) {
// tex.image.uploaded = true;
// load
int width, height, channels;
unsigned char* pixels = stbi_load(tex.filename.c_str(), &width, &height, &channels, STBI_rgb_alpha);
if (!pixels)
{
SPDLOG_ERROR("Failed to load image: {}", tex.filename);
continue;
}
// reduce the image
if (width > tex.maxwidth && tex.maxwidth != 0) {
unsigned char* pixels_resized = (unsigned char*)malloc(width * height * STBI_rgb_alpha);
stbir_resize_uint8(pixels, width, height, 0, pixels_resized, tex.image.width, tex.image.height, 0, STBI_rgb_alpha);
stbi_image_free(pixels);
pixels = pixels_resized;
}
SPDLOG_DEBUG("Uploading '{}' ({}x{})", tex.filename, tex.image.width, tex.image.height);
size_t upload_size = tex.image.width * tex.image.height * STBI_rgb_alpha;
submit_image_upload_cmd(device_data, &tex.image, pixels, upload_size);
stbi_image_free(pixels);
}
}
/* Bounce the image to display back to color attachment layout for
* rendering on top of it.
*/
@ -1474,15 +1549,29 @@ static void setup_swapchain_data(struct swapchain_data *data,
NULL, &data->command_pool));
}
static void destroy_vk_image(struct device_data *device_data, vk_image& image)
{
device_data->vtable.DestroyImageView(device_data->device, image.image_view, NULL);
device_data->vtable.DestroyImage(device_data->device, image.image, NULL);
device_data->vtable.FreeMemory(device_data->device, image.mem, NULL);
image = {};
}
static void shutdown_device_font(struct device_data *device_data)
{
device_data->vtable.DestroyImageView(device_data->device, device_data->font_img.image_view, NULL);
device_data->vtable.DestroyImage(device_data->device, device_data->font_img.image, NULL);
device_data->vtable.FreeMemory(device_data->device, device_data->font_img.mem, NULL);
destroy_vk_image(device_data, device_data->font_img);
}
static void shutdown_textures(struct device_data *device_data)
{
for (auto& tex : device_data->textures)
{
device_data->vtable.FreeDescriptorSets(device_data->device, device_data->descriptor_pool, 1, &tex.descset);
destroy_vk_image(device_data, tex.image);
}
// device_data->vtable.DestroyBuffer(device_data->device, device_data->font_img.buffer, NULL);
// device_data->vtable.FreeMemory(device_data->device, device_data->font_img.buffer_mem, NULL);
device_data->font_img = {};
HUDElements.image_infos = {};
HUDElements.background_image_infos = {};
}
static void shutdown_swapchain_data(struct swapchain_data *data)
@ -1879,6 +1968,7 @@ static void overlay_DestroyDevice(
struct device_data *device_data = FIND(struct device_data, device);
if (!is_blacklisted()) {
shutdown_device_font(device_data);
shutdown_textures(device_data);
IM_FREE(device_data->font_atlas);
device_unmap_queues(device_data);
}

Loading…
Cancel
Save