GPUShader: Implement workaround for gizmo drawing on sRGB framebuffer
This solution involves adding a uniform to each fragment shader that is used by gizmo drawing and use the framebuffer state to set this uniform accordingly. This solution can also be carried to external shaders (addons). A single line of code would then be enough to fix the issue. The only trickery here is the dummy define: `#define srgb_to_framebuffer_space(a)` This is in order to avoid breaking other DRW shaders that use the same fragment shader code but do not need the tranformation. Related to T74139 Reviewed By: brecht, campbellbarton Differential Revision: https://developer.blender.org/D7261
This commit is contained in:
parent
bf49bb354f
commit
21c658b718
|
@ -1 +1 @@
|
|||
Subproject commit d348bde0f96809e289b0514c015cafb97f2dcf79
|
||||
Subproject commit 47a32a5370d36942674621e5a03e57e8dd4986d8
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -5,4 +5,5 @@ out vec4 fragColor;
|
|||
void main()
|
||||
{
|
||||
fragColor = finalColor;
|
||||
fragColor = blender_srgb_to_framebuffer_space(fragColor);
|
||||
}
|
||||
|
|
|
@ -5,4 +5,5 @@ out vec4 fragColor;
|
|||
void main()
|
||||
{
|
||||
fragColor = finalColor;
|
||||
fragColor = blender_srgb_to_framebuffer_space(fragColor);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -5,4 +5,5 @@ out vec4 fragColor;
|
|||
void main()
|
||||
{
|
||||
fragColor = finalColor;
|
||||
fragColor = blender_srgb_to_framebuffer_space(fragColor);
|
||||
}
|
||||
|
|
|
@ -17,4 +17,5 @@ void main()
|
|||
#else
|
||||
fragColor = color;
|
||||
#endif
|
||||
fragColor = blender_srgb_to_framebuffer_space(fragColor);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue