MacOS: Enable support for EDR rendering #105662

Merged
Brecht Van Lommel merged 26 commits from Jason-Fielder/blender:macos_EDR_support into main 2023-08-09 14:25:23 +02:00
28 changed files with 258 additions and 37 deletions

View File

@ -25,6 +25,8 @@
#include <cassert>
#include <vector>
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT_EDR = MTLPixelFormatRGBA16Float;
static void ghost_fatal_error_dialog(const char *msg)
{
@autoreleasepool {
@ -85,6 +87,19 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
[m_metalLayer removeAllAnimations];
[m_metalLayer setDevice:metalDevice];
m_metalLayer.allowsNextDrawableTimeout = NO;
/* Enable EDR support. This is done by:
* 1. Using a floating point render target, so that values ouside 0..1 can be used
* 2. Informing the OS that we are EDR aware, and intend to use values outside 0..1
* 3. Setting the extended sRGB color space so that the OS knows how to interpret the
* values. */
m_metalLayer.wantsExtendedDynamicRangeContent = YES;
m_metalLayer.pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT_EDR;
const CFStringRef name = kCGColorSpaceExtendedSRGB;
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
m_metalLayer.colorspace = colorspace;
CGColorSpaceRelease(colorspace);
metalInit();
}
else {
@ -199,8 +214,6 @@ GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
return GHOST_kSuccess;
}
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm;
void GHOST_ContextCGL::metalInit()
{
@autoreleasepool {
@ -266,11 +279,12 @@ void GHOST_ContextCGL::metalInit()
desc.fragmentFunction = [library newFunctionWithName:@"fragment_shader"];
desc.vertexFunction = [library newFunctionWithName:@"vertex_shader"];
[desc.colorAttachments objectAtIndexedSubscript:0].pixelFormat =
METAL_FRAMEBUFFERPIXEL_FORMAT_EDR;
/* Ensure library is released. */
[library autorelease];
[desc.colorAttachments objectAtIndexedSubscript:0].pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT;
m_metalRenderPipeline = (MTLRenderPipelineState *)[device
newRenderPipelineStateWithDescriptor:desc
error:&error];
@ -332,7 +346,7 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
id<MTLDevice> device = m_metalLayer.device;
MTLTextureDescriptor *overlayDesc = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA16Float
texture2DDescriptorWithPixelFormat:METAL_FRAMEBUFFERPIXEL_FORMAT_EDR
width:width
height:height
mipmapped:NO];
@ -347,12 +361,9 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
else {
overlayTex.label = [NSString
stringWithFormat:@"Metal Overlay for GHOST Context %p", this]; //@"";
// NSLog(@"Created new Metal Overlay (backbuffer) for context %p\n", this);
}
m_defaultFramebufferMetalTexture[current_swapchain_index].texture =
overlayTex; //[(MTLTexture *)overlayTex retain];
m_defaultFramebufferMetalTexture[current_swapchain_index].texture = overlayTex;
/* Clear texture on create */
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];

View File

@ -347,6 +347,20 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
[m_metalLayer removeAllAnimations];
[m_metalLayer setDevice:metalDevice];
if (type == GHOST_kDrawingContextTypeMetal) {
/* Enable EDR support. This is done by:
* 1. Using a floating point render target, so that values ouside 0..1 can be used
* 2. Informing the OS that we are EDR aware, and intend to use values outside 0..1
* 3. Setting the extended sRGB color space so that the OS knows how to interpret the
* values. */
m_metalLayer.wantsExtendedDynamicRangeContent = YES;
m_metalLayer.pixelFormat = MTLPixelFormatRGBA16Float;
const CFStringRef name = kCGColorSpaceExtendedSRGB;
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
m_metalLayer.colorspace = colorspace;
CGColorSpaceRelease(colorspace);
}
m_metalView = [[CocoaMetalView alloc] initWithFrame:rect];
[m_metalView setWantsLayer:YES];
[m_metalView setLayer:m_metalLayer];

View File

@ -169,7 +169,16 @@ vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay)
* merge UI using alpha blending in the correct color space. */
if (parameters.use_overlay) {
col.rgb = pow(col.rgb, vec3(parameters.exponent * 2.2));
col = clamp(col, 0.0, 1.0);
if (!parameters.use_hdr) {
brecht marked this conversation as resolved Outdated

would still use clamp(col, 0.0, 1.0) here. and move the max inside the else-clause

would still use `clamp(col, 0.0, 1.0)` here. and move the `max` inside the else-clause

As would even go further and suggest to move all clamping inside the if-else clause for clarity.

if (!parameters.use_extended) {
  col = clamp(col, 0.0, 1.0);
}
else {
  col = mix(min(col, 0.0), clamp(col, 0.0, 1.0), col_overlay.a);
}

This way, the code is easier to refactor if we need to change the else clause.

As would even go further and suggest to move all clamping inside the if-else clause for clarity. ``` if (!parameters.use_extended) { col = clamp(col, 0.0, 1.0); } else { col = mix(min(col, 0.0), clamp(col, 0.0, 1.0), col_overlay.a); } ``` This way, the code is easier to refactor if we need to change the else clause.
/* If we're not using an extended colour space, clamp the color 0..1. */
col = clamp(col, 0.0, 1.0);
}
fclem marked this conversation as resolved Outdated

Comment style: Capital + fullstop.

Comment style: Capital + fullstop.
else {
/* When using extended colorspace, interpolate towards clamped color to improve display of
* alpha-blended overlays. */
col = mix(max(col, 0.0), clamp(col, 0.0, 1.0), col_overlay.a);
}
col *= 1.0 - col_overlay.a;
col += col_overlay; /* Assumed unassociated alpha. */
col.rgb = pow(col.rgb, vec3(1.0 / 2.2));

View File

@ -290,7 +290,8 @@ bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
const float exponent,
const float dither,
const bool use_predivide,
const bool use_overlay)
const bool use_overlay,
fclem marked this conversation as resolved

use_extended -> use_hdr I think is more clear, since that's the name of the option. EDR I guess is a macOS specific term.

use_extended -> use_hdr I think is more clear, since that's the name of the option. EDR I guess is a macOS specific term.
const bool use_hdr)
{
return impl->gpuDisplayShaderBind(config,
input,
@ -302,7 +303,8 @@ bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
exponent,
dither,
use_predivide,
use_overlay);
use_overlay,
use_hdr);
}
void OCIO_gpuDisplayShaderUnbind()

View File

@ -197,7 +197,8 @@ bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
const float exponent,
const float dither,
const bool use_predivide,
const bool use_overlay);
const bool use_overlay,
const bool use_hdr);
void OCIO_gpuDisplayShaderUnbind(void);
void OCIO_gpuCacheFree(void);

View File

@ -113,7 +113,8 @@ class IOCIOImpl {
const float /*exponent*/,
const float /*dither*/,
const bool /*use_predivide*/,
const bool /*use_overlay*/)
const bool /*use_overlay*/,
const bool /*use_hdr*/)
{
return false;
}
@ -310,7 +311,8 @@ class OCIOImpl : public IOCIOImpl {
const float exponent,
const float dither,
const bool use_predivide,
const bool use_overlay);
const bool use_overlay,
const bool use_hdr);
void gpuDisplayShaderUnbind(void);
void gpuCacheFree(void);

View File

@ -515,7 +515,8 @@ static void updateGPUDisplayParameters(OCIO_GPUShader &shader,
float exponent,
float dither,
bool use_predivide,
bool use_overlay)
bool use_overlay,
bool use_hdr)
{
bool do_update = false;
if (shader.parameters_buffer == nullptr) {
@ -543,6 +544,10 @@ static void updateGPUDisplayParameters(OCIO_GPUShader &shader,
data.use_overlay = use_overlay;
do_update = true;
}
if (bool(data.use_hdr) != use_hdr) {
data.use_hdr = use_hdr;
do_update = true;
}
if (do_update) {
GPU_uniformbuf_update(shader.parameters_buffer, &data);
}
@ -684,7 +689,8 @@ bool OCIOImpl::gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
const float exponent,
const float dither,
const bool use_predivide,
const bool use_overlay)
const bool use_overlay,
const bool use_hdr)
{
/* Get GPU shader from cache or create new one. */
OCIO_GPUDisplayShader &display_shader = getGPUDisplayShader(
@ -719,7 +725,7 @@ bool OCIOImpl::gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
GPU_uniformbuf_bind(textures.uniforms_buffer, UNIFORMBUF_SLOT_LUTS);
}
updateGPUDisplayParameters(shader, scale, exponent, dither, use_predivide, use_overlay);
updateGPUDisplayParameters(shader, scale, exponent, dither, use_predivide, use_overlay, use_hdr);
GPU_uniformbuf_bind(shader.parameters_buffer, UNIFORMBUF_SLOT_DISPLAY);
/* TODO(fclem): remove remains of IMM. */

View File

@ -36,7 +36,7 @@ struct OCIO_GPUParameters {
float exponent;
bool1 use_predivide;
bool1 use_overlay;
bool1 use_hdr;
int _pad0;
int _pad1;
int _pad2;
};

View File

@ -58,6 +58,7 @@ class RENDER_PT_color_management(RenderButtonsPanel, Panel):
'BLENDER_WORKBENCH_NEXT'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
@ -84,6 +85,36 @@ class RENDER_PT_color_management(RenderButtonsPanel, Panel):
col.prop(scene.sequencer_colorspace_settings, "name", text="Sequencer")
class RENDER_PT_color_management_display_settings(RenderButtonsPanel, Panel):
bl_label = "Display"
bl_parent_id = "RENDER_PT_color_management"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {
'BLENDER_RENDER',
'BLENDER_EEVEE',
'BLENDER_EEVEE_NEXT',
'BLENDER_WORKBENCH',
'BLENDER_WORKBENCH_NEXT'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
scene = context.scene
view = scene.view_settings
# Only enable display sub-section if HDR support is available.
import gpu
layout.enabled = gpu.capabilities.hdr_support_get()
# Only display HDR toggle for non-Filmic display transforms.
col = layout.column(align=True)
sub = col.row()
sub.active = (view.view_transform != "Filmic" and view.view_transform != "Filmic Log")
sub.prop(view, "use_hdr_view")
class RENDER_PT_color_management_curves(RenderButtonsPanel, Panel):
bl_label = "Use Curves"
bl_parent_id = "RENDER_PT_color_management"
@ -1223,6 +1254,7 @@ classes = (
RENDER_PT_opengl_film,
RENDER_PT_hydra_debug,
RENDER_PT_color_management,
RENDER_PT_color_management_display_settings,
RENDER_PT_color_management_curves,
RENDER_PT_simplify,
RENDER_PT_simplify_viewport,

View File

@ -64,6 +64,7 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
#include "GPU_capabilities.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
@ -1902,7 +1903,16 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
bool is_ortho = false;
float winmat[4][4];
if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey))) {
/* Determine desired offscreen format depending on HDR availability. */
bool use_hdr = false;
if (scene && ((scene->view_settings.flag & COLORMANAGE_VIEW_USE_HDR) != 0)) {
use_hdr = GPU_hdr_support();
}
eGPUTextureFormat desired_format = (use_hdr) ? GPU_RGBA16F : GPU_RGBA8;
if (ofs && ((GPU_offscreen_width(ofs) != sizex) || (GPU_offscreen_height(ofs) != sizey) ||
(GPU_offscreen_format(ofs) != desired_format)))
{
/* sizes differ, can't reuse */
ofs = nullptr;
}
@ -1921,7 +1931,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
ofs = GPU_offscreen_create(sizex,
sizey,
true,
GPU_RGBA8,
desired_format,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_HOST_READ,
err_out);
if (ofs == nullptr) {
@ -2392,7 +2402,7 @@ void ED_view3d_depth_override(Depsgraph *depsgraph,
rv3d->rflag |= RV3D_ZOFFSET_DISABLED;
/* Needed in cases the 3D Viewport isn't already setup. */
WM_draw_region_viewport_ensure(region, SPACE_VIEW3D);
WM_draw_region_viewport_ensure(scene, region, SPACE_VIEW3D);
WM_draw_region_viewport_bind(region);
GPUViewport *viewport = WM_draw_region_get_viewport(region);

View File

@ -52,6 +52,7 @@ bool GPU_compute_shader_support(void);
bool GPU_shader_storage_buffer_objects_support(void);
bool GPU_shader_image_load_store_support(void);
bool GPU_shader_draw_parameters_support(void);
bool GPU_hdr_support(void);
brecht marked this conversation as resolved Outdated

Would use GPU_hdr_support even if the style guide doesn't require it

Would use `GPU_hdr_support` even if the style guide doesn't require it
bool GPU_mem_stats_supported(void);
void GPU_mem_stats_get(int *totalmem, int *freemem);

View File

@ -653,6 +653,11 @@ int GPU_offscreen_height(const GPUOffScreen *offscreen);
*/
struct GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *offscreen);
/**
* Return the texture format of a #GPUOffScreen.
brecht marked this conversation as resolved Outdated

Comment needs to be updated.

Comment needs to be updated.
*/
eGPUTextureFormat GPU_offscreen_format(const GPUOffScreen *offscreen);
/**
* Return the internals of a #GPUOffScreen. Does not give ownership.
* \note only to be used by viewport code!

View File

@ -182,6 +182,11 @@ bool GPU_shader_draw_parameters_support()
return GCaps.shader_draw_parameters_support;
}
bool GPU_hdr_support()
{
return GCaps.hdr_viewport_support;
}
int GPU_max_shader_storage_buffer_bindings()
{
return GCaps.max_shader_storage_buffer_bindings;

View File

@ -48,6 +48,7 @@ struct GPUCapabilities {
bool shader_image_load_store_support = false;
bool shader_draw_parameters_support = false;
bool transform_feedback_support = false;
bool hdr_viewport_support = false;
/* OpenGL related workarounds. */
bool mip_render_workaround = false;

View File

@ -785,6 +785,11 @@ GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
return ofs->color;
}
eGPUTextureFormat GPU_offscreen_format(const GPUOffScreen *offscreen)
{
return GPU_texture_format(offscreen->color);
}
void GPU_offscreen_viewport_data_get(GPUOffScreen *ofs,
GPUFrameBuffer **r_fb,
GPUTexture **r_color,

View File

@ -441,6 +441,8 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
GPUTexture *color_overlay = viewport->color_overlay_tx[view];
bool use_ocio = false;
bool use_hdr = GPU_hdr_support() &&
((viewport->view_settings.flag & COLORMANAGE_VIEW_USE_HDR) != 0);
if (viewport->do_color_management && display_colorspace) {
/* During the binding process the last used VertexFormat is tested and can assert as it is not
@ -467,6 +469,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
fclem marked this conversation as resolved Outdated

Blank line

Blank line
GPU_batch_uniform_1i(batch, "overlay", do_overlay_merge);
GPU_batch_uniform_1i(batch, "display_transform", display_colorspace);
GPU_batch_uniform_1i(batch, "use_hdr", use_hdr);
}
GPU_texture_bind(color, 0);

View File

@ -420,6 +420,7 @@ void MTLBackend::capabilities_init(MTLContext *ctx)
GCaps.compute_shader_support = true;
GCaps.shader_storage_buffer_objects_support = true;
GCaps.shader_draw_parameters_support = true;
GCaps.hdr_viewport_support = true;
GCaps.geometry_shader_support = false;

View File

@ -234,6 +234,7 @@ static void detect_workarounds()
GCaps.shader_image_load_store_support = false;
GCaps.shader_draw_parameters_support = false;
GCaps.shader_storage_buffer_objects_support = false;
GCaps.hdr_viewport_support = false;
GLContext::base_instance_support = false;
GLContext::clear_texture_support = false;
GLContext::copy_image_support = false;
@ -546,6 +547,7 @@ void GLBackend::capabilities_init()
epoxy_gl_version() >= 43;
GCaps.geometry_shader_support = true;
GCaps.max_samplers = GCaps.max_textures;
GCaps.hdr_viewport_support = false;
if (GCaps.compute_shader_support) {
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &GCaps.max_work_group_count[0]);

View File

@ -36,7 +36,15 @@ void main()
vec4 overlay_col = texture(overlays_texture, texCoord_interp.xy);
if (overlay) {
fragColor = clamp(fragColor, 0.0, 1.0);
if (!use_hdr) {
brecht marked this conversation as resolved Outdated

Same here as in the OCIO shader.

Same here as in the OCIO shader.
/* If we're not using an extended colour space, clamp the color 0..1. */
fragColor = clamp(fragColor, 0.0, 1.0);
}
else {
/* When using extended colorspace, interpolate towards clamped color to improve display of
* alpha-blended overlays. */
fragColor = mix(max(fragColor, 0.0), clamp(fragColor, 0.0, 1.0), overlay_col.a);
}
fragColor *= 1.0 - overlay_col.a;
fragColor += overlay_col;
}

View File

@ -17,6 +17,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_merge)
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
.push_constant(Type::BOOL, "display_transform")
.push_constant(Type::BOOL, "overlay")
.push_constant(Type::BOOL, "use_hdr")
/* Sampler slots should match OCIO's. */
.sampler(0, ImageType::FLOAT_2D, "image_texture")
.sampler(1, ImageType::FLOAT_2D, "overlays_texture")

View File

@ -297,6 +297,15 @@ void IMB_display_buffer_transform_apply(unsigned char *display_buffer,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
bool predivide);
void IMB_display_buffer_transform_apply_float(
float *float_display_buffer,
float *linear_buffer,
int width,
int height,
int channels,
const struct ColorManagedViewSettings *view_settings,
const struct ColorManagedDisplaySettings *display_settings,
bool predivide);
void IMB_display_buffer_release(void *cache_handle);

View File

@ -42,6 +42,8 @@
#include "BKE_image_format.h"
#include "BKE_main.h"
#include "GPU_capabilities.h"
#include "RNA_define.h"
#include "SEQ_iterator.h"
@ -2790,6 +2792,31 @@ void IMB_display_buffer_transform_apply(uchar *display_buffer,
MEM_freeN(buffer);
}
void IMB_display_buffer_transform_apply_float(float *float_display_buffer,
float *linear_buffer,
int width,
int height,
int channels,
const ColorManagedViewSettings *view_settings,
const ColorManagedDisplaySettings *display_settings,
bool predivide)
{
float *buffer;
ColormanageProcessor *cm_processor = IMB_colormanagement_display_processor_new(view_settings,
display_settings);
buffer = static_cast<float *>(MEM_mallocN(size_t(channels) * width * height * sizeof(float),
"display transform temp buffer"));
memcpy(buffer, linear_buffer, size_t(channels) * width * height * sizeof(float));
IMB_colormanagement_processor_apply(cm_processor, buffer, width, height, channels, predivide);
IMB_colormanagement_processor_free(cm_processor);
memcpy(float_display_buffer, buffer, size_t(channels) * width * height * sizeof(float));
MEM_freeN(buffer);
}
void IMB_display_buffer_release(void *cache_handle)
{
if (cache_handle) {
@ -4080,6 +4107,8 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
const float gamma = applied_view_settings->gamma;
const float scale = (exposure == 0.0f) ? 1.0f : powf(2.0f, exposure);
const float exponent = (gamma == 1.0f) ? 1.0f : 1.0f / max_ff(FLT_EPSILON, gamma);
const bool use_hdr = GPU_hdr_support() &&
(applied_view_settings->flag & COLORMANAGE_VIEW_USE_HDR) != 0;
OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
@ -4094,7 +4123,8 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
exponent,
dither,
predivide,
do_overlay_merge);
do_overlay_merge,
use_hdr);
OCIO_configRelease(config);

View File

@ -207,6 +207,7 @@ typedef struct ColorManagedColorspaceSettings {
/** #ColorManagedViewSettings.flag */
enum {
COLORMANAGE_VIEW_USE_CURVES = (1 << 0),
COLORMANAGE_VIEW_USE_HDR = (1 << 1),
};
#ifdef __cplusplus

View File

@ -1273,6 +1273,16 @@ static void rna_def_colormanage(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Curves", "Use RGB curved for pre-display transformation");
RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagement_update");
prop = RNA_def_property(srna, "use_hdr_view", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", COLORMANAGE_VIEW_USE_HDR);
RNA_def_property_ui_text(
prop,
"High Dynamic Range",
"Enable high dynamic range display in rendered viewport, uncapping display brightness. This "
"requires a monitor with HDR support and a view transform designed for HDR. "
"'Filmic' does not generate HDR colors");
RNA_def_property_update(prop, NC_WINDOW, "rna_ColorManagedColorspaceSettings_reload_update");
/* ** Color-space ** */
srna = RNA_def_struct(brna, "ColorManagedInputColorspaceSettings", nullptr);
RNA_def_struct_path_func(srna, "rna_ColorManagedInputColorspaceSettings_path");

View File

@ -228,6 +228,19 @@ static PyObject *pygpu_shader_image_load_store_support_get(PyObject * /*self*/)
{
return PyBool_FromLong(GPU_shader_image_load_store_support());
}
PyDoc_STRVAR(pygpu_hdr_support_get_doc,
".. function:: hdr_support_get()\n"
"\n"
" Return whether GPU backend supports High Dynamic range for viewport.\n"
"\n"
" :return: HDR support available.\n"
" :rtype: bool\n");
static PyObject *pygpu_hdr_support_get(PyObject * /*self*/)
{
return PyBool_FromLong(GPU_hdr_support());
}
/** \} */
/* -------------------------------------------------------------------- */
@ -302,6 +315,10 @@ static PyMethodDef pygpu_capabilities__tp_methods[] = {
(PyCFunction)pygpu_shader_image_load_store_support_get,
METH_NOARGS,
pygpu_shader_image_load_store_support_get_doc},
{"hdr_support_get",
(PyCFunction)pygpu_hdr_support_get,
METH_NOARGS,
pygpu_hdr_support_get_doc},
{nullptr, nullptr, 0, nullptr},
};

View File

@ -245,6 +245,7 @@ struct RenderStats *RE_GetStats(struct Render *re);
* Caller is responsible for allocating `rect` in correct size!
*/
void RE_ResultGet32(struct Render *re, unsigned int *rect);
void RE_ResultGetFloat(struct Render *re, float *rect);
void RE_render_result_full_channel_name(char *fullname,
const char *layname,

View File

@ -1597,7 +1597,7 @@ void *WM_draw_cb_activate(wmWindow *win, void (*draw)(const wmWindow *, void *),
void WM_draw_cb_exit(wmWindow *win, void *handle);
void WM_redraw_windows(bContext *C);
void WM_draw_region_viewport_ensure(ARegion *region, short space_type);
void WM_draw_region_viewport_ensure(Scene *scene, ARegion *region, short space_type);
void WM_draw_region_viewport_bind(ARegion *region);
void WM_draw_region_viewport_unbind(ARegion *region);

View File

@ -39,6 +39,7 @@
#include "ED_view3d.hh"
#include "GPU_batch_presets.h"
#include "GPU_capabilities.h"
#include "GPU_context.h"
#include "GPU_debug.h"
#include "GPU_framebuffer.h"
@ -662,8 +663,25 @@ static void wm_draw_offscreen_texture_parameters(GPUOffScreen *offscreen)
GPU_texture_mipmap_mode(texture, false, false);
}
static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_viewport)
static eGPUTextureFormat get_hdr_framebuffer_format(const Scene *scene)
{
bool use_hdr = false;
if (scene && ((scene->view_settings.flag & COLORMANAGE_VIEW_USE_HDR) != 0)) {
use_hdr = GPU_hdr_support();
}
eGPUTextureFormat desired_format = (use_hdr) ? GPU_RGBA16F : GPU_RGBA8;
return desired_format;
}
static void wm_draw_region_buffer_create(Scene *scene,
ARegion *region,
bool stereo,
bool use_viewport)
{
/* Determine desired offscreen format depending on HDR availability. */
eGPUTextureFormat desired_format = get_hdr_framebuffer_format(scene);
if (region->draw_buffer) {
if (region->draw_buffer->stereo != stereo) {
/* Free draw buffer on stereo changes. */
@ -673,7 +691,8 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_
/* Free offscreen buffer on size changes. Viewport auto resizes. */
GPUOffScreen *offscreen = region->draw_buffer->offscreen;
if (offscreen && (GPU_offscreen_width(offscreen) != region->winx ||
GPU_offscreen_height(offscreen) != region->winy))
GPU_offscreen_height(offscreen) != region->winy ||
GPU_offscreen_format(offscreen) != desired_format))
{
wm_draw_region_buffer_free(region);
}
@ -692,8 +711,12 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_
/* Allocate off-screen buffer if it does not exist. This one has no
* depth or multi-sample buffers. 3D view creates own buffers with
* the data it needs. */
GPUOffScreen *offscreen = GPU_offscreen_create(
region->winx, region->winy, false, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
GPUOffScreen *offscreen = GPU_offscreen_create(region->winx,
region->winy,
false,
desired_format,
GPU_TEXTURE_USAGE_SHADER_READ,
nullptr);
if (!offscreen) {
WM_report(RPT_ERROR, "Region could not be drawn!");
return;
@ -946,7 +969,8 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
GPU_debug_group_begin(use_viewport ? "Viewport" : "ARegion");
if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) {
wm_draw_region_buffer_create(region, true, use_viewport);
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, true, use_viewport);
for (int view = 0; view < 2; view++) {
eStereoViews sview;
@ -969,7 +993,8 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
}
else {
wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID);
wm_draw_region_buffer_create(region, false, use_viewport);
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, false, use_viewport);
wm_draw_region_bind(region, 0);
ED_region_do_draw(C, region);
wm_draw_region_unbind(region);
@ -1002,7 +1027,8 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
region->type->layout(C, region);
}
wm_draw_region_buffer_create(region, false, false);
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, false, false);
wm_draw_region_bind(region, 0);
GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);
ED_region_do_draw(C, region);
@ -1157,13 +1183,16 @@ static void wm_draw_window(bContext *C, wmWindow *win)
wm_draw_window_onscreen(C, win, -1);
}
else {
/* Determine desired offscreen format depending on HDR availability. */
eGPUTextureFormat desired_format = get_hdr_framebuffer_format(WM_window_get_active_scene(win));
/* For side-by-side and top-bottom, we need to render each view to an
* an off-screen texture and then draw it. This used to happen for all
* stereo methods, but it's less efficient than drawing directly. */
const int width = WM_window_pixels_x(win);
const int height = WM_window_pixels_y(win);
GPUOffScreen *offscreen = GPU_offscreen_create(
width, height, false, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
width, height, false, desired_format, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
if (offscreen) {
GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
@ -1314,8 +1343,11 @@ uint8_t *WM_window_pixels_read_from_offscreen(bContext *C, wmWindow *win, int r_
r_size[0] = WM_window_pixels_x(win);
r_size[1] = WM_window_pixels_y(win);
/* Determine desired offscreen format depending on HDR availability. */
eGPUTextureFormat desired_format = get_hdr_framebuffer_format(WM_window_get_active_scene(win));
GPUOffScreen *offscreen = GPU_offscreen_create(
r_size[0], r_size[1], false, GPU_RGBA8, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
r_size[0], r_size[1], false, desired_format, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
if (UNLIKELY(!offscreen)) {
return nullptr;
}
@ -1557,7 +1589,9 @@ void wm_draw_region_test(bContext *C, ScrArea *area, ARegion *region)
{
/* Function for redraw timer benchmark. */
bool use_viewport = WM_region_use_viewport(area, region);
wm_draw_region_buffer_create(region, false, use_viewport);
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
wm_draw_region_buffer_create(scene, region, false, use_viewport);
wm_draw_region_bind(region, 0);
ED_region_do_draw(C, region);
wm_draw_region_unbind(region);
@ -1589,10 +1623,10 @@ void WM_redraw_windows(bContext *C)
*
* \{ */
void WM_draw_region_viewport_ensure(ARegion *region, short space_type)
void WM_draw_region_viewport_ensure(Scene *scene, ARegion *region, short space_type)
{
bool use_viewport = wm_region_use_viewport_by_type(space_type, region->regiontype);
wm_draw_region_buffer_create(region, false, use_viewport);
wm_draw_region_buffer_create(scene, region, false, use_viewport);
}
void WM_draw_region_viewport_bind(ARegion *region)