-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Triangles rendering (with per vertex color) #4195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Any new opinions or use-case about this new draft patch that use the vertex color ? I've been able to get it work with spine (with lots of code interface taken/modified from another repository), With Imgui, that is much more easier to integrate: But, the issue with current function interface is that it requests to draw triangles 1 per 1 (even they are batched afterwards).
Allows to provide separates pointers for position/color/texture, with their own stride, and sending indices as int/short/char. Software rendering isn't too bad since it draws at 40 fps for the same example (window + demo window, nothing selected). But it can drop when adding more windows, or resizing. Edit: add software rendering stats |
@1bsyl Hi |
hi @rmg-nik Thanks for the feedback. Though a vertex API api could still be added, simply calling with : |
Guys, should this feature be merged into SDL master branch? Or we should forget about spine runtime integration? |
It seems to me that before accepting anything, it is necessary to discuss all the points and hear the opinion of the main developers of the SDL. |
With previous tries / PR , it shows how to use the SDL_RenderGeometry to run: |
@1bsyl @akk0rd87 Hi |
@rmg-nik, thanks. I'll try it at weekend. |
@rmg-nik, thanks ! got it working with my sdl build |
@1bsyl My Spine example is based on https://github.com/GerogeChong/spine-sdl but I've simplified this code a lot for demonstration purposes. |
With previous commit, with Dear ImGui + software renderer gets better results.
|
Hello, is there any plan to add D3D9? |
@baidwwy just added the D3D9, but not tested |
@1bsyl Hi
|
@icculus Could you please offer some feedback/direction for this? Thanks! |
I believe we're planning to merge this shortly. |
@rmg-nik
|
*/ | ||
extern DECLSPEC int SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, | ||
SDL_Texture *texture, | ||
const float *xy, int xy_stride, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd expect these parameters to use the same types as the ones in the SDL_Vertex
struct (eg an array of SDL_Color
instead of an array of int
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SDL_Color are int anyway.
SDL_RenderGeometryRaw is added for app that are non SDL (eg: librocket, dear imgui, nuklear, spine).
So it's better to present them a basic type than something they don't know, they will need to look for, and that are going to cast anyway.
If you want to draw triangles with an SDL app, more friendly to use SDL_Vertex and SDL_RenderGeometry.
* | ||
* \return 0 on success, or -1 if the operation is not supported | ||
*/ | ||
extern DECLSPEC int SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there much point to having this function considering all the vertex attributes are mandatory (you can't pass in nulls)? Flexibility is nice I guess, but IMO API flexibility should come from real-world use cases after determining simpler APIs can't satisfy specific needs rather than providing a kitchen sink in the hope that people will actually need everything there.
Personally I'd prefer it if just SDL_RenderGeometry
existed - there's pros and cons to accepting an array of structures versus multiple independent arrays, but picking one of the two and sticking with it feels more in line with SDL_Render's simple design philosophy compared to lower level graphics APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having just a single simpler / less catch-all external API will also help keep backend implementations simple too. For example the ability to memcpy an array of SDL_Vertex
structs directly, and pass that all the way through to the GPU without looping over each vertex, is possible on several backends if the higher level API isn't too loose with its constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(uv can be null, indices can be null)
After trying to integrate the SDL_vertex with real-world libs, it appears I need to allocate/loop/re-assign the datas.
So this the common denominator when integrating with the tested libs. The simpliest if you don't want to re-alloc and re-order datas.
SDL_RenderGeometry and SDL_RenderGeometryRaw share the same backend interface. (SDL_RenderGeometry is just 5 lines)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to rename this to SDL_RenderGeometryEx
just to have a consistent naming (we have SDL_RenderCopyEx
)?
src/render/direct3d/SDL_render_d3d.c
Outdated
int j; | ||
float *xy_; | ||
SDL_Color col_; | ||
if (size_indice == 4) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be better to pass indices directly into graphics API backends instead of doing CPU-side remapping. Every GPU backend supports hardware-accelerated indexed triangle rendering. There a couple considerations though:
- uint8 indices aren't supported by most modern graphics APIs. Personally I wouldn't bother supporting them.
- uint32 indices aren't supported by some GLES devices. They're still useful to support natively but you might need a fallback like this, just for the GLES backend (I don't know whether D3D9 and D3D11 have a feature query for that, too).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the infos about int8/32
Actually: librocket uses 'int' and imgui 'short'. Hence this size parameter.
(And I just added the extra uint8 possibility just in case ...)
I agree, it's better to pass indices directly. But this is more work for this PR, and this remains a possibility for improvement.
(Btw, this is the reason why indice/size/int is sent the back-end and not converted in SDL_render.c)
src/render/metal/SDL_render_metal.m
Outdated
@@ -279,26 +281,35 @@ - (void)dealloc | |||
|
|||
switch (cache->vertexFunction) { | |||
case SDL_METAL_VERTEX_SOLID: | |||
/* position (float2) */ | |||
vertdesc.layouts[0].stride = sizeof(float) * 2; | |||
/* position (float2), color (float4) */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
colors are unsigned normalized 8 bit values in the higher level API, so you don't need the uint8 -> float conversion in backends like Metal where it's easy to pass the same type all the way through to the GPU.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the info, I think gles2 back-end can do the same with (glVertexAttribPointer with 'normalized' param).
I am not so familiar with metal to change this quickly, I'll do it probably when I have some spare time. (no need to change the shader, right ?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. It's not a big deal either way, it just might simplify some code (or it might add more complexity elsewhere, I'm not sure).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've just modified this way ..
I know you made the change, but if I may chip in, I would prefer to have colors be floats instead of int. Since this is a lower level API, the user should expect to work closer to the metal when using it. More importantly, for multithreading, I always want to compute all the required data on threads then feed the raw data to the renderer on the main thread so there's as little blocking as possible. By taking float colors, I can easily do the conversion from SDL_Color myself if needed. Ideally, SDL_RenderGeometryRaw wouldn't do any transformation whatsoever, just take the raw data and feed it to the GPU without touching it. And we can still have a highler level SDL_RenderGeometry that takes an SDL_Color type and does the conversion for SDL_RenderGeometryRaw. |
From a GPU perspective, normalized byte colour components are exactly as close to the metal as float colour components. GPUs will take either one natively. I'm not sure whether the software renderer backend could take float colours natively or not. If you're suggesting the RenderGeometryRaw API should have a parameter specifying the vertex format, that's not unheard of for similar APIs but also seems a bit complicated. |
[--use-rendergeometry mode1|mode2] mode1: Draw sprite2 as triangles that can be recombined as rect by software renderer mode2: Draw sprite2 as triangles that can *not* be recombined as rect by software renderer Use an 'indices' array
--use-texture: an option to load icon.bmp as a texture handle mouse motion: rotate the triangle
1dc443c
to
018541b
Compare
@slouken: just re-based and committed ! |
Android builder in buildbot is showing a lot of I also suggest using I suggest the following, but can't test it - is it OK? diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index a4e59e3..77c0c6e 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -3343,7 +3343,7 @@ SDL_RenderCopyExF(SDL_Renderer * renderer, SDL_Texture * texture,
}
-#define SDL_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER))
+#define SDL_OFFSETOF(_TYPE,_MEMBER) ((intptr_t)&(((_TYPE*)0)->_MEMBER))
int
SDL_RenderGeometry(SDL_Renderer *renderer,
SDL_Texture *texture,
diff --git a/src/render/software/SDL_triangle.c b/src/render/software/SDL_triangle.c
index 8c9bc63..ad1812d 100644
--- a/src/render/software/SDL_triangle.c
+++ b/src/render/software/SDL_triangle.c
@@ -156,21 +156,21 @@ static void bounding_rect(const SDL_Point *a, const SDL_Point *b, const SDL_Poin
/* Use 64 bits precision to prevent overflow when interpolating color / texture with wide triangles */
#define TRIANGLE_GET_TEXTCOORD \
- int srcx = ((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area; \
- int srcy = ((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area; \
+ int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \
+ int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \
#define TRIANGLE_GET_MAPPED_COLOR \
- int r = ((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area; \
- int g = ((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area; \
- int b = ((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area; \
- int a = ((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area; \
+ int r = (int)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \
+ int g = (int)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \
+ int b = (int)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \
+ int a = (int)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); \
int color = SDL_MapRGBA(format, r, g, b, a); \
#define TRIANGLE_GET_COLOR \
- int r = ((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area; \
- int g = ((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area; \
- int b = ((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area; \
- int a = ((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area; \
+ int r = (int)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \
+ int g = (int)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \
+ int b = (int)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \
+ int a = (int)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); \
#define TRIANGLE_END_LOOP \ |
@sezero |
Is this not supported when the Vulkan backend is in use? |
The patch only adds an explicit int cast onto the whole result to avoid the warning |
@AJenbo This an API to use with the SDL renderer (SDL_renderer), and there is no Vulkan backend with it, so it's just not applicable. (I think @icculus has one SDL_renderer/Vulkan in development, but it's not in the main branch) @sezero : ok, then feel free to commit it, and I'll double-check (later) |
Applied as 8270172 |
I've double checked and this is ok, thanks |
I had the barest of starts, a long time ago. It's definitely worth finishing at some point, but it's not even close right now. |
For those interested in Spine, I modified the spine-sfml runtime to use SDL2 instead of SFML using the wonderful SDL_RenderGeometry. The call to SDL_RenderGeometry is equivalent to the one rmg-nik did. I'm providing spine-c and spine-cpp versions as well as working examples (matching the spine-sfml folders) and basic documentation: |
Information about SDL integration with other libraries can be found there: https://wiki.libsdl.org/Libraries |
Second attempt to render triangles with SDL, adding SDL_RenderGeometry
In this version, triangles can be non uniform, with a per vertex color.
Textures can also have a per vertex modulation.
Using the adviced prototype:
Description
Back-end added: Software, Opengl, OpenGLES2, D3D11, METAL, D3D9, OpengGLES
Metal and OpenGLES2 are modified more internally so that 'color' isn't uniform anymore but an attribute.
Software Renderer tries also to reconstruct SDL_Rect from Vertex, and to use faster SDL_RenderCopy when possible.
I've checked that it integrates correctly with DearImGui. (see example files here: ocornut/imgui#3926 )
And also with Spine (using spine-c runtime)
With Nuklear ( Immediate-Mode-UI/Nuklear#280 )
With Librocket (libRocket/libRocket#301 )
With Microui ( rxi/microui#48 )
Some parts are used from the various patches
Existing Issue(s)
Referencing
#772 : SDL_RenderGeometry
#692 : Implement polygon rendering