//------------------------------------------------------------------------------ // Copyright (c) 2001-2005, Haiku, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // // File Name: DisplayDriverPainter.cpp // Author: Stephan Aßmus // Description: Implementation of DisplayDriver based on top of Painter // //------------------------------------------------------------------------------ #include #include #include #include "LayerData.h" #include "Painter.h" #include "PNGDump.h" #include "RenderingBuffer.h" #ifdef __HAIKU__ #define USE_ACCELERANT 1 #else #define USE_ACCELERANT 0 #endif #if USE_ACCELERANT #include "AccelerantHWInterface.h" #else #include "ViewHWInterface.h" #endif #include "DisplayDriverPainter.h" // constructor DisplayDriverPainter::DisplayDriverPainter() : DisplayDriver(), fPainter(new Painter()), #if USE_ACCELERANT fGraphicsCard(new AccelerantHWInterface()), #else fGraphicsCard(new ViewHWInterface()), #endif fAvailableHWAccleration(0) { } // destructor DisplayDriverPainter::~DisplayDriverPainter() { delete fGraphicsCard; } // Initialize bool DisplayDriverPainter::Initialize() { status_t err = fGraphicsCard->Initialize(); if (err < B_OK) fprintf(stderr, "HWInterface::Initialize() failed: %s\n", strerror(err)); if (err >= B_OK) { fAvailableHWAccleration = fGraphicsCard->AvailableHWAcceleration(); return DisplayDriver::Initialize(); } return false; } // Shutdown void DisplayDriverPainter::Shutdown() { DisplayDriver::Shutdown(); } // ConstrainClippingRegion void DisplayDriverPainter::ConstrainClippingRegion(BRegion *region) { if (Lock()) { if (!region) { // BRegion empty; // fPainter->ConstrainClipping(empty); if (RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer()) { BRegion all; all.Include(BRect(0, 0, buffer->Width() - 1, buffer->Height() - 1)); fPainter->ConstrainClipping(all); } } else { fPainter->ConstrainClipping(*region); } Unlock(); } } // CopyRegion() does a topological sort of the rects in the // region. The algorithm was suggested by Ingo Weinhold. // It compares each rect with each rect and builds a tree // of successors so we know the order in which they can be copied. // For example, let's suppose these rects are in a BRegion: // ************ // * B * // ************ // ************* // * * // * A **************** // * ** * // ************** * // * C * // * * // * * // *************** // When copying stuff from LEFT TO RIGHT, TOP TO BOTTOM, the // result of the sort will be C, A, B. For this direction, we search // for the rects that have no neighbors to their right and to their // bottom, These can be copied without drawing into the area of // rects yet to be copied. If you move from RIGHT TO LEFT, BOTTOM TO TOP, // you go look for the ones that have no neighbors to their top and left. // // Here I draw some rays to illustrate LEFT TO RIGHT, TOP TO BOTTOM: // ************ // * B * // ************ // ************* // * * // * A ****************----------------- // * ** * // ************** * // * C * // * * // * * // *************** // | // | // | // | // There are no rects in the area defined by the rays to the right // and bottom of rect C, so that's the one we want to copy first // (for positive x and y offsets). // Since A is to the left of C and B is to the top of C, The "node" // for C will point to the nodes of A and B as its "successors". Therefor, // A and B will have an "indegree" of 1 for C pointing to them. C will // have and "indegree" of 0, because there was no rect to which C // was to the left or top of. When comparing A and B, neither is left // or top from the other and in the sense that the algorithm cares about. // NOTE: comparisson of coordinates assumes that rects don't overlap // and don't share the actual edge either (as is the case in BRegions). struct node { node() { pointers = NULL; } node(const BRect& r, int32 maxPointers) { init(r, maxPointers); } ~node() { delete [] pointers; } void init(const BRect& r, int32 maxPointers) { rect = r; pointers = new node*[maxPointers]; in_degree = 0; next_pointer = 0; } void push(node* node) { pointers[next_pointer] = node; next_pointer++; } node* top() { return pointers[next_pointer]; } node* pop() { node* ret = top(); next_pointer--; return ret; } BRect rect; int32 in_degree; node** pointers; int32 next_pointer; }; bool is_left_of(const BRect& a, const BRect& b) { return (a.right < b.left); } bool is_above(const BRect& a, const BRect& b) { return (a.bottom < b.top); } // CopyRegion void DisplayDriverPainter::CopyRegion(/*const*/ BRegion* region, int32 xOffset, int32 yOffset) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(region->Frame()); int32 count = region->CountRects(); // TODO: make this step unnecessary // (by using different stack impl inside node) node nodes[count]; for (int32 i= 0; i < count; i++) { nodes[i].init(region->RectAt(i), count); } for (int32 i = 0; i < count; i++) { BRect a = region->RectAt(i); for (int32 k = i + 1; k < count; k++) { BRect b = region->RectAt(k); int cmp = 0; // compare horizontally if (xOffset > 0) { if (is_left_of(a, b)) { cmp -= 1; } else if (is_left_of(b, a)) { cmp += 1; } } else if (xOffset < 0) { if (is_left_of(a, b)) { cmp += 1; } else if (is_left_of(b, a)) { cmp -= 1; } } // compare vertically if (yOffset > 0) { if (is_above(a, b)) { cmp -= 1; } else if (is_above(b, a)) { cmp += 1; } } else if (yOffset < 0) { if (is_above(a, b)) { cmp += 1; } else if (is_above(b, a)) { cmp -= 1; } } // add appropriate node as successor if (cmp > 0) { nodes[i].push(&nodes[k]); nodes[k].in_degree++; } else if (cmp < 0) { nodes[k].push(&nodes[i]); nodes[i].in_degree++; } } } // put all nodes onto a stack that have an "indegree" count of zero stack inDegreeZeroNodes; for (int32 i = 0; i < count; i++) { if (nodes[i].in_degree == 0) { inDegreeZeroNodes.push(&nodes[i]); } } // pop the rects from the stack, do the actual copy operation // and decrease the "indegree" count of the other rects not // currently on the stack and to which the current rect pointed // to. If their "indegree" count reaches zero, put them onto the // stack as well. clipping_rect* sortedRectList = NULL; int32 nextSortedIndex = 0; if (fAvailableHWAccleration & HW_ACC_COPY_REGION) sortedRectList = new clipping_rect[count]; while (!inDegreeZeroNodes.empty()) { node* n = inDegreeZeroNodes.top(); inDegreeZeroNodes.pop(); // do the software implementation or add to sorted // rect list for using the HW accelerated version // later if (sortedRectList) { sortedRectList[nextSortedIndex].left = (int32)n->rect.left; sortedRectList[nextSortedIndex].top = (int32)n->rect.top; sortedRectList[nextSortedIndex].right = (int32)n->rect.right; sortedRectList[nextSortedIndex].bottom = (int32)n->rect.bottom; nextSortedIndex++; } else { BRect touched = _CopyRect(n->rect, xOffset, yOffset); fGraphicsCard->Invalidate(touched); } for (int32 k = 0; k < n->next_pointer; k++) { n->pointers[k]->in_degree--; if (n->pointers[k]->in_degree == 0) inDegreeZeroNodes.push(n->pointers[k]); } } // trigger the HW accelerated version if is was available if (sortedRectList) fGraphicsCard->CopyRegion(sortedRectList, count, xOffset, yOffset); delete[] sortedRectList; fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // CopyRegionList // // * used to move windows arround on screen // TODO: Since the regions are passed to CopyRegion() one by one, // the case of different regions overlapping each other at source // and/or dest locations is not handled. // We also don't handle the case where multiple regions should have // been combined into one larger region (with effectively the same // rects), so that the sorting would compare them all at once. If // this turns out to be a problem, we can easily rewrite the function // here. In any case, to copy overlapping regions in app_server doesn't // make much sense to me. void DisplayDriverPainter::CopyRegionList(BList* list, BList* pList, int32 rCount, BRegion* clipReg) { if (Lock()) { for (int32 i = 0; i < rCount; i++) { BRegion* region = (BRegion*)list->ItemAt(i); BPoint* offset = (BPoint*)pList->ItemAt(i); CopyRegion(region, (int32)offset->x, (int32)offset->y); } Unlock(); } } // InvertRect void DisplayDriverPainter::InvertRect(const BRect &r) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(fPainter->ClipRect(r)); BRect touched = fPainter->InvertRect(r); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // DrawBitmap void DisplayDriverPainter::DrawBitmap(ServerBitmap *bitmap, const BRect &source, const BRect &dest, const DrawData *d) { if (Lock()) { BRect clipped = fPainter->ClipRect(dest); fGraphicsCard->HideSoftwareCursor(clipped); fPainter->SetDrawData(d); BRect touched = fPainter->DrawBitmap(bitmap, source, dest); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillArc void DisplayDriverPainter::FillArc(const BRect &r, const float &angle, const float &span, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); float xRadius = r.Width() / 2.0; float yRadius = r.Width() / 2.0; BPoint center(r.left + xRadius, r.top + yRadius); BRect touched = fPainter->FillArc(center, xRadius, yRadius, angle, span); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillBezier void DisplayDriverPainter::FillBezier(BPoint *pts, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->FillBezier(pts); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillEllipse void DisplayDriverPainter::FillEllipse(const BRect &r, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); float xRadius = r.Width() / 2.0; float yRadius = r.Height() / 2.0; BPoint center(r.left + xRadius, r.top + yRadius); BRect touched = fPainter->FillEllipse(center, xRadius, yRadius); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillPolygon void DisplayDriverPainter::FillPolygon(BPoint *ptlist, int32 numpts, const BRect &bounds, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->FillPolygon(ptlist, numpts); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillRect void DisplayDriverPainter::FillRect(const BRect& r, const RGBColor& color) { if (Lock()) { BRect vr(min_c(r.left, r.right), min_c(r.top, r.bottom), max_c(r.left, r.right), max_c(r.top, r.bottom)); vr = fPainter->ClipRect(vr); if (vr.IsValid()) { fGraphicsCard->HideSoftwareCursor(vr); // try hardware optimized version first if (fAvailableHWAccleration & HW_ACC_FILL_REGION) { BRegion region(vr); region.IntersectWith(fPainter->ClippingRegion()); fGraphicsCard->FillRegion(region, color); } else { fPainter->FillRect(vr, color.GetColor32()); fGraphicsCard->Invalidate(vr); } fGraphicsCard->ShowSoftwareCursor(); } Unlock(); } } // FillRect void DisplayDriverPainter::FillRect(const BRect &r, const DrawData *d) { if (Lock()) { BRect vr(min_c(r.left, r.right), min_c(r.top, r.bottom), max_c(r.left, r.right), max_c(r.top, r.bottom)); vr = fPainter->ClipRect(vr); if (vr.IsValid()) { fGraphicsCard->HideSoftwareCursor(vr); bool doInSoftware = true; // try hardware optimized version first if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) && (d->GetDrawingMode() == B_OP_COPY || d->GetDrawingMode() == B_OP_OVER)) { if (d->GetPattern() == B_SOLID_HIGH) { BRegion region(vr); region.IntersectWith(fPainter->ClippingRegion()); fGraphicsCard->FillRegion(region, d->HighColor()); doInSoftware = false; } else if (d->GetPattern() == B_SOLID_LOW) { BRegion region(vr); region.IntersectWith(fPainter->ClippingRegion()); fGraphicsCard->FillRegion(region, d->LowColor()); doInSoftware = false; } } if (doInSoftware) { fPainter->SetDrawData(d); BRect touched = fPainter->FillRect(vr); fGraphicsCard->Invalidate(touched); } fGraphicsCard->ShowSoftwareCursor(); } Unlock(); } } // FillRegion void DisplayDriverPainter::FillRegion(BRegion& r, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(fPainter->ClipRect(r.Frame())); bool doInSoftware = true; // try hardware optimized version first if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) && (d->GetDrawingMode() == B_OP_COPY || d->GetDrawingMode() == B_OP_OVER)) { if (d->GetPattern() == B_SOLID_HIGH) { fGraphicsCard->FillRegion(r, d->HighColor()); doInSoftware = false; } else if (d->GetPattern() == B_SOLID_LOW) { fGraphicsCard->FillRegion(r, d->LowColor()); doInSoftware = false; } } if (doInSoftware) { fPainter->SetDrawData(d); BRect touched = fPainter->FillRect(r.RectAt(0)); int32 count = r.CountRects(); for (int32 i = 1; i < count; i++) { touched = touched | fPainter->FillRect(r.RectAt(i)); } fGraphicsCard->Invalidate(touched); } fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillRoundRect void DisplayDriverPainter::FillRoundRect(const BRect &r, const float &xrad, const float &yrad, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->FillRoundRect(r, xrad, yrad); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // FillShape void DisplayDriverPainter::FillShape(const BRect &bounds, const int32 &opcount, const int32 *oplist, const int32 &ptcount, const BPoint *ptlist, const DrawData *d) { if (Lock()) { printf("DisplayDriverPainter::FillShape() - what is this stuff that gets passed here?\n"); Unlock(); } } // FillTriangle void DisplayDriverPainter::FillTriangle(BPoint *pts, const BRect &bounds, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->FillTriangle(pts[0], pts[1], pts[2]); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeArc void DisplayDriverPainter::StrokeArc(const BRect &r, const float &angle, const float &span, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); float xRadius = r.Width() / 2.0; float yRadius = r.Width() / 2.0; BPoint center(r.left + xRadius, r.top + yRadius); BRect touched = fPainter->StrokeArc(center, xRadius, yRadius, angle, span); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeBezier void DisplayDriverPainter::StrokeBezier(BPoint *pts, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->StrokeBezier(pts); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeEllipse void DisplayDriverPainter::StrokeEllipse(const BRect &r, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); float xRadius = r.Width() / 2.0; float yRadius = r.Height() / 2.0; BPoint center(r.left + xRadius, r.top + yRadius); BRect touched = fPainter->StrokeEllipse(center, xRadius, yRadius); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeLine // // * this function is only used by Decorators // * it assumes a one pixel wide line void DisplayDriverPainter::StrokeLine(const BPoint &start, const BPoint &end, const RGBColor &color) { if (Lock()) { BRect touched(min_c(start.x, end.x), min_c(start.y, end.y), max_c(start.x, end.x), max_c(start.y, end.y)); touched = fPainter->ClipRect(touched); fGraphicsCard->HideSoftwareCursor(touched); if (!fPainter->StraightLine(start, end, color.GetColor32())) { static DrawData context; context.SetHighColor(color); context.SetDrawingMode(B_OP_OVER); StrokeLine(start, end, &context); } else { fGraphicsCard->Invalidate(touched); } fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeLine void DisplayDriverPainter::StrokeLine(const BPoint &start, const BPoint &end, DrawData* context) { if (Lock()) { BRect touched(min_c(start.x, end.x), min_c(start.y, end.y), max_c(start.x, end.x), max_c(start.y, end.y)); touched = fPainter->ClipRect(touched); fGraphicsCard->HideSoftwareCursor(touched); touched = fPainter->StrokeLine(start, end, context); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeLineArray void DisplayDriverPainter::StrokeLineArray(const int32 &numlines, const LineArrayData *linedata, const DrawData *d) { if(!d || !linedata || numlines <= 0) return; if (Lock()) { fGraphicsCard->HideSoftwareCursor(); DrawData context; context.SetDrawingMode(B_OP_COPY); const LineArrayData *data; data = (const LineArrayData *)&(linedata[0]); context.SetHighColor(data->color); BRect touched = fPainter->StrokeLine(data->pt1, data->pt2, &context); for (int32 i = 1; i < numlines; i++) { data = (const LineArrayData *)&(linedata[i]); context.SetHighColor(data->color); touched = touched | fPainter->StrokeLine(data->pt1, data->pt2, &context); } fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokePoint // // * this function is only used by Decorators void DisplayDriverPainter::StrokePoint(const BPoint& pt, const RGBColor &color) { StrokeLine(pt, pt, color); } // StrokePoint void DisplayDriverPainter::StrokePoint(const BPoint& pt, DrawData *context) { StrokeLine(pt, pt, context); } // StrokePolygon void DisplayDriverPainter::StrokePolygon(BPoint *ptlist, int32 numpts, const BRect &bounds, const DrawData *d, bool closed) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->StrokePolygon(ptlist, numpts, closed); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeRect // // this function is used to draw a one pixel wide rect void DisplayDriverPainter::StrokeRect(const BRect &r, const RGBColor &color) { if (Lock()) { // support invalid rects BRect vr(min_c(r.left, r.right), min_c(r.top, r.bottom), max_c(r.left, r.right), max_c(r.top, r.bottom)); fGraphicsCard->HideSoftwareCursor(vr); fPainter->StrokeRect(vr, color.GetColor32()); /* fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(vr.left, vr.top, vr.right, vr.top))); fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(vr.left, vr.top + 1, vr.left, vr.bottom - 1))); fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(vr.right, vr.top + 1, vr.right, vr.bottom - 1))); fGraphicsCard->Invalidate(fPainter->ClipRect(BRect(vr.left, vr.bottom, vr.right, vr.bottom)));*/ fGraphicsCard->Invalidate(fPainter->ClipRect(vr)); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeRect void DisplayDriverPainter::StrokeRect(const BRect &r, const DrawData *d) { if (Lock()) { // support invalid rects BRect vr(min_c(r.left, r.right), min_c(r.top, r.bottom), max_c(r.left, r.right), max_c(r.top, r.bottom)); float extend = -ceilf(d->PenSize() / 2.0); vr.InsetBy(extend, extend); fGraphicsCard->HideSoftwareCursor(vr); fPainter->SetDrawData(d); BRect touched = fPainter->StrokeRect(r); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeRegion void DisplayDriverPainter::StrokeRegion(BRegion& r, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->StrokeRect(r.RectAt(0)); int32 count = r.CountRects(); for (int32 i = 1; i < count; i++) { touched = touched | fPainter->StrokeRect(r.RectAt(i)); } fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeRoundRect void DisplayDriverPainter::StrokeRoundRect(const BRect &r, const float &xrad, const float &yrad, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->StrokeRoundRect(r, xrad, yrad); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // StrokeShape void DisplayDriverPainter::StrokeShape(const BRect &bounds, const int32 &opcount, const int32 *oplist, const int32 &ptcount, const BPoint *ptlist, const DrawData *d) { if (Lock()) { printf("DisplayDriverPainter::StrokeShape() - what is this stuff that gets passed here?\n"); Unlock(); } } // StrokeTriangle void DisplayDriverPainter::StrokeTriangle(BPoint *pts, const BRect &bounds, const DrawData *d) { if (Lock()) { fGraphicsCard->HideSoftwareCursor(); fPainter->SetDrawData(d); BRect touched = fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); Unlock(); } } // DrawString void DisplayDriverPainter::DrawString(const char *string, const int32 &length, const BPoint &pt, const RGBColor &color, escapement_delta *delta) { static DrawData d; d.SetHighColor(color); // TODO: Why is escapement_delta a part of the state stack? if (delta) d.SetEscapementDelta(*delta); DrawString(string, length, pt, &d); } // DrawString void DisplayDriverPainter::DrawString(const char *string, const int32 &length, const BPoint &pt, DrawData *d) { if (Lock()) { fPainter->SetDrawData(d); //bigtime_t now = system_time(); // TODO: BoundingBox is quite slow!! Optimizing it will be beneficial. // Cursiously, the DrawString after it is actually faster!?! // TODO: make the availability of the hardware cursor part of the // HW acceleration flags and skip all calculations for HideSoftwareCursor // in case we don't have one. BRect b = fPainter->BoundingBox(string, length, pt); // stop here if we're supposed to render outside of the clipping if (fPainter->ClippingRegion()->Frame().Intersects(b)) { //printf("bounding box '%s': %lld µs\n", string, system_time() - now); fGraphicsCard->HideSoftwareCursor(b); //now = system_time(); BRect touched = fPainter->DrawString(string, length, pt); //printf("drawing string: %lld µs\n", system_time() - now); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); } Unlock(); } } // StringWidth float DisplayDriverPainter::StringWidth(const char *string, int32 length, const DrawData *d) { float width = 0.0; if (Lock()) { fPainter->SetDrawData(d); width = fPainter->StringWidth(string, length); Unlock(); } return width; } // StringWidth float DisplayDriverPainter::StringWidth(const char *string, int32 length, const ServerFont &font) { static DrawData d; d.SetFont(font); return StringWidth(string, length, &d); } // StringHeight float DisplayDriverPainter::StringHeight(const char *string, int32 length, const DrawData *d) { float height = 0.0; if (Lock()) { fPainter->SetDrawData(d); static BPoint dummy(0.0, 0.0); height = fPainter->BoundingBox(string, length, dummy).Height(); Unlock(); } return height; } // GetBoundingBoxes void DisplayDriverPainter::GetBoundingBoxes(const char *string, int32 count, font_metric_mode mode, escapement_delta *delta, BRect *rectarray, const DrawData *d) { // ?!? each glyph or what? printf("DisplayDriverPainter::GetBoundingBoxes()\n"); } // GetEscapements void DisplayDriverPainter::GetEscapements(const char *string, int32 charcount, escapement_delta *delta, escapement_delta *escapements, escapement_delta *offsets, const DrawData *d) { printf("DisplayDriverPainter::GetEscapements()\n"); } // GetEdges void DisplayDriverPainter::GetEdges(const char *string, int32 charcount, edge_info *edgearray, const DrawData *d) { printf("DisplayDriverPainter::GetEdges()\n"); } // GetHasGlyphs void DisplayDriverPainter::GetHasGlyphs(const char *string, int32 charcount, bool *hasarray) { printf("DisplayDriverPainter::GetHasGlyphs()\n"); } // GetTruncatedStrings void DisplayDriverPainter::GetTruncatedStrings(const char **instrings, const int32 &stringcount, const uint32 &mode, const float &maxwidth, char **outstrings) { printf("DisplayDriverPainter::GetTruncatedStrings()\n"); } // HideCursor void DisplayDriverPainter::HideCursor() { fGraphicsCard->SetCursorVisible(false); } // IsCursorHidden bool DisplayDriverPainter::IsCursorHidden() { return !fGraphicsCard->IsCursorVisible(); } // MoveCursorTo void DisplayDriverPainter::MoveCursorTo(const float &x, const float &y) { fGraphicsCard->MoveCursorTo(x, y); } // ShowCursor void DisplayDriverPainter::ShowCursor() { fGraphicsCard->SetCursorVisible(true); } // ObscureCursor void DisplayDriverPainter::ObscureCursor() { // TODO: I don't think this has anything to do with the DisplayDriver // implement elsewhere!! } // SetCursor void DisplayDriverPainter::SetCursor(ServerCursor *cursor) { fGraphicsCard->SetCursor(cursor); } // GetCursorPosition BPoint DisplayDriverPainter::GetCursorPosition() { return fGraphicsCard->GetCursorPosition(); } // IsCursorObscured bool DisplayDriverPainter::IsCursorObscured(bool state) { // TODO: I don't think this has anything to do with the DisplayDriver // implement elsewhere!! return false; } // Lock bool DisplayDriverPainter::Lock(bigtime_t timeout) { bool success = false; // NOTE: I'm hoping I don't change the semantics and implications of // the original implementation, but I need the locker to be somewhere // else in order to serialize only the access to the back buffer if (timeout == B_INFINITE_TIMEOUT) { success = fGraphicsCard->Lock(); //printf("DisplayDriverPainter::Lock()\n"); } else { success = (fGraphicsCard->LockWithTimeout(timeout) >= B_OK) ? true : false; //printf("DisplayDriverPainter::LockWithTimeout(): %d\n", success); } return success; } // Unlock void DisplayDriverPainter::Unlock() { //printf("DisplayDriverPainter::Unlock()\n"); fGraphicsCard->Unlock(); } // SetMode void DisplayDriverPainter::SetMode(const display_mode &mode) { if (Lock()) { if (fGraphicsCard->SetMode(mode) >= B_OK) { fPainter->AttachToBuffer(fGraphicsCard->DrawingBuffer()); DisplayDriver::SetMode(mode); } else { fprintf(stderr, "DisplayDriverPainter::SetMode() - unsupported " "mode!\n"); } Unlock(); } } // DumpToFile bool DisplayDriverPainter::DumpToFile(const char *path) { if (Lock()) { RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); if (buffer) { BRect bounds(0.0, 0.0, buffer->Width() - 1, buffer->Height() - 1); // TODO: Don't assume B_RGBA32!! SaveToPNG(path, bounds, B_RGBA32, buffer->Bits(), buffer->BitsLength(), buffer->BytesPerRow()); } Unlock(); } return true; } // DumpToBitmap ServerBitmap* DisplayDriverPainter::DumpToBitmap() { return NULL; } // SetDPMSMode status_t DisplayDriverPainter::SetDPMSMode(const uint32 &state) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->SetDPMSMode(state); Unlock(); } return ret; } // DPMSMode uint32 DisplayDriverPainter::DPMSMode() { uint32 mode = 0; if (Lock()) { mode = fGraphicsCard->DPMSMode(); Unlock(); } return mode; } // DPMSCapabilities uint32 DisplayDriverPainter::DPMSCapabilities() { uint32 caps = 0; if (Lock()) { caps = fGraphicsCard->DPMSMode(); Unlock(); } return caps; } // GetDeviceInfo status_t DisplayDriverPainter::GetDeviceInfo(accelerant_device_info *info) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->GetDeviceInfo(info); Unlock(); } return ret; } // GetModeList status_t DisplayDriverPainter::GetModeList(display_mode **mode_list, uint32 *count) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->GetModeList(mode_list, count); Unlock(); } return ret; } // GetPixelClockLimits status_t DisplayDriverPainter::GetPixelClockLimits(display_mode *mode, uint32 *low, uint32 *high) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->GetPixelClockLimits(mode, low, high); Unlock(); } return ret; } // GetTimingConstraints status_t DisplayDriverPainter::GetTimingConstraints(display_timing_constraints *dtc) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->GetTimingConstraints(dtc); Unlock(); } return ret; } // ProposeMode status_t DisplayDriverPainter::ProposeMode(display_mode *candidate, const display_mode *low, const display_mode *high) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->ProposeMode(candidate, low, high); Unlock(); } return ret; } // WaitForRetrace status_t DisplayDriverPainter::WaitForRetrace(bigtime_t timeout) { status_t ret = B_ERROR; if (Lock()) { ret = fGraphicsCard->WaitForRetrace(timeout); Unlock(); } return ret; } // _CopyRect BRect DisplayDriverPainter::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const { BRect dst; RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); if (buffer) { BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); dst = src; dst.OffsetBy(xOffset, yOffset); if (clip.Intersects(src) && clip.Intersects(dst)) { uint32 bpr = buffer->BytesPerRow(); uint8* bits = (uint8*)buffer->Bits(); // clip source rect src = src & clip; // clip dest rect dst = dst & clip; // move dest back over source and clip source to dest dst.OffsetBy(-xOffset, -yOffset); src = src & dst; // calc offset in buffer bits += (int32)src.left * 4 + (int32)src.top * bpr; uint32 width = src.IntegerWidth() + 1; uint32 height = src.IntegerHeight() + 1; _CopyRect(bits, width, height, bpr, xOffset, yOffset); // offset dest again, because it is return value dst.OffsetBy(xOffset, yOffset); } } return dst; } // _CopyRect void DisplayDriverPainter::_CopyRect(uint8* src, uint32 width, uint32 height, uint32 bpr, int32 xOffset, int32 yOffset) const { int32 xIncrement; int32 yIncrement; if (xOffset > 0) { // copy from right to left xIncrement = -1; src += (width - 1) * 4; } else { // copy from left to right xIncrement = 1; } if (yOffset > 0) { // copy from bottom to top yIncrement = -bpr; src += (height - 1) * bpr; } else { // copy from top to bottom yIncrement = bpr; } uint8* dst = src + yOffset * bpr + xOffset * 4; for (uint32 y = 0; y < height; y++) { uint32* srcHandle = (uint32*)src; uint32* dstHandle = (uint32*)dst; for (uint32 x = 0; x < width; x++) { *dstHandle = *srcHandle; srcHandle += xIncrement; dstHandle += xIncrement; } src += yIncrement; dst += yIncrement; } }