Home » U++ Library support » Draw, Display, Images, Bitmaps, Icons » BufferPainter::Fill(Image,...) optimization question
BufferPainter::Fill(Image,...) optimization question [message #53749] |
Mon, 27 April 2020 14:51  |
Tom1
Messages: 1301 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi Mirek,
After getting inspired by the recent improvements in DrawImage(), I tested the BufferPainter::Fill(Image,...) using images with both kind=IMAGE_OPAQUE and kind=IMAGE_ALPHA. It seems they apparently render at the same speed. Is there any room for "easy" optimization when rendering opaque images?
(I really tried to look for the code where the rendering is actually done, but BufferPainter is way too complex for me to navigate... Maybe you could point out the file and line where the decision between opaque rendering and alpha blending is actually done.)
Best regards,
Tom
|
|
|
Re: BufferPainter::Fill(Image,...) optimization question [message #53750 is a reply to message #53749] |
Mon, 27 April 2020 16:51   |
Tom1
Messages: 1301 Registered: March 2007
|
Ultimate Contributor |
|
|
Hi,
Never mind... after all I managed to get through and found the fillers.
While this is not much, I noticed that the following changes improve BufferPainter::Fill(Image,...) performance by about 5 % for MT and about 13 % for ST on my computer. The changes (centered around adding and handling of 'kind' for SpanSource) follow.
Painter/BufferPainter.h:
struct SpanSource {
int kind;
SpanSource(){
kind = IMAGE_OPAQUE;
}
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
virtual ~SpanSource() {}
};
Painter/Fillers.cpp:
void SpanFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
s += len;
return;
}
if(alpha != 256)
val = alpha * val >> 8;
if(val == 256) {
if(ss->kind==IMAGE_OPAQUE) memcpy(t,s,len*sizeof(RGBA));
else{
for(int i = 0; i < len; i++) {
if(s[i].a == 255)
t[i] = s[i];
else
AlphaBlend(t[i], s[i]);
}
}
t += len;
s += len;
}
else {
const RGBA *e = t + len;
while(t < e)
AlphaBlendCover8(*t++, *s++, val);
}
}
Painter/Image.cpp:
struct PainterImageSpan : SpanSource, PainterImageSpanData {
LinearInterpolator interpolator;
PainterImageSpan(const PainterImageSpanData& f)
: PainterImageSpanData(f) {
interpolator.Set(xform);
kind = image.GetKindNoScan(); // Tom added
}
This just leaves me wondering why is the improvement so insignificant, no matter there is no longer any comparison and/or blending required. Is there yet another layer of transferring pixels somewhere?
Please review the changes. If they are correct and sensible -- which I'm not sure about -- feel free to merge.
Best regards,
Tom
EDIT: Changed default SpanSource::kind to IMAGE_OPAQUE to boost all kinds of filling. The change introduced a slight improvement over the previous round.
[Updated on: Tue, 28 April 2020 00:48] Report message to a moderator
|
|
|
Re: BufferPainter::Fill(Image,...) optimization question [message #54159 is a reply to message #53750] |
Thu, 04 June 2020 18:38   |
 |
mirek
Messages: 14255 Registered: November 2005
|
Ultimate Member |
|
|
Tom1 wrote on Mon, 27 April 2020 16:51Hi,
Never mind... after all I managed to get through and found the fillers.
While this is not much, I noticed that the following changes improve BufferPainter::Fill(Image,...) performance by about 5 % for MT and about 13 % for ST on my computer. The changes (centered around adding and handling of 'kind' for SpanSource) follow.
Painter/BufferPainter.h:
struct SpanSource {
int kind;
SpanSource(){
kind = IMAGE_OPAQUE;
}
virtual void Get(RGBA *span, int x, int y, unsigned len) = 0;
virtual ~SpanSource() {}
};
Painter/Fillers.cpp:
void SpanFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
s += len;
return;
}
if(alpha != 256)
val = alpha * val >> 8;
if(val == 256) {
if(ss->kind==IMAGE_OPAQUE) memcpy(t,s,len*sizeof(RGBA));
else{
for(int i = 0; i < len; i++) {
if(s[i].a == 255)
t[i] = s[i];
else
AlphaBlend(t[i], s[i]);
}
}
t += len;
s += len;
}
else {
const RGBA *e = t + len;
while(t < e)
AlphaBlendCover8(*t++, *s++, val);
}
}
Painter/Image.cpp:
struct PainterImageSpan : SpanSource, PainterImageSpanData {
LinearInterpolator interpolator;
PainterImageSpan(const PainterImageSpanData& f)
: PainterImageSpanData(f) {
interpolator.Set(xform);
kind = image.GetKindNoScan(); // Tom added
}
This just leaves me wondering why is the improvement so insignificant, no matter there is no longer any comparison and/or blending required. Is there yet another layer of transferring pixels somewhere?
Please review the changes. If they are correct and sensible -- which I'm not sure about -- feel free to merge.
Best regards,
Tom
EDIT: Changed default SpanSource::kind to IMAGE_OPAQUE to boost all kinds of filling. The change introduced a slight improvement over the previous round.
I have moved over to this, unfortunately it is more complicated because even opaque image can return zero alpha for areas it does not cover....
|
|
|
Re: BufferPainter::Fill(Image,...) optimization question [message #54161 is a reply to message #54159] |
Thu, 04 June 2020 18:49   |
 |
mirek
Messages: 14255 Registered: November 2005
|
Ultimate Member |
|
|
So this is (likely) the correct code:
void SpanFiller::Render(int val, int len)
{
if(val == 0) {
t += len;
s += len;
return;
}
if(alpha != 256)
val = alpha * val >> 8;
if(val == 256 && ss->opaque) {
const RGBA *e = s + len;
const RGBA *s0 = s;
while(s < e && s->a == 0)
s++;
t += s - s0;
s0 = s;
while(s < e && s->a != 255)
s++;
AlphaBlend(t, s0, val, s - s0);
t += s - s0;
s0 = s;
while(s < e && s->a == 255)
s++;
memcpy32(t, s0, s - s0);
t += s - s0;
s0 = s;
while(s < e && s->a)
s++;
AlphaBlend(t, s0, val, s - s0);
}
else
AlphaBlend(t, s, val, len);
t += len;
s += len;
}
Unfortunately it is then slower than new SSE2 AlphaBlend path, so...
Mirek
|
|
|
|
Goto Forum:
Current Time: Mon Apr 28 15:27:12 CEST 2025
Total time taken to generate the page: 0.04364 seconds
|