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
13 changed files with 59 additions and 18 deletions
Showing only changes of commit 2e8755b261 - Show all commits

View File

@ -88,6 +88,18 @@ 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 tha 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);
metalInit();
}
else {
@ -518,7 +530,7 @@ GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
*
* Use Metal layer to avoid Viewport lagging on macOS, see #60043. */
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm;
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatRGBA16Float;
static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA;
void GHOST_ContextCGL::metalInit()

View File

@ -343,6 +343,17 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
[m_metalLayer setPresentsWithTransaction:NO];
[m_metalLayer removeAllAnimations];
[m_metalLayer setDevice:metalDevice];
// 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 tha 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];

View File

@ -169,7 +169,10 @@ 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_extended) {
/* if we're not using an extended colour space, clamp the color 0..1 */
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.
col = clamp(col, 0.0, 1.0);
}
col *= 1.0 - col_overlay.a;
fclem marked this conversation as resolved Outdated

Comment style: Capital + fullstop.

Comment style: Capital + fullstop.
col += col_overlay; /* Assumed unassociated alpha. */
col.rgb = pow(col.rgb, vec3(1.0 / 2.2));

View File

@ -289,7 +289,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_extended)
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.
{
return impl->gpuDisplayShaderBind(config,
input,
@ -301,7 +302,8 @@ bool OCIO_gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
exponent,
dither,
use_predivide,
use_overlay);
use_overlay,
use_extended);
}
void OCIO_gpuDisplayShaderUnbind()

View File

@ -196,7 +196,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_extended);
void OCIO_gpuDisplayShaderUnbind(void);
void OCIO_gpuCacheFree(void);

View File

@ -114,7 +114,8 @@ class IOCIOImpl {
const float /*exponent*/,
const float /*dither*/,
const bool /*use_predivide*/,
const bool /*use_overlay*/)
const bool /*use_overlay*/,
const bool /*use_extended*/)
{
return false;
}
@ -317,7 +318,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_extended);
void gpuDisplayShaderUnbind(void);
void gpuCacheFree(void);

View File

@ -512,7 +512,8 @@ static void updateGPUDisplayParameters(OCIO_GPUShader &shader,
float exponent,
float dither,
bool use_predivide,
bool use_overlay)
bool use_overlay,
bool use_extended)
{
bool do_update = false;
if (shader.parameters_buffer == nullptr) {
@ -540,6 +541,10 @@ static void updateGPUDisplayParameters(OCIO_GPUShader &shader,
data.use_overlay = use_overlay;
do_update = true;
}
if (bool(data.use_extended) != use_extended) {
data.use_extended = use_extended;
do_update = true;
}
if (do_update) {
GPU_uniformbuf_update(shader.parameters_buffer, &data);
}
@ -678,7 +683,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_extended)
{
/* Get GPU shader from cache or create new one. */
OCIO_GPUDisplayShader &display_shader = getGPUDisplayShader(
@ -713,7 +719,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_extended);
GPU_uniformbuf_bind(shader.parameters_buffer, UNIFORMBUF_SLOT_DISPLAY);
/* TODO(fclem): remove remains of IMM. */

View File

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

View File

@ -56,6 +56,8 @@ displays:
- !<View> {name: Filmic Log, colorspace: Filmic Log}
- !<View> {name: Raw, colorspace: Raw}
- !<View> {name: False Color, colorspace: False Color}
Extended sRGB:
- !<View> {name: Standard, colorspace: sRGB}
XYZ:
- !<View> {name: Standard, colorspace: XYZ}
- !<View> {name: DCI, colorspace: dci_xyz}
@ -63,7 +65,7 @@ displays:
None:
- !<View> {name: Standard, colorspace: Raw}
active_displays: [sRGB, XYZ, None]
active_displays: [sRGB, Extended sRGB, XYZ, None]
active_views: [Standard, Filmic, Filmic Log, Raw, False Color]
colorspaces:

View File

@ -425,7 +425,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect)
{
char err_out[256] = "unknown";
GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, true, GPU_RGBA8, err_out);
GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, true, GPU_RGBA16F, err_out);
GPU_offscreen_bind(offscreen, true);
GPU_clear_color(0.0f, 0.0f, 0.0f, 0.0f);

View File

@ -1887,7 +1887,7 @@ ImBuf *ED_view3d_draw_offscreen_imbuf(Depsgraph *depsgraph,
if (own_ofs) {
/* bind */
ofs = GPU_offscreen_create(sizex, sizey, true, GPU_RGBA8, err_out);
ofs = GPU_offscreen_create(sizex, sizey, true, GPU_RGBA16F, err_out);
if (ofs == nullptr) {
DRW_opengl_context_disable();
return nullptr;

View File

@ -4097,6 +4097,7 @@ 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_extended = STRPREFIX(display_settings->display_device, "Extended");
OCIO_ConstConfigRcPtr *config = OCIO_getCurrentConfig();
@ -4111,7 +4112,8 @@ bool IMB_colormanagement_setup_glsl_draw_from_space(
exponent,
dither,
predivide,
do_overlay_merge);
do_overlay_merge,
use_extended);
OCIO_configRelease(config);

View File

@ -685,7 +685,7 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_
* depth or multisample buffers. 3D view creates own buffers with
* the data it needs. */
GPUOffScreen *offscreen = GPU_offscreen_create(
region->winx, region->winy, false, GPU_RGBA8, NULL);
region->winx, region->winy, false, GPU_RGBA16F, NULL);
if (!offscreen) {
WM_report(RPT_ERROR, "Region could not be drawn!");
return;
@ -1148,7 +1148,7 @@ static void wm_draw_window(bContext *C, wmWindow *win)
* 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, NULL);
GPUOffScreen *offscreen = GPU_offscreen_create(width, height, false, GPU_RGBA16F, NULL);
if (offscreen) {
GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
@ -1223,7 +1223,7 @@ uint *WM_window_pixels_read_offscreen(bContext *C, wmWindow *win, int r_size[2])
r_size[0] = WM_window_pixels_x(win);
r_size[1] = WM_window_pixels_y(win);
GPUOffScreen *offscreen = GPU_offscreen_create(r_size[0], r_size[1], false, GPU_RGBA8, NULL);
GPUOffScreen *offscreen = GPU_offscreen_create(r_size[0], r_size[1], false, GPU_RGBA16F, NULL);
if (UNLIKELY(!offscreen)) {
return NULL;
}