Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed SDL(3)_SetRenderScale handling #7178

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

bog-dan-ro
Copy link

Fixed mouse handling when using SDL_SetRenderScale for HiDPI.

Fixed #6065

@ocornut
Copy link
Owner

ocornut commented Dec 29, 2023

Hello Bogdan!
thanks for the PR. I think it’d be important to see if this strategy can make sense in multi-viewport mode. Would you be able to test it in docking branch with multi-viewport enabled, and consider if varying render scale are possible / make sense? In particular, there’s normally a continuity of valid mouse coordinate values in the gap between os windows, and i am not sure how this could be affected by render scale.

@bog-dan-ro
Copy link
Author

@ocornut Hi, thanks for your quick reply.

I don't see how it will work, because usually we call SDL_SetRenderScale once ... but I'll think about it :).
Anyway, I have only my laptop with me and no way to test it with multiple view with different pixel densities, but when I'll get back home (after 8th Jan), I'll give it a try, but considering that I'm call SDL_SetRenderScale once I don't see how it will work.
The only way I see it working is if SDL_SetRenderScale is issued from imgui every time when the window is moved, but I still see an issue if the window is (partially) visible on multiple screens with different scale factors.

Here is the test that I was using to test my patch:
main.cpp:

#include <SDL3/SDL.h>
#include <backends/imgui_impl_sdl3.h>
#include <backends/imgui_impl_sdlrenderer3.h>

int main(int argc, char *argv[]) {
    if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
        SDL_Log("SDL_Init failed (%s)", SDL_GetError());
        return 1;
    }

    SDL_Window *window = NULL;
    SDL_Renderer *renderer = NULL;
    constexpr int wflags = SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_RESIZABLE;
    if (SDL_CreateWindowAndRenderer(640, 480, wflags, &window, &renderer) < 0) {
        SDL_Log("SDL_CreateWindowAndRenderer failed (%s)", SDL_GetError());
        SDL_Quit();
        return 1;
    }
    SDL_SetWindowTitle(window, "X-Mas");
    const auto scale = SDL_GetWindowDisplayScale(window);
    SDL_SetRenderScale(renderer, scale, scale);

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io{ImGui::GetIO()};
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableSetMousePos;

    ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
    ImGui_ImplSDLRenderer3_Init(renderer);

    while (1) {
        int finished = 0;
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            ImGui_ImplSDL3_ProcessEvent(&event);
            if (event.type == SDL_EVENT_QUIT) {
                finished = 1;
                break;
            }
        }
        if (finished) {
            break;
        }

        ImGui_ImplSDLRenderer3_NewFrame();
        ImGui_ImplSDL3_NewFrame();
        ImGui::NewFrame();

        ImGui::Begin("X-Mas", nullptr);
        ImGui::Text("Hello there !");
        ImGui::End();

        ImGui::Render();

        SDL_SetRenderDrawColor(renderer, 80, 80, 80, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);

        ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData());

        SDL_RenderPresent(renderer);
    }
    ImGui_ImplSDLRenderer3_Shutdown();
    ImGui_ImplSDL3_Shutdown();
    ImGui::DestroyContext();
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();
}

CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)

project(SDL3_imgui LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)

find_package(SDL3 QUIET)

if(NOT SDL3_FOUND)
    set(SDL_SHARED TRUE CACHE BOOL "Build a SDL shared library (if available)")
    set(SDL_STATIC TRUE CACHE BOOL "Build a SDL static library (if available)")
    FetchContent_Declare(
        SDL
        GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
        GIT_TAG main  # Replace this with a particular git tag or git hash
        GIT_SHALLOW TRUE
        GIT_PROGRESS TRUE
    )
    message(STATUS "Using SDL3 via FetchContent")
    FetchContent_MakeAvailable(SDL)
    set_property(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_deps/sdl-src" PROPERTY EXCLUDE_FROM_ALL TRUE)
endif()

FetchContent_Declare(
  imgui
  GIT_REPOSITORY "https://github.com/bog-dan-ro/imgui.git"
  GIT_TAG master
)

FetchContent_GetProperties(imgui)
if (NOT imgui_POPULATED)
  FetchContent_Populate(imgui)
endif ()

add_library(imgui
  ${imgui_SOURCE_DIR}/imgui.cpp
  ${imgui_SOURCE_DIR}/imgui.h
  ${imgui_SOURCE_DIR}/imconfig.h
  ${imgui_SOURCE_DIR}/imgui_demo.cpp
  ${imgui_SOURCE_DIR}/imgui_draw.cpp
  ${imgui_SOURCE_DIR}/imgui_internal.h
  ${imgui_SOURCE_DIR}/imgui_tables.cpp
  ${imgui_SOURCE_DIR}/imgui_widgets.cpp
  ${imgui_SOURCE_DIR}/imstb_rectpack.h
  ${imgui_SOURCE_DIR}/imstb_textedit.h
  ${imgui_SOURCE_DIR}/imstb_truetype.h
  ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
  ${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.h
  ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.h
  ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
  ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.h
  ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp)

target_include_directories(imgui PUBLIC ${imgui_SOURCE_DIR})
target_link_libraries(imgui PUBLIC SDL3::SDL3)

FetchContent_MakeAvailable(imgui)

add_executable(${PROJECT_NAME} main.cpp)
target_compile_definitions(${PROJECT_NAME}
    PRIVATE
        GL_GLEXT_PROTOTYPES
)
target_link_libraries(${PROJECT_NAME}
    PRIVATE
        SDL3::SDL3
        imgui
)

include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

@@ -71,7 +71,7 @@ struct ImGui_ImplSDL3_Data
int PendingMouseLeaveFrame;
char* ClipboardTextData;
bool MouseCanUseGlobalState;

ImVec2 RenderScale() const { ImVec2 res; SDL_GetRenderScale(Renderer, &res.x, &res.y); return res;}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renderer is able to be null in cases where SDL_Renderer isn't being used (IE: OpenGL, etc), so this needs to be able to handle that.

@@ -267,6 +267,7 @@ struct ImVec2
#ifdef IM_VEC2_CLASS_EXTRA
IM_VEC2_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2.
#endif
inline ImVec2 & operator /=(ImVec2 other) {x /= other.x; y /= other.y; return *this; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are already math operators defined for ImVec2, they're just disabled by default, and none of the backends enable them. Not sure if there's a reason for that or if it was just out of habit.

It might be easier to just match the existing backends and do the math manually per-component for consistency.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are disabled by default as I think it caused issues for users of IM_VEC2_CLASS_EXTRA with own math class + own math operators, though honestly I am not sure of specifics off-hand that that might need a separate investigation.

But yeah at the moment it'd be good if backends didn't rely on those.

@PathogenDavid
Copy link
Contributor

I think it’d be important to see if this strategy can make sense in multi-viewport mode.

This change only applies to SDL_Renderer as far as I can tell, and SDL_Renderer doesn't support multi-viewport, I think we can only theorize.

I do wonder if Dear ImGui should even support SDL_RenderSetScale at all though. If possible it might make more sense for us to always render at 100% scale and say that if people want to scale their GUIs along with their app they need to use ImGui::ScaleAllSizes etc--Otherwise we're just ending up in a situation where a single (famously problematic) render backend can be scaled using a method that's completely different from all the others.


As an aside, we already use SDL_RenderSetScale in example_sdl2_sdlrenderer2 for DPI scaling as of 5a3f82e.

I can't imagine that's just always been broken, so someone should double-check that this PR didn't cause problems with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using SDL_RenderSetScale with sdl_sdlrenderer backend
3 participants