From 9ed4e691c8bf05895384822eea04db409d324acc Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 3 May 2007 02:52:40 +0000 Subject: [PATCH] delay creation of Windows GDI regions as long as possible, to avoid overruning the GDI limit svn: r6122 --- src/mred/mred.cxx | 2 +- src/mred/wxs/wxscheme.cxx | 4 + src/wxcommon/Region.cxx | 142 +++++++++++++++--- src/wxcommon/Region.h | 12 +- src/wxwindow/src/base/wb_gdi.cxx | 247 +++++++++++++++++++++++++++++++ src/wxwindow/src/msw/wx_dc.cxx | 30 ++-- 6 files changed, 398 insertions(+), 39 deletions(-) diff --git a/src/mred/mred.cxx b/src/mred/mred.cxx index 1e027f432c..0c892513ef 100644 --- a/src/mred/mred.cxx +++ b/src/mred/mred.cxx @@ -3662,7 +3662,7 @@ int wxHiEventTrampoline(int (*_wha_f)(void *), void *wha_data) if (het->in_progress) { /* We have leftover work; jump and finish it (non-atomically). - But don't swap until we've juped back in, because the jump-in + But don't swap until we've jumped back in, because the jump-in point might be trying to suspend the thread (and that should complete before any swap). */ scheme_end_atomic_no_swap(); diff --git a/src/mred/wxs/wxscheme.cxx b/src/mred/wxs/wxscheme.cxx index 4525a0bb40..d074489746 100644 --- a/src/mred/wxs/wxscheme.cxx +++ b/src/mred/wxs/wxscheme.cxx @@ -53,6 +53,7 @@ #ifdef wx_msw # include "wx_pdf.h" +extern void wx_release_lazy_regions(); #endif #include @@ -250,6 +251,9 @@ START_XFORM_SKIP; static void collect_start_callback(void) { +#ifdef wx_msw + wx_release_lazy_regions(); +#endif draw_gc_bm(1); orig_collect_start_callback(); } diff --git a/src/wxcommon/Region.cxx b/src/wxcommon/Region.cxx index 3640ac738c..dc44743583 100644 --- a/src/wxcommon/Region.cxx +++ b/src/wxcommon/Region.cxx @@ -38,6 +38,8 @@ typedef struct { typedef int cairo_matrix_p; #endif +/**************************************************************************/ + wxRegion::wxRegion(wxDC *_dc, wxRegion *r, Bool _no_prgn) { dc = _dc; @@ -45,7 +47,7 @@ wxRegion::wxRegion(wxDC *_dc, wxRegion *r, Bool _no_prgn) locked = 0; #ifdef wx_msw - rgn = NULL; + lazy_rgn = NULL; #endif #ifdef wx_x rgn = NULL; @@ -66,9 +68,10 @@ wxRegion::~wxRegion() void wxRegion::Cleanup() { #ifdef wx_msw - if (rgn) { - DeleteObject(rgn); - rgn = NULL; + if (lazy_rgn) { + if (real_rgn) + lazy_rgn->DoneRgn(real_rgn); + lazy_rgn = NULL; } #endif #ifdef wx_x @@ -88,6 +91,35 @@ void wxRegion::Cleanup() } } +void wxRegion::Lock(int delta) +{ +#ifdef wx_msw + if (!locked) { + if (lazy_rgn) { + real_rgn = lazy_rgn->GetRgn(); + } + } +#endif + + locked += delta; + +#ifdef wx_msw + if (!locked) { + if (lazy_rgn) { + lazy_rgn->DoneRgn(real_rgn); + real_rgn = NULL; + } + } +#endif +} + +#ifdef wx_msw +HRGN wxRegion::GetRgn() +{ + return real_rgn; +} +#endif + void wxRegion::SetRectangle(double x, double y, double width, double height) { double xw, yh; @@ -120,7 +152,7 @@ void wxRegion::SetRectangle(double x, double y, double width, double height) ih = ((int)floor(y + height)) - iy; #ifdef wx_msw - rgn = CreateRectRgn(ix, iy, ix + iw, iy + ih); + lazy_rgn = new RectLazyRgn(ix, iy, iw, ih); #endif #ifdef wx_x { @@ -217,7 +249,7 @@ void wxRegion::SetRoundedRectangle(double x, double y, double width, double heig } # ifdef wx_msw - rgn = CreateRoundRectRgn(ix, iy, ix + iw, iy + ih, xradius, yradius); + lazy_rgn = new RoundRectLazyRgn(ix, iy, iw, ih, xradius, yradius); # endif # ifdef wx_mac /* This code uses the current port. We don't know what the current @@ -290,7 +322,7 @@ void wxRegion::SetEllipse(double x, double y, double width, double height) #endif #ifdef wx_msw - rgn = CreateEllipticRgn(ix, iy, ix + iw, iy + ih); + lazy_rgn = new EllipticLazyRgn(ix, iy, iw, ih); #endif #ifdef wx_mac /* This code uses the current port. We don't know what the current @@ -375,7 +407,7 @@ void wxRegion::SetPolygon(int n, wxPoint points[], double xoffset, double yoffse } #ifdef wx_msw - rgn = CreatePolygonRgn(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? ALTERNATE : WINDING); + lazy_rgn = new PolygonLazyRgn(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? ALTERNATE : WINDING); #endif #ifdef wx_x rgn = XPolygonRegion(cpoints, n, (fillStyle == wxODDEVEN_RULE) ? EvenOddRule : WindingRule); @@ -648,11 +680,13 @@ void wxRegion::Union(wxRegion *r) } #ifdef wx_msw - if (!rgn) { - rgn = CreateRectRgn(0, 0, 1, 1); - CombineRgn(rgn, r->rgn, rgn, RGN_COPY); - } else - CombineRgn(rgn, r->rgn, rgn, RGN_OR); + if (!lazy_rgn) { + lazy_rgn = r->lazy_rgn; + } else if (!r->lazy_rgn) { + /* no change */ + } else { + lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_OR); + } #endif #ifdef wx_x if (!rgn) { @@ -684,8 +718,13 @@ void wxRegion::Intersect(wxRegion *r) } #ifdef wx_msw - if (!rgn) return; - CombineRgn(rgn, r->rgn, rgn, RGN_AND); + if (!lazy_rgn) return; + if (!r->lazy_rgn) { + lazy_rgn = NULL; + return; + } + + lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_AND); #endif #ifdef wx_x if (!rgn) return; @@ -716,8 +755,12 @@ void wxRegion::Subtract(wxRegion *r) } #ifdef wx_msw - if (!rgn) return; - CombineRgn(rgn, rgn, r->rgn, RGN_DIFF); + if (!lazy_rgn) return; + if (!r->lazy_rgn) { + /* No change */ + return; + } + lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_DIFF); #endif #ifdef wx_x if (!rgn) return; @@ -750,8 +793,12 @@ void wxRegion::Xor(wxRegion *r) } #ifdef wx_msw - if (!rgn) return; - CombineRgn(rgn, rgn, r->rgn, RGN_XOR); + if (!lazy_rgn) return; + if (!r->lazy_rgn) { + return; + } + + lazy_rgn = new UnionLazyRgn(lazy_rgn, r->lazy_rgn, RGN_XOR); #endif #ifdef wx_x if (!rgn) return; @@ -777,8 +824,21 @@ void wxRegion::BoundingBox(double *x, double *y, double *w, double *h) double v; #ifdef wx_msw RECT r; + HRGN rgn; - GetRgnBox(rgn, &r); + if (real_rgn) + rgn = real_rgn; + else + rgn = lazy_rgn->GetRgn(); + + if (rgn) + GetRgnBox(rgn, &r); + else { + r.left = r.top = r.right = r.bottom = 0; + } + + if (!real_rgn) + lazy_rgn->DoneRgn(rgn); *x = r.left; *y = r.top; @@ -826,9 +886,25 @@ Bool wxRegion::Empty() { #ifdef wx_msw RECT r; - if (!rgn) return TRUE; + HRGN rgn; + Bool is_empty; - return (GetRgnBox(rgn, &r) == NULLREGION); + if (!lazy_rgn) return TRUE; + + if (real_rgn) + rgn = real_rgn; + else + rgn = lazy_rgn->GetRgn(); + + if (!rgn) + is_empty = 1; + else + is_empty = (GetRgnBox(rgn, &r) == NULLREGION); + + if (!real_rgn) + lazy_rgn->DoneRgn(rgn); + + return is_empty; #endif #ifdef wx_x if (!rgn) return TRUE; @@ -849,7 +925,7 @@ Bool wxRegion::IsInRegion(double x, double y) { int ix, iy; - if (!rgn) return FALSE; + if (Empty()) return FALSE; x = dc->FLogicalToUnscrolledDeviceX(x); y = dc->FLogicalToUnscrolledDeviceY(y); @@ -862,7 +938,25 @@ Bool wxRegion::IsInRegion(double x, double y) return XPointInRegion(rgn, ix, iy); #endif #ifdef wx_msw - return PtInRegion(rgn, ix, iy); + { + HRGN rgn; + Bool in_rgn; + + if (real_rgn) + rgn = real_rgn; + else + rgn = lazy_rgn->GetRgn(); + + if (rgn) + in_rgn = PtInRegion(rgn, ix, iy); + else + in_rgn = 0; + + if (!real_rgn) + lazy_rgn->DoneRgn(rgn); + + return in_rgn; + } #endif #ifdef wx_mac { diff --git a/src/wxcommon/Region.h b/src/wxcommon/Region.h index 8896bf04de..ee1940dab7 100644 --- a/src/wxcommon/Region.h +++ b/src/wxcommon/Region.h @@ -41,12 +41,17 @@ typedef void *XtRegion; class wxPathRgn; class wxPath; +#ifdef wx_msw +class LazyRgn; +#endif class wxRegion : public wxObject { public: #ifdef wx_msw - HRGN rgn; + LazyRgn *lazy_rgn; + HRGN real_rgn; + HRGN GetRgn(); #endif #ifdef wx_x XtRegion rgn; @@ -56,12 +61,15 @@ class wxRegion : public wxObject #endif wxPathRgn *prgn; wxDC *dc; - char is_ps, locked, no_prgn; + char is_ps, no_prgn; + int locked; wxRegion(wxDC *dc, wxRegion *r = NULL, Bool no_prgn = FALSE); ~wxRegion(); inline wxDC *GetDC() { return dc; } + + void Lock(int v); void SetRectangle(double x, double y, double width, double height); void SetRoundedRectangle(double x, double y, double width, double height, double radius = 20.0); diff --git a/src/wxwindow/src/base/wb_gdi.cxx b/src/wxwindow/src/base/wb_gdi.cxx index 310a3be76e..8eddca345a 100644 --- a/src/wxwindow/src/base/wb_gdi.cxx +++ b/src/wxwindow/src/base/wb_gdi.cxx @@ -704,6 +704,253 @@ wxIntPoint::~wxIntPoint (void) { } +/**************************************************************************/ + #include "../../../wxcommon/FontDirectory.cxx" +/**************************************************************************/ + +#ifdef wx_msw + +class LazyRgn : public wxObject { +public: + int used_refcount; + HRGN cached_rgn, used_rgn; + LazyRgn *lazy_cache_prev, *lazy_cache_next; + + LazyRgn(); + HRGN GetRgn(); + virtual HRGN DetatchRgn(HRGN rgn); + virtual void DoneRgn(HRGN rgn); + virtual HRGN ToRegion(); + + void Chain(); + void Unchain(); +}; + +static LazyRgn *lazy_rgn_cache; +int lazy_cache_count; +#define MAX_CACHE_SIZE 100 + +LazyRgn::LazyRgn() : wxObject(WXGC_NO_CLEANUP) { } + +HRGN LazyRgn::DetatchRgn(HRGN rgn) +{ + if (rgn) { + HRGN rgn2; + + rgn2 = CreateRectRgn(0, 0, 1, 1); + CombineRgn(rgn2, rgn, rgn2, RGN_COPY); + + DoneRgn(rgn); + + return rgn2; + } else { + DoneRgn(rgn); + return NULL; + } +} + +void LazyRgn::DoneRgn(HRGN rgn) +{ + if (rgn && (rgn == used_rgn)) { + --used_refcount; + if (!used_refcount) { + used_rgn = NULL; + if (rgn) { + cached_rgn = rgn; + if (lazy_cache_count >= MAX_CACHE_SIZE) { + LazyRgn *l; + for (l = lazy_rgn_cache; l->lazy_cache_next; l = l->lazy_cache_next) { } + l->Unchain(); + DeleteObject(l->cached_rgn); + l->cached_rgn = NULL; + } + Chain(); + } + } + } else { + if (rgn) + DeleteObject(rgn); + } +} + +HRGN LazyRgn::GetRgn() +{ + if (used_rgn) { + } else if (cached_rgn) { + used_rgn = cached_rgn; + Unchain(); + cached_rgn = NULL; + } else { + used_rgn = ToRegion(); + } + + if (used_rgn) + used_refcount++; + + return used_rgn; +} + +HRGN LazyRgn::ToRegion() { return NULL; } + +void LazyRgn::Chain() +{ + lazy_cache_next = lazy_rgn_cache; + lazy_cache_prev = NULL; + lazy_rgn_cache = this; + if (lazy_cache_next) + lazy_cache_next->lazy_cache_prev = this; + lazy_cache_count++; +} + +void LazyRgn::Unchain() +{ + if (lazy_cache_next) + lazy_cache_next->lazy_cache_prev = lazy_cache_prev; + if (lazy_cache_prev) + lazy_cache_prev->lazy_cache_next = lazy_cache_next; + else + lazy_rgn_cache = lazy_cache_next; + --lazy_cache_count; +} + +#ifdef MZ_PRECISE_GC +START_XFORM_SKIP; +#endif + +void wx_release_lazy_regions(void) +{ + LazyRgn *l; + for (l = lazy_rgn_cache; l; l = l->lazy_cache_next) { + DeleteObject(l->cached_rgn); + l->cached_rgn = NULL; + } + lazy_rgn_cache = NULL; + lazy_cache_count = 0; +} + +#ifdef MZ_PRECISE_GC +END_XFORM_SKIP; +#endif + +/* - - - - - - - - - - - - - - - - - - */ + +class RectLazyRgn : public LazyRgn { +public: + int ix, iy, iw, ih; + RectLazyRgn(int _ix, int _iy, int _iw, int _ih); + virtual HRGN ToRegion(); +}; + +RectLazyRgn::RectLazyRgn(int _ix, int _iy, int _iw, int _ih) { + ix = _ix; + iy = _iy; + iw = _iw; + ih = _ih; +} + +HRGN RectLazyRgn::ToRegion() +{ + return CreateRectRgn(ix, iy, ix + iw, iy + ih); +} + +/* - - - - - - - - - - - - - - - - - - */ + +class RoundRectLazyRgn : public LazyRgn { +public: + int ix, iy, iw, ih, xradius, yradius; + RoundRectLazyRgn(int _ix, int _iy, int _iw, int _ih, int _xr, int _yr); + virtual HRGN ToRegion(); +}; + +RoundRectLazyRgn::RoundRectLazyRgn(int _ix, int _iy, int _iw, int _ih, int _xradius, int _yradius) { + ix = _ix; + iy = _iy; + iw = _iw; + ih = _ih; + xradius = _xradius; + yradius = _yradius; +} + +HRGN RoundRectLazyRgn::ToRegion() +{ + return CreateRoundRectRgn(ix, iy, ix + iw, iy + ih, xradius, yradius); +} + +/* - - - - - - - - - - - - - - - - - - */ + +class EllipticLazyRgn : public LazyRgn { +public: + int ix, iy, iw, ih; + EllipticLazyRgn(int _ix, int _iy, int _iw, int _ih); + virtual HRGN ToRegion(); +}; + +EllipticLazyRgn::EllipticLazyRgn(int _ix, int _iy, int _iw, int _ih) { + ix = _ix; + iy = _iy; + iw = _iw; + ih = _ih; +} + +HRGN EllipticLazyRgn::ToRegion() +{ + return CreateEllipticRgn(ix, iy, ix + iw, iy + ih); +} + +/* - - - - - - - - - - - - - - - - - - */ + +class PolygonLazyRgn : public LazyRgn { +public: + POINT *cpoints; + int n, mode; + PolygonLazyRgn(POINT *_cpoints, int _n, int _mode); + virtual HRGN ToRegion(); +}; + +PolygonLazyRgn::PolygonLazyRgn(POINT *_cpoints, int _n, int _mode) +{ + cpoints = _cpoints; + n = _n; + mode = _mode; +} + +HRGN PolygonLazyRgn::ToRegion() +{ + return CreatePolygonRgn(cpoints, n, mode); +} + +/* - - - - - - - - - - - - - - - - - - */ + +class UnionLazyRgn : public LazyRgn { +public: + LazyRgn *a, *b; + int mode; + UnionLazyRgn(LazyRgn *_a, LazyRgn *_b, int _mode); + virtual HRGN ToRegion(); +}; + +UnionLazyRgn::UnionLazyRgn(LazyRgn *_a, LazyRgn *_b, int _mode) +{ + a = _a; + b = _b; + mode = _mode; +} + +HRGN UnionLazyRgn::ToRegion() +{ + HRGN ar, br; + ar = a->GetRgn(); + br = b->GetRgn(); + ar = a->DetatchRgn(ar); + CombineRgn(ar, ar, br, mode); + b->DoneRgn(br); + return ar; +} + +#endif + +/**************************************************************************/ + #include "../../../wxcommon/Region.cxx" diff --git a/src/wxwindow/src/msw/wx_dc.cxx b/src/wxwindow/src/msw/wx_dc.cxx index 3801c3f8e1..46e8553546 100644 --- a/src/wxwindow/src/msw/wx_dc.cxx +++ b/src/wxwindow/src/msw/wx_dc.cxx @@ -153,7 +153,7 @@ wxDC::~wxDC(void) if (current_pen) current_pen->Lock(-1); if (current_brush) current_brush->Lock(-1); - if (clipping) --clipping->locked; + if (clipping) clipping->Lock(-1); if (filename) delete[] filename; @@ -417,25 +417,27 @@ void wxDC::SetClippingRegion(wxRegion *c) if (c && (c->dc != this)) return; if (clipping) - --clipping->locked; + clipping->Lock(-1); clipping = c; if (clipping) - clipping->locked++; + clipping->Lock(1); dc = ThisDC(FALSE); if (dc) DoClipping(dc); DoneDC(dc); } -static HRGN empty_rgn; +static HRGN empty_rgn, full_rgn; void wxDC::DoClipping(HDC dc) { if (clipping) { - if (clipping->rgn) { - SelectClipRgn(dc, clipping->rgn); + HRGN rgn; + rgn = clipping->GetRgn(); + if (rgn) { + SelectClipRgn(dc, rgn); OffsetClipRgn(dc, canvas_scroll_dx, canvas_scroll_dy); } else { if (!empty_rgn) @@ -443,10 +445,9 @@ void wxDC::DoClipping(HDC dc) SelectClipRgn(dc, empty_rgn); } } else { - HRGN rgn; - rgn = CreateRectRgn(0, 0, 32000, 32000); - SelectClipRgn(dc, rgn); - DeleteObject(rgn); + if (!full_rgn) + full_rgn = CreateRectRgn(0, 0, 32000, 32000); + SelectClipRgn(dc, full_rgn); } } @@ -1204,8 +1205,13 @@ void wxDC::DrawPath(wxPath *p, double xoffset, double yoffset,int fillStyle) k += j; } - if (clipping && clipping->rgn) - CombineRgn(rgn, clipping->rgn, rgn, RGN_AND); + if (clipping) { + HRGN crgn; + crgn = clipping->GetRgn(); + if (crgn) { + CombineRgn(rgn, crgn, rgn, RGN_AND); + } + } SelectClipRgn(dc, rgn);