diff --git a/release/scripts/addons b/release/scripts/addons index d348bde0f96..47a32a5370d 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit d348bde0f96809e289b0514c015cafb97f2dcf79 +Subproject commit 47a32a5370d36942674621e5a03e57e8dd4986d8 diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 1434cac5f97..09b9b63d07a 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1296,9 +1296,6 @@ void DRW_draw_callbacks_post_scene(void) DRW_state_reset(); GPU_framebuffer_bind(dfbl->overlay_fb); - /* Disable sRGB encoding from the fixed function pipeline since all the drawing in this - * function is done with sRGB color. Avoid double transform. */ - glDisable(GL_FRAMEBUFFER_SRGB); GPU_matrix_projection_set(rv3d->winmat); GPU_matrix_set(rv3d->viewmat); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index fe2debd4344..361e5e76acc 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1348,6 +1348,7 @@ void UI_widgetbase_draw_cache_flush(void) (float *)g_widget_base_batch.params); GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params); GPU_matrix_bind(batch->interface); + GPU_shader_set_srgb_uniform(batch->interface); GPU_batch_bind(batch); GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index fd92d864a28..f94cd778e13 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1162,6 +1162,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v rgba_uchar_to_float(fcol, kcd->colors.point_a); GPU_batch_uniform_4fv(batch, "color", fcol); GPU_matrix_bind(batch->interface); + GPU_shader_set_srgb_uniform(batch->interface); GPU_point_size(11); if (snapped_verts_count > 0) { GPU_batch_draw_advanced(batch, 0, snapped_verts_count, 0, 0); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index af94b5b6e21..1e1d4373fea 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -653,13 +653,13 @@ static void image_main_region_draw(const bContext *C, ARegion *region) GPU_clear(GPU_COLOR_BIT); GPU_framebuffer_bind(fbl->overlay_fb); - glDisable(GL_FRAMEBUFFER_SRGB); /* XXX not supported yet, disabling for now */ scene->r.scemode &= ~R_COMP_CROP; /* clear and setup matrix */ UI_GetThemeColor3fv(TH_BACK, col); + srgb_to_linearrgb_v3_v3(col, col); GPU_clear_color(col[0], col[1], col[2], 1.0f); GPU_clear(GPU_COLOR_BIT); GPU_depth_test(false); diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 1e576f6fea4..6ea1bbbcc10 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -265,6 +265,7 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra bool prev_ma_match = (mpoly->mat_nr == (ob_eval->actcol - 1)); GPU_matrix_bind(geom->interface); + GPU_shader_set_srgb_uniform(geom->interface); GPU_batch_bind(geom); /* TODO(fclem): If drawcall count becomes a problem in the future diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index a8a0288f895..85e81607225 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -314,6 +314,7 @@ data_to_c_simple(shaders/gpu_shader_gpencil_fill_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_gpencil_fill_frag.glsl SRC) data_to_c_simple(shaders/gpu_shader_cfg_world_clip_lib.glsl SRC) +data_to_c_simple(shaders/gpu_shader_colorspace_lib.glsl SRC) data_to_c_simple(shaders/gpu_shader_common_obinfos_lib.glsl SRC) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index bb26f5d41a3..1fb0b7c1f6b 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -31,6 +31,7 @@ extern "C" { typedef struct GPUShader GPUShader; struct GPUTexture; struct GPUUniformBuffer; +struct GPUShaderInterface; /* GPU Shader * - only for fragment shaders now @@ -49,6 +50,11 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *libcode, const char *defines, const char *shader_name); +GPUShader *GPU_shader_create_from_python(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines); GPUShader *GPU_shader_create_ex(const char *vertexcode, const char *fragcode, const char *geocode, @@ -83,6 +89,8 @@ int GPU_shader_get_program(GPUShader *shader); void *GPU_shader_get_interface(GPUShader *shader); +void GPU_shader_set_srgb_uniform(const struct GPUShaderInterface *interface); + int GPU_shader_get_uniform(GPUShader *shader, const char *name); int GPU_shader_get_uniform_ensure(GPUShader *shader, const char *name); int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin); @@ -101,6 +109,8 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name); char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_binary_len); +void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear); + /* Builtin/Non-generated shaders */ typedef enum eGPUBuiltinShader { /* specialized drawing */ diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h index f0c1c4c0b98..3e7bad409a3 100644 --- a/source/blender/gpu/GPU_shader_interface.h +++ b/source/blender/gpu/GPU_shader_interface.h @@ -56,6 +56,7 @@ typedef enum { GPU_UNIFORM_BASE_INSTANCE, /* int baseInstance */ GPU_UNIFORM_RESOURCE_CHUNK, /* int resourceChunk */ GPU_UNIFORM_RESOURCE_ID, /* int resourceId */ + GPU_UNIFORM_SRGB_TRANSFORM, /* bool srgbTarget */ GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */ diff --git a/source/blender/gpu/intern/gpu_batch.c b/source/blender/gpu/intern/gpu_batch.c index b0a24b1f2ff..3e0a1e57664 100644 --- a/source/blender/gpu/intern/gpu_batch.c +++ b/source/blender/gpu/intern/gpu_batch.c @@ -675,6 +675,7 @@ void GPU_batch_draw(GPUBatch *batch) #endif GPU_batch_program_use_begin(batch); GPU_matrix_bind(batch->interface); // external call. + GPU_shader_set_srgb_uniform(batch->interface); GPU_batch_bind(batch); GPU_batch_draw_advanced(batch, 0, 0, 0, 0); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index 59d0be2cefb..e6092b55fc4 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -514,6 +514,11 @@ void GPU_framebuffer_bind(GPUFrameBuffer *fb) if (GPU_framebuffer_active_get() != fb) { glBindFramebuffer(GL_FRAMEBUFFER, fb->object); glEnable(GL_FRAMEBUFFER_SRGB); + + GPUTexture *first_target = fb->attachments[GPU_FB_COLOR_ATTACHMENT0].tex; + const bool is_srgb_target = (first_target && + (GPU_texture_format(first_target) == GPU_SRGB8_A8)); + GPU_shader_set_framebuffer_srgb_target(is_srgb_target); } gpu_framebuffer_current_set(fb); @@ -549,6 +554,7 @@ void GPU_framebuffer_restore(void) glBindFramebuffer(GL_FRAMEBUFFER, GPU_framebuffer_default()); gpu_framebuffer_current_set(NULL); glDisable(GL_FRAMEBUFFER_SRGB); + GPU_shader_set_framebuffer_srgb_target(false); } } @@ -944,6 +950,7 @@ void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) GPUFrameBuffer *ofs_fb = gpu_offscreen_fb_get(ofs); GPU_framebuffer_bind(ofs_fb); glDisable(GL_FRAMEBUFFER_SRGB); + GPU_shader_set_framebuffer_srgb_target(false); } void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore) diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index 4523df8be7c..b30fbd66670 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -151,6 +151,7 @@ void immBindProgram(GLuint program, const GPUShaderInterface *shaderface) glUseProgram(program); get_attr_locations(&imm.vertex_format, &imm.attr_binding, shaderface); GPU_matrix_bind(shaderface); + GPU_shader_set_srgb_uniform(shaderface); } void immBindBuiltinProgram(eGPUBuiltinShader shader_id) diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 1a0daf4ac41..dc26a1a8e7b 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -134,21 +134,25 @@ extern char datatoc_gpu_shader_gpencil_fill_vert_glsl[]; extern char datatoc_gpu_shader_gpencil_fill_frag_glsl[]; extern char datatoc_gpu_shader_cfg_world_clip_lib_glsl[]; +extern char datatoc_gpu_shader_colorspace_lib_glsl[]; + const struct GPUShaderConfigData GPU_shader_cfg_data[GPU_SHADER_CFG_LEN] = { [GPU_SHADER_CFG_DEFAULT] = { .lib = "", - .def = "", + .def = "#define blender_srgb_to_framebuffer_space(a) a\n", }, [GPU_SHADER_CFG_CLIPPED] = { .lib = datatoc_gpu_shader_cfg_world_clip_lib_glsl, - .def = "#define USE_WORLD_CLIP_PLANES\n", + .def = "#define USE_WORLD_CLIP_PLANES\n" + "#define blender_srgb_to_framebuffer_space(a) a\n", }, }; /* cache of built-in shaders (each is created on first use) */ static GPUShader *builtin_shaders[GPU_SHADER_CFG_LEN][GPU_SHADER_BUILTIN_LEN] = {{NULL}}; +static int g_shader_builtin_srgb_transform = 0; #ifndef NDEBUG static uint g_shaderid = 0; @@ -289,6 +293,28 @@ GPUShader *GPU_shader_create(const char *vertexcode, vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname); } +GPUShader *GPU_shader_create_from_python(const char *vertexcode, + const char *fragcode, + const char *geocode, + const char *libcode, + const char *defines) +{ + char *libcodecat = NULL; + + if (libcode == NULL) { + libcode = datatoc_gpu_shader_colorspace_lib_glsl; + } + else { + libcode = libcodecat = BLI_strdupcat(libcode, datatoc_gpu_shader_colorspace_lib_glsl); + } + + GPUShader *sh = GPU_shader_create_ex( + vertexcode, fragcode, geocode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, NULL); + + MEM_SAFE_FREE(libcodecat); + return sh; +} + GPUShader *GPU_shader_load_from_binary(const char *binary, const int binary_format, const int binary_len, @@ -629,6 +655,7 @@ void GPU_shader_bind(GPUShader *shader) glUseProgram(shader->program); GPU_matrix_bind(shader->interface); + GPU_shader_set_srgb_uniform(shader->interface); } void GPU_shader_unbind(void) @@ -835,6 +862,15 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText glUniform1i(location, number); } +void GPU_shader_set_srgb_uniform(const GPUShaderInterface *interface) +{ + const GPUShaderInput *srgb_uniform = GPU_shaderinterface_uniform_builtin( + interface, GPU_UNIFORM_SRGB_TRANSFORM); + if (srgb_uniform) { + glUniform1i(srgb_uniform->location, g_shader_builtin_srgb_transform); + } +} + int GPU_shader_get_attribute(GPUShader *shader, const char *name) { BLI_assert(shader && shader->program); @@ -859,6 +895,11 @@ char *GPU_shader_get_binary(GPUShader *shader, uint *r_binary_format, int *r_bin return r_binary; } +void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear) +{ + g_shader_builtin_srgb_transform = use_srgb_to_linear; +} + static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { [GPU_SHADER_TEXT] = { @@ -983,6 +1024,7 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = { { .vert = datatoc_gpu_shader_3D_clipped_uniform_color_vert_glsl, .frag = datatoc_gpu_shader_uniform_color_frag_glsl, + .defs = datatoc_gpu_shader_colorspace_lib_glsl, }, [GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] = @@ -1162,8 +1204,12 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, /* common case */ if (sh_cfg == GPU_SHADER_CFG_DEFAULT) { - *sh_p = GPU_shader_create( - stages->vert, stages->frag, stages->geom, NULL, stages->defs, __func__); + *sh_p = GPU_shader_create_from_arrays({ + .vert = (const char *[]){stages->vert, NULL}, + .geom = (const char *[]){stages->geom, NULL}, + .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, + .defs = (const char *[]){stages->defs, NULL}, + }); } else if (sh_cfg == GPU_SHADER_CFG_CLIPPED) { /* Remove eventually, for now ensure support for each shader has been added. */ @@ -1182,7 +1228,7 @@ GPUShader *GPU_shader_get_builtin_shader_with_config(eGPUBuiltinShader shader, *sh_p = GPU_shader_create_from_arrays({ .vert = (const char *[]){world_clip_lib, stages->vert, NULL}, .geom = (const char *[]){stages->geom ? world_clip_lib : NULL, stages->geom, NULL}, - .frag = (const char *[]){stages->frag, NULL}, + .frag = (const char *[]){datatoc_gpu_shader_colorspace_lib_glsl, stages->frag, NULL}, .defs = (const char *[]){world_clip_def, stages->defs, NULL}, }); } diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c index b877da3f1d5..cb1cd9a6f6d 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.c +++ b/source/blender/gpu/intern/gpu_shader_interface.c @@ -68,6 +68,7 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u) [GPU_UNIFORM_BASE_INSTANCE] = "baseInstance", [GPU_UNIFORM_RESOURCE_CHUNK] = "resourceChunk", [GPU_UNIFORM_RESOURCE_ID] = "resourceId", + [GPU_UNIFORM_SRGB_TRANSFORM] = "srgbTarget", [GPU_UNIFORM_CUSTOM] = NULL, [GPU_NUM_UNIFORMS] = NULL, diff --git a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl index 4f275c5b220..1333c00682c 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_smooth_color_frag.glsl @@ -5,4 +5,5 @@ out vec4 fragColor; void main() { fragColor = finalColor; + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl index 7bd44ba9b88..3a2d96c9929 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_smooth_color_frag.glsl @@ -5,4 +5,5 @@ out vec4 fragColor; void main() { fragColor = finalColor; + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl new file mode 100644 index 00000000000..aae659516bb --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_colorspace_lib.glsl @@ -0,0 +1,16 @@ + +/* Undefine the macro that avoids compilation errors. */ +#undef blender_srgb_to_framebuffer_space + +uniform bool srgbTarget = false; + +vec4 blender_srgb_to_framebuffer_space(vec4 color) +{ + if (srgbTarget) { + vec3 c = max(color.rgb, vec3(0.0)); + vec3 c1 = c * (1.0 / 12.92); + vec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4)); + color.rgb = mix(c1, c2, step(vec3(0.04045), c)); + } + return color; +} diff --git a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl index 6c214534812..99d8b6ab685 100644 --- a/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_flat_color_frag.glsl @@ -5,4 +5,5 @@ out vec4 fragColor; void main() { fragColor = finalColor; + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl index d9f84964eb4..2033401db67 100644 --- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -17,4 +17,5 @@ void main() #else fragColor = color; #endif + fragColor = blender_srgb_to_framebuffer_space(fragColor); } diff --git a/source/blender/python/gpu/gpu_py_shader.c b/source/blender/python/gpu/gpu_py_shader.c index bd52fbb0de5..38a5629a2cc 100644 --- a/source/blender/python/gpu/gpu_py_shader.c +++ b/source/blender/python/gpu/gpu_py_shader.c @@ -120,8 +120,8 @@ static PyObject *bpygpu_shader_new(PyTypeObject *UNUSED(type), PyObject *args, P return NULL; } - GPUShader *shader = GPU_shader_create( - params.vertexcode, params.fragcode, params.geocode, params.libcode, params.defines, NULL); + GPUShader *shader = GPU_shader_create_from_python( + params.vertexcode, params.fragcode, params.geocode, params.libcode, params.defines); if (shader == NULL) { PyErr_SetString(PyExc_Exception, "Shader Compile Error, see console for more details"); @@ -609,6 +609,10 @@ PyDoc_STRVAR( " To debug shaders, use the --debug-gpu-shaders command line option" " to see full GLSL shader compilation and linking errors.\n" "\n" + " For drawing user interface elements and gizmos, use " + " ``fragOutput = blender_srgb_to_framebuffer_space(fragOutput)``" + " to transform the output sRGB colors to the framebuffer colorspace." + "\n" " :param vertexcode: Vertex shader code.\n" " :type vertexcode: str\n" " :param fragcode: Fragment shader code.\n"