From f5b6cf65b27a78f055c668b11f03ed6e3187c775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Wed, 28 Dec 2005 19:53:00 +0000 Subject: [PATCH] * extracted the frame buffer memcpy routine from HWInterface.cpp into a new frame_buffer_support.h * added blend32 routine for blending a certain color with a scanline in the frame buffer * added "solid" versions of B_OP_ALPHA drawing with B_ALPHA_OVERLAY alha function (blending on top of a non-transparent background such as the frame buffer) * implemented an optimized shortcut for alpha blended FillRect() in Painter * used the "packed" version of scanlines for shapes with an outline thicker than 4 pixels (and filled shapes anyways), this improves drawing speed when there are a few anti-aliased pixels at the beginning of a scanline, then a solid fill and some anti-aliased pixels at the end of the scanline. Such as large letters. To summarize: The alpha blending in Painter seems to be about 1.45 times faster than on BeOS R5 which benefits drawing large shapes. For example, drawing a large alpha blended rounded rect is 1.28 times faster on the Haiku app_server. On the other hand, B_OP_COPY is quite tough to beat. It is currently 10 times faster on R5. But a great deal seems to be caused by the Painter rasterization algorithm itself, since commenting out the actual drawing doesn't gain any speed. The other useful experience I collected was that reading and writing and over the PCI bus in the same loop really hurts performance. It is actually faster (like 1.8 times!!) to allocate a second buffer, read from frame buffer into that, doing the blending at the same time, then writing the buffer back to the screen. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15698 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/drawing/HWInterface.cpp | 89 ++---------- src/servers/app/drawing/Painter/Jamfile | 1 + src/servers/app/drawing/Painter/Painter.cpp | 83 ++++++++++-- src/servers/app/drawing/Painter/Painter.h | 7 +- src/servers/app/drawing/Painter/defines.h | 9 +- .../Painter/drawing_modes/DrawingMode.h | 7 +- .../drawing_modes/DrawingModeAlphaCOSolid.h | 114 ++++++++++++++++ .../drawing_modes/DrawingModeAlphaPOSolid.h | 112 +++++++++++++++ .../drawing_modes/DrawingModeCopySolid.h | 2 +- .../Painter/drawing_modes/PixelFormat.cpp | 32 +++-- .../app/drawing/frame_buffer_support.h | 127 ++++++++++++++++++ 11 files changed, 472 insertions(+), 111 deletions(-) create mode 100644 src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaCOSolid.h create mode 100644 src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h create mode 100644 src/servers/app/drawing/frame_buffer_support.h diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index aa71b44648..8e5b862ed5 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -1,8 +1,15 @@ -// HWInterface.cpp +//------------------------------------------------------------------------------ +// Copyright 2005, Haiku, Inc. All rights reserved. +// Distributed under the terms of the MIT License. +// +// Author: Stephan Aßmus, +//------------------------------------------------------------------------------ #include #include +#include "frame_buffer_support.h" + #include "RenderingBuffer.h" #include "ServerCursor.h" #include "SystemPalette.h" @@ -388,86 +395,6 @@ HWInterface::_DrawCursor(BRect area) const } } -/* -// gfxcpy -inline -void -gfxcpy(uint8* dst, uint8* src, int32 numBytes) -{ - uint64* d64 = (uint64*)dst; - uint64* s64 = (uint64*)src; - int32 numBytesBegin = numBytes; - while (numBytes >= 32) { - *d64++ = *s64++; - *d64++ = *s64++; - *d64++ = *s64++; - *d64++ = *s64++; - numBytes -= 32; - } - while (numBytes >= 16) { - *d64++ = *s64++; - *d64++ = *s64++; - numBytes -= 16; - } - while (numBytes >= 8) { - *d64++ = *s64++; - numBytes -= 8; - } - if (numBytes > 0) { - // update original pointers - dst += numBytesBegin - numBytes; - src += numBytesBegin - numBytes; - numBytesBegin = numBytes; - - uint32* d32 = (uint32*)dst; - uint32* s32 = (uint32*)src; - while (numBytes >= 4) { - *d32++ = *s32++; - numBytes -= 4; - } - // update original pointers - dst += numBytesBegin - numBytes; - src += numBytesBegin - numBytes; - - while (numBytes > 0) { - *dst++ = *src++; - numBytes--; - } - } -}*/ - -// gfxcpy32 -// * numBytes is expected to be a multiple of 4 -inline -void -gfxcpy32(uint8* dst, uint8* src, int32 numBytes) -{ - uint64* d64 = (uint64*)dst; - uint64* s64 = (uint64*)src; - int32 numBytesStart = numBytes; - while (numBytes >= 32) { - *d64++ = *s64++; - *d64++ = *s64++; - *d64++ = *s64++; - *d64++ = *s64++; - numBytes -= 32; - } - if (numBytes >= 16) { - *d64++ = *s64++; - *d64++ = *s64++; - numBytes -= 16; - } - if (numBytes >= 8) { - *d64++ = *s64++; - numBytes -= 8; - } - if (numBytes == 4) { - uint32* d32 = (uint32*)(dst + numBytesStart - numBytes); - uint32* s32 = (uint32*)(src + numBytesStart - numBytes); - *d32 = *s32; - } -} - // _CopyToFront // // * source is assumed to be already at the right offset diff --git a/src/servers/app/drawing/Painter/Jamfile b/src/servers/app/drawing/Painter/Jamfile index 03fe84cb6c..481b0c081f 100644 --- a/src/servers/app/drawing/Painter/Jamfile +++ b/src/servers/app/drawing/Painter/Jamfile @@ -5,6 +5,7 @@ AddSubDirSupportedPlatforms libbe_test ; UseLibraryHeaders agg ; UsePrivateHeaders app interface shared [ FDirName servers app ] ; +UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter font_support ] ; UseFreeTypeHeaders ; diff --git a/src/servers/app/drawing/Painter/Painter.cpp b/src/servers/app/drawing/Painter/Painter.cpp index c86b6d6365..ac0d7ca155 100644 --- a/src/servers/app/drawing/Painter/Painter.cpp +++ b/src/servers/app/drawing/Painter/Painter.cpp @@ -26,6 +26,8 @@ #include #include +#include "frame_buffer_support.h" + #include "DrawState.h" #include "AGGTextRenderer.h" @@ -63,7 +65,8 @@ Painter::Painter() fBaseRenderer(NULL), fOutlineRenderer(NULL), fOutlineRasterizer(NULL), - fScanline(NULL), + fUnpackedScanline(NULL), + fPackedScanline(NULL), fRasterizer(NULL), fRenderer(NULL), fFontRendererSolid(NULL), @@ -76,7 +79,6 @@ Painter::Painter() fValidClipping(false), fDrawingMode(B_OP_COPY), fAlphaSrcMode(B_PIXEL_ALPHA), -// fAlphaSrcMode(B_CONSTANT_ALPHA), fAlphaFncMode(B_ALPHA_OVERLAY), fPenLocation(0.0, 0.0), fLineCapMode(B_BUTT_CAP), @@ -149,7 +151,8 @@ Painter::AttachToBuffer(RenderingBuffer* buffer) // the renderer used for filling paths fRenderer = new renderer_type(*fBaseRenderer); fRasterizer = new rasterizer_type(); - fScanline = new scanline_type(); + fUnpackedScanline = new scanline_unpacked_type(); + fPackedScanline = new scanline_packed_type(); #if ALIASED_DRAWING fRasterizer->gamma(agg::gamma_threshold(0.5)); @@ -665,6 +668,22 @@ Painter::FillRect(const BRect& r) const return _Clipped(rect); } } + if (fDrawingMode == B_OP_ALPHA && fAlphaFncMode == B_ALPHA_OVERLAY) { + pattern p = *fPatternHandler->GetR5Pattern(); + if (p == B_SOLID_HIGH) { + BRect rect(a, b); + _BlendRect32(rect, fPatternHandler->HighColor().GetColor32()); + return _Clipped(rect); + } else if (p == B_SOLID_LOW) { + rgb_color c = fPatternHandler->LowColor().GetColor32(); + if (fAlphaSrcMode == B_CONSTANT_ALPHA) + c.alpha = fPatternHandler->HighColor().GetColor32().alpha; + BRect rect(a, b); + _BlendRect32(rect, c); + return _Clipped(rect); + } + } + // account for stricter interpretation of coordinates in AGG // the rectangle ranges from the top-left (.0, .0) @@ -769,8 +788,11 @@ Painter::StrokeRoundRect(const BRect& r, float xRadius, float yRadius) const // make the inner rect work as a hole fRasterizer->filling_rule(agg::fill_even_odd); - - agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer); + + if (fPenSize > 4) + agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); + else + agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); // reset to default fRasterizer->filling_rule(agg::fill_non_zero); @@ -1007,8 +1029,10 @@ Painter::_MakeEmpty() fOutlineRasterizer = NULL; #endif - delete fScanline; - fScanline = NULL; + delete fUnpackedScanline; + fUnpackedScanline = NULL; + delete fPackedScanline; + fPackedScanline = NULL; delete fRasterizer; fRasterizer = NULL; @@ -1199,7 +1223,10 @@ Painter::_DrawEllipse(BPoint center, float xRadius, float yRadius, // make the inner ellipse work as a hole fRasterizer->filling_rule(agg::fill_even_odd); - agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer); + if (fPenSize > 4) + agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); + else + agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); // reset to default fRasterizer->filling_rule(agg::fill_non_zero); @@ -1390,6 +1417,38 @@ Painter::_InvertRect32(BRect r) const } } +// _BlendRect32 +void +Painter::_BlendRect32(const BRect& r, const rgb_color& c) const +{ + if (fBuffer && fValidClipping) { + uint8* dst = fBuffer->row(0); + uint32 bpr = fBuffer->stride(); + + int32 left = (int32)r.left; + int32 top = (int32)r.top; + int32 right = (int32)r.right; + int32 bottom = (int32)r.bottom; + + // fill rects, iterate over clipping boxes + fBaseRenderer->first_clip_box(); + do { + int32 x1 = max_c(fBaseRenderer->xmin(), left); + int32 x2 = min_c(fBaseRenderer->xmax(), right); + if (x1 <= x2) { + int32 y1 = max_c(fBaseRenderer->ymin(), top); + int32 y2 = min_c(fBaseRenderer->ymax(), bottom); + + uint8* offset = dst + x1 * 4 + y1 * bpr; + for (; y1 <= y2; y1++) { + blend_line32(offset, x2 - x1 + 1, c.red, c.green, c.blue, c.alpha); + offset += bpr; + } + } + } while (fBaseRenderer->next_clip_box()); + } +} + // #pragma mark - template @@ -1465,7 +1524,11 @@ Painter::_StrokePath(VertexSource& path) const agg::conv_clip_polygon > clippedPath(stroke); clippedPath.clip_box(-500, -500, fBuffer->width() + 500, fBuffer->height() + 500); fRasterizer->add_path(clippedPath); - agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer); + + if (fPenSize > 4) + agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); + else + agg::render_scanlines(*fRasterizer, *fUnpackedScanline, *fRenderer); // } else { // TODO: update to AGG 2.3 to get rid of the remaining problems: // rects which are 2 or 1 pixel high/wide don't render at all. @@ -1489,7 +1552,7 @@ Painter::_FillPath(VertexSource& path) const agg::conv_clip_polygon clippedPath(path); clippedPath.clip_box(-500, -500, fBuffer->width() + 500, fBuffer->height() + 500); fRasterizer->add_path(clippedPath); - agg::render_scanlines(*fRasterizer, *fScanline, *fRenderer); + agg::render_scanlines(*fRasterizer, *fPackedScanline, *fRenderer); return _Clipped(_BoundingBox(clippedPath)); } diff --git a/src/servers/app/drawing/Painter/Painter.h b/src/servers/app/drawing/Painter/Painter.h index c4f251a837..5039a8ef07 100644 --- a/src/servers/app/drawing/Painter/Painter.h +++ b/src/servers/app/drawing/Painter/Painter.h @@ -236,7 +236,9 @@ class Painter { BRect bitmapRect, BRect viewRect) const; - void _InvertRect32(BRect r) const; + void _InvertRect32( BRect r) const; + void _BlendRect32( const BRect& r, + const rgb_color& c) const; template @@ -256,7 +258,8 @@ class Painter { outline_renderer_type* fOutlineRenderer; outline_rasterizer_type* fOutlineRasterizer; - scanline_type* fScanline; + scanline_unpacked_type* fUnpackedScanline; + scanline_packed_type* fPackedScanline; rasterizer_type* fRasterizer; renderer_type* fRenderer; diff --git a/src/servers/app/drawing/Painter/defines.h b/src/servers/app/drawing/Painter/defines.h index d67dc599c1..496195692b 100644 --- a/src/servers/app/drawing/Painter/defines.h +++ b/src/servers/app/drawing/Painter/defines.h @@ -13,12 +13,11 @@ #include #include #include -//#include #include #include #include #include -//#include +#include #include #include @@ -35,14 +34,16 @@ typedef agg::renderer_primitives outline_renderer_type; typedef agg::rasterizer_outline outline_rasterizer_type; - typedef agg::scanline_bin scanline_type; + typedef agg::scanline_bin scanline_unpacked_type; + typedef agg::scanline_bin scanline_packed_type; typedef agg::rasterizer_scanline_aa<> rasterizer_type; typedef agg::renderer_scanline_bin_solid renderer_type; #else typedef agg::renderer_outline_aa outline_renderer_type; typedef agg::rasterizer_outline_aa outline_rasterizer_type; - typedef agg::scanline_u8 scanline_type; + typedef agg::scanline_u8 scanline_unpacked_type; + typedef agg::scanline_p8 scanline_packed_type; typedef agg::rasterizer_scanline_aa<> rasterizer_type; typedef agg::renderer_scanline_aa_solid renderer_type; #endif diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h index c1b10e62c9..db9c1e8520 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingMode.h @@ -9,6 +9,8 @@ #ifndef DRAWING_MODE_H #define DRAWING_MODE_H +#include "frame_buffer_support.h" + #include "PatternHandler.h" #include "PixelFormat.h" @@ -17,11 +19,6 @@ class PatternHandler; typedef PixelFormat::color_type color_type; typedef PixelFormat::agg_buffer agg_buffer; -union pixel32 { - uint32 data32; - uint8 data8[4]; -}; - // BLEND // // This macro assumes source alpha in range 0..255 and diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaCOSolid.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaCOSolid.h new file mode 100644 index 0000000000..94cfb78ce3 --- /dev/null +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaCOSolid.h @@ -0,0 +1,114 @@ +/* + * Copyright 2005, Stephan Aßmus . All rights reserved. + * Distributed under the terms of the MIT License. + * + * DrawingMode implementing B_OP_ALPHA in "Constant Overlay" mode on B_RGBA32. + * + */ + +#ifndef DRAWING_MODE_ALPHA_CO_SOLID_H +#define DRAWING_MODE_ALPHA_CO_SOLID_H + +#include "DrawingModeAlphaCO.h" + +// blend_pixel_alpha_co_solid +void +blend_pixel_alpha_co_solid(int x, int y, const color_type& c, uint8 cover, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint8* p = buffer->row(y) + (x << 2); + uint16 alpha = pattern->HighColor().GetColor32().alpha * cover; + if (alpha == 255 * 255) { + ASSIGN_ALPHA_CO(p, c.r, c.g, c.b); + } else { + BLEND_ALPHA_CO(p, c.r, c.g, c.b, alpha); + } +} + +// blend_hline_alpha_co_solid +void +blend_hline_alpha_co_solid(int x, int y, unsigned len, + const color_type& c, uint8 cover, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint16 alpha = pattern->HighColor().GetColor32().alpha * cover; + if (alpha == 255 * 255) { + // cache the color as 32bit values + uint32 v; + uint8* p8 = (uint8*)&v; + p8[0] = c.b; + p8[1] = c.g; + p8[2] = c.r; + p8[3] = 255; + // row offset as 32bit pointer + uint32* p32 = (uint32*)(buffer->row(y)) + x; + do { + *p32 = v; + p32++; + x++; + } while(--len); + } else { + uint8* p = buffer->row(y) + (x << 2); + if (len < 4) { + do { + BLEND_ALPHA_CO(p, c.r, c.g, c.b, alpha); + x++; + p += 4; + } while(--len); + } else { + alpha = alpha >> 8; + blend_line32(p, len, c.r, c.g, c.b, alpha); + } + } +} + +// blend_solid_hspan_alpha_co_solid +void +blend_solid_hspan_alpha_co_solid(int x, int y, unsigned len, + const color_type& c, const uint8* covers, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint8* p = buffer->row(y) + (x << 2); + uint8 hAlpha = pattern->HighColor().GetColor32().alpha; + do { + uint16 alpha = hAlpha * *covers; + if (alpha) { + if (alpha == 255 * 255) { + ASSIGN_ALPHA_CO(p, c.r, c.g, c.b); + } else { + BLEND_ALPHA_CO(p, c.r, c.g, c.b, alpha); + } + } + covers++; + p += 4; + x++; + } while(--len); +} + + + +// blend_solid_vspan_alpha_co_solid +void +blend_solid_vspan_alpha_co_solid(int x, int y, unsigned len, + const color_type& c, const uint8* covers, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint8* p = buffer->row(y) + (x << 2); + uint8 hAlpha = pattern->HighColor().GetColor32().alpha; + do { + uint16 alpha = hAlpha * *covers; + if (alpha) { + if (alpha == 255 * 255) { + ASSIGN_ALPHA_CO(p, c.r, c.g, c.b); + } else { + BLEND_ALPHA_CO(p, c.r, c.g, c.b, alpha); + } + } + covers++; + p += buffer->stride(); + y++; + } while(--len); +} + +#endif // DRAWING_MODE_ALPHA_CO_SOLID_H + diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h new file mode 100644 index 0000000000..8f269dd781 --- /dev/null +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeAlphaPOSolid.h @@ -0,0 +1,112 @@ +/* + * Copyright 2005, Stephan Aßmus . All rights reserved. + * Distributed under the terms of the MIT License. + * + * DrawingMode implementing B_OP_ALPHA in "Constant Overlay" mode on B_RGBA32. + * + */ + +#ifndef DRAWING_MODE_ALPHA_PO_SOLID_H +#define DRAWING_MODE_ALPHA_PO_SOLID_H + +#include "DrawingModeAlphaPO.h" + +// blend_pixel_alpha_po_solid +void +blend_pixel_alpha_po_solid(int x, int y, const color_type& c, uint8 cover, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint8* p = buffer->row(y) + (x << 2); + uint16 alpha = c.a * cover; + if (alpha == 255 * 255) { + ASSIGN_ALPHA_PO(p, c.r, c.g, c.b); + } else { + BLEND_ALPHA_PO(p, c.r, c.g, c.b, alpha); + } +} + +// blend_hline_alpha_po_solid +void +blend_hline_alpha_po_solid(int x, int y, unsigned len, + const color_type& c, uint8 cover, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint16 alpha = c.a * cover; + if (alpha == 255 * 255) { + // cache the color as 32bit values + uint32 v; + uint8* p8 = (uint8*)&v; + p8[0] = c.b; + p8[1] = c.g; + p8[2] = c.r; + p8[3] = 255; + // row offset as 32bit pointer + uint32* p32 = (uint32*)(buffer->row(y)) + x; + do { + *p32 = v; + p32++; + x++; + } while(--len); + } else { + uint8* p = buffer->row(y) + (x << 2); + if (len < 4) { + do { + BLEND_ALPHA_CO(p, c.r, c.g, c.b, alpha); + x++; + p += 4; + } while(--len); + } else { + alpha = alpha >> 8; + blend_line32(p, len, c.r, c.g, c.b, alpha); + } + } +} + +// blend_solid_hspan_alpha_po_solid +void +blend_solid_hspan_alpha_po_solid(int x, int y, unsigned len, + const color_type& c, const uint8* covers, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint8* p = buffer->row(y) + (x << 2); + do { + uint16 alpha = c.a * *covers; + if (alpha) { + if(alpha == 255 * 255) { + ASSIGN_ALPHA_PO(p, c.r, c.g, c.b); + } else { + BLEND_ALPHA_PO(p, c.r, c.g, c.b, alpha); + } + } + covers++; + p += 4; + x++; + } while(--len); +} + + + +// blend_solid_vspan_alpha_po_solid +void +blend_solid_vspan_alpha_po_solid(int x, int y, unsigned len, + const color_type& c, const uint8* covers, + agg_buffer* buffer, const PatternHandler* pattern) +{ + uint8* p = buffer->row(y) + (x << 2); + do { + uint16 alpha = c.a * *covers; + if (alpha) { + if (alpha == 255 * 255) { + ASSIGN_ALPHA_PO(p, c.r, c.g, c.b); + } else { + BLEND_ALPHA_PO(p, c.r, c.g, c.b, alpha); + } + } + covers++; + p += buffer->stride(); + y++; + } while(--len); +} + +#endif // DRAWING_MODE_ALPHA_PO_SOLID_H + diff --git a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeCopySolid.h b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeCopySolid.h index b1a4170526..8e1789d829 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/DrawingModeCopySolid.h +++ b/src/servers/app/drawing/Painter/drawing_modes/DrawingModeCopySolid.h @@ -32,7 +32,7 @@ blend_hline_copy_solid(int x, int y, unsigned len, const color_type& c, uint8 cover, agg_buffer* buffer, const PatternHandler* pattern) { - if(cover == 255) { + if (cover == 255) { // cache the color as 32bit value uint32 v; uint8* p8 = (uint8*)&v; diff --git a/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp b/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp index dd4d1b44cc..cd16c77cc0 100644 --- a/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp +++ b/src/servers/app/drawing/Painter/drawing_modes/PixelFormat.cpp @@ -17,8 +17,10 @@ #include "DrawingModeAdd.h" #include "DrawingModeAlphaCC.h" #include "DrawingModeAlphaCO.h" +#include "DrawingModeAlphaCOSolid.h" #include "DrawingModeAlphaPC.h" #include "DrawingModeAlphaPO.h" +#include "DrawingModeAlphaPOSolid.h" #include "DrawingModeBlend.h" #include "DrawingModeCopy.h" #include "DrawingModeCopySolid.h" @@ -230,10 +232,17 @@ PixelFormat::SetDrawingMode(drawing_mode mode, source_alpha alphaSrcMode, case B_OP_ALPHA: if (alphaSrcMode == B_CONSTANT_ALPHA) { if (alphaFncMode == B_ALPHA_OVERLAY) { - fBlendPixel = blend_pixel_alpha_co; - fBlendHLine = blend_hline_alpha_co; - fBlendSolidHSpan = blend_solid_hspan_alpha_co; - fBlendSolidVSpan = blend_solid_vspan_alpha_co; + if (fPatternHandler->IsSolid()) { + fBlendPixel = blend_pixel_alpha_co_solid; + fBlendHLine = blend_hline_alpha_co_solid; + fBlendSolidHSpan = blend_solid_hspan_alpha_co_solid; + fBlendSolidVSpan = blend_solid_vspan_alpha_co_solid; + } else { + fBlendPixel = blend_pixel_alpha_co; + fBlendHLine = blend_hline_alpha_co; + fBlendSolidHSpan = blend_solid_hspan_alpha_co; + fBlendSolidVSpan = blend_solid_vspan_alpha_co; + } fBlendColorHSpan = blend_color_hspan_alpha_co; } else if (alphaFncMode == B_ALPHA_COMPOSITE) { fBlendPixel = blend_pixel_alpha_cc; @@ -244,10 +253,17 @@ PixelFormat::SetDrawingMode(drawing_mode mode, source_alpha alphaSrcMode, } } else if (alphaSrcMode == B_PIXEL_ALPHA){ if (alphaFncMode == B_ALPHA_OVERLAY) { - fBlendPixel = blend_pixel_alpha_po; - fBlendHLine = blend_hline_alpha_po; - fBlendSolidHSpan = blend_solid_hspan_alpha_po; - fBlendSolidVSpan = blend_solid_vspan_alpha_po; + if (fPatternHandler->IsSolid()) { + fBlendPixel = blend_pixel_alpha_po_solid; + fBlendHLine = blend_hline_alpha_po_solid; + fBlendSolidHSpan = blend_solid_hspan_alpha_po_solid; + fBlendSolidVSpan = blend_solid_vspan_alpha_po_solid; + } else { + fBlendPixel = blend_pixel_alpha_po; + fBlendHLine = blend_hline_alpha_po; + fBlendSolidHSpan = blend_solid_hspan_alpha_po; + fBlendSolidVSpan = blend_solid_vspan_alpha_po; + } fBlendColorHSpan = blend_color_hspan_alpha_po; } else if (alphaFncMode == B_ALPHA_COMPOSITE) { fBlendPixel = blend_pixel_alpha_pc; diff --git a/src/servers/app/drawing/frame_buffer_support.h b/src/servers/app/drawing/frame_buffer_support.h new file mode 100644 index 0000000000..8fcb038451 --- /dev/null +++ b/src/servers/app/drawing/frame_buffer_support.h @@ -0,0 +1,127 @@ +//------------------------------------------------------------------------------ +// Copyright 2005, Haiku, Inc. All rights reserved. +// Distributed under the terms of the MIT License. +// +// Author: Stephan Aßmus, +//------------------------------------------------------------------------------ + +#ifndef SUPPORT_H +#define SUPPORT_H + +#include + +// gfxcpy +static inline void +gfxcpy(uint8* dst, uint8* src, int32 numBytes) +{ + uint64* d64 = (uint64*)dst; + uint64* s64 = (uint64*)src; + int32 numBytesBegin = numBytes; + while (numBytes >= 32) { + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 32; + } + while (numBytes >= 16) { + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 16; + } + while (numBytes >= 8) { + *d64++ = *s64++; + numBytes -= 8; + } + if (numBytes > 0) { + // update original pointers + dst += numBytesBegin - numBytes; + src += numBytesBegin - numBytes; + numBytesBegin = numBytes; + + uint32* d32 = (uint32*)dst; + uint32* s32 = (uint32*)src; + while (numBytes >= 4) { + *d32++ = *s32++; + numBytes -= 4; + } + // update original pointers + dst += numBytesBegin - numBytes; + src += numBytesBegin - numBytes; + + while (numBytes > 0) { + *dst++ = *src++; + numBytes--; + } + } +} + +// gfxcpy32 +// * numBytes is expected to be a multiple of 4 +static inline void +gfxcpy32(uint8* dst, uint8* src, int32 numBytes) +{ + uint64* d64 = (uint64*)dst; + uint64* s64 = (uint64*)src; + int32 numBytesStart = numBytes; + while (numBytes >= 32) { + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 32; + } + if (numBytes >= 16) { + *d64++ = *s64++; + *d64++ = *s64++; + numBytes -= 16; + } + if (numBytes >= 8) { + *d64++ = *s64++; + numBytes -= 8; + } + if (numBytes == 4) { + uint32* d32 = (uint32*)(dst + numBytesStart - numBytes); + uint32* s32 = (uint32*)(src + numBytesStart - numBytes); + *d32 = *s32; + } +} + +union pixel32 { + uint32 data32; + uint8 data8[4]; +}; + +// blend_line32 +static inline void +blend_line32(uint8* buffer, int32 pixels, uint8 r, uint8 g, uint8 b, uint8 a) +{ + pixel32 p; + + r = (r * a) >> 8; + g = (g * a) >> 8; + b = (b * a) >> 8; + a = 255 - a; + + uint8 tempBuffer[pixels * 4]; + + uint8* t = tempBuffer; + uint8* s = buffer; + + for (int32 i = 0; i < pixels; i++) { + p.data32 = *(uint32*)s; + + t[0] = ((p.data8[0] * a) >> 8) + b; + t[1] = ((p.data8[1] * a) >> 8) + g; + t[2] = ((p.data8[2] * a) >> 8) + r; + + t += 4; + s += 4; + } + + gfxcpy32(buffer, tempBuffer, pixels * 4); +} + +#endif // SUPPORT_H + +