Problem with rendering sdl gpu scene in imgui window

I have a problem with rendering sdl gpu scene in imgui window

#include "imgui/imgui.h"
#include "imgui/imgui_impl_sdl3.h"
#include "imgui/imgui_impl_sdlgpu3.h"
#include <stdio.h>     
#include <stdlib.h>  
#include <SDL3/SDL.h>
#include <iostream>
#include <vector>

// Main code
int main(int, char**)
{
    // Setup SDL
    // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function]
    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
    {
        printf("Error: SDL_Init(): %s\n", SDL_GetError());
        return -1;
    }

    // Create SDL window graphics context
    float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay());
    SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY;
    SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_GPU example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags);
    if (window == nullptr)
    {
        printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
        return -1;
    }
    SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
    SDL_ShowWindow(window);

    // Create GPU Device
    SDL_GPUDevice* gpu_device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_METALLIB, true, nullptr);
    if (gpu_device == nullptr)
    {
        printf("Error: SDL_CreateGPUDevice(): %s\n", SDL_GetError());
        return -1;
    }

    // Claim window for GPU Device
    if (!SDL_ClaimWindowForGPUDevice(gpu_device, window))
    {
        printf("Error: SDL_ClaimWindowForGPUDevice(): %s\n", SDL_GetError());
        return -1;
    }
    SDL_SetGPUSwapchainParameters(gpu_device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_MAILBOX);

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();
    //ImGui::StyleColorsLight();

    // Setup scaling
    ImGuiStyle& style = ImGui::GetStyle();
    style.ScaleAllSizes(main_scale);        // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
    style.FontScaleDpi = main_scale;        // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose)

    // Setup Platform/Renderer backends
    ImGui_ImplSDL3_InitForSDLGPU(window);
    ImGui_ImplSDLGPU3_InitInfo init_info = {};
    init_info.Device = gpu_device;
    init_info.ColorTargetFormat = SDL_GetGPUSwapchainTextureFormat(gpu_device, window);
    init_info.MSAASamples = SDL_GPU_SAMPLECOUNT_1;
    ImGui_ImplSDLGPU3_Init(&init_info);

    // Our state
    bool show_demo_window = true;
    ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

    // Main loop
    bool done = false;
    while (!done)
    {
        // Poll and handle events (inputs, window resize, etc.)
        // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
        // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
        // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
        // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
        // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function]
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            ImGui_ImplSDL3_ProcessEvent(&event);
            if (event.type == SDL_EVENT_QUIT)
                done = true;
            if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window))
                done = true;
        }

        // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function]
        if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)
        {
            SDL_Delay(10);
            continue;
        }
         
        // Start the Dear ImGui frame
        ImGui_ImplSDLGPU3_NewFrame();
        ImGui_ImplSDL3_NewFrame();
        ImGui::NewFrame();

        size_t width = 800, height = 600;
        SDL_GPUCommandBuffer* cmdBuffor = SDL_AcquireGPUCommandBuffer(gpu_device);
        SDL_GPUTexture* swapTexture = nullptr;

        SDL_GPUTextureCreateInfo texInfo{};
        texInfo.type = SDL_GPU_TEXTURETYPE_2D;
        texInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
        texInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER;
        texInfo.width = width;
        texInfo.height = height;
        texInfo.num_levels = 1;
        texInfo.layer_count_or_depth = 1;

        swapTexture = SDL_CreateGPUTexture(gpu_device, &texInfo);

        SDL_GPUColorTargetInfo colorTargetInfo{};
        colorTargetInfo.texture = swapTexture;
        colorTargetInfo.clear_color = SDL_FColor{ 0.0f, 1.0f, 1.0f, 1.0f };
        colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR;
        colorTargetInfo.store_op = SDL_GPU_STOREOP_STORE;

        SDL_GPURenderPass* renderPass = SDL_BeginGPURenderPass(cmdBuffor, &colorTargetInfo, 1, nullptr);
        SDL_EndGPURenderPass(renderPass);
        
        SDL_GPUTransferBufferCreateInfo tbufInfo {};
        tbufInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
        tbufInfo.size = width * height * 4;

        SDL_GPUTransferBuffer* transferBuffor = SDL_CreateGPUTransferBuffer(gpu_device, &tbufInfo);

        SDL_GPUCopyPass* copyPass = SDL_BeginGPUCopyPass(cmdBuffor);
        SDL_GPUTextureRegion region{};
        region.texture = swapTexture;
        region.mip_level = 0;
        region.layer = 0;
        region.x = 0;
        region.y = 0;
        region.z = 0;
        region.w = width;
        region.h = height;
        region.d = 1;
        
        SDL_GPUTextureTransferInfo xferInfo{};
        xferInfo.transfer_buffer = transferBuffor;
        xferInfo.offset = 0;
        xferInfo.pixels_per_row = (Uint32)width;
        xferInfo.rows_per_layer = (Uint32)height;        

        SDL_DownloadFromGPUTexture(copyPass, &region, &xferInfo);
        SDL_EndGPUCopyPass(copyPass);

        SDL_GPUFence* const fence = SDL_SubmitGPUCommandBufferAndAcquireFence(cmdBuffor);
        SDL_WaitForGPUFences(gpu_device, true, &fence, 1);
        SDL_ReleaseGPUFence(gpu_device, fence);

        void* pixels = SDL_MapGPUTransferBuffer(gpu_device, transferBuffor, false);
        if (!pixels) {
            SDL_Log("Failed to map transfer buffer: %s\n", SDL_GetError());
            return -1;
        }
        SDL_UnmapGPUTransferBuffer(gpu_device, transferBuffor);
        SDL_ReleaseGPUTransferBuffer(gpu_device, transferBuffor);

        SDL_Surface* surface = SDL_CreateSurfaceFrom(
            (int)width, (int)height,
            SDL_PIXELFORMAT_RGBA8888,
            pixels,
            (int)(width * 4)
        );

        ImGui::Begin("Preview");

        ImVec2 pos = ImGui::GetCursorScreenPos();

            ImGui::Image(
                surface,
                pos,
                ImVec2(0, 1),
                ImVec2(1, 0)
            );
            
        ImGui::End();

        if (show_demo_window)
            ImGui::ShowDemoWindow(&show_demo_window);

        // Rendering
        ImGui::Render();
        ImDrawData* draw_data = ImGui::GetDrawData();
        const bool is_minimized = (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f);

        SDL_GPUCommandBuffer* command_buffer = SDL_AcquireGPUCommandBuffer(gpu_device); // Acquire a GPU command buffer

        SDL_GPUTexture* swapchain_texture;
        SDL_AcquireGPUSwapchainTexture(command_buffer, window, &swapchain_texture, nullptr, nullptr); // Acquire a swapchain texture

        if (swapchain_texture != nullptr && !is_minimized)
        {
            // This is mandatory: call ImGui_ImplSDLGPU3_PrepareDrawData() to upload the vertex/index buffer!
            ImGui_ImplSDLGPU3_PrepareDrawData(draw_data, command_buffer);

            // Setup and start a render pass
            SDL_GPUColorTargetInfo target_info = {};
            target_info.texture = swapchain_texture;
            target_info.clear_color = SDL_FColor{ clear_color.x, clear_color.y, clear_color.z, clear_color.w };
            target_info.load_op = SDL_GPU_LOADOP_CLEAR;
            target_info.store_op = SDL_GPU_STOREOP_STORE;
            target_info.mip_level = 0;
            target_info.layer_or_depth_plane = 0;
            target_info.cycle = false;
            SDL_GPURenderPass* render_pass = SDL_BeginGPURenderPass(command_buffer, &target_info, 1, nullptr);

            // Render ImGui
            ImGui_ImplSDLGPU3_RenderDrawData(draw_data, command_buffer, render_pass);

            SDL_EndGPURenderPass(render_pass);
        }

        // Submit the command buffer
        SDL_SubmitGPUCommandBuffer(command_buffer);
    }

    // Cleanup
    // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function]
    SDL_WaitForGPUIdle(gpu_device);
    ImGui_ImplSDL3_Shutdown();
    ImGui_ImplSDLGPU3_Shutdown();
    ImGui::DestroyContext();

    SDL_ReleaseWindowFromGPUDevice(gpu_device, window);
    SDL_DestroyGPUDevice(gpu_device);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

i wanted to make something like that
460246666-d6792a2e-20e3-4e5b-b76c-3bcb450e307c

Can someone help me

You don’t need to render to a texture for this, just figure out where your ImGui preview window is, set the viewport to that, render your scene, set the viewport back to the whole screen, then render ImGui.

The order should be like:

  1. Do all your game logic
  2. Determine what to render
  3. Make your ImGui calls
  4. Figure out where your preview window is, and save this for later
  5. Do any copy passes you need
  6. Call ImGui_ImplSDLGPU3_PrepareDrawData() (which basically just does a copy pass for ImGui data)
  7. Start your rendering pass
  8. Set the viewport to where your preview window will go
  9. Render your scene
  10. Set the viewport back to the whole screen
  11. Call ImGui_ImplSDLGPU3_RenderDrawData()
  12. End your rendering pass, submit the command buffer, etc

This will be faster than rendering to a texture and then reusing it to draw your preview window, and a lot faster than rendering to a texture then copying it to system RAM for some bizarre reason.