1
1
This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/screen/screendump.c
Campbell Barton 93dac7da2c 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
2023-04-21 21:31:26 +10:00

275 lines
6.9 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup edscr
* Making screenshots of the entire window or sub-regions.
*/
#include <errno.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_image_format.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BLT_translation.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_prototypes.h"
#include "UI_interface.h"
#include "WM_api.h"
#include "WM_types.h"
#include "screen_intern.h"
typedef struct ScreenshotData {
uint *dumprect;
int dumpsx, dumpsy;
rcti crop;
bool use_crop;
ImageFormatData im_format;
} ScreenshotData;
/* call from both exec and invoke */
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_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");
scd->dumpsx = dumprect_size[0];
scd->dumpsy = dumprect_size[1];
scd->dumprect = dumprect;
if (area) {
scd->crop = area->totrct;
}
BKE_image_format_init(&scd->im_format, false);
op->customdata = scd;
return true;
}
op->customdata = NULL;
return false;
}
static void screenshot_data_free(wmOperator *op)
{
ScreenshotData *scd = op->customdata;
if (scd) {
if (scd->dumprect) {
MEM_freeN(scd->dumprect);
}
MEM_freeN(scd);
op->customdata = NULL;
}
}
static int screenshot_exec(bContext *C, wmOperator *op)
{
const bool use_crop = STREQ(op->idname, "SCREEN_OT_screenshot_area");
ScreenshotData *scd = op->customdata;
bool ok = false;
if (scd == NULL) {
/* when running exec directly */
screenshot_data_create(C, op, use_crop ? CTX_wm_area(C) : NULL);
scd = op->customdata;
}
if (scd) {
if (scd->dumprect) {
ImBuf *ibuf;
char path[FILE_MAX];
RNA_string_get(op->ptr, "filepath", path);
BLI_path_abs(path, BKE_main_blendfile_path_from_global());
/* operator ensures the extension */
ibuf = IMB_allocImBuf(scd->dumpsx, scd->dumpsy, 24, 0);
ibuf->rect = scd->dumprect;
/* crop to show only single editor */
if (use_crop) {
IMB_rect_crop(ibuf, &scd->crop);
scd->dumprect = ibuf->rect;
}
if ((scd->im_format.planes == R_IMF_PLANES_BW) &&
(scd->im_format.imtype != R_IMF_IMTYPE_MULTILAYER)) {
/* bw screenshot? - users will notice if it fails! */
IMB_color_to_bw(ibuf);
}
if (BKE_imbuf_write(ibuf, path, &scd->im_format)) {
ok = true;
}
else {
BKE_reportf(op->reports, RPT_ERROR, "Could not write image: %s", strerror(errno));
}
IMB_freeImBuf(ibuf);
}
}
screenshot_data_free(op);
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const bool use_crop = STREQ(op->idname, "SCREEN_OT_screenshot_area");
ScrArea *area = NULL;
if (use_crop) {
area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy);
if (area_test != NULL) {
area = area_test;
}
}
if (screenshot_data_create(C, op, area)) {
if (RNA_struct_property_is_set(op->ptr, "filepath")) {
return screenshot_exec(C, op);
}
/* extension is added by 'screenshot_check' after */
char filepath[FILE_MAX];
BLI_snprintf(filepath, FILE_MAX, "//%s", DATA_("screen"));
const char *blendfile_path = BKE_main_blendfile_path_from_global();
if (blendfile_path[0] != '\0') {
BLI_strncpy(filepath, blendfile_path, sizeof(filepath));
BLI_path_extension_replace(filepath, sizeof(filepath), ""); /* strip '.blend' */
}
RNA_string_set(op->ptr, "filepath", filepath);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
return OPERATOR_CANCELLED;
}
static bool screenshot_check(bContext *UNUSED(C), wmOperator *op)
{
ScreenshotData *scd = op->customdata;
return WM_operator_filesel_ensure_ext_imtype(op, &scd->im_format);
}
static void screenshot_cancel(bContext *UNUSED(C), wmOperator *op)
{
screenshot_data_free(op);
}
static bool screenshot_draw_check_prop(PointerRNA *UNUSED(ptr),
PropertyRNA *prop,
void *UNUSED(user_data))
{
const char *prop_id = RNA_property_identifier(prop);
return !STREQ(prop_id, "filepath");
}
static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
ScreenshotData *scd = op->customdata;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
/* image template */
PointerRNA ptr;
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, &scd->im_format, &ptr);
uiTemplateImageSettings(layout, &ptr, false);
/* main draw call */
uiDefAutoButsRNA(
layout, op->ptr, screenshot_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
}
static bool screenshot_poll(bContext *C)
{
if (G.background) {
return false;
}
return WM_operator_winactive(C);
}
static void screen_screenshot_impl(wmOperatorType *ot)
{
ot->invoke = screenshot_invoke;
ot->check = screenshot_check;
ot->exec = screenshot_exec;
ot->cancel = screenshot_cancel;
ot->ui = screenshot_draw;
ot->poll = screenshot_poll;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE,
FILE_SPECIAL,
FILE_SAVE,
WM_FILESEL_FILEPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
}
void SCREEN_OT_screenshot(wmOperatorType *ot)
{
ot->name = "Save Screenshot";
ot->idname = "SCREEN_OT_screenshot";
ot->description = "Capture a picture of the whole Blender window";
screen_screenshot_impl(ot);
ot->flag = 0;
}
void SCREEN_OT_screenshot_area(wmOperatorType *ot)
{
/* NOTE: the term "area" is a Blender internal name, "Editor" makes more sense for the UI. */
ot->name = "Save Screenshot (Editor)";
ot->idname = "SCREEN_OT_screenshot_area";
ot->description = "Capture a picture of an editor";
screen_screenshot_impl(ot);
ot->flag = OPTYPE_DEPENDS_ON_CURSOR;
}