diff options
author | Jeroen Bakker <jeroen@blender.org> | 2022-02-15 18:21:56 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2022-02-16 14:04:57 +0300 |
commit | 8839d309894c55bb514cc7cd16026e487c55ae17 (patch) | |
tree | 0fcd189e877fd1a91764d3d0b86d785c5d9de8ff /source/blender/imbuf/intern/rasterizer_test.cc | |
parent | 86762e8371ccecd411a463031d44618d4eec70ac (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.cc | 79 |
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 |