* 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
This commit is contained in:
@@ -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, <[email protected]>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <agg_span_image_filter_rgba32.h>
|
||||
#include <agg_span_interpolator_linear.h>
|
||||
|
||||
#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<class VertexSource>
|
||||
@@ -1465,7 +1524,11 @@ Painter::_StrokePath(VertexSource& path) const
|
||||
agg::conv_clip_polygon<agg::conv_stroke<VertexSource> > 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<VertexSource> 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));
|
||||
}
|
||||
|
||||
@@ -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<class VertexSource>
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -13,12 +13,11 @@
|
||||
#include <agg_rasterizer_outline.h>
|
||||
#include <agg_rasterizer_outline_aa.h>
|
||||
#include <agg_rasterizer_scanline_aa.h>
|
||||
//#include <agg_renderer_mclip.h>
|
||||
#include <agg_renderer_outline_aa.h>
|
||||
#include <agg_renderer_primitives.h>
|
||||
#include <agg_renderer_scanline.h>
|
||||
#include <agg_scanline_bin.h>
|
||||
//#include <agg_scanline_p.h>
|
||||
#include <agg_scanline_p.h>
|
||||
#include <agg_scanline_u.h>
|
||||
#include <agg_rendering_buffer.h>
|
||||
|
||||
@@ -35,14 +34,16 @@
|
||||
typedef agg::renderer_primitives<renderer_base> outline_renderer_type;
|
||||
typedef agg::rasterizer_outline<outline_renderer_type> 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_base> renderer_type;
|
||||
#else
|
||||
typedef agg::renderer_outline_aa<renderer_base> outline_renderer_type;
|
||||
typedef agg::rasterizer_outline_aa<outline_renderer_type> 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_base> renderer_type;
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2005, Stephan Aßmus <superstippi@gmx.de>. 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
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2005, Stephan Aßmus <superstippi@gmx.de>. 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright 2005, Haiku, Inc. All rights reserved.
|
||||
// Distributed under the terms of the MIT License.
|
||||
//
|
||||
// Author: Stephan Aßmus, <[email protected]>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef SUPPORT_H
|
||||
#define SUPPORT_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user