From 10cf2793c6ec006bd83312d29dd1746bc9d6dffc Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 8 Aug 2025 15:56:28 +0200 Subject: [PATCH] Added SDL_GPU3 example. --- Image-Loading-and-Displaying-Examples.md | 125 +++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/Image-Loading-and-Displaying-Examples.md b/Image-Loading-and-Displaying-Examples.md index 1a08fad..898662e 100644 --- a/Image-Loading-and-Displaying-Examples.md +++ b/Image-Loading-and-Displaying-Examples.md @@ -8,6 +8,7 @@ - [Example for DirectX9 users](#example-for-directx9-users) - [Example for DirectX11 users](#example-for-directx11-users) - [Example for DirectX12 users](#example-for-directx12-users) +- [Example for SDL_GPU users](#example-for-sdl_gpu-users) - [Example for SDL_Renderer users](#example-for-sdl_renderer-users) - [Example for Vulkan users](#example-for-vulkan-users) - [Example for WebGPU users](#example-for-webgpu-users) @@ -583,6 +584,130 @@ ImGui::End(); ---- +## Example for SDL_GPU users + +**IMPORTANT** The code below requires 1.92.2 (IMGUI_VERSION_NUM >= 19214) as the type of ImTextureID for SDL_GPU3 backend changed from 'SDL_GPUTextureSamplerBinding*' to 'SDL_GPUTexture*'. + +We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to load images from disk. + +Add at the top of one of your source files: +```cpp +#define _CRT_SECURE_NO_WARNINGS +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +bool LoadTextureFromMemory(const void* data, size_t data_size, SDL_GPUDevice* device, SDL_GPUTexture** out_texture, int* out_width, int* out_height) +{ + // Load from disk into a raw RGBA buffer + int image_width = 0; + int image_height = 0; + unsigned char* image_data = stbi_load_from_memory((const unsigned char*)data, (int)data_size, &image_width, &image_height, NULL, 4); + if (image_data == NULL) + return false; + + // Create texture + SDL_GPUTextureCreateInfo texture_info = {}; + texture_info.type = SDL_GPU_TEXTURETYPE_2D; + texture_info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; + texture_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; + texture_info.width = image_width; + texture_info.height = image_height; + texture_info.layer_count_or_depth = 1; + texture_info.num_levels = 1; + texture_info.sample_count = SDL_GPU_SAMPLECOUNT_1; + + SDL_GPUTexture* texture = SDL_CreateGPUTexture(device, &texture_info); + + // Create transfer buffer + // FIXME: A real engine would likely keep one around, see what the SDL_GPU backend is doing. + SDL_GPUTransferBufferCreateInfo transferbuffer_info = {}; + transferbuffer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; + transferbuffer_info.size = image_width * image_height * 4; + SDL_GPUTransferBuffer* transferbuffer = SDL_CreateGPUTransferBuffer(device, &transferbuffer_info); + IM_ASSERT(transferbuffer != NULL); + + // Copy to transfer buffer + uint32_t upload_pitch = image_width * 4; + void* texture_ptr = SDL_MapGPUTransferBuffer(device, transferbuffer, true); + for (int y = 0; y < image_height; y++) + memcpy((void*)((uintptr_t)texture_ptr + y * upload_pitch), image_data + y * upload_pitch, upload_pitch); + SDL_UnmapGPUTransferBuffer(device, transferbuffer); + + SDL_GPUTextureTransferInfo transfer_info = {}; + transfer_info.offset = 0; + transfer_info.transfer_buffer = transferbuffer; + + SDL_GPUTextureRegion texture_region = {}; + texture_region.texture = texture; + texture_region.x = (Uint32)0; + texture_region.y = (Uint32)0; + texture_region.w = (Uint32)image_width; + texture_region.h = (Uint32)image_height; + texture_region.d = 1; + + // Upload + SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device); + SDL_GPUCopyPass* copy_pass = SDL_BeginGPUCopyPass(cmd); + SDL_UploadToGPUTexture(copy_pass, &transfer_info, &texture_region, false); + SDL_EndGPUCopyPass(copy_pass); + SDL_SubmitGPUCommandBuffer(cmd); + + SDL_ReleaseGPUTransferBuffer(device, transferbuffer); + + *out_texture = texture; + *out_width = image_width; + *out_height = image_height; + stbi_image_free(image_data); + + return true; +} + +// Open and read a file, then forward to LoadTextureFromMemory() +bool LoadTextureFromFile(const char* file_name, SDL_GPUDevice* device, SDL_GPUTexture** out_texture, int* out_width, int* out_height) +{ + FILE* f = fopen(file_name, "rb"); + if (f == NULL) + return false; + fseek(f, 0, SEEK_END); + size_t file_size = (size_t)ftell(f); + if (file_size == -1) + return false; + fseek(f, 0, SEEK_SET); + void* file_data = IM_ALLOC(file_size); + fread(file_data, 1, file_size, f); + fclose(f); + bool ret = LoadTextureFromMemory(file_data, file_size, device, out_texture, out_width, out_height); + IM_FREE(file_data); + return ret; +} + +void DestroyTexture(SDL_GPUDevice* device, SDL_GPUTexture* texture) +{ + SDL_ReleaseGPUTexture(device, texture); +} +``` + +Load our texture after initialising SDL3 and SDL_GPU: +```cpp +SDL_GPUTexture* my_texture; +int my_image_width, my_image_height; +bool ret = LoadTextureFromFile("MyImage01.jpg", gpu_device, &my_texture, &my_image_width, &my_image_height); +IM_ASSERT(ret); +``` + +Now that we have a SDL_GPUTexture* and its dimensions, we can display it in our main loop: +```cpp +ImGui::Begin("SDL_GPU Texture Test"); +ImGui::Text("pointer = %p", &my_texture); +ImGui::Text("size = %d x %d", my_image_width, my_image_height); +ImGui::Image((ImTextureID)(intptr_t)my_texture, ImVec2((float)my_image_width, (float)my_image_height)); +ImGui::End(); +``` + +##### [Return to Index](#index) + +---- + ## Example for SDL_Renderer users We will here use [stb_image.h](https://github.com/nothings/stb/blob/master/stb_image.h) to load images from disk.