diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc index b051adc6c71..6bbc6ea5dbc 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_color.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_color.cc @@ -361,7 +361,13 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3]) if (win) { /* Fallback to simple opengl picker. */ - WM_window_pixel_sample_read(wm, win, mval, r_col); + if (WM_capabilities_flag() & WM_CAPABILITY_GPU_FRONT_BUFFER_READ) { + WM_window_pixels_read_sample(wm, win, mval, r_col); + } + else { + WM_window_pixels_read_sample_offscreen(C, win, mval, r_col); + } + IMB_colormanagement_display_to_scene_linear_v3(r_col, display); } else { diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 89bb7158b30..2241ac319cf 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -56,12 +56,15 @@ static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area) { int dumprect_size[2]; + wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); /* do redraw so we don't show popups/menus */ WM_redraw_windows(C); - uint *dumprect = WM_window_pixels_read_offscreen(C, win, dumprect_size); + uint *dumprect = (WM_capabilities_flag() & WM_CAPABILITY_GPU_FRONT_BUFFER_READ) ? + WM_window_pixels_read(wm, win, dumprect_size) : + WM_window_pixels_read_offscreen(C, win, dumprect_size); if (dumprect) { ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot"); diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 917407eece3..948fd8f945a 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -286,6 +286,11 @@ void GPU_offscreen_free(GPUOffScreen *ofs); void GPU_offscreen_bind(GPUOffScreen *ofs, bool save); void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore); void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat format, void *pixels); +/** + * A version of #GPU_offscreen_read_pixels that reads into a region. + */ +void GPU_offscreen_read_pixels_region( + GPUOffScreen *offscreen, eGPUDataFormat data_format, int x, int y, int w, int h, void *r_data); void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y); int GPU_offscreen_width(const GPUOffScreen *ofs); int GPU_offscreen_height(const GPUOffScreen *ofs); diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index b281753ad1a..fd01db57b92 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -701,15 +701,26 @@ void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y) ofs_fb->blit_to(GPU_COLOR_BIT, 0, ctx->active_fb, 0, x, y); } -void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat format, void *pixels) +void GPU_offscreen_read_pixels_region( + GPUOffScreen *ofs, eGPUDataFormat format, int x, int y, int w, int h, void *r_pixels) +{ + BLI_assert(ELEM(format, GPU_DATA_UBYTE, GPU_DATA_FLOAT)); + BLI_assert(x >= 0 && y >= 0 && w > 0 && h > 0); + BLI_assert(x + w <= GPU_texture_width(ofs->color)); + BLI_assert(y + h <= GPU_texture_height(ofs->color)); + + GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); + GPU_framebuffer_read_color(ofs_fb, x, y, w, h, 4, 0, format, r_pixels); +} + +void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat format, void *r_pixels) { BLI_assert(ELEM(format, GPU_DATA_UBYTE, GPU_DATA_FLOAT)); const int w = GPU_texture_width(ofs->color); const int h = GPU_texture_height(ofs->color); - GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); - GPU_framebuffer_read_color(ofs_fb, 0, 0, w, h, 4, 0, format, pixels); + GPU_offscreen_read_pixels_region(ofs, format, 0, 0, w, h, r_pixels); } int GPU_offscreen_width(const GPUOffScreen *ofs) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 0d970685582..051856da0c9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -129,6 +129,10 @@ typedef enum eWM_CapabilitiesFlag { WM_CAPABILITY_CURSOR_WARP = (1 << 0), /** Ability to access window positions & move them. */ WM_CAPABILITY_WINDOW_POSITION = (1 << 1), + /** + * Reading from the back-buffer is supported. + */ + WM_CAPABILITY_GPU_FRONT_BUFFER_READ = (1 << 2), } eWM_CapabilitiesFlag; eWM_CapabilitiesFlag WM_capabilities_flag(void); @@ -159,6 +163,11 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm, * the front-buffer state to be invalid under some EGL configurations. */ uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]); +void WM_window_pixels_read_sample(const wmWindowManager *wm, + const wmWindow *win, + const int pos[2], + float r_col[3]); + /** * Draw the window & read pixels from an off-screen buffer (slower than #WM_window_pixels_read). * @@ -166,6 +175,10 @@ uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, in * (see in-line code comments for details). */ uint *WM_window_pixels_read_offscreen(struct bContext *C, struct wmWindow *win, int r_size[2]); +bool WM_window_pixels_read_sample_offscreen(struct bContext *C, + struct wmWindow *win, + const int pos[2], + float r_col[3]); /** * Support for native pixel size diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index ebe670bfa21..c31327200c0 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -1237,6 +1237,36 @@ uint *WM_window_pixels_read_offscreen(bContext *C, wmWindow *win, int r_size[2]) return rect; } +bool WM_window_pixels_read_sample_offscreen(bContext *C, + wmWindow *win, + const int pos[2], + float r_col[3]) +{ + /* A version of #WM_window_pixels_read_offscreen. */ + + const int size[2] = {WM_window_pixels_x(win), WM_window_pixels_y(win)}; + zero_v3(r_col); + + /* While this shouldn't happen, return in the case it does. */ + BLI_assert((uint)pos[0] < (uint)size[0] && (uint)pos[1] < (uint)size[1]); + if (!((uint)pos[0] < (uint)size[0] && (uint)pos[1] < (uint)size[1])) { + return false; + } + + GPUOffScreen *offscreen = GPU_offscreen_create(size[0], size[1], false, GPU_RGBA8, NULL); + if (UNLIKELY(!offscreen)) { + return false; + } + float rect_pixel[4]; + GPU_offscreen_bind(offscreen, false); + wm_draw_window_onscreen(C, win, -1); + GPU_offscreen_unbind(offscreen, false); + GPU_offscreen_read_pixels_region(offscreen, GPU_DATA_FLOAT, pos[0], pos[1], 1, 1, rect_pixel); + GPU_offscreen_free(offscreen); + copy_v3_v3(r_col, rect_pixel); + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 186d74620e4..5f008b86449 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -1827,6 +1827,10 @@ eWM_CapabilitiesFlag WM_capabilities_flag(void) return flag; } + /* NOTE: this is not the intended use of #WM_ghost_backend (for 3.5 release only). */ + const char *ghost_backend = WM_ghost_backend(); + const bool is_wayland = ghost_backend && STREQ(ghost_backend, "WAYLAND"); + flag = 0; if (GHOST_SupportsCursorWarp()) { flag |= WM_CAPABILITY_CURSOR_WARP; @@ -1834,6 +1838,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag(void) if (GHOST_SupportsWindowPosition()) { flag |= WM_CAPABILITY_WINDOW_POSITION; } + if (is_wayland == false) { + flag |= WM_CAPABILITY_GPU_FRONT_BUFFER_READ; + } return flag; } @@ -2151,28 +2158,6 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv return win_other; } -void WM_window_pixel_sample_read(const wmWindowManager *wm, - const wmWindow *win, - const int pos[2], - float r_col[3]) -{ - bool setup_context = wm->windrawable != win; - - if (setup_context) { - GHOST_ActivateWindowDrawingContext(win->ghostwin); - GPU_context_active_set(win->gpuctx); - } - - GPU_frontbuffer_read_pixels(pos[0], pos[1], 1, 1, 3, GPU_DATA_FLOAT, r_col); - - if (setup_context) { - if (wm->windrawable) { - GHOST_ActivateWindowDrawingContext(wm->windrawable->ghostwin); - GPU_context_active_set(wm->windrawable->gpuctx); - } - } -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -2217,6 +2202,29 @@ uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2]) return (uint *)rect; } +void WM_window_pixels_read_sample(const wmWindowManager *wm, + const wmWindow *win, + const int pos[2], + float r_col[3]) +{ + BLI_assert(WM_capabilities_flag() & WM_CAPABILITY_GPU_FRONT_BUFFER_READ); + bool setup_context = wm->windrawable != win; + + if (setup_context) { + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GPU_context_active_set(win->gpuctx); + } + + GPU_frontbuffer_read_pixels(pos[0], pos[1], 1, 1, 3, GPU_DATA_FLOAT, r_col); + + if (setup_context) { + if (wm->windrawable) { + GHOST_ActivateWindowDrawingContext(wm->windrawable->ghostwin); + GPU_context_active_set(wm->windrawable->gpuctx); + } + } +} + /** \} */ /* -------------------------------------------------------------------- */