On Sat, 20 Feb 2021 18:37:38 -0800 Mark Solomonik <marik.solomo...@gmail.com> said:
> Hello, > I am trying to implement a 3D engine from scratch with XCB. To do this, I > have to set the color of every individual pixel before drawing it. > > I noticed that calling xcb_alloc_color and xcb_alloc_color_reply are > bottlenecking the program and making it slow to draw individual triangles. > > Below is how I am setting the color before drawing each pixel, straight > from this tutorial > <https://www.x.org/releases/X11R7.7/doc/libxcb/tutorial/index.html#usecolor> > : > > void set_drawing_color(xcb_connection_t *c, xcb_colormap_t colormap, > xcb_gcontext_t gcontext, int r, int g, int b) { > xcb_alloc_color_reply_t *color_info; > uint32_t mask; > uint32_t value[3]; > color_info = xcb_alloc_color_reply(c, xcb_alloc_color(c, colormap, > r, g, b), NULL); > > if (!color_info) > return 0; > free(color_info); > > mask = XCB_GC_FOREGROUND; > value[0] = color_info->pixel; > xcb_change_gc(c, gcontext, mask, value);} > > Is this an appropriate way to set the color? No. Just hell-no. No NO Double-extra-no with a cherry on top. > Is there a more efficient way to do so? Yes. > Slightly unrelated question: as someone completely new to Xorg and > Linux graphics in general, > how do you deal with the lack of documentation for XCB? Use Xlib. Or just use a toolkit higher up the stack. XCB really is for people who already know X backwards. It can buy some speedups in some corner-cases by avoiding round trips to the server and back and putting the job of doing it async in your hands. Don't start with XCB. It's a great way to drive yourself insane. > Thanks, Allocating colors comes from a time when you had displays with limited numbers of colors. Perhaps only 2 (black and white) and ylou needed to know what pixel value is black or white, or a display with 4, 8, 16, 32, 64 etc. or 256 colors only. These were mapped to a palette of colors able to be user-defined OR They may have been a fixed values that could never be changed by software. Allocating a color meant one of 2 things depending on the situation above. It either would go and find a free color value and give it the color your asked for, or if X had run out of colors, it'd pick the "closest match" and tell you that. The days of color palettes or these displays is pretty much over. In theory if you with to run on ancient or esoteric hardware you may still have to do this, but I'd suggest then using something like a 666 color cube (6 values for red, green and blue so 0->5 each) and then "pick the closest" and do dithering. There are other variation on this, but I won't get into that. What you want to be doing is just filling in pixel values based on the RGB masks in the visual you are using. you can query the visual for its RGb masks and this then tells you if its RGB, BGR, 30 bit, 24 bit or 16/15bit (565/555) or perhaps even 12 bit (444). etc. Reality is that there is a limited number of these RGB arrangements in t he real world and some are much more common than others. I'd optimize for the most common then have a "slow but works" path for the rest. Print some debug and have users inform you they hit a slow path to see if it's worth supporting. The advantage of dealing with it all as RGB true color is the paletted case where you would use XAllocColor to allocate a 666 colorcube is just a reduced quality version of all the true color modes. Now... You didn't mention this, but I imagine you are also doing something really bad... and that is drawing pixel by pixel with something like XDrawPoint()... DO NOT DO THIS!!!!! It's insane. Given what you describe doing a 3D engine from scratch - you are explicitly avoiding OpenGL because you want to learn how to do your own rendering or just do it as a challenge. Lucky for you... I wrote one of these 3D engines about 25 years ago ... for X11. I did update it a bit to do true color etc. ... so the code is old and crusty and has mistakes in it I'd not make after 25 years of X11... but it should help inspire you: http://www.rasterman.com/files/tex.tar.gz Fun thing... these days it gets like 1000 fps - back in '96 I was getting about 40fps... and it only runs on a single core so I never threaded it - ifI could I might get a lot more FPS now (in 1996 more than 1 CPU was not something you through about). But the crux of the above is .. you want to use XShmPutImage (Note you will need a fallback to XPutImage for remote XServers as XShmPutImage is for local XServers only which is 99.9% of cases). You want have a shared memory blob of pixels you are writing to (probably 2 of them actually for front and back buffer), then fill in this blob of memory directly by just writing pixel values, when done XShmPutImagae it to a window. You could do the latter in a thread and have the "fill in the buffer" part also farmed off to one or more threads - when it'd done it wakes up the "putimage" thread to throw it at the screen. An XSync() after the putimage will do a round trip here and wait for the xserver to finish this put so you don't run too far ahead. As this would be a dedicated putimage thread this will be fine. Once this sync returns the shm buffer is available for re-use. So keep 2 or 3 buffers around and put them to the screen and then when those complete put them back in the pool/ring buffer of "buffers" to be available for the rendering thread(s) to fill up. You do not need the XRender protocol for any of this. It's not useful given what I suspect you are doing (which is almost exactly what I did 25 years ago). -- ------------- Codito, ergo sum - "I code, therefore I am" -------------- Carsten Haitzler - ras...@rasterman.com _______________________________________________ xorg@lists.x.org: X.Org support Archives: http://lists.freedesktop.org/archives/xorg Info: https://lists.x.org/mailman/listinfo/xorg Your subscription address: %(user_address)s