[Bf-blender-cvs] [1ddde2d83c8] temp-image-buffer-rasterizer: Split rasterizer target to support other drawing targets.

Jeroen Bakker noreply at git.blender.org
Wed Mar 2 13:55:05 CET 2022


Commit: 1ddde2d83c82d13f6c1400d2eddb3fa28d91f3e7
Author: Jeroen Bakker
Date:   Wed Mar 2 13:54:43 2022 +0100
Branches: temp-image-buffer-rasterizer
https://developer.blender.org/rB1ddde2d83c82d13f6c1400d2eddb3fa28d91f3e7

Split rasterizer target to support other drawing targets.

===================================================================

M	source/blender/imbuf/IMB_rasterizer.hh
A	source/blender/imbuf/intern/rasterizer_target.hh
M	source/blender/imbuf/intern/rasterizer_test.cc

===================================================================

diff --git a/source/blender/imbuf/IMB_rasterizer.hh b/source/blender/imbuf/IMB_rasterizer.hh
index 4473a52921f..facc67a0da9 100644
--- a/source/blender/imbuf/IMB_rasterizer.hh
+++ b/source/blender/imbuf/IMB_rasterizer.hh
@@ -51,6 +51,7 @@
  *
  * \code{.cc}
  * Rasterizer<MyVertexShader, MyFragmentShader> rasterizer(&image_buffer);
+ * rasterizer.activate_drawing_target(&image_buffer);
  * rasterizer.get_vertex_shader().mat = float4x4::identity();
  * rasterizer.draw_triangle(
  *   VertexInput{float2(0.0, 1.0)},
@@ -72,6 +73,7 @@
 
 #include "intern/rasterizer_clamping.hh"
 #include "intern/rasterizer_stats.hh"
+#include "intern/rasterizer_target.hh"
 
 #include <optional>
 
@@ -177,11 +179,11 @@ template<typename FragmentInput, typename FragmentOutput> class AbstractFragment
 template<typename FragmentInput> class Rasterline {
  public:
   /** Row where this rasterline will be rendered. */
-  uint32_t y ;
+  uint32_t y;
   /** Starting X coordinate of the rasterline. */
-  uint32_t start_x ;
+  uint32_t start_x;
   /** Ending X coordinate of the rasterline. */
-  uint32_t end_x ;
+  uint32_t end_x;
   /** Input data for the fragment shader on (start_x, y). */
   FragmentInput start_data;
   /** Delta to add to the start_input to create the data for the next fragment. */
@@ -201,7 +203,7 @@ template<typename Rasterline, int64_t BufferSize> class Rasterlines {
  public:
   Vector<Rasterline, BufferSize> buffer;
 
-  explicit Rasterlines() 
+  explicit Rasterlines()
   {
     buffer.reserve(BufferSize);
   }
@@ -239,6 +241,7 @@ template<typename Rasterline, int64_t BufferSize> class Rasterlines {
 
 template<typename VertexShader,
          typename FragmentShader,
+         typename DrawingTarget = ImageBufferDrawingTarget,
 
          /**
           * To improve branching performance the rasterlines are buffered and flushed when this
@@ -261,6 +264,7 @@ class Rasterizer {
   using VertexOutputType = typename VertexShader::VertexOutputType;
   using FragmentInputType = typename FragmentShader::FragmentInputType;
   using FragmentOutputType = typename FragmentShader::FragmentOutputType;
+  using TargetBufferType = typename DrawingTarget::InnerType;
 
   /** Check if the vertex shader and the fragment shader can be linked together. */
   static_assert(std::is_same_v<InterfaceInnerType, FragmentInputType>);
@@ -269,17 +273,44 @@ class Rasterizer {
   VertexShader vertex_shader_;
   FragmentShader fragment_shader_;
   Rasterlines<RasterlineType, RasterlinesSize> rasterlines_;
-  ImBuf *image_buffer_;
+  /** Active image buffer that is used as drawing target. */
 
   const CenterPixelClampingMethod clamping_method;
+  ImageBufferDrawingTarget drawing_target_;
 
  public:
   Statistics stats;
 
-  explicit Rasterizer(ImBuf *image_buffer) : image_buffer_(image_buffer)
+  explicit Rasterizer()
   {
   }
 
+  /** Activate the giver image buffer to be used as the active drawing target. */
+  void activate_drawing_target(TargetBufferType *new_drawing_target)
+  {
+    deactivate_drawing_target();
+    drawing_target_.activate(new_drawing_target);
+  }
+
+  /**
+   * Deactivate active drawing target.
+   *
+   * Will flush any rasterlines before deactivating.
+   */
+  void deactivate_drawing_target()
+  {
+    if (has_active_drawing_target()) {
+      flush();
+    }
+    drawing_target_.deactivate();
+    BLI_assert(!has_active_drawing_target());
+  }
+
+  bool has_active_drawing_target() const
+  {
+    return drawing_target_.has_active_target();
+  }
+
   virtual ~Rasterizer() = default;
 
   VertexShader &vertex_shader()
@@ -295,6 +326,9 @@ class Rasterizer {
                      const VertexInputType &p2,
                      const VertexInputType &p3)
   {
+    BLI_assert_msg(has_active_drawing_target(),
+                   "Drawing requires an active drawing target. Use `activate_drawing_target` to "
+                   "activate a drawing target.");
     stats.increase_triangles();
 
     std::array<VertexOutputType, 3> vertex_out;
@@ -308,13 +342,16 @@ class Rasterizer {
     const VertexOutputType &p1_out = vertex_out[0];
     const VertexOutputType &p2_out = vertex_out[1];
     const VertexOutputType &p3_out = vertex_out[2];
-    const bool triangle_not_visible =
-        (p1_out.coord[0] < 0.0 && p2_out.coord[0] < 0.0 && p3_out.coord[0] < 0.0) ||
-        (p1_out.coord[1] < 0.0 && p2_out.coord[1] < 0.0 && p3_out.coord[1] < 0.0) ||
-        (p1_out.coord[0] >= image_buffer_->x && p2_out.coord[0] >= image_buffer_->x &&
-         p3_out.coord[0] >= image_buffer_->x) ||
-        (p1_out.coord[1] >= image_buffer_->y && p2_out.coord[1] >= image_buffer_->y &&
-         p3_out.coord[1] >= image_buffer_->y);
+    const bool triangle_not_visible = (p1_out.coord[0] < 0.0 && p2_out.coord[0] < 0.0 &&
+                                       p3_out.coord[0] < 0.0) ||
+                                      (p1_out.coord[1] < 0.0 && p2_out.coord[1] < 0.0 &&
+                                       p3_out.coord[1] < 0.0) ||
+                                      (p1_out.coord[0] >= drawing_target_.get_width() &&
+                                       p2_out.coord[0] >= drawing_target_.get_width() &&
+                                       p3_out.coord[0] >= drawing_target_.get_width()) ||
+                                      (p1_out.coord[1] >= drawing_target_.get_height() &&
+                                       p2_out.coord[1] >= drawing_target_.get_height() &&
+                                       p3_out.coord[1] >= drawing_target_.get_height());
     if (triangle_not_visible) {
       stats.increase_discarded_triangles();
       return;
@@ -323,6 +360,9 @@ class Rasterizer {
     rasterize_triangle(vertex_out);
   }
 
+  /**
+   * Flush any not drawn rasterlines onto the active drawing target.
+   */
   void flush()
   {
     if (rasterlines_.is_empty()) {
@@ -423,7 +463,7 @@ class Rasterizer {
                       const InterfaceInnerType &fragment_add)
   {
     for (int y = from_y; y < to_y; y++) {
-      if (y >= 0 && y < image_buffer_->y) {
+      if (y >= 0 && y < drawing_target_.get_height()) {
         std::optional<RasterlineType> rasterline = clamped_rasterline(
             y, left.coord[0], right.coord[0], left.data, fragment_add);
         if (rasterline) {
@@ -589,7 +629,7 @@ class Rasterizer {
                                                    InterfaceInnerType start_data,
                                                    const InterfaceInnerType fragment_add)
   {
-    BLI_assert(y >= 0 && y < image_buffer_->y);
+    BLI_assert(y >= 0 && y < drawing_target_.get_height());
 
     stats.increase_rasterlines();
     if (start_x >= end_x) {
@@ -600,7 +640,7 @@ class Rasterizer {
       stats.increase_discarded_rasterlines();
       return std::nullopt;
     }
-    if (start_x >= image_buffer_->x) {
+    if (start_x >= drawing_target_.get_width()) {
       stats.increase_discarded_rasterlines();
       return std::nullopt;
     }
@@ -619,8 +659,8 @@ class Rasterizer {
     start_data += fragment_add * delta_to_anchor;
 
     uint32_t end_xi = clamping_method.column_for(end_x);
-    if (end_xi > image_buffer_->x) {
-      end_xi = image_buffer_->x;
+    if (end_xi > drawing_target_.get_width()) {
+      end_xi = drawing_target_.get_width();
       is_clamped = true;
     }
 
@@ -638,15 +678,15 @@ class Rasterizer {
   void render_rasterline(const RasterlineType &rasterline)
   {
     FragmentInputType data = rasterline.start_data;
+    float *pixel_ptr = drawing_target_.get_pixel_ptr(rasterline.start_x, rasterline.y);
     for (uint32_t x = rasterline.start_x; x < rasterline.end_x; x++) {
-      uint32_t pixel_index = (rasterline.y * image_buffer_->x + x);
-      float *pixel_ptr = &image_buffer_->rect_float[pixel_index * 4];
 
       FragmentOutputType fragment_out;
       fragment_shader_.fragment(data, &fragment_out);
       copy_v4_v4(pixel_ptr, &fragment_out[0]);
 
       data += rasterline.fragment_add;
+      pixel_ptr += drawing_target_.get_pixel_stride();
     }
 
     stats.increase_drawn_fragments(rasterline.end_x - rasterline.start_x);
diff --git a/source/blender/imbuf/intern/rasterizer_target.hh b/source/blender/imbuf/intern/rasterizer_target.hh
new file mode 100644
index 00000000000..25830b4006a
--- /dev/null
+++ b/source/blender/imbuf/intern/rasterizer_target.hh
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#pragma once
+
+/** \file
+ * \ingroup imbuf
+ *
+ * Rasterizer drawing target.
+ */
+
+#include "BLI_sys_types.h"
+
+namespace blender::imbuf::rasterizer {
+
+/**
+ * An abstract implementation of a drawing target. Will make it possible to switch to other render
+ * targets then only ImBuf types.
+ */
+template<typename Inner> class AbstractDrawingTarget {
+ public:
+  using InnerType = Inner;
+  virtual uint64_t get_width() const = 0;
+  virtual uint64_t get_height() const = 0;
+  virtual float *get_pixel_ptr(uint64_t x, uint64_t y) = 0;
+  virtual int64_t get_pixel_stride() const = 0;
+  virtual bool has_active_target() const = 0;
+  virtual void activate(Inner *instance) = 0;
+  virtual void deactivate() = 0;
+};
+
+class ImageBufferDrawingTarget : public AbstractDrawingTarget<ImBuf> {
+ private:
+  ImBuf *image_buffer_ = nullptr;
+
+ public:
+  bool has_active_target() const override
+  {
+    return image_buffer_ != nullptr;
+  }
+
+  void activate(ImBuf *image_buffer) override
+  {
+    image_buffer_ = image_buffer;
+  }
+
+  void deactivate() override
+  {
+    image_buffer_ = nullptr;
+  }
+
+  uint64_t get_width() const override
+  {
+    return image_buffer_->x;
+  };
+
+  uint64_t get_height() const override
+  {
+    return image_buffer_->y;
+  }
+
+  float *get_pixel_ptr(uint64_t x, uint64_t y) override
+  {
+    BLI_assert(has_active_target());
+    uint64_t pixel_index = y * image_buffer_->x + x;
+    return &image_buffer_->rect_float[pixel_index * 4];
+  }
+  int64_t get_pixel_stride() const override
+  {
+    return 4;
+  }
+};
+
+}  // namespace blender::imbuf::rasterizer
diff --git a/source/blender/imbuf/intern/rasterizer_test.cc b/source/blender/imbuf/intern/rasterizer_test.cc
index d96e4b199f5..608dcb43833 100644

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list