0

some time ago I followed some SDL tutorial to blit some images and have a test function that loops through a vector of SDL textures and destination reacts and then call the following function to copy the image into the window.

void SpriteSheets::draw(const Sprite* sprite, SDL_Rect* dest) {
    SDL_RenderCopy(renderer, sprite->texture, sprite->rect, dest);
    SDL_RenderPresent(renderer);
}

// this is probably not relevant but including the clear/calling the draw function
void SpriteSheets::clearScreen() {
    SDL_SetRenderDrawColor(renderer, 150, 0, 100, 0); // debug color
    SDL_RenderClear(renderer);
}

void GameContext::drawSprites() {
    const auto& sprites  = std::get<comp::sprite>(c.components);
    const auto& position = std::get<comp::position>(c.components);

    SpriteSheets::clearScreen();

    for ( size_t i = 0; i < sprites.size(); i++ ) {
        SDL_Rect dest;
        dest.h = 50;
        dest.w = 50;
        dest.x = position[i].x();
        dest.y = position[i].y();
        SpriteSheets::draw(&sprites[i], &dest);
    }
}

This all "works" in that it renders all the "sprites" just fine

Then I setup imgui which was fine (I rewrote most of the sdl/vulkan example to use the vulkan c++ bindings instead of the c api) 90% of the code/structure is from the imgui example https://github.com/ocornut/imgui/blob/master/examples/example_sdl_vulkan/main.cpp with each part organized into separate functions.

// relevant gui clear...
// at some point clear color is set to this
    this->clear_color = ImVec4(0.0f, 1.0f, 0.5f, 0.00f); //gross color for debugging
// snip
void Gui::clear(bool should_clear) {
    ImGui::Render();
    if ( should_clear ) memcpy(&wd.ClearValue.color.float32[0], &clear_color, 4 * sizeof(float));
}
// snip

void GraphicContext::mainLoop(GameContext* game) {
    //Frame Setup
    gui.frameSetup(); //rebuild swapchain if needed and then call imgui begin frame

    // draw the "game" 
    // which is just a few static png's at different locations
    game->drawSprites(); //when surounded by imgui functions it is hidden and not displayed

    //draw the imgui menu overtop
    if ( gui.show_demo_window ) ImGui::ShowDemoWindow(&gui.show_demo_window);

    //End frame
    gui.clear(false); // has ImGui::Render(); and conditional copy clear color 
    gui.frameRender(); // put all the imgui commands into a command buffer
    gui.framePresent(); // submit Queue
}

Again the imgui setup "works" in that I successfully show the demo window. additionally, I can make my own windows easily and don't have an issue with the API.

My problem is that I can only get these two concepts to work separately. If I remove the clear screen/ copy clear value to clear_color the background color gui.clear(false); instead of gui.clear(true) for imgui the clear color is black/it still covers the sdl sprites. (same with setting the clear value to have an alpha of 0.) I've tried ordering the "drawSprites" call before and after the imgui frame but its always overwriting it/covering it.

I realize I'm not including a minimal reproducible example and I'm not including all of the imgui functions but its alot of boilerplate (vulkan makes the setup/render/present functions 100+ lines and including the setup for the contexts pushes that another 600+ lines.)

Does anyone know how to either prevent imgui from clearing the screen (I'm already clearing the screen in the sdl section) (change the render pass maybe?)

//relevant part of frameRender()
{
    VkRenderPassBeginInfo info{
        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
        .pNext = NULL,
        .renderPass = wd.RenderPass,
        .framebuffer = fd->Framebuffer,
        //.renderArea = {{0,0}, {wd.Width, wd.Height}},
        .clearValueCount = 1,
        .pClearValues = &wd.ClearValue
    };
    // the initializer for this doesn't work and idk why.
    // when I set the second two zeros in the render area initalizer list to width and height 
    // it wants to be converted to uint32 but when I do that it crashes with a read acess violation.
    info.renderArea.extent.width = wd.Width;
    info.renderArea.extent.height = wd.Height;

    vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}

I tried setting the clear value count/pClearValue to NULL but that just makes the info struct no longer valid/crash (there must be at least 1 entry) and I rechecked that the alpha was 0 for the clear color at this point.

Alternatively, I could try to combine all the sdl draws into the imgui command buffer (or replace drawing with sdl with pure vulkan)

I've been debugging this for hours slowly rewriting all the example code to get a feel for how its setup but I'm in the exact same position I was ages ago with little to no progress on it drawing overtop of the rest of the window.

I probably have to redo the whole Vulkan tutorial because its been a year since I touched it and my problems probably obvious but I was hoping because I was using imgui and sdl I could write a bit of an engine first and dip back into the rendering backend to optimize stuff later if needed.

BlueLightning42
  • 344
  • 4
  • 15
  • How do you create your renderpass attachment (what's `attachment.loadOp`, most importantly)? GUI don't need separate clear if you render to the same framebuffer. You need to "clear, render sprites, render gui, present", but you present after each sprite and (probably - we don't see the code) never at the end. – keltar Apr 27 '20 at 05:12
  • Aside from that, I really don't think it is a good idea to mix SDL renderer with direct calls to underlying rendering API. It could be disasterous with GL, but vulkan is less stateful so maybe not so bad here. Wouldn't it be simplier and much more flexible to render via e.g. vulkan directly and use SDL only to window/event handling? – keltar Apr 27 '20 at 05:14
  • [Imgui source](https://github.com/ocornut/imgui/blob/master/examples/example_sdl_vulkan/main.cpp) FrameRender and FramePresent are from here. renderpass attachment is in imgui_impl_vulkan.cpp `attachment.loadOp = wd->ClearEnable ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;` ...so finding that I've set ClearEnable to False. -now I'm in the position where imgui still overwrites the sdl draws but acts as if it isn't being cleared (ghost images from all the previous frames when dragged). but thats at least progress. – BlueLightning42 Apr 27 '20 at 18:52
  • I'm not sure how sdl is rendering internally but I guess that means its blocked by the imgui rendering...I'll try and just use vulkan directly (I was trying to seperate the underlying rendering api so if its swapped out the draw calls are abstracted from it and can remain unchanged but I guess its just removing control from me...thank you for the response anyways – BlueLightning42 Apr 27 '20 at 18:57

0 Answers0