chore(deps): pin cef2gtk dmabuf churn
- commit
- 94546f0ee3810084d5588fabd7481b1aabb9136a
- author
- brice · · 2026-07-14 16:10 UTC
- parent
- c5ad8c0
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
6 files · +165 -127
M go.mod +1 -1
| @@ -7,7 +7,7 @@ require ( | |||
| 7 | 7 | github.com/andybalholm/brotli v1.2.2 | |
| 8 | 8 | github.com/bnema/purego v0.11.0-bnema.4 | |
| 9 | 9 | github.com/bnema/purego-cef v0.13.4-0.20260714140305-f0b7414af67e | |
| 10 | - | github.com/bnema/purego-cef2gtk v0.8.4 | |
| 10 | + | github.com/bnema/purego-cef2gtk v0.8.4-0.20260714160309-bbd397409ebe | |
| 11 | 11 | github.com/bnema/purego-pipewire v0.1.5-0.20260714124450-6504b9cdf02a | |
| 12 | 12 | github.com/bnema/purego-sqlite v0.1.4-0.20260714131321-3614fe683b9c | |
| 13 | 13 | github.com/bnema/puregotk v0.7.0 | |
| @@ -7,7 +7,7 @@ require ( | |||||
| 7 | github.com/andybalholm/brotli v1.2.2 | 7 | github.com/andybalholm/brotli v1.2.2 | ||
| 8 | github.com/bnema/purego v0.11.0-bnema.4 | 8 | github.com/bnema/purego v0.11.0-bnema.4 | ||
| 9 | github.com/bnema/purego-cef v0.13.4-0.20260714140305-f0b7414af67e | 9 | github.com/bnema/purego-cef v0.13.4-0.20260714140305-f0b7414af67e | ||
| 10 | - | github.com/bnema/purego-cef2gtk v0.8.4 | 10 | + | github.com/bnema/purego-cef2gtk v0.8.4-0.20260714160309-bbd397409ebe |
| 11 | github.com/bnema/purego-pipewire v0.1.5-0.20260714124450-6504b9cdf02a | 11 | github.com/bnema/purego-pipewire v0.1.5-0.20260714124450-6504b9cdf02a | ||
| 12 | github.com/bnema/purego-sqlite v0.1.4-0.20260714131321-3614fe683b9c | 12 | github.com/bnema/purego-sqlite v0.1.4-0.20260714131321-3614fe683b9c | ||
| 13 | github.com/bnema/puregotk v0.7.0 | 13 | github.com/bnema/puregotk v0.7.0 | ||
M go.sum +2 -0 generated file: collapsed
M vendor/github.com/bnema/purego-cef2gtk/internal/cefadapter/accelerated_paint.go +34 -37 generated file: collapsed
M vendor/github.com/bnema/purego-cef2gtk/internal/dmabuf/frame.go +38 -19 generated file: collapsed
M vendor/github.com/bnema/purego-cef2gtk/internal/gtkgdk/renderer.go +89 -69
| @@ -96,29 +96,10 @@ type ownedFrame struct { | |||
| 96 | 96 | SourceSize dmabuf.Size | |
| 97 | 97 | Format dmabuf.FourCC | |
| 98 | 98 | Modifier uint64 | |
| 99 | - | Planes []ownedPlane | |
| 99 | + | Plane ownedPlane | |
| 100 | 100 | onError func(error) | |
| 101 | 101 | } | |
| 102 | 102 | ||
| 103 | - | func (f *ownedFrame) borrowed() dmabuf.BorrowedFrame { | |
| 104 | - | if f == nil { | |
| 105 | - | return dmabuf.BorrowedFrame{} | |
| 106 | - | } | |
| 107 | - | planes := make([]dmabuf.Plane, len(f.Planes)) | |
| 108 | - | for i, plane := range f.Planes { | |
| 109 | - | planes[i] = dmabuf.Plane{FD: plane.FD, Stride: plane.Stride, Offset: plane.Offset, Size: plane.Size} | |
| 110 | - | } | |
| 111 | - | return dmabuf.BorrowedFrame{ | |
| 112 | - | CodedSize: f.CodedSize, | |
| 113 | - | VisibleRect: f.VisibleRect, | |
| 114 | - | ContentRect: f.ContentRect, | |
| 115 | - | SourceSize: f.SourceSize, | |
| 116 | - | Format: f.Format, | |
| 117 | - | Modifier: f.Modifier, | |
| 118 | - | Planes: planes, | |
| 119 | - | } | |
| 120 | - | } | |
| 121 | - | ||
| 122 | 103 | // Renderer owns a GtkPicture presenter and imports callback-scoped CEF DMABUFs | |
| 123 | 104 | // as GdkDmabufTexture instances. The initial implementation supports only | |
| 124 | 105 | // single-plane RGB frames. Duplicated FDs are handed to GTK with a native | |
| @@ -132,7 +113,9 @@ type Renderer struct { | |||
| 132 | 113 | formats dmabufFormatSet | |
| 133 | 114 | builder dmabufTextureBuilder | |
| 134 | 115 | current *ownedTexture | |
| 135 | - | retired []*ownedTexture | |
| 116 | + | retired [retiredTextureLimit]*ownedTexture | |
| 117 | + | retiredStart int | |
| 118 | + | retiredCount int | |
| 136 | 119 | pictureSetPaintable func(*gdk.Texture) | |
| 137 | 120 | firstTextureSwapMu sync.Mutex | |
| 138 | 121 | firstTextureSwap func() | |
| @@ -367,11 +350,11 @@ func (r *Renderer) ImportAndQueueAsync(info *cef.AcceleratedPaintInfo, onError f | |||
| 367 | 350 | if r == nil { | |
| 368 | 351 | return ErrNilRenderer | |
| 369 | 352 | } | |
| 370 | - | frame, err := cefadapter.BorrowedFrameFromAcceleratedPaint(info) | |
| 353 | + | frame, err := cefadapter.SinglePlaneFrameFromAcceleratedPaint(info) | |
| 371 | 354 | if err != nil { | |
| 372 | 355 | return err | |
| 373 | 356 | } | |
| 374 | - | owned, err := r.duplicateFrame(frame) | |
| 357 | + | owned, err := r.duplicateSinglePlaneFrame(frame) | |
| 375 | 358 | if err != nil { | |
| 376 | 359 | return err | |
| 377 | 360 | } | |
| @@ -385,11 +368,11 @@ func (r *Renderer) ImportAndQueueAsync(info *cef.AcceleratedPaintInfo, onError f | |||
| 385 | 368 | // on the GTK main loop. | |
| 386 | 369 | func (r *Renderer) ImportAndQueueOnGTKThread(info *cef.AcceleratedPaintInfo) (queued gtkgl.QueuedFrame, retErr error) { | |
| 387 | 370 | start := time.Now() | |
| 388 | - | frame, err := cefadapter.BorrowedFrameFromAcceleratedPaint(info) | |
| 371 | + | frame, err := cefadapter.SinglePlaneFrameFromAcceleratedPaint(info) | |
| 389 | 372 | if err != nil { | |
| 390 | 373 | return gtkgl.QueuedFrame{}, err | |
| 391 | 374 | } | |
| 392 | - | owned, err := r.duplicateFrame(frame) | |
| 375 | + | owned, err := r.duplicateSinglePlaneFrame(frame) | |
| 393 | 376 | if err != nil { | |
| 394 | 377 | return gtkgl.QueuedFrame{}, err | |
| 395 | 378 | } | |
| @@ -535,7 +518,24 @@ func (r *Renderer) importAndSwapOwnedFrame(frame *ownedFrame) error { | |||
| 535 | 518 | return nil | |
| 536 | 519 | } | |
| 537 | 520 | ||
| 538 | - | func (r *Renderer) duplicateFrame(frame dmabuf.BorrowedFrame) (_ *ownedFrame, retErr error) { | |
| 521 | + | // duplicateFrame keeps the slice-backed compatibility path for callers outside | |
| 522 | + | // the GDK import hot path. | |
| 523 | + | func (r *Renderer) duplicateFrame(frame dmabuf.BorrowedFrame) (*ownedFrame, error) { | |
| 524 | + | if err := frame.Validate(); err != nil { | |
| 525 | + | return nil, err | |
| 526 | + | } | |
| 527 | + | return r.duplicateSinglePlaneFrame(dmabuf.SinglePlaneFrame{ | |
| 528 | + | CodedSize: frame.CodedSize, | |
| 529 | + | VisibleRect: frame.VisibleRect, | |
| 530 | + | ContentRect: frame.ContentRect, | |
| 531 | + | SourceSize: frame.SourceSize, | |
| 532 | + | Format: frame.Format, | |
| 533 | + | Modifier: frame.Modifier, | |
| 534 | + | Plane: frame.Planes[0], | |
| 535 | + | }) | |
| 536 | + | } | |
| 537 | + | ||
| 538 | + | func (r *Renderer) duplicateSinglePlaneFrame(frame dmabuf.SinglePlaneFrame) (_ *ownedFrame, retErr error) { | |
| 539 | 539 | if r == nil { | |
| 540 | 540 | return nil, ErrNilRenderer | |
| 541 | 541 | } | |
| @@ -553,24 +553,19 @@ func (r *Renderer) duplicateFrame(frame dmabuf.BorrowedFrame) (_ *ownedFrame, re | |||
| 553 | 553 | SourceSize: frame.SourceSize, | |
| 554 | 554 | Format: frame.Format, | |
| 555 | 555 | Modifier: frame.Modifier, | |
| 556 | - | Planes: make([]ownedPlane, len(frame.Planes)), | |
| 557 | - | } | |
| 558 | - | for i := range owned.Planes { | |
| 559 | - | owned.Planes[i].FD = -1 | |
| 556 | + | Plane: ownedPlane{FD: -1}, | |
| 560 | 557 | } | |
| 561 | 558 | defer func() { | |
| 562 | 559 | if retErr != nil { | |
| 563 | 560 | r.releaseOwnedFrame(owned) | |
| 564 | 561 | } | |
| 565 | 562 | }() | |
| 566 | - | for i, plane := range frame.Planes { | |
| 567 | - | ownedFD, err := dup(plane.FD) | |
| 568 | - | if err != nil { | |
| 569 | - | r.recordFDDupFailure() | |
| 570 | - | return nil, err | |
| 571 | - | } | |
| 572 | - | owned.Planes[i] = ownedPlane{FD: ownedFD, Stride: plane.Stride, Offset: plane.Offset, Size: plane.Size} | |
| 563 | + | ownedFD, err := dup(frame.Plane.FD) | |
| 564 | + | if err != nil { | |
| 565 | + | r.recordFDDupFailure() | |
| 566 | + | return nil, err | |
| 573 | 567 | } | |
| 568 | + | owned.Plane = ownedPlane{FD: ownedFD, Stride: frame.Plane.Stride, Offset: frame.Plane.Offset, Size: frame.Plane.Size} | |
| 574 | 569 | return owned, nil | |
| 575 | 570 | } | |
| 576 | 571 | ||
| @@ -584,27 +579,26 @@ func (r *Renderer) buildTextureFromOwnedFrame(frame *ownedFrame) (built *ownedTe | |||
| 584 | 579 | if frame == nil { | |
| 585 | 580 | return nil, dmabuf.ErrInvalidPlaneFD | |
| 586 | 581 | } | |
| 587 | - | borrowed := frame.borrowed() | |
| 588 | - | if err := borrowed.Validate(); err != nil { | |
| 582 | + | if err := frame.validate(); err != nil { | |
| 589 | 583 | return nil, err | |
| 590 | 584 | } | |
| 591 | - | gdkFormat := gdkTextureFormat(borrowed.Format) | |
| 592 | - | if r.formats != nil && !r.formats.Contains(uint32(gdkFormat), borrowed.Modifier) { | |
| 585 | + | gdkFormat := gdkTextureFormat(frame.Format) | |
| 586 | + | if r.formats != nil && !r.formats.Contains(uint32(gdkFormat), frame.Modifier) { | |
| 593 | 587 | r.recordUnsupportedFormat() | |
| 594 | - | return nil, fmt.Errorf("%w: %s as %s modifier 0x%x", ErrUnsupportedFormat, borrowed.Format, gdkFormat, borrowed.Modifier) | |
| 588 | + | return nil, fmt.Errorf("%w: %s as %s modifier 0x%x", ErrUnsupportedFormat, frame.Format, gdkFormat, frame.Modifier) | |
| 595 | 589 | } | |
| 596 | - | r.traceFrame(borrowed, gdkFormat) | |
| 590 | + | r.traceFrame(frame, gdkFormat) | |
| 597 | 591 | closeFD := r.closeFD | |
| 598 | 592 | if closeFD == nil { | |
| 599 | 593 | closeFD = unix.Close | |
| 600 | 594 | } | |
| 601 | 595 | ||
| 602 | - | ownedFD := borrowed.Planes[0].FD | |
| 596 | + | ownedFD := frame.Plane.FD | |
| 603 | 597 | textureOwnsFD := false | |
| 604 | 598 | defer func() { | |
| 605 | 599 | if !textureOwnsFD { | |
| 606 | 600 | _ = closeFD(ownedFD) | |
| 607 | - | frame.Planes[0].FD = -1 | |
| 601 | + | frame.Plane.FD = -1 | |
| 608 | 602 | } | |
| 609 | 603 | }() | |
| 610 | 604 | destroyNotify, destroyNotifyErr := resolveDestroyNotify() | |
| @@ -613,11 +607,11 @@ func (r *Renderer) buildTextureFromOwnedFrame(frame *ownedFrame) (built *ownedTe | |||
| 613 | 607 | return nil, fmt.Errorf("%w: native close GDestroyNotify unavailable: %w", ErrTextureBuildFailed, destroyNotifyErr) | |
| 614 | 608 | } | |
| 615 | 609 | ||
| 616 | - | plane := borrowed.Planes[0] | |
| 617 | - | r.builder.SetWidth(uint(borrowed.CodedSize.Width)) | |
| 618 | - | r.builder.SetHeight(uint(borrowed.CodedSize.Height)) | |
| 610 | + | plane := frame.Plane | |
| 611 | + | r.builder.SetWidth(uint(frame.CodedSize.Width)) | |
| 612 | + | r.builder.SetHeight(uint(frame.CodedSize.Height)) | |
| 619 | 613 | r.builder.SetFourcc(uint32(gdkFormat)) | |
| 620 | - | r.builder.SetModifier(borrowed.Modifier) | |
| 614 | + | r.builder.SetModifier(frame.Modifier) | |
| 621 | 615 | r.builder.SetPremultiplied(false) | |
| 622 | 616 | r.builder.SetNPlanes(1) | |
| 623 | 617 | if r.display != nil { | |
| @@ -653,9 +647,9 @@ func (r *Renderer) buildTextureFromOwnedFrame(frame *ownedFrame) (built *ownedTe | |||
| 653 | 647 | return nil, ErrTextureBuildFailed | |
| 654 | 648 | } | |
| 655 | 649 | textureOwnsFD = true | |
| 656 | - | frame.Planes[0].FD = -1 | |
| 650 | + | frame.Plane.FD = -1 | |
| 657 | 651 | r.recordTextureBuilt() | |
| 658 | - | r.traceTexturePresent(borrowed, gdkFormat, texture) | |
| 652 | + | r.traceTexturePresent(frame, gdkFormat, texture) | |
| 659 | 653 | return &ownedTexture{texture: texture}, nil | |
| 660 | 654 | } | |
| 661 | 655 | ||
| @@ -698,6 +692,22 @@ func (r *Renderer) releaseOwnedFrame(frame *ownedFrame) { | |||
| 698 | 692 | closeOwnedFrame(frame, closeFD) | |
| 699 | 693 | } | |
| 700 | 694 | ||
| 695 | + | func (f *ownedFrame) validate() error { | |
| 696 | + | if f == nil { | |
| 697 | + | return dmabuf.ErrInvalidPlaneFD | |
| 698 | + | } | |
| 699 | + | return (dmabuf.SinglePlaneFrame{ | |
| 700 | + | CodedSize: f.CodedSize, | |
| 701 | + | Format: f.Format, | |
| 702 | + | Plane: dmabuf.Plane{ | |
| 703 | + | FD: f.Plane.FD, | |
| 704 | + | Stride: f.Plane.Stride, | |
| 705 | + | Offset: f.Plane.Offset, | |
| 706 | + | Size: f.Plane.Size, | |
| 707 | + | }, | |
| 708 | + | }).Validate() | |
| 709 | + | } | |
| 710 | + | ||
| 701 | 711 | func closeOwnedFrame(frame *ownedFrame, closeFD func(int) error) { | |
| 702 | 712 | if frame == nil { | |
| 703 | 713 | return | |
| @@ -705,11 +715,9 @@ func closeOwnedFrame(frame *ownedFrame, closeFD func(int) error) { | |||
| 705 | 715 | if closeFD == nil { | |
| 706 | 716 | closeFD = unix.Close | |
| 707 | 717 | } | |
| 708 | - | for i := range frame.Planes { | |
| 709 | - | if frame.Planes[i].FD >= 0 { | |
| 710 | - | _ = closeFD(frame.Planes[i].FD) | |
| 711 | - | frame.Planes[i].FD = -1 | |
| 712 | - | } | |
| 718 | + | if frame.Plane.FD >= 0 { | |
| 719 | + | _ = closeFD(frame.Plane.FD) | |
| 720 | + | frame.Plane.FD = -1 | |
| 713 | 721 | } | |
| 714 | 722 | } | |
| 715 | 723 | ||
| @@ -717,25 +725,37 @@ func (r *Renderer) retireOwnedTexture(owned *ownedTexture) { | |||
| 717 | 725 | if r == nil || owned == nil { | |
| 718 | 726 | return | |
| 719 | 727 | } | |
| 720 | - | r.retired = append(r.retired, owned) | |
| 721 | - | for len(r.retired) > retiredTextureLimit { | |
| 722 | - | oldest := r.retired[0] | |
| 723 | - | copy(r.retired, r.retired[1:]) | |
| 724 | - | r.retired[len(r.retired)-1] = nil | |
| 725 | - | r.retired = r.retired[:len(r.retired)-1] | |
| 728 | + | if r.retiredCount == retiredTextureLimit { | |
| 729 | + | oldest := r.retired[r.retiredStart] | |
| 730 | + | r.retired[r.retiredStart] = owned | |
| 731 | + | r.retiredStart = (r.retiredStart + 1) % retiredTextureLimit | |
| 726 | 732 | r.releaseOwnedTexture(oldest) | |
| 733 | + | return | |
| 734 | + | } | |
| 735 | + | index := (r.retiredStart + r.retiredCount) % retiredTextureLimit | |
| 736 | + | r.retired[index] = owned | |
| 737 | + | r.retiredCount++ | |
| 738 | + | } | |
| 739 | + | ||
| 740 | + | func (r *Renderer) retiredAt(offset int) *ownedTexture { | |
| 741 | + | if r == nil || offset < 0 || offset >= r.retiredCount { | |
| 742 | + | return nil | |
| 727 | 743 | } | |
| 744 | + | return r.retired[(r.retiredStart+offset)%retiredTextureLimit] | |
| 728 | 745 | } | |
| 729 | 746 | ||
| 730 | 747 | func (r *Renderer) releaseRetiredTextures() { | |
| 731 | 748 | if r == nil { | |
| 732 | 749 | return | |
| 733 | 750 | } | |
| 734 | - | for _, owned := range r.retired { | |
| 735 | - | r.releaseOwnedTexture(owned) | |
| 751 | + | for r.retiredCount > 0 { | |
| 752 | + | index := r.retiredStart | |
| 753 | + | r.releaseOwnedTexture(r.retired[index]) | |
| 754 | + | r.retired[index] = nil | |
| 755 | + | r.retiredStart = (r.retiredStart + 1) % retiredTextureLimit | |
| 756 | + | r.retiredCount-- | |
| 736 | 757 | } | |
| 737 | - | clear(r.retired) | |
| 738 | - | r.retired = nil | |
| 758 | + | r.retiredStart = 0 | |
| 739 | 759 | } | |
| 740 | 760 | ||
| 741 | 761 | func (r *Renderer) releaseOwnedTexture(owned *ownedTexture) { | |
| @@ -762,11 +782,11 @@ func gdkTextureFormat(format dmabuf.FourCC) dmabuf.FourCC { | |||
| 762 | 782 | } | |
| 763 | 783 | } | |
| 764 | 784 | ||
| 765 | - | func (r *Renderer) traceFrame(frame dmabuf.BorrowedFrame, gdkFormat dmabuf.FourCC) { | |
| 785 | + | func (r *Renderer) traceFrame(frame *ownedFrame, gdkFormat dmabuf.FourCC) { | |
| 766 | 786 | if os.Getenv("PUREGO_CEF2GTK_GDK_TRACE") == "" || r == nil || r.frameTraces.Add(1) > 8 { | |
| 767 | 787 | return | |
| 768 | 788 | } | |
| 769 | - | plane := frame.Planes[0] | |
| 789 | + | plane := frame.Plane | |
| 770 | 790 | fmt.Fprintf(os.Stderr, | |
| 771 | 791 | "cef2gtk-gdk-dmabuf frame coded=%dx%d visible=%dx%d+%d+%d content=%dx%d+%d+%d source=%dx%d cef_format=%s gdk_format=%s modifier=0x%x fd=%d stride=%d offset=%d size=%d\n", | |
| 772 | 792 | frame.CodedSize.Width, frame.CodedSize.Height, | |
| @@ -776,7 +796,7 @@ func (r *Renderer) traceFrame(frame dmabuf.BorrowedFrame, gdkFormat dmabuf.FourC | |||
| 776 | 796 | frame.Format, gdkFormat, frame.Modifier, plane.FD, plane.Stride, plane.Offset, plane.Size) | |
| 777 | 797 | } | |
| 778 | 798 | ||
| 779 | - | func (r *Renderer) traceTexturePresent(frame dmabuf.BorrowedFrame, gdkFormat dmabuf.FourCC, texture *gdk.Texture) { | |
| 799 | + | func (r *Renderer) traceTexturePresent(frame *ownedFrame, gdkFormat dmabuf.FourCC, texture *gdk.Texture) { | |
| 780 | 800 | if os.Getenv("PUREGO_CEF2GTK_GDK_TRACE") == "" || r == nil || r.textureTraces.Add(1) > 8 { | |
| 781 | 801 | return | |
| 782 | 802 | } | |
| @@ -96,29 +96,10 @@ type ownedFrame struct { | |||||
| 96 | SourceSize dmabuf.Size | 96 | SourceSize dmabuf.Size | ||
| 97 | Format dmabuf.FourCC | 97 | Format dmabuf.FourCC | ||
| 98 | Modifier uint64 | 98 | Modifier uint64 | ||
| 99 | - | Planes []ownedPlane | 99 | + | Plane ownedPlane |
| 100 | onError func(error) | 100 | onError func(error) | ||
| 101 | } | 101 | } | ||
| 102 | 102 | ||||
| 103 | - | func (f *ownedFrame) borrowed() dmabuf.BorrowedFrame { | |||
| 104 | - | if f == nil { | |||
| 105 | - | return dmabuf.BorrowedFrame{} | |||
| 106 | - | } | |||
| 107 | - | planes := make([]dmabuf.Plane, len(f.Planes)) | |||
| 108 | - | for i, plane := range f.Planes { | |||
| 109 | - | planes[i] = dmabuf.Plane{FD: plane.FD, Stride: plane.Stride, Offset: plane.Offset, Size: plane.Size} | |||
| 110 | - | } | |||
| 111 | - | return dmabuf.BorrowedFrame{ | |||
| 112 | - | CodedSize: f.CodedSize, | |||
| 113 | - | VisibleRect: f.VisibleRect, | |||
| 114 | - | ContentRect: f.ContentRect, | |||
| 115 | - | SourceSize: f.SourceSize, | |||
| 116 | - | Format: f.Format, | |||
| 117 | - | Modifier: f.Modifier, | |||
| 118 | - | Planes: planes, | |||
| 119 | - | } | |||
| 120 | - | } | |||
| 121 | - | ||||
| 122 | // Renderer owns a GtkPicture presenter and imports callback-scoped CEF DMABUFs | 103 | // Renderer owns a GtkPicture presenter and imports callback-scoped CEF DMABUFs | ||
| 123 | // as GdkDmabufTexture instances. The initial implementation supports only | 104 | // as GdkDmabufTexture instances. The initial implementation supports only | ||
| 124 | // single-plane RGB frames. Duplicated FDs are handed to GTK with a native | 105 | // single-plane RGB frames. Duplicated FDs are handed to GTK with a native | ||
| @@ -132,7 +113,9 @@ type Renderer struct { | |||||
| 132 | formats dmabufFormatSet | 113 | formats dmabufFormatSet | ||
| 133 | builder dmabufTextureBuilder | 114 | builder dmabufTextureBuilder | ||
| 134 | current *ownedTexture | 115 | current *ownedTexture | ||
| 135 | - | retired []*ownedTexture | 116 | + | retired [retiredTextureLimit]*ownedTexture |
| 117 | + | retiredStart int | |||
| 118 | + | retiredCount int | |||
| 136 | pictureSetPaintable func(*gdk.Texture) | 119 | pictureSetPaintable func(*gdk.Texture) | ||
| 137 | firstTextureSwapMu sync.Mutex | 120 | firstTextureSwapMu sync.Mutex | ||
| 138 | firstTextureSwap func() | 121 | firstTextureSwap func() | ||
| @@ -367,11 +350,11 @@ func (r *Renderer) ImportAndQueueAsync(info *cef.AcceleratedPaintInfo, onError f | |||||
| 367 | if r == nil { | 350 | if r == nil { | ||
| 368 | return ErrNilRenderer | 351 | return ErrNilRenderer | ||
| 369 | } | 352 | } | ||
| 370 | - | frame, err := cefadapter.BorrowedFrameFromAcceleratedPaint(info) | 353 | + | frame, err := cefadapter.SinglePlaneFrameFromAcceleratedPaint(info) |
| 371 | if err != nil { | 354 | if err != nil { | ||
| 372 | return err | 355 | return err | ||
| 373 | } | 356 | } | ||
| 374 | - | owned, err := r.duplicateFrame(frame) | 357 | + | owned, err := r.duplicateSinglePlaneFrame(frame) |
| 375 | if err != nil { | 358 | if err != nil { | ||
| 376 | return err | 359 | return err | ||
| 377 | } | 360 | } | ||
| @@ -385,11 +368,11 @@ func (r *Renderer) ImportAndQueueAsync(info *cef.AcceleratedPaintInfo, onError f | |||||
| 385 | // on the GTK main loop. | 368 | // on the GTK main loop. | ||
| 386 | func (r *Renderer) ImportAndQueueOnGTKThread(info *cef.AcceleratedPaintInfo) (queued gtkgl.QueuedFrame, retErr error) { | 369 | func (r *Renderer) ImportAndQueueOnGTKThread(info *cef.AcceleratedPaintInfo) (queued gtkgl.QueuedFrame, retErr error) { | ||
| 387 | start := time.Now() | 370 | start := time.Now() | ||
| 388 | - | frame, err := cefadapter.BorrowedFrameFromAcceleratedPaint(info) | 371 | + | frame, err := cefadapter.SinglePlaneFrameFromAcceleratedPaint(info) |
| 389 | if err != nil { | 372 | if err != nil { | ||
| 390 | return gtkgl.QueuedFrame{}, err | 373 | return gtkgl.QueuedFrame{}, err | ||
| 391 | } | 374 | } | ||
| 392 | - | owned, err := r.duplicateFrame(frame) | 375 | + | owned, err := r.duplicateSinglePlaneFrame(frame) |
| 393 | if err != nil { | 376 | if err != nil { | ||
| 394 | return gtkgl.QueuedFrame{}, err | 377 | return gtkgl.QueuedFrame{}, err | ||
| 395 | } | 378 | } | ||
| @@ -535,7 +518,24 @@ func (r *Renderer) importAndSwapOwnedFrame(frame *ownedFrame) error { | |||||
| 535 | return nil | 518 | return nil | ||
| 536 | } | 519 | } | ||
| 537 | 520 | ||||
| 538 | - | func (r *Renderer) duplicateFrame(frame dmabuf.BorrowedFrame) (_ *ownedFrame, retErr error) { | 521 | + | // duplicateFrame keeps the slice-backed compatibility path for callers outside |
| 522 | + | // the GDK import hot path. | |||
| 523 | + | func (r *Renderer) duplicateFrame(frame dmabuf.BorrowedFrame) (*ownedFrame, error) { | |||
| 524 | + | if err := frame.Validate(); err != nil { | |||
| 525 | + | return nil, err | |||
| 526 | + | } | |||
| 527 | + | return r.duplicateSinglePlaneFrame(dmabuf.SinglePlaneFrame{ | |||
| 528 | + | CodedSize: frame.CodedSize, | |||
| 529 | + | VisibleRect: frame.VisibleRect, | |||
| 530 | + | ContentRect: frame.ContentRect, | |||
| 531 | + | SourceSize: frame.SourceSize, | |||
| 532 | + | Format: frame.Format, | |||
| 533 | + | Modifier: frame.Modifier, | |||
| 534 | + | Plane: frame.Planes[0], | |||
| 535 | + | }) | |||
| 536 | + | } | |||
| 537 | + | ||||
| 538 | + | func (r *Renderer) duplicateSinglePlaneFrame(frame dmabuf.SinglePlaneFrame) (_ *ownedFrame, retErr error) { | |||
| 539 | if r == nil { | 539 | if r == nil { | ||
| 540 | return nil, ErrNilRenderer | 540 | return nil, ErrNilRenderer | ||
| 541 | } | 541 | } | ||
| @@ -553,24 +553,19 @@ func (r *Renderer) duplicateFrame(frame dmabuf.BorrowedFrame) (_ *ownedFrame, re | |||||
| 553 | SourceSize: frame.SourceSize, | 553 | SourceSize: frame.SourceSize, | ||
| 554 | Format: frame.Format, | 554 | Format: frame.Format, | ||
| 555 | Modifier: frame.Modifier, | 555 | Modifier: frame.Modifier, | ||
| 556 | - | Planes: make([]ownedPlane, len(frame.Planes)), | 556 | + | Plane: ownedPlane{FD: -1}, |
| 557 | - | } | |||
| 558 | - | for i := range owned.Planes { | |||
| 559 | - | owned.Planes[i].FD = -1 | |||
| 560 | } | 557 | } | ||
| 561 | defer func() { | 558 | defer func() { | ||
| 562 | if retErr != nil { | 559 | if retErr != nil { | ||
| 563 | r.releaseOwnedFrame(owned) | 560 | r.releaseOwnedFrame(owned) | ||
| 564 | } | 561 | } | ||
| 565 | }() | 562 | }() | ||
| 566 | - | for i, plane := range frame.Planes { | 563 | + | ownedFD, err := dup(frame.Plane.FD) |
| 567 | - | ownedFD, err := dup(plane.FD) | 564 | + | if err != nil { |
| 568 | - | if err != nil { | 565 | + | r.recordFDDupFailure() |
| 569 | - | r.recordFDDupFailure() | 566 | + | return nil, err |
| 570 | - | return nil, err | |||
| 571 | - | } | |||
| 572 | - | owned.Planes[i] = ownedPlane{FD: ownedFD, Stride: plane.Stride, Offset: plane.Offset, Size: plane.Size} | |||
| 573 | } | 567 | } | ||
| 568 | + | owned.Plane = ownedPlane{FD: ownedFD, Stride: frame.Plane.Stride, Offset: frame.Plane.Offset, Size: frame.Plane.Size} | |||
| 574 | return owned, nil | 569 | return owned, nil | ||
| 575 | } | 570 | } | ||
| 576 | 571 | ||||
| @@ -584,27 +579,26 @@ func (r *Renderer) buildTextureFromOwnedFrame(frame *ownedFrame) (built *ownedTe | |||||
| 584 | if frame == nil { | 579 | if frame == nil { | ||
| 585 | return nil, dmabuf.ErrInvalidPlaneFD | 580 | return nil, dmabuf.ErrInvalidPlaneFD | ||
| 586 | } | 581 | } | ||
| 587 | - | borrowed := frame.borrowed() | 582 | + | if err := frame.validate(); err != nil { |
| 588 | - | if err := borrowed.Validate(); err != nil { | |||
| 589 | return nil, err | 583 | return nil, err | ||
| 590 | } | 584 | } | ||
| 591 | - | gdkFormat := gdkTextureFormat(borrowed.Format) | 585 | + | gdkFormat := gdkTextureFormat(frame.Format) |
| 592 | - | if r.formats != nil && !r.formats.Contains(uint32(gdkFormat), borrowed.Modifier) { | 586 | + | if r.formats != nil && !r.formats.Contains(uint32(gdkFormat), frame.Modifier) { |
| 593 | r.recordUnsupportedFormat() | 587 | r.recordUnsupportedFormat() | ||
| 594 | - | return nil, fmt.Errorf("%w: %s as %s modifier 0x%x", ErrUnsupportedFormat, borrowed.Format, gdkFormat, borrowed.Modifier) | 588 | + | return nil, fmt.Errorf("%w: %s as %s modifier 0x%x", ErrUnsupportedFormat, frame.Format, gdkFormat, frame.Modifier) |
| 595 | } | 589 | } | ||
| 596 | - | r.traceFrame(borrowed, gdkFormat) | 590 | + | r.traceFrame(frame, gdkFormat) |
| 597 | closeFD := r.closeFD | 591 | closeFD := r.closeFD | ||
| 598 | if closeFD == nil { | 592 | if closeFD == nil { | ||
| 599 | closeFD = unix.Close | 593 | closeFD = unix.Close | ||
| 600 | } | 594 | } | ||
| 601 | 595 | ||||
| 602 | - | ownedFD := borrowed.Planes[0].FD | 596 | + | ownedFD := frame.Plane.FD |
| 603 | textureOwnsFD := false | 597 | textureOwnsFD := false | ||
| 604 | defer func() { | 598 | defer func() { | ||
| 605 | if !textureOwnsFD { | 599 | if !textureOwnsFD { | ||
| 606 | _ = closeFD(ownedFD) | 600 | _ = closeFD(ownedFD) | ||
| 607 | - | frame.Planes[0].FD = -1 | 601 | + | frame.Plane.FD = -1 |
| 608 | } | 602 | } | ||
| 609 | }() | 603 | }() | ||
| 610 | destroyNotify, destroyNotifyErr := resolveDestroyNotify() | 604 | destroyNotify, destroyNotifyErr := resolveDestroyNotify() | ||
| @@ -613,11 +607,11 @@ func (r *Renderer) buildTextureFromOwnedFrame(frame *ownedFrame) (built *ownedTe | |||||
| 613 | return nil, fmt.Errorf("%w: native close GDestroyNotify unavailable: %w", ErrTextureBuildFailed, destroyNotifyErr) | 607 | return nil, fmt.Errorf("%w: native close GDestroyNotify unavailable: %w", ErrTextureBuildFailed, destroyNotifyErr) | ||
| 614 | } | 608 | } | ||
| 615 | 609 | ||||
| 616 | - | plane := borrowed.Planes[0] | 610 | + | plane := frame.Plane |
| 617 | - | r.builder.SetWidth(uint(borrowed.CodedSize.Width)) | 611 | + | r.builder.SetWidth(uint(frame.CodedSize.Width)) |
| 618 | - | r.builder.SetHeight(uint(borrowed.CodedSize.Height)) | 612 | + | r.builder.SetHeight(uint(frame.CodedSize.Height)) |
| 619 | r.builder.SetFourcc(uint32(gdkFormat)) | 613 | r.builder.SetFourcc(uint32(gdkFormat)) | ||
| 620 | - | r.builder.SetModifier(borrowed.Modifier) | 614 | + | r.builder.SetModifier(frame.Modifier) |
| 621 | r.builder.SetPremultiplied(false) | 615 | r.builder.SetPremultiplied(false) | ||
| 622 | r.builder.SetNPlanes(1) | 616 | r.builder.SetNPlanes(1) | ||
| 623 | if r.display != nil { | 617 | if r.display != nil { | ||
| @@ -653,9 +647,9 @@ func (r *Renderer) buildTextureFromOwnedFrame(frame *ownedFrame) (built *ownedTe | |||||
| 653 | return nil, ErrTextureBuildFailed | 647 | return nil, ErrTextureBuildFailed | ||
| 654 | } | 648 | } | ||
| 655 | textureOwnsFD = true | 649 | textureOwnsFD = true | ||
| 656 | - | frame.Planes[0].FD = -1 | 650 | + | frame.Plane.FD = -1 |
| 657 | r.recordTextureBuilt() | 651 | r.recordTextureBuilt() | ||
| 658 | - | r.traceTexturePresent(borrowed, gdkFormat, texture) | 652 | + | r.traceTexturePresent(frame, gdkFormat, texture) |
| 659 | return &ownedTexture{texture: texture}, nil | 653 | return &ownedTexture{texture: texture}, nil | ||
| 660 | } | 654 | } | ||
| 661 | 655 | ||||
| @@ -698,6 +692,22 @@ func (r *Renderer) releaseOwnedFrame(frame *ownedFrame) { | |||||
| 698 | closeOwnedFrame(frame, closeFD) | 692 | closeOwnedFrame(frame, closeFD) | ||
| 699 | } | 693 | } | ||
| 700 | 694 | ||||
| 695 | + | func (f *ownedFrame) validate() error { | |||
| 696 | + | if f == nil { | |||
| 697 | + | return dmabuf.ErrInvalidPlaneFD | |||
| 698 | + | } | |||
| 699 | + | return (dmabuf.SinglePlaneFrame{ | |||
| 700 | + | CodedSize: f.CodedSize, | |||
| 701 | + | Format: f.Format, | |||
| 702 | + | Plane: dmabuf.Plane{ | |||
| 703 | + | FD: f.Plane.FD, | |||
| 704 | + | Stride: f.Plane.Stride, | |||
| 705 | + | Offset: f.Plane.Offset, | |||
| 706 | + | Size: f.Plane.Size, | |||
| 707 | + | }, | |||
| 708 | + | }).Validate() | |||
| 709 | + | } | |||
| 710 | + | ||||
| 701 | func closeOwnedFrame(frame *ownedFrame, closeFD func(int) error) { | 711 | func closeOwnedFrame(frame *ownedFrame, closeFD func(int) error) { | ||
| 702 | if frame == nil { | 712 | if frame == nil { | ||
| 703 | return | 713 | return | ||
| @@ -705,11 +715,9 @@ func closeOwnedFrame(frame *ownedFrame, closeFD func(int) error) { | |||||
| 705 | if closeFD == nil { | 715 | if closeFD == nil { | ||
| 706 | closeFD = unix.Close | 716 | closeFD = unix.Close | ||
| 707 | } | 717 | } | ||
| 708 | - | for i := range frame.Planes { | 718 | + | if frame.Plane.FD >= 0 { |
| 709 | - | if frame.Planes[i].FD >= 0 { | 719 | + | _ = closeFD(frame.Plane.FD) |
| 710 | - | _ = closeFD(frame.Planes[i].FD) | 720 | + | frame.Plane.FD = -1 |
| 711 | - | frame.Planes[i].FD = -1 | |||
| 712 | - | } | |||
| 713 | } | 721 | } | ||
| 714 | } | 722 | } | ||
| 715 | 723 | ||||
| @@ -717,25 +725,37 @@ func (r *Renderer) retireOwnedTexture(owned *ownedTexture) { | |||||
| 717 | if r == nil || owned == nil { | 725 | if r == nil || owned == nil { | ||
| 718 | return | 726 | return | ||
| 719 | } | 727 | } | ||
| 720 | - | r.retired = append(r.retired, owned) | 728 | + | if r.retiredCount == retiredTextureLimit { |
| 721 | - | for len(r.retired) > retiredTextureLimit { | 729 | + | oldest := r.retired[r.retiredStart] |
| 722 | - | oldest := r.retired[0] | 730 | + | r.retired[r.retiredStart] = owned |
| 723 | - | copy(r.retired, r.retired[1:]) | 731 | + | r.retiredStart = (r.retiredStart + 1) % retiredTextureLimit |
| 724 | - | r.retired[len(r.retired)-1] = nil | |||
| 725 | - | r.retired = r.retired[:len(r.retired)-1] | |||
| 726 | r.releaseOwnedTexture(oldest) | 732 | r.releaseOwnedTexture(oldest) | ||
| 733 | + | return | |||
| 734 | + | } | |||
| 735 | + | index := (r.retiredStart + r.retiredCount) % retiredTextureLimit | |||
| 736 | + | r.retired[index] = owned | |||
| 737 | + | r.retiredCount++ | |||
| 738 | + | } | |||
| 739 | + | ||||
| 740 | + | func (r *Renderer) retiredAt(offset int) *ownedTexture { | |||
| 741 | + | if r == nil || offset < 0 || offset >= r.retiredCount { | |||
| 742 | + | return nil | |||
| 727 | } | 743 | } | ||
| 744 | + | return r.retired[(r.retiredStart+offset)%retiredTextureLimit] | |||
| 728 | } | 745 | } | ||
| 729 | 746 | ||||
| 730 | func (r *Renderer) releaseRetiredTextures() { | 747 | func (r *Renderer) releaseRetiredTextures() { | ||
| 731 | if r == nil { | 748 | if r == nil { | ||
| 732 | return | 749 | return | ||
| 733 | } | 750 | } | ||
| 734 | - | for _, owned := range r.retired { | 751 | + | for r.retiredCount > 0 { |
| 735 | - | r.releaseOwnedTexture(owned) | 752 | + | index := r.retiredStart |
| 753 | + | r.releaseOwnedTexture(r.retired[index]) | |||
| 754 | + | r.retired[index] = nil | |||
| 755 | + | r.retiredStart = (r.retiredStart + 1) % retiredTextureLimit | |||
| 756 | + | r.retiredCount-- | |||
| 736 | } | 757 | } | ||
| 737 | - | clear(r.retired) | 758 | + | r.retiredStart = 0 |
| 738 | - | r.retired = nil | |||
| 739 | } | 759 | } | ||
| 740 | 760 | ||||
| 741 | func (r *Renderer) releaseOwnedTexture(owned *ownedTexture) { | 761 | func (r *Renderer) releaseOwnedTexture(owned *ownedTexture) { | ||
| @@ -762,11 +782,11 @@ func gdkTextureFormat(format dmabuf.FourCC) dmabuf.FourCC { | |||||
| 762 | } | 782 | } | ||
| 763 | } | 783 | } | ||
| 764 | 784 | ||||
| 765 | - | func (r *Renderer) traceFrame(frame dmabuf.BorrowedFrame, gdkFormat dmabuf.FourCC) { | 785 | + | func (r *Renderer) traceFrame(frame *ownedFrame, gdkFormat dmabuf.FourCC) { |
| 766 | if os.Getenv("PUREGO_CEF2GTK_GDK_TRACE") == "" || r == nil || r.frameTraces.Add(1) > 8 { | 786 | if os.Getenv("PUREGO_CEF2GTK_GDK_TRACE") == "" || r == nil || r.frameTraces.Add(1) > 8 { | ||
| 767 | return | 787 | return | ||
| 768 | } | 788 | } | ||
| 769 | - | plane := frame.Planes[0] | 789 | + | plane := frame.Plane |
| 770 | fmt.Fprintf(os.Stderr, | 790 | fmt.Fprintf(os.Stderr, | ||
| 771 | "cef2gtk-gdk-dmabuf frame coded=%dx%d visible=%dx%d+%d+%d content=%dx%d+%d+%d source=%dx%d cef_format=%s gdk_format=%s modifier=0x%x fd=%d stride=%d offset=%d size=%d\n", | 791 | "cef2gtk-gdk-dmabuf frame coded=%dx%d visible=%dx%d+%d+%d content=%dx%d+%d+%d source=%dx%d cef_format=%s gdk_format=%s modifier=0x%x fd=%d stride=%d offset=%d size=%d\n", | ||
| 772 | frame.CodedSize.Width, frame.CodedSize.Height, | 792 | frame.CodedSize.Width, frame.CodedSize.Height, | ||
| @@ -776,7 +796,7 @@ func (r *Renderer) traceFrame(frame dmabuf.BorrowedFrame, gdkFormat dmabuf.FourC | |||||
| 776 | frame.Format, gdkFormat, frame.Modifier, plane.FD, plane.Stride, plane.Offset, plane.Size) | 796 | frame.Format, gdkFormat, frame.Modifier, plane.FD, plane.Stride, plane.Offset, plane.Size) | ||
| 777 | } | 797 | } | ||
| 778 | 798 | ||||
| 779 | - | func (r *Renderer) traceTexturePresent(frame dmabuf.BorrowedFrame, gdkFormat dmabuf.FourCC, texture *gdk.Texture) { | 799 | + | func (r *Renderer) traceTexturePresent(frame *ownedFrame, gdkFormat dmabuf.FourCC, texture *gdk.Texture) { |
| 780 | if os.Getenv("PUREGO_CEF2GTK_GDK_TRACE") == "" || r == nil || r.textureTraces.Add(1) > 8 { | 800 | if os.Getenv("PUREGO_CEF2GTK_GDK_TRACE") == "" || r == nil || r.textureTraces.Add(1) > 8 { | ||
| 781 | return | 801 | return | ||
| 782 | } | 802 | } | ||