Fix #106264: Color picker broken with Wayland & AMD GPU
- Use off-screen drawing when reading from the front-buffer isn't supported. - Add a capabilities flag for reading the front-buffer which is always disabled on WAYLAND. - Add GPU_offscreen_read_pixels_region, used for reading a sub-region of an off-screen buffer - use for color-picking a single pixel. Fix from [0] with conflicts resolved, worked around [1] not being applied by checking if Wayland is in use via WM_ghost_backend(). [0]:6cc2c16d06
[1]:4e51008a82
This commit is contained in:
@@ -361,7 +361,13 @@ void eyedropper_color_sample_fl(bContext *C, const int m_xy[2], float r_col[3])
|
|||||||
|
|
||||||
if (win) {
|
if (win) {
|
||||||
/* Fallback to simple opengl picker. */
|
/* 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);
|
IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@@ -56,12 +56,15 @@ static int screenshot_data_create(bContext *C, wmOperator *op, ScrArea *area)
|
|||||||
{
|
{
|
||||||
int dumprect_size[2];
|
int dumprect_size[2];
|
||||||
|
|
||||||
|
wmWindowManager *wm = CTX_wm_manager(C);
|
||||||
wmWindow *win = CTX_wm_window(C);
|
wmWindow *win = CTX_wm_window(C);
|
||||||
|
|
||||||
/* do redraw so we don't show popups/menus */
|
/* do redraw so we don't show popups/menus */
|
||||||
WM_redraw_windows(C);
|
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) {
|
if (dumprect) {
|
||||||
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
|
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
|
||||||
|
@@ -286,6 +286,11 @@ void GPU_offscreen_free(GPUOffScreen *ofs);
|
|||||||
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
|
void GPU_offscreen_bind(GPUOffScreen *ofs, bool save);
|
||||||
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
|
void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore);
|
||||||
void GPU_offscreen_read_pixels(GPUOffScreen *ofs, eGPUDataFormat format, void *pixels);
|
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);
|
void GPU_offscreen_draw_to_screen(GPUOffScreen *ofs, int x, int y);
|
||||||
int GPU_offscreen_width(const GPUOffScreen *ofs);
|
int GPU_offscreen_width(const GPUOffScreen *ofs);
|
||||||
int GPU_offscreen_height(const GPUOffScreen *ofs);
|
int GPU_offscreen_height(const GPUOffScreen *ofs);
|
||||||
|
@@ -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);
|
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));
|
BLI_assert(ELEM(format, GPU_DATA_UBYTE, GPU_DATA_FLOAT));
|
||||||
|
|
||||||
const int w = GPU_texture_width(ofs->color);
|
const int w = GPU_texture_width(ofs->color);
|
||||||
const int h = GPU_texture_height(ofs->color);
|
const int h = GPU_texture_height(ofs->color);
|
||||||
|
|
||||||
GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs);
|
GPU_offscreen_read_pixels_region(ofs, format, 0, 0, w, h, r_pixels);
|
||||||
GPU_framebuffer_read_color(ofs_fb, 0, 0, w, h, 4, 0, format, pixels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int GPU_offscreen_width(const GPUOffScreen *ofs)
|
int GPU_offscreen_width(const GPUOffScreen *ofs)
|
||||||
|
@@ -129,6 +129,10 @@ typedef enum eWM_CapabilitiesFlag {
|
|||||||
WM_CAPABILITY_CURSOR_WARP = (1 << 0),
|
WM_CAPABILITY_CURSOR_WARP = (1 << 0),
|
||||||
/** Ability to access window positions & move them. */
|
/** Ability to access window positions & move them. */
|
||||||
WM_CAPABILITY_WINDOW_POSITION = (1 << 1),
|
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;
|
||||||
|
|
||||||
eWM_CapabilitiesFlag WM_capabilities_flag(void);
|
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.
|
* 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]);
|
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).
|
* 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).
|
* (see in-line code comments for details).
|
||||||
*/
|
*/
|
||||||
uint *WM_window_pixels_read_offscreen(struct bContext *C, struct wmWindow *win, int r_size[2]);
|
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
|
* Support for native pixel size
|
||||||
|
@@ -1237,6 +1237,36 @@ uint *WM_window_pixels_read_offscreen(bContext *C, wmWindow *win, int r_size[2])
|
|||||||
return rect;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@@ -1827,6 +1827,10 @@ eWM_CapabilitiesFlag WM_capabilities_flag(void)
|
|||||||
return flag;
|
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;
|
flag = 0;
|
||||||
if (GHOST_SupportsCursorWarp()) {
|
if (GHOST_SupportsCursorWarp()) {
|
||||||
flag |= WM_CAPABILITY_CURSOR_WARP;
|
flag |= WM_CAPABILITY_CURSOR_WARP;
|
||||||
@@ -1834,6 +1838,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag(void)
|
|||||||
if (GHOST_SupportsWindowPosition()) {
|
if (GHOST_SupportsWindowPosition()) {
|
||||||
flag |= WM_CAPABILITY_WINDOW_POSITION;
|
flag |= WM_CAPABILITY_WINDOW_POSITION;
|
||||||
}
|
}
|
||||||
|
if (is_wayland == false) {
|
||||||
|
flag |= WM_CAPABILITY_GPU_FRONT_BUFFER_READ;
|
||||||
|
}
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2151,28 +2158,6 @@ wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mv
|
|||||||
return win_other;
|
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;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
Reference in New Issue
Block a user