Fix #139901: UI: Incorrect flow when drawing scopes

When drawing image scope the vulkan backend raised some asserts. After
checking them the issue was in the calling code, that could lead to
undefined behavior on other platforms as well.

It isn't allowed to have an immediate mode shader bound, when performing
batch drawing. There was also a point batch that didn't use any point
shader resulting in undefined behavior as well.

For 5.0 we should add this as a GPU module check.

Pull Request: https://projects.blender.org/blender/blender/pulls/139926
This commit is contained in:
Jeroen Bakker
2025-06-06 14:01:02 +02:00
parent 0c41c0372e
commit 9e221a10d3
3 changed files with 27 additions and 5 deletions

View File

@@ -602,6 +602,10 @@ void ui_draw_but_HISTOGRAM(ARegion *region,
static void waveform_draw_one(const float *waveform, int waveform_num, const float col[3])
{
BLI_assert_msg(
!immIsShaderBound(),
"It is not allowed to draw a batch when immediate mode has a shader bound. It will "
"use the incorrect shader and is hard to discover.");
GPUVertFormat format = {0};
const uint pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -653,8 +657,8 @@ static void waveform_draw_rgb(const float *waveform,
blender::gpu::Batch *batch = GPU_batch_create_ex(
GPU_PRIM_POINTS, vbo, nullptr, GPU_BATCH_OWNS_VBO);
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_SMOOTH_COLOR);
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POINT_FLAT_COLOR);
GPU_batch_uniform_1f(batch, "size", 1.0f);
GPU_batch_draw(batch);
GPU_batch_discard(batch);
}
@@ -836,7 +840,9 @@ void ui_draw_but_WAVEFORM(ARegion *region,
GPU_matrix_translate_2f(rect.xmin, yofs);
GPU_matrix_scale_2f(w, h);
immUnbindProgram();
waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, col);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_matrix_pop();
@@ -857,11 +863,11 @@ void ui_draw_but_WAVEFORM(ARegion *region,
GPU_matrix_push();
GPU_matrix_translate_2f(rect.xmin, yofs);
GPU_matrix_scale_2f(w, h);
immUnbindProgram();
waveform_draw_one(scopes->waveform_1, scopes->waveform_tot, colors_alpha[0]);
waveform_draw_one(scopes->waveform_2, scopes->waveform_tot, colors_alpha[1]);
waveform_draw_one(scopes->waveform_3, scopes->waveform_tot, colors_alpha[2]);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
GPU_matrix_pop();
}
/* PARADE / YCC (3 channels) */
@@ -872,7 +878,7 @@ void ui_draw_but_WAVEFORM(ARegion *region,
SCOPES_WAVEFRM_YCC_JPEG))
{
const int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE);
immUnbindProgram();
GPU_matrix_push();
GPU_matrix_translate_2f(rect.xmin, yofs);
GPU_matrix_scale_2f(w3, h);
@@ -889,6 +895,7 @@ void ui_draw_but_WAVEFORM(ARegion *region,
scopes->waveform_3, scopes->waveform_tot, (rgb) ? colors_alpha[2] : colorsycc_alpha[2]);
GPU_matrix_pop();
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
/* min max */

View File

@@ -26,6 +26,16 @@ GPUVertFormat *immVertexFormat();
void immBindShader(GPUShader *shader);
/** Call after your last immEnd, or before binding another program. */
void immUnbindProgram();
/**
* Check if there is a shader bound.
*
* Useful to trigger asserts when immediate mode drawing and
* batch based drawing are mixed. It isn't allowed to have an immediate mode shader bound when a
* batch is drawn.
*
* TODO: We should move these asserts to batch drawing, but didn't do that as it was never forced.
*/
bool immIsShaderBound();
/** Must supply exactly vertex_len vertices. */
void immBegin(GPUPrimType, uint vertex_len);

View File

@@ -73,6 +73,11 @@ void immUnbindProgram()
imm->shader = nullptr;
}
bool immIsShaderBound()
{
return imm->shader != nullptr;
}
GPUShader *immGetShader()
{
return imm->shader;