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>
simple-image-loader
Nicolas Adenis-Lamarre 2 years ago committed by jackun
parent e0736d97ed
commit f75e44c1e8
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

@ -304,6 +304,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `alpha` | Set the opacity of all text and frametime graph `0.0`-`1.0` |
| `arch` | Show if the application is 32- or 64-bit |
| `background_alpha` | Set the opacity of the background `0.0`-`1.0` |
| `background_image` | Display a background image from argument path on the whole screen (eventually transparent) |
| `battery_color` | Change the battery text color |
| `battery_icon` | Display battery icon instead of percent |
| `battery` | Display current battery percent and energy consumption |
@ -351,6 +352,8 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `horizontal` | Display Mangohud in a horizontal position |
| `hud_compact` | Display compact version of MangoHud |
| `hud_no_margin` | Remove margins around MangoHud |
| `image` | Display an image from argument path |
| `image_max_width` | Maximize the image by a max number of pixel for the width |
| `io_read`<br> `io_write` | Show non-cached IO read/write, in MiB/s |
| `log_duration` | Set amount of time the logging will run for (in seconds) |
| `log_interval` | Change the default log interval. Default is `100` |

@ -143,6 +143,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

@ -259,7 +259,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 @@ static 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;
}
}
}

@ -19,6 +19,7 @@
#include <IconsForkAwesome.h>
#include "version.h"
#include "blacklist.h"
#include "load_textures.h"
#define CHAR_CELSIUS "\xe2\x84\x83"
#define CHAR_FAHRENHEIT "\xe2\x84\x89"
@ -716,6 +717,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(){
ImguiNextColumnFirstItem();
ImGui::PushFont(HUDElements.sw_stats->font1);
@ -1179,6 +1246,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 {
@ -59,6 +79,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);

@ -44,7 +44,8 @@ vklayer_files = files(
'vulkan.cpp',
'blacklist.cpp',
'file_utils.cpp',
'intel.cpp'
'intel.cpp',
'load_textures.cpp',
)
opengl_files = []
if ['windows', 'mingw'].contains(host_machine.system())

@ -114,6 +114,7 @@ extern void control_client_check(int control, int& control_client, const std::st
extern void process_control_socket(int& control_client, overlay_params &params);
extern void control_send(int control_client, const char *cmd, unsigned cmdlen, const char *param, unsigned paramlen);
extern int global_control_client;
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

@ -444,6 +444,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)
@ -658,6 +661,7 @@ static void set_param_defaults(struct overlay_params *params){
params->preset = -1;
params->font_size = 24;
params->table_columns = 3;
params->image_max_width = 0;
}
void

@ -71,6 +71,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) \
@ -281,6 +284,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;

@ -4955,6 +4955,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
{
stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;

@ -51,6 +51,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;
@ -63,6 +66,22 @@ namespace MangoHud { namespace GL {
}}
#endif
struct vk_image {
VkImage image;
VkImageView view;
VkDeviceMemory mem;
uint32_t width, height;
size_t size;
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;
@ -158,12 +177,16 @@ struct swapchain_data {
std::list<overlay_draw *> draws; /* List of struct overlay_draw */
bool font_uploaded;
VkImage font_image;
VkImageView font_image_view;
VkDeviceMemory font_mem;
//VkImage font_image;
//VkImageView font_image_view;
//VkDeviceMemory font_mem;
VkBuffer upload_font_buffer;
VkDeviceMemory upload_font_buffer_mem;
struct vk_image font_image;
size_t font_params_hash = 0;
std::vector<struct texture_info> textures;
/**/
ImGuiContext* imgui_context;
ImFontAtlas* font_atlas;
@ -214,6 +237,7 @@ static void unmap_object(uint64_t obj)
/**/
static void shutdown_swapchain_font(struct swapchain_data*);
ImTextureID add_texture(swapchain_stats* stats, const std::string& filename, int* width, int* height, int maxwidth);
static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo,
VkLayerFunction func)
@ -291,6 +315,22 @@ static struct device_data *new_device_data(VkDevice device, struct instance_data
return data;
}
static VkDescriptorSet alloc_descriptor_set(const struct swapchain_data *data)
{
VkDescriptorSet descriptor_set {};
struct device_data *device_data = data->device;
VkDescriptorSetAllocateInfo alloc_info {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = data->descriptor_pool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &data->descriptor_layout;
VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device,
&alloc_info,
&descriptor_set));
return descriptor_set;
}
static struct queue_data *new_queue_data(VkQueue queue,
const VkQueueFamilyProperties *family_props,
uint32_t family_index,
@ -623,9 +663,7 @@ static void create_image(struct swapchain_data *data,
uint32_t width,
uint32_t height,
VkFormat format,
VkImage& image,
VkDeviceMemory& image_mem,
VkImageView& image_view)
vk_image& image)
{
struct device_data *device_data = data->device;
@ -644,10 +682,10 @@ static void create_image(struct swapchain_data *data,
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info,
NULL, &image));
NULL, &image.image));
VkMemoryRequirements font_image_req;
device_data->vtable.GetImageMemoryRequirements(device_data->device,
image, &font_image_req);
image.image, &font_image_req);
VkMemoryAllocateInfo image_alloc_info = {};
image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
image_alloc_info.allocationSize = font_image_req.size;
@ -655,33 +693,31 @@ static void create_image(struct swapchain_data *data,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
font_image_req.memoryTypeBits);
VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info,
NULL, &image_mem));
NULL, &image.mem));
VK_CHECK(device_data->vtable.BindImageMemory(device_data->device,
image,
image_mem, 0));
image.image,
image.mem, 0));
/* Font image view */
VkImageViewCreateInfo view_info = {};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view_info.image = image;
view_info.image = image.image;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.format = format;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.layerCount = 1;
VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info,
NULL, &image_view));
NULL, &image.view));
update_image_descriptor(data, image_view, descriptor_set);
update_image_descriptor(data, image.view, descriptor_set);
}
static VkDescriptorSet create_image_with_desc(struct swapchain_data *data,
uint32_t width,
uint32_t height,
VkFormat format,
VkImage& image,
VkDeviceMemory& image_mem,
VkImageView& image_view)
vk_image& image)
{
struct device_data *device_data = data->device;
@ -696,10 +732,71 @@ static VkDescriptorSet create_image_with_desc(struct swapchain_data *data,
&alloc_info,
&descriptor_set));
create_image(data, descriptor_set, width, height, format, image, image_mem, image_view);
create_image(data, descriptor_set, width, height, format, image);
return descriptor_set;
}
// TODO Synchronous image data upload, make it async
static void submit_image_upload_cmd(struct swapchain_data *data, vk_image *img, void *pixels, size_t upload_size)
{
if (img->uploaded)
return;
struct device_data *device_data = data->device;
auto start = Clock::now();
VkCommandBuffer cmd_buffer;
VkCommandBufferAllocateInfo cmd_buffer_info = {};
cmd_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmd_buffer_info.commandPool = data->command_pool;
cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmd_buffer_info.commandBufferCount = 1;
VK_CHECK(device_data->vtable.AllocateCommandBuffers(device_data->device,
&cmd_buffer_info,
&cmd_buffer));
VK_CHECK(device_data->set_device_loader_data(device_data->device,
cmd_buffer));
VkCommandBufferBeginInfo buffer_begin_info = {};
buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
VK_CHECK(device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info));
VkBuffer buffer;
VkDeviceMemory buffer_mem;
upload_image_data(device_data, cmd_buffer, pixels, upload_size, img->width, img->height,
buffer, buffer_mem, img->image);
device_data->vtable.EndCommandBuffer(cmd_buffer);
VkFence fence;
VkFenceCreateInfo fence_info = {};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
VK_CHECK(device_data->vtable.CreateFence(device_data->device,
&fence_info,
NULL,
&fence));
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmd_buffer;
VkResult r;
VK_CHECK(r = device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, fence));
if (r == VK_SUCCESS)
VK_CHECK(device_data->vtable.WaitForFences(device_data->device, 1, &fence, VK_TRUE, UINT64_MAX));
device_data->vtable.FreeCommandBuffers(device_data->device, data->command_pool, 1, &cmd_buffer);
device_data->vtable.DestroyFence(device_data->device, fence, NULL);
device_data->vtable.DestroyBuffer(device_data->device, buffer, NULL);
device_data->vtable.FreeMemory(device_data->device, buffer_mem, NULL);
img->uploaded = true;
auto dur = Clock::now() - start;
auto dur_us = std::chrono::duration_cast<std::chrono::microseconds>(dur).count();
SPDLOG_DEBUG("upload duration: {} us, {} bytes, {:0.02f} MiB/s", dur_us, upload_size, upload_size/(dur_us/1e6f)/(1024*1024));
}
static void check_fonts(struct swapchain_data* data)
{
struct device_data *device_data = data->device;
@ -720,9 +817,9 @@ static void check_fonts(struct swapchain_data* data)
shutdown_swapchain_font(data);
if (desc_set)
create_image(data, desc_set, width, height, VK_FORMAT_R8G8B8A8_UNORM, data->font_image, data->font_mem, data->font_image_view);
create_image(data, desc_set, width, height, VK_FORMAT_R8G8B8A8_UNORM, data->font_image);
else
desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8G8B8A8_UNORM, data->font_image, data->font_mem, data->font_image_view);
desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8G8B8A8_UNORM, data->font_image);
data->font_atlas->SetTexID((ImTextureID)desc_set);
data->font_uploaded = false;
@ -746,7 +843,37 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
int width, height;
data->font_atlas->GetTexDataAsRGBA32(&pixels, &width, &height);
size_t upload_size = width * height * 4 * sizeof(char);
upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image);
upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image.image);
}
ImTextureID add_texture(swapchain_stats* stats, const std::string& filename, int* width, int* height, int maxwidth) {
struct texture_info ti {};
int original_width, original_height, channels;
// FIXME hacks
struct swapchain_data *data = reinterpret_cast<swapchain_data *>((char*)stats - ((char*)&((swapchain_data*)0)->sw_stats));
// 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);
create_image(data, ti.descset, *width, *height, VK_FORMAT_R8G8B8A8_UNORM, ti.image);
update_image_descriptor(data, ti.image.view, ti.descset);
ti.filename = filename;
ti.maxwidth = maxwidth;
data->textures.push_back(ti);
return (ImTextureID) ti.descset;
}
static void CreateOrResizeBuffer(struct device_data *data,
@ -816,6 +943,39 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
ensure_swapchain_fonts(data, draw->command_buffer);
/* ensure_textures */
for (auto& tex : data->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(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.
*/
@ -1419,16 +1579,31 @@ 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.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_swapchain_font(struct swapchain_data *data)
{
struct device_data *device_data = data->device;
destroy_vk_image(device_data, data->font_image);
}
device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL);
device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL);
device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL);
static void shutdown_textures(struct swapchain_data *data)
{
struct device_data *device_data = data->device;
for (auto& tex : data->textures)
{
device_data->vtable.FreeDescriptorSets(device_data->device, data->descriptor_pool, 1, &tex.descset);
destroy_vk_image(device_data, tex.image);
}
device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL);
device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL);
HUDElements.image_infos = {};
HUDElements.background_image_infos = {};
}
static void shutdown_swapchain_data(struct swapchain_data *data)
@ -1465,6 +1640,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data)
device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL);
shutdown_swapchain_font(data);
shutdown_textures(data);
IM_FREE(data->font_atlas);
ImGui::DestroyContext(data->imgui_context);

Loading…
Cancel
Save