MacOS: Enable support for EDR rendering #105662
@ -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];
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
/* 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
Clément Foucault
commented
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));
|
||||
|
@ -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
Brecht Van Lommel
commented
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()
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -36,7 +36,7 @@ struct OCIO_GPUParameters {
|
||||
float exponent;
|
||||
bool1 use_predivide;
|
||||
bool1 use_overlay;
|
||||
bool1 use_hdr;
|
||||
int _pad0;
|
||||
int _pad1;
|
||||
int _pad2;
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
Jeroen Bakker
commented
Would use 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);
|
||||
|
@ -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
Jeroen Bakker
commented
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!
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
Clément Foucault
commented
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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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]);
|
||||
|
@ -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
Jeroen Bakker
commented
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;
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -207,6 +207,7 @@ typedef struct ColorManagedColorspaceSettings {
|
||||
/** #ColorManagedViewSettings.flag */
|
||||
enum {
|
||||
COLORMANAGE_VIEW_USE_CURVES = (1 << 0),
|
||||
COLORMANAGE_VIEW_USE_HDR = (1 << 1),
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -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");
|
||||
|
@ -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},
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user
would still use
clamp(col, 0.0, 1.0)
here. and move themax
inside the else-clauseAs would even go further and suggest to move all clamping inside the if-else clause for clarity.
This way, the code is easier to refactor if we need to change the else clause.