[Bf-blender-cvs] [a5a4dd20905] temp-texture-painting-gpu: Fixed some issues when removing unused tiles.
Jeroen Bakker
noreply at git.blender.org
Wed Oct 12 12:58:16 CEST 2022
Commit: a5a4dd20905725d5f26e5fc9f181145128d6d358
Author: Jeroen Bakker
Date: Wed Oct 12 12:42:20 2022 +0200
Branches: temp-texture-painting-gpu
https://developer.blender.org/rBa5a4dd20905725d5f26e5fc9f181145128d6d358
Fixed some issues when removing unused tiles.
===================================================================
M source/blender/editors/sculpt_paint/sculpt_paint_image.cc
M source/blender/gpu/shaders/sculpt_paint/infos/sculpt_paint_image_info.hh
M source/blender/gpu/shaders/sculpt_paint/sculpt_paint_image_merge_comp.glsl
M source/blender/gpu/shaders/sculpt_paint/sculpt_paint_tile_lib.glsl
===================================================================
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index a44b9141578..8c3c5d337ea 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -553,11 +553,11 @@ static void init_paint_brush(const SculptSession &ss,
* - Only tiles that are painted on are loaded in memory, painted on and merged back to the actual
* texture.
*/
-
template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
struct Info {
struct {
- bool in_use : 1;
+ bool in_use_stroke : 1;
+ bool in_use_frame : 1;
/* Does this sub tile needs to be updated (CPU->GPU transfer).*/
bool needs_update : 1;
bool should_be_removed : 1;
@@ -578,10 +578,14 @@ template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
public:
GPUSubTileTexture()
{
+ paint_tiles_.reserve(Depth);
+ infos_.reserve(Depth);
+
for (int i = 0; i < Depth; i++) {
layer_lookup_[i] = LayerIdUnused;
}
}
+
~GPUSubTileTexture()
{
if (gpu_texture_) {
@@ -603,26 +607,47 @@ template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
}
}
+ void reset_usage_stroke()
+ {
+ printf("%s\n", __func__);
+ for (Info &info : infos_) {
+ info.flags.in_use_stroke = false;
+ }
+ }
+
+ void reset_usage_frame()
+ {
+ printf("%s\n", __func__);
+ for (Info &info : infos_) {
+ info.flags.in_use_frame = false;
+ }
+ }
+
void mark_usage(TileNumber tile_number, int2 sub_tile_id)
{
+ validate();
for (int index : paint_tiles_.index_range()) {
PaintTileData &tile = paint_tiles_[index];
if (tile.tile_number == tile_number && tile.sub_tile_id == sub_tile_id) {
Info &info = infos_[index];
- if (!info.flags.in_use) {
+ if (!info.flags.in_use_stroke) {
printf("%s: mark existing {tile:%d, sub_tile:%d,%d}\n",
__func__,
tile_number,
UNPACK2(sub_tile_id));
}
- info.flags.in_use = true;
+ info.flags.in_use_stroke = true;
+ info.flags.in_use_frame = true;
+ info.flags.should_be_removed = false;
+ validate();
return;
}
}
/* Tile not yet added, add a new one.*/
Info info;
- info.flags.in_use = true;
+ info.flags.in_use_stroke = true;
+ info.flags.in_use_frame = true;
info.flags.needs_update = true;
info.flags.should_be_removed = false;
infos_.append(info);
@@ -635,32 +660,69 @@ template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
printf(
"%s: mark new {tile:%d, sub_tile:%d,%d}\n", __func__, tile_number, UNPACK2(sub_tile_id));
+ validate();
}
/** Remove all sub tiles that are currently flagged not to be used (flags.in_use = false). */
void remove_unused()
{
- for (int i = 0; i < layer_lookup_.size(); i++) {
- int index = layer_lookup_[i];
+ validate();
+ Vector<int64_t> index_changes;
+ for (int layer_id = 0; layer_id < Depth; layer_id++) {
+ int index = layer_lookup_[layer_id];
if (index == -1) {
continue;
}
infos_[index].flags.should_be_removed = false;
- if (infos_[index].flags.in_use == false) {
+ if (infos_[index].flags.in_use_stroke == false) {
infos_[index].flags.should_be_removed = true;
- paint_tiles_[index].layer_id = LayerIdMarkRemoval;
- printf("%s: remove sub tile at layer %d\n", __func__, i);
- layer_lookup_[i] = -1;
+ PaintTileData &paint_tile = paint_tiles_[index];
+ BLI_assert(paint_tile.layer_id == layer_id);
+ paint_tile.layer_id = LayerIdMarkRemoval;
+ printf("%s: remove sub tile at layer %d->%d {tile:%d, sub_tile:%d,%d}\n",
+ __func__,
+ layer_id,
+ index,
+ paint_tile.tile_number,
+ UNPACK2(paint_tile.sub_tile_id));
+ layer_lookup_[layer_id] = LayerIdUnused;
+ index_changes.append(index);
}
}
+ /* Early exit when no removals where marked. */
+ if (index_changes.is_empty()) {
+ return;
+ }
+
+ for (int layer_id = 0; layer_id < Depth; layer_id++) {
+ int decrement = 0;
+ int index = layer_lookup_[layer_id];
+ if (index == LayerIdUnused) {
+ continue;
+ }
+ for (int64_t change : index_changes) {
+ if (index > change) {
+ decrement += 1;
+ }
+ }
+ if (decrement == 0) {
+ continue;
+ }
+ printf("%s: correct index of %d->%d to %d\n", __func__, layer_id, index, index - decrement);
+ int corrected_index = index - decrement;
+ layer_lookup_[layer_id] = corrected_index;
+ }
+
infos_.remove_if([&](Info &info) { return info.flags.should_be_removed; });
paint_tiles_.remove_if(
[&](PaintTileData &tile) { return tile.layer_id == LayerIdMarkRemoval; });
+ validate();
}
void assign_layer_ids()
{
+ validate();
for (int64_t index : paint_tiles_.index_range()) {
PaintTileData &tile = paint_tiles_[index];
@@ -676,6 +738,7 @@ template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
UNPACK2(tile.sub_tile_id),
tile.layer_id);
}
+ validate();
}
int first_empty_layer_id() const
@@ -720,8 +783,8 @@ template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
/* TODO: Copy correct data from ImBuf.*/
- GPU_texture_update_sub(
- gpu_texture_, GPU_DATA_FLOAT, buffer, 0, 0, tile.layer_id, Size, Size, 1);
+ // GPU_texture_update_sub(
+ // gpu_texture_, GPU_DATA_FLOAT, buffer, 0, 0, tile.layer_id, Size, Size, 1);
info.flags.needs_update = false;
}
@@ -775,6 +838,42 @@ template<int32_t Size, int32_t Depth = 512> class GPUSubTileTexture {
GPU_storagebuf_bind(tile_buf_get(), GPU_shader_get_ssbo(shader, "paint_tile_buf"));
GPU_shader_uniform_1i(shader, "paint_tile_buf_len", paint_tiles_len());
}
+
+ /* Go over each paint tile that is currently in use for the current frame.*/
+ template<typename Predicate> void foreach_in_frame(Predicate &&predicate)
+ {
+ for (int64_t index : infos_.index_range()) {
+ Info &info = infos_[index];
+ if (!info.flags.in_use_frame) {
+ continue;
+ }
+ predicate(paint_tiles_[index]);
+ }
+ }
+
+ /* Checks if the structure is still consistent.*/
+ void validate()
+ {
+ BLI_assert(paint_tiles_.size() == infos_.size());
+ int num_filled_layers = 0;
+ for (int index : paint_tiles_.index_range()) {
+ PaintTileData &paint_tile = paint_tiles_[index];
+ // Info &info = infos_[index];
+ BLI_assert(paint_tile.layer_id == LayerIdUnused ||
+ layer_lookup_[paint_tile.layer_id] == index);
+ if (paint_tile.layer_id != LayerIdUnused) {
+ num_filled_layers += 1;
+ }
+ }
+
+ int num_filled_lookups = 0;
+ for (int index : IndexRange(Depth)) {
+ if (layer_lookup_[index] != LayerIdUnused) {
+ num_filled_lookups += 1;
+ }
+ }
+ BLI_assert(num_filled_layers == num_filled_lookups);
+ }
};
struct GPUSculptPaintData {
@@ -863,7 +962,6 @@ static void ensure_gpu_buffers(TexturePaintingUserData &data)
if (paint_data.steps.is_empty()) {
PBVH *pbvh = ss.pbvh;
BKE_pbvh_frame_selection_clear(pbvh);
- paint_data.tile_texture.reset_usage();
}
for (PBVHNode *node : MutableSpan<PBVHNode *>(data.nodes, data.nodes_len)) {
@@ -927,6 +1025,7 @@ static void gpu_painting_paint_step(TexturePaintingUserData &data,
}
}
+/** Merge the changes from the current frame into the GPU texture. */
static void gpu_painting_image_merge(GPUSculptPaintData &batches,
Image &image,
ImageUser &image_user,
@@ -937,7 +1036,15 @@ static void gpu_painting_image_merge(GPUSculptPaintData &batches,
GPU_shader_bind(shader);
batches.tile_texture.bind(shader);
GPU_texture_image_bind(canvas_tex, GPU_shader_get_texture_binding(shader, "texture_img"));
- GPU_compute_dispatch(shader, image_buffer.x, image_buffer.y, 1);
+ batches.tile_texture.foreach_in_frame([shader](PaintTileData &paint_tile) {
+ printf("%s: merging tile %d {tile:%d sub_tile:%d,%d} \n",
+ __func__,
+ paint_tile.layer_id,
+ paint_tile.tile_number,
+ UNPACK2(paint_tile.sub_tile_id));
+ GPU_shader_uniform_1i(shader, "layer_id", paint_tile.layer_id);
+ GPU_compute_dispatch(shader, TEXTURE_STREAMING_TILE_SIZE, TEXTURE_STREAMING_TILE_SIZE, 1);
+ });
}
static void init_paint_step(const SculptSession &ss,
@@ -1055,9 +1162,20 @@ static void dispatch_gpu_batches(TexturePaintingUserData &data)
BKE_image_release_ibuf(data.image_data.image, image_buffer, nullptr);
}
+}
+
+static void gpu_frame_end(TexturePaintingUserData &data)
+{
+ SculptSession &ss = *data.ob->sculpt;
+ if (!ss.mode.texture_paint.gpu_data) {
+ return;
+ }
+
+ GPUSculptPaintData &batches = *static_cast<GPUSculptPaintData *>(ss.mode.texture_paint.gpu_data);
/* Reset GPU data for next frame. */
batches.steps.clear();
+ batches.tile_texture.reset_usage_frame();
}
/** \} */
@@ -1166,6 +1284,7 @@ void SCULPT_paint_image_batches_flush(PaintModeSettings *paint_mode_settings,
// TIMEIT_START(paint_image_gpu);
GPU_debug_group_begin("SCULPT_paint_brush");
dispatch_gpu_batches(data);
+ gpu_frame_end(data);
GPU_debug_group_end();
// TIMEIT_END(paint_image_gpu);
}
@@ -1175,7 +1294,7 @@ void SCULPT_paint_image_batches_flush(PaintModeSettings *paint_mode_settings,
void SCULPT_paint_image_batches_finalize(PaintModeSettings *UNUSED(paint_mode_settings),
Sculpt *UNUSED(sd),
- Object *UNUSED(ob))
+ Object *ob)
{
if (!SCULPT_use_image_paint_compute()) {
return;
@@ -1186,6 +1305,9 @@ void SCULPT_paint_image_batches_finalize(PaintModeSettings *UNUS
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list