[Bf-blender-cvs] [854d3d4645e] temp-texture-painting-gpu: Painting first pixels to intermediate buffer.
Jeroen Bakker
noreply at git.blender.org
Fri Sep 30 15:50:29 CEST 2022
Commit: 854d3d4645ed2ab6475ce399c39189df29ba0a0d
Author: Jeroen Bakker
Date: Wed Sep 28 13:04:18 2022 +0200
Branches: temp-texture-painting-gpu
https://developer.blender.org/rB854d3d4645ed2ab6475ce399c39189df29ba0a0d
Painting first pixels to intermediate buffer.
===================================================================
M source/blender/blenkernel/BKE_pbvh_pixels.hh
M source/blender/blenkernel/intern/pbvh_pixels.cc
M source/blender/editors/sculpt_paint/CMakeLists.txt
M source/blender/editors/sculpt_paint/sculpt_intern.h
M source/blender/editors/sculpt_paint/sculpt_paint_image.cc
A source/blender/editors/sculpt_paint/sculpt_shaders.cc
M source/blender/gpu/shaders/sculpt_paint/infos/sculpt_paint_image_info.hh
M source/blender/gpu/shaders/sculpt_paint/sculpt_paint_image_comp.glsl
===================================================================
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index da6dc368536..ca82418fb79 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -17,6 +17,7 @@
#include "IMB_imbuf_types.h"
#include "GPU_sculpt_shader_shared.h"
+#include "GPU_storage_buffer.h"
namespace blender::bke::pbvh::pixels {
@@ -29,6 +30,7 @@ namespace blender::bke::pbvh::pixels {
struct Triangles {
/** Data accessed by the inner loop of the painting brush. */
Vector<TrianglePaintInput> paint_input;
+ GPUStorageBuf *gpu_buffer = nullptr;
public:
void append(const int3 vert_indices)
@@ -49,11 +51,15 @@ struct Triangles {
return paint_input[index];
}
- void clear()
+ ~Triangles()
{
- paint_input.clear();
+ clear();
}
+ /** Clear data associated with self. */
+ void clear();
+ void ensure_gpu_buffer();
+
uint64_t size() const
{
return paint_input.size();
@@ -94,6 +100,7 @@ struct UDIMTilePixels {
rcti dirty_region;
Vector<PackedPixelRow> pixel_rows;
+ int64_t gpu_buffer_offset;
UDIMTilePixels()
{
@@ -134,11 +141,22 @@ struct NodeData {
Vector<UDIMTileUndo> undo_regions;
Triangles triangles;
+ struct {
+ /** Contains GPU buffer for all associated pixels. Tiles have a range inside this buffer
+ * (#UDIMTilePixels.start_index, #UDIMTilePixels.end_index). */
+ GPUStorageBuf *pixels = nullptr;
+ } gpu_buffers;
+
NodeData()
{
flags.dirty = false;
}
+ ~NodeData()
+ {
+ clear_data();
+ }
+
UDIMTilePixels *find_tile_data(const image::ImageTileWrapper &image_tile)
{
for (UDIMTilePixels &tile : tiles) {
@@ -186,6 +204,18 @@ struct NodeData {
{
tiles.clear();
triangles.clear();
+ if (gpu_buffers.pixels) {
+ GPU_storagebuf_free(gpu_buffers.pixels);
+ gpu_buffers.pixels = nullptr;
+ }
+ }
+
+ void ensure_gpu_buffers()
+ {
+ triangles.ensure_gpu_buffer();
+ if (gpu_buffers.pixels == nullptr) {
+ build_pixels_gpu_buffer();
+ }
}
static void free_func(void *instance)
@@ -193,6 +223,9 @@ struct NodeData {
NodeData *node_data = static_cast<NodeData *>(instance);
MEM_delete(node_data);
}
+
+ private:
+ void build_pixels_gpu_buffer();
};
NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node);
diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc
index f733f3145ec..fdae9d51986 100644
--- a/source/blender/blenkernel/intern/pbvh_pixels.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels.cc
@@ -23,6 +23,60 @@
namespace blender::bke::pbvh::pixels {
+void Triangles::clear()
+{
+ paint_input.clear();
+ if (gpu_buffer) {
+ GPU_storagebuf_free(gpu_buffer);
+ gpu_buffer = nullptr;
+ }
+}
+
+void Triangles::ensure_gpu_buffer()
+{
+ if (gpu_buffer) {
+ return;
+ }
+ gpu_buffer = GPU_storagebuf_create_ex(
+ mem_size(), paint_input.data(), GPU_USAGE_STATIC, __func__);
+}
+
+/**
+ * Update the gpu buffer offsets of the given tiles.
+ * \return the total needed buffer length.
+ */
+static int64_t update_gpu_buffer_offsets(MutableSpan<UDIMTilePixels> tiles)
+{
+ int64_t elem_len = 0;
+ for (UDIMTilePixels &tile : tiles) {
+ tile.gpu_buffer_offset = elem_len;
+ elem_len += tile.pixel_rows.size();
+ }
+ return elem_len;
+}
+
+static void flatten_pixel_rows(Vector<PackedPixelRow> &elements, Span<UDIMTilePixels> tiles)
+{
+ for (const UDIMTilePixels &tile : tiles) {
+ BLI_assert(elements.size() == tile.gpu_buffer_offset);
+ elements.extend(tile.pixel_rows);
+ }
+}
+
+void NodeData::build_pixels_gpu_buffer()
+{
+ BLI_assert(gpu_buffers.pixels == nullptr);
+
+ int64_t elem_len = update_gpu_buffer_offsets(tiles);
+ /* TODO(jbakker): we should store the packed pixels in a single vector per node to reduce
+ * copying. */
+ Vector<PackedPixelRow> elements;
+ elements.reserve(elem_len);
+ flatten_pixel_rows(elements, tiles);
+ gpu_buffers.pixels = GPU_storagebuf_create_ex(
+ elem_len * sizeof(PackedPixelRow), elements.data(), GPU_USAGE_STATIC, __func__);
+}
+
/**
* During debugging this check could be enabled.
* It will write to each image pixel that is covered by the PBVH.
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 2709ac3fd91..139be705178 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC
sculpt_paint_color.c
sculpt_paint_image.cc
sculpt_pose.c
+ sculpt_shaders.cc
sculpt_smooth.c
sculpt_transform.c
sculpt_undo.c
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index cdfa9c2586f..ae0bc8cfb92 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -34,6 +34,7 @@ struct Object;
struct SculptUndoNode;
struct bContext;
struct PaintModeSettings;
+struct GPUShader;
/* Updates */
@@ -1821,6 +1822,13 @@ void SCULPT_bmesh_topology_rake(
/* end sculpt_brush_types.c */
+/* sculpt_shaders.cc */
+
+struct GPUShader *SCULPT_shader_paint_image_get(void);
+void SCULPT_shader_free(void);
+
+/* end sculpt_shadders.cc */
+
/* sculpt_ops.c */
void SCULPT_OT_brush_stroke(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index 906ab50d51d..0fdfc3ebdc4 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -14,6 +14,11 @@
#include "BLI_math_color_blend.h"
#include "BLI_task.h"
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
+#include "GPU_debug.h"
+#include "GPU_shader.h"
+
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -49,11 +54,16 @@ struct ImageData {
}
};
+/* -------------------------------------------------------------------- */
+/** \name CPU
+ * \{ */
+
struct TexturePaintingUserData {
Object *ob;
Brush *brush;
PBVHNode **nodes;
ImageData image_data;
+ int32_t nodes_len;
};
/** Reading and writing to image buffer with 4 float channels. */
@@ -368,6 +378,12 @@ static void do_paint_pixels(void *__restrict userdata,
node_data.flags.dirty |= pixels_updated;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo
+ * \{ */
+
static void undo_region_tiles(
ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th)
{
@@ -457,6 +473,102 @@ static void do_mark_dirty_regions(void *__restrict userdata,
BKE_pbvh_pixels_mark_image_dirty(*node, *data->image_data.image, *data->image_data.image_user);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GPU
+ * \{ */
+
+static void ensure_gpu_buffers(TexturePaintingUserData &data)
+{
+ for (PBVHNode *node : MutableSpan<PBVHNode *>(data.nodes, data.nodes_len)) {
+ NodeData &node_data = BKE_pbvh_pixels_node_data_get(*node);
+ node_data.ensure_gpu_buffers();
+ }
+}
+
+static void dispatch_gpu_painting(TexturePaintingUserData &data)
+{
+ GPUShader *shader = SCULPT_shader_paint_image_get();
+ GPU_shader_bind(shader);
+
+ ImageUser local_image_user = *data.image_data.image_user;
+ GPUTexture *tex = nullptr;
+
+ LISTBASE_FOREACH (ImageTile *, tile, &data.image_data.image->tiles) {
+ ImageTileWrapper image_tile(tile);
+ local_image_user.tile = image_tile.get_tile_number();
+
+ ImBuf *image_buffer = BKE_image_acquire_ibuf(
+ data.image_data.image, &local_image_user, nullptr);
+ if (image_buffer == nullptr) {
+ continue;
+ }
+
+ bool texture_needs_clearing = true;
+
+ /* Ensure that texture size is same as tile size. */
+ if (tex == nullptr || GPU_texture_width(tex) != image_buffer->x ||
+ GPU_texture_height(tex) != image_buffer->y) {
+ if (tex) {
+ GPU_texture_free(tex);
+ tex = nullptr;
+ }
+ tex = GPU_texture_create_2d(
+ __func__, image_buffer->x, image_buffer->y, 1, GPU_RGBA32F, nullptr);
+ }
+
+ /* Dispatch all nodes that paint on the active tile. */
+ for (PBVHNode *node : MutableSpan<PBVHNode *>(data.nodes, data.nodes_len)) {
+ NodeData &node_data = BKE_pbvh_pixels_node_data_get(*node);
+
+ for (UDIMTilePixels &tile_pixels : node_data.tiles) {
+ if (tile_pixels.tile_number != image_tile.get_tile_number()) {
+ continue;
+ }
+
+ /* Only clear the texture when it is used for the first time. */
+ if (texture_needs_clearing) {
+ GPU_texture_clear(tex, GPU_DATA_FLOAT, float4(0.0f, 0.0f, 0.0f, 0.0f));
+ texture_needs_clearing = false;
+ }
+
+ GPU_shader_bind(shader);
+ GPU_texture_image_bind(tex, GPU_shader_get_texture_binding(shader, "out_img"));
+ GPU_storagebuf_bind(node_data.triangles.gpu_buffer,
+ GPU_shader_get_ssbo(shader, "paint_input"));
+ GPU_storagebuf_bind(node_data.gpu_buffers.pixels,
+ GPU_shader_get_ssbo(shader, "pixel_row_buf"));
+ GPU_shader_uniform_1i(shader, "pixel_row_offset", tile_pixels.gpu_buffer_offset);
+
+ GPU_compute_dispatch(shader, tile_pixels.pixel_rows.size(), 1, 1);
+ }
+ node_data.ensure_gpu_buffers();
+ }
+
+#if 0
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
+ float *tex_data = static_cast<float *>(GPU_texture_read(tex, GPU_DATA_FLOAT, 0));
+ for (int i = 0; i < 10; i++) {
+ printf("%f,", tex_data[i]);
+ }
+ printf("\n");
+ MEM_freeN(tex_data);
+#endif
+
+ /* Integrate active tile to draw engine texture. */
+
+ BKE_image_release_ibuf(data.image_data.image, image_buffer, nullptr);
+ }
+
+ if (tex) {
+ GPU_texture_free(tex);
+ tex = nullptr;
+ }
+}
+
+/** \} */
+
} // namespace blender::ed::sculpt_paint::paint::image
extern "C" {
@@ -494,6 +606,13 @@ bool SCULPT_use_image_paint_brush(PaintModeSettings *settings,
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list