forked from joejulian/gio
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bfa6bc1c2 |
@@ -115,6 +115,9 @@ func (c *context) Unlock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) Refresh() error {
|
func (c *context) Refresh() error {
|
||||||
|
if C.gio_makeCurrent(c.ctx) == 0 {
|
||||||
|
return errors.New("[EAGLContext setCurrentContext] failed")
|
||||||
|
}
|
||||||
if !c.init {
|
if !c.init {
|
||||||
c.init = true
|
c.init = true
|
||||||
c.frameBuffer = c.c.CreateFramebuffer()
|
c.frameBuffer = c.c.CreateFramebuffer()
|
||||||
|
|||||||
@@ -111,6 +111,8 @@ func (c *glContext) Unlock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *glContext) Refresh() error {
|
func (c *glContext) Refresh() error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
C.gio_updateContext(c.ctx)
|
C.gio_updateContext(c.ctx)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,8 +165,6 @@ type frameEvent struct {
|
|||||||
Sync bool
|
Sync bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// The caller must hold the context lock while using API, Refresh,
|
|
||||||
// RenderTarget, or Present.
|
|
||||||
type context interface {
|
type context interface {
|
||||||
API() gpu.API
|
API() gpu.API
|
||||||
RenderTarget() (gpu.RenderTarget, error)
|
RenderTarget() (gpu.RenderTarget, error)
|
||||||
|
|||||||
+10
-21
@@ -154,10 +154,6 @@ func (w *Window) validateAndProcess(size image.Point, sync bool, frame *op.Ops,
|
|||||||
sync = true
|
sync = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := w.lockContext(); err != nil {
|
|
||||||
w.destroyGPU()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if sync && w.ctx != nil {
|
if sync && w.ctx != nil {
|
||||||
if err := w.ctx.Refresh(); err != nil {
|
if err := w.ctx.Refresh(); err != nil {
|
||||||
if errors.Is(err, errOutOfDate) {
|
if errors.Is(err, errOutOfDate) {
|
||||||
@@ -171,11 +167,14 @@ func (w *Window) validateAndProcess(size image.Point, sync bool, frame *op.Ops,
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.unlockContext()
|
w.ctxNeedsLock = true
|
||||||
if err := w.lockContext(); err != nil {
|
}
|
||||||
|
if w.ctx != nil && w.ctxNeedsLock {
|
||||||
|
if err := w.ctx.Lock(); err != nil {
|
||||||
w.destroyGPU()
|
w.destroyGPU()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
w.ctxNeedsLock = false
|
||||||
}
|
}
|
||||||
if w.gpu == nil && !w.nocontext {
|
if w.gpu == nil && !w.nocontext {
|
||||||
gpu, err := gpu.New(w.ctx.API())
|
gpu, err := gpu.New(w.ctx.API())
|
||||||
@@ -510,17 +509,6 @@ func (c *callbacks) ActionAt(p f32.Point) (system.Action, bool) {
|
|||||||
return c.w.queue.ActionAt(p)
|
return c.w.queue.ActionAt(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) lockContext() error {
|
|
||||||
if w.ctx == nil || !w.ctxNeedsLock {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := w.ctx.Lock(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.ctxNeedsLock = false
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Window) unlockContext() {
|
func (w *Window) unlockContext() {
|
||||||
if w.ctx == nil || w.ctxNeedsLock {
|
if w.ctx == nil || w.ctxNeedsLock {
|
||||||
return
|
return
|
||||||
@@ -531,9 +519,9 @@ func (w *Window) unlockContext() {
|
|||||||
|
|
||||||
func (w *Window) destroyGPU() {
|
func (w *Window) destroyGPU() {
|
||||||
if w.gpu != nil {
|
if w.gpu != nil {
|
||||||
if err := w.lockContext(); err == nil {
|
if err := w.ctx.Lock(); err == nil {
|
||||||
w.gpu.Release()
|
w.gpu.Release()
|
||||||
w.unlockContext()
|
w.ctx.Unlock()
|
||||||
}
|
}
|
||||||
w.gpu = nil
|
w.gpu = nil
|
||||||
}
|
}
|
||||||
@@ -683,11 +671,12 @@ func (w *Window) processEvent(e event.Event) bool {
|
|||||||
w.coalesced.destroy = &e2
|
w.coalesced.destroy = &e2
|
||||||
case ViewEvent:
|
case ViewEvent:
|
||||||
if !e2.Valid() && w.gpu != nil {
|
if !e2.Valid() && w.gpu != nil {
|
||||||
if err := w.lockContext(); err == nil {
|
if err := w.ctx.Lock(); err == nil {
|
||||||
w.gpu.Release()
|
w.gpu.Release()
|
||||||
w.unlockContext()
|
w.ctx.Unlock()
|
||||||
}
|
}
|
||||||
w.gpu = nil
|
w.gpu = nil
|
||||||
|
w.ctxNeedsLock = true
|
||||||
}
|
}
|
||||||
w.coalesced.view = &e2
|
w.coalesced.view = &e2
|
||||||
case ConfigEvent:
|
case ConfigEvent:
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
// SPDX-License-Identifier: Unlicense OR MIT
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gioui.org/gpu"
|
||||||
|
"gioui.org/op"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateAndProcessRelocksAfterRefresh(t *testing.T) {
|
||||||
|
ctx := &testContext{}
|
||||||
|
w := &Window{
|
||||||
|
ctx: ctx,
|
||||||
|
gpu: &testGPU{},
|
||||||
|
ctxNeedsLock: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.validateAndProcess(image.Pt(320, 240), true, new(op.Ops), nil); err != nil {
|
||||||
|
t.Fatalf("validateAndProcess returned error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := []string{"refresh", "lock", "render-target", "present"}
|
||||||
|
if got := ctx.ops; !equalStringSlices(got, want) {
|
||||||
|
t.Fatalf("unexpected call order:\n got %v\n want %v", got, want)
|
||||||
|
}
|
||||||
|
if w.ctxNeedsLock {
|
||||||
|
t.Fatalf("context should remain current after a successful frame")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateAndProcessSkipsRedundantRelock(t *testing.T) {
|
||||||
|
ctx := &testContext{}
|
||||||
|
w := &Window{
|
||||||
|
ctx: ctx,
|
||||||
|
gpu: &testGPU{},
|
||||||
|
ctxNeedsLock: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := w.validateAndProcess(image.Pt(320, 240), false, new(op.Ops), nil); err != nil {
|
||||||
|
t.Fatalf("validateAndProcess returned error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := []string{"render-target", "present"}
|
||||||
|
if got := ctx.ops; !equalStringSlices(got, want) {
|
||||||
|
t.Fatalf("unexpected call order:\n got %v\n want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testContext struct {
|
||||||
|
ops []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContext) API() gpu.API {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContext) RenderTarget() (gpu.RenderTarget, error) {
|
||||||
|
c.ops = append(c.ops, "render-target")
|
||||||
|
return gpu.OpenGLRenderTarget{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContext) Present() error {
|
||||||
|
c.ops = append(c.ops, "present")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContext) Refresh() error {
|
||||||
|
c.ops = append(c.ops, "refresh")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContext) Release() {}
|
||||||
|
|
||||||
|
func (c *testContext) Lock() error {
|
||||||
|
c.ops = append(c.ops, "lock")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *testContext) Unlock() {
|
||||||
|
c.ops = append(c.ops, "unlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
type testGPU struct{}
|
||||||
|
|
||||||
|
func (g *testGPU) Release() {}
|
||||||
|
|
||||||
|
func (g *testGPU) Clear(color.NRGBA) {}
|
||||||
|
|
||||||
|
func (g *testGPU) Frame(*op.Ops, gpu.RenderTarget, image.Point) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalStringSlices(a, b []string) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user