* 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:
Stephan Aßmus
2005-12-28 19:53:00 +00:00
parent 22bc93e31c
commit f5b6cf65b2
11 changed files with 472 additions and 111 deletions
+8 -81
View File
@@ -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
+1
View File
@@ -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 ;
+73 -10
View File
@@ -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));
}
+5 -2
View File
@@ -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;
+5 -4
View File
@@ -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