Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2022-02-15 18:21:56 +0300
committerJeroen Bakker <jeroen@blender.org>2022-02-16 14:04:57 +0300
commit8839d309894c55bb514cc7cd16026e487c55ae17 (patch)
tree0fcd189e877fd1a91764d3d0b86d785c5d9de8ff /source/blender/imbuf/intern/rasterizer_test.cc
parent86762e8371ccecd411a463031d44618d4eec70ac (diff)
Image buffer rasterizer using CPP templates.
For the 3d texture brush project we need a fast CPU based rasterizer. This is an initial implementation for a rasterizer that easy to extend and optimize. The idea is to implement a rasterizer on top of the ImBuf structure. The implementation uses CPP templates, resulting each usage to be optimized by the compiler individually. A user of the rasterizer can define a vertex shader, fragment shader, the inputs and interface, similar to existing concepts when using OpenGL. The rasterizer only supports triangles. [Future extensions] Currently the rasterlines are buffered and when the buffer is full it will be flushed. This is a tradeoff between local memory and branch prediction. We expect that adding triangles are typically done by a loop by the caller. But in certain cases we could buffer the input triangles and take this responsibility for additional performance. Configurable clamping. When rasterizing the clamping is done to a corner of a image pixel. Ideally clamping should consired center pixels or use a pixel coverage to identify how to clamp during rasterization. Currently only supports float4 as a fragment output type. float, byte and int textures aren't supported. Rasterline discard function. For cases that rasterlines don't need to be drawn based on vertex data. A use case could be that an influence factor is 0 for the whole triangle. Current implementation is single threaded. When using multiple threads with their own rasterizer could lead to render artifacts. We could provide a scheduler that collects work in buckets based on the rasterline y. [Todos] * Only supports one winding directional. Should be able to support any winding direction. * Use coord as name for the frag position. Current UV is too related to a specific usecase. * Add more test cases. Differential Revision: https://developer.blender.org/D14126
Diffstat (limited to 'source/blender/imbuf/intern/rasterizer_test.cc')
-rw-r--r--source/blender/imbuf/intern/rasterizer_test.cc79
1 files changed, 79 insertions, 0 deletions
diff --git a/source/blender/imbuf/intern/rasterizer_test.cc b/source/blender/imbuf/intern/rasterizer_test.cc
new file mode 100644
index 00000000000..862743c32c4
--- /dev/null
+++ b/source/blender/imbuf/intern/rasterizer_test.cc
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include "testing/testing.h"
+
+#include "IMB_rasterizer.hh"
+
+namespace blender::imbuf::rasterizer::tests {
+
+const uint32_t IMBUF_SIZE = 128;
+
+struct VertexInput {
+ float2 uv;
+
+ VertexInput(float2 uv) : uv(uv)
+ {
+ }
+};
+
+class VertexShader : public AbstractVertexShader<VertexInput, float> {
+ public:
+ float2 image_size;
+ void vertex(const VertexInputType &input, VertexOutputType *r_output) override
+ {
+ r_output->uv = input.uv * image_size;
+ r_output->data = 1.0f;
+ }
+};
+
+class FragmentShader : public AbstractFragmentShader<float, float4> {
+ public:
+ void fragment(const FragmentInputType &input, FragmentOutputType *r_output) override
+ {
+ *r_output = float4(input, input, input, 1.0);
+ }
+};
+
+TEST(imbuf_rasterizer, draw_triangle)
+{
+ ImBuf image_buffer;
+ IMB_initImBuf(&image_buffer, IMBUF_SIZE, IMBUF_SIZE, 0, IB_rectfloat);
+
+ Rasterizer<VertexShader, FragmentShader, 4096, Stats> rasterizer(&image_buffer);
+
+ VertexShader &vertex_shader = rasterizer.vertex_shader();
+ vertex_shader.image_size = float2(image_buffer.x, image_buffer.y);
+
+ EXPECT_EQ(rasterizer.stats.triangles, 0);
+ EXPECT_EQ(rasterizer.stats.discarded_triangles, 0);
+ EXPECT_EQ(rasterizer.stats.rasterlines, 0);
+ EXPECT_EQ(rasterizer.stats.discarded_rasterlines, 0);
+ EXPECT_EQ(rasterizer.stats.clamped_rasterlines, 0);
+ EXPECT_EQ(rasterizer.stats.drawn_fragments, 0);
+
+ rasterizer.draw_triangle(
+ VertexInput(float2(0.1, 0.1)), VertexInput(float2(0.5, 0.2)), VertexInput(float2(0.4, 0.9)));
+ rasterizer.flush();
+
+ /*
+ EXPECT_EQ(rasterizer.stats.triangles, 1);
+ EXPECT_EQ(rasterizer.stats.discarded_triangles, 0);
+ EXPECT_EQ(rasterizer.stats.rasterlines, 245);
+ EXPECT_EQ(rasterizer.stats.discarded_rasterlines, 1);
+ EXPECT_EQ(rasterizer.stats.clamped_rasterlines, 0);
+ // EXPECT_EQ(rasterizer.stats.drawn_fragments, 0);
+ */
+
+ for (int y = 0; y < IMBUF_SIZE; y++) {
+ for (int x = 0; x < IMBUF_SIZE; x++) {
+ int pixel_offset = y * IMBUF_SIZE + x;
+ float *pixel = &image_buffer.rect_float[pixel_offset * 4];
+ printf("%s", *pixel < 0.5 ? " " : "#");
+ }
+ printf("\n");
+ }
+
+ imb_freerectImbuf_all(&image_buffer);
+}
+
+} // namespace blender::imbuf::rasterizer::tests