瀏覽代碼

Merge branch 'master' into panel_uniforms

leonsal 8 年之前
父節點
當前提交
028ece13aa
共有 11 個文件被更改,包括 221 次插入39 次删除
  1. 5 0
      geometry/geometry.go
  2. 19 13
      gls/gls.go
  3. 2 0
      gls/program.go
  4. 2 2
      gls/uniform.go
  5. 13 2
      gls/vbo.go
  6. 18 4
      gui/control_folder.go
  7. 10 3
      gui/list.go
  8. 2 1
      gui/scroller.go
  9. 0 14
      gui/tree.go
  10. 74 0
      util/stats/stats.go
  11. 76 0
      util/stats/table.go

+ 5 - 0
geometry/geometry.go

@@ -78,10 +78,15 @@ func (g *Geometry) Dispose() {
 		return
 	}
 
+	// Delete VAO and indices buffer
 	if g.gs != nil {
 		g.gs.DeleteVertexArrays(g.handleVAO)
 		g.gs.DeleteBuffers(g.handleIndices)
 	}
+	// Delete this geometry VBO buffers
+	for i := 0; i < len(g.vbos); i++ {
+		g.vbos[i].Dispose()
+	}
 	g.Init()
 }
 

+ 19 - 13
gls/gls.go

@@ -19,8 +19,8 @@ import (
 // methods to call OpenGL functions.
 type GLS struct {
 	stats               Stats             // statistics
-	Prog                *Program          // current active program
-	programs            map[*Program]bool // programs cache
+	prog                *Program          // current active shader program
+	programs            map[*Program]bool // shader programs cache
 	checkErrors         bool              // check openGL API errors flag
 	viewportX           int32             // cached last set viewport x
 	viewportY           int32             // cached last set viewport y
@@ -49,12 +49,15 @@ type GLS struct {
 // Stats contains counters of OpenGL resources being used as well
 // the cummulative numbers of some OpenGL calls for performance evaluation.
 type Stats struct {
-	Vaos      int    // Number of Vertex Array Objects
-	Vbos      int    // Number of Vertex Buffer Objects
-	Textures  int    // Number of Textures
-	Caphits   uint64 // Cummulative number of hits for Enable/Disable
-	Unisets   uint64 // Cummulative number of uniform sets
-	Drawcalls uint64 // Cummulative number of draw calls
+	Shaders    int    // Current number of shader programs
+	Vaos       int    // Number of Vertex Array Objects
+	Buffers    int    // Number of Buffer Objects
+	Textures   int    // Number of Textures
+	Caphits    uint64 // Cummulative number of hits for Enable/Disable
+	UnilocHits uint64 // Cummulative number of uniform location cache hits
+	UnilocMiss uint64 // Cummulative number of uniform location cache misses
+	Unisets    uint64 // Cummulative number of uniform sets
+	Drawcalls  uint64 // Cummulative number of draw calls
 }
 
 // Polygon side view.
@@ -126,7 +129,7 @@ func (gs *GLS) reset() {
 	gs.depthMask = uintUndef
 	gs.capabilities = make(map[int]int)
 	gs.programs = make(map[*Program]bool)
-	gs.Prog = nil
+	gs.prog = nil
 
 	gs.blendEquation = uintUndef
 	gs.blendSrc = uintUndef
@@ -169,6 +172,7 @@ func (gs *GLS) setDefaultState() {
 func (gs *GLS) Stats(s *Stats) {
 
 	*s = gs.stats
+	s.Shaders = len(gs.programs)
 }
 
 func (gs *GLS) ActiveTexture(texture uint32) {
@@ -270,9 +274,10 @@ func (gs *GLS) CreateShader(stype uint32) uint32 {
 	return uint32(h)
 }
 
-func (gs *GLS) DeleteBuffers(vbos ...uint32) {
+func (gs *GLS) DeleteBuffers(bufs ...uint32) {
 
-	C.glDeleteBuffers(C.GLsizei(len(vbos)), (*C.GLuint)(&vbos[0]))
+	C.glDeleteBuffers(C.GLsizei(len(bufs)), (*C.GLuint)(&bufs[0]))
+	gs.stats.Buffers -= len(bufs)
 }
 
 func (gs *GLS) DeleteShader(shader uint32) {
@@ -294,6 +299,7 @@ func (gs *GLS) DeleteTextures(tex ...uint32) {
 func (gs *GLS) DeleteVertexArrays(vaos ...uint32) {
 
 	C.glDeleteVertexArrays(C.GLsizei(len(vaos)), (*C.GLuint)(&vaos[0]))
+	gs.stats.Vaos -= len(vaos)
 }
 
 func (gs *GLS) DepthFunc(mode uint32) {
@@ -372,7 +378,7 @@ func (gs *GLS) GenBuffer() uint32 {
 
 	var buf uint32
 	C.glGenBuffers(1, (*C.GLuint)(&buf))
-	gs.stats.Vbos++
+	gs.stats.Buffers++
 	return buf
 }
 
@@ -627,7 +633,7 @@ func (gs *GLS) UseProgram(prog *Program) {
 		panic("Invalid program")
 	}
 	C.glUseProgram(C.GLuint(prog.handle))
-	gs.Prog = prog
+	gs.prog = prog
 
 	// Inserts program in cache if not already there.
 	if !gs.programs[prog] {

+ 2 - 0
gls/program.go

@@ -159,6 +159,7 @@ func (prog *Program) GetUniformLocation(name string) int32 {
 	// Try to get from the cache
 	loc, ok := prog.uniforms[name]
 	if ok {
+		prog.gs.stats.UnilocHits++
 		return loc
 	}
 	// Get location from GL
@@ -168,6 +169,7 @@ func (prog *Program) GetUniformLocation(name string) int32 {
 	if loc < 0 {
 		log.Warn("GetUniformLocation(%s) NOT FOUND", name)
 	}
+	prog.gs.stats.UnilocMiss++
 	return loc
 }
 

+ 2 - 2
gls/uniform.go

@@ -22,7 +22,7 @@ type Uniform struct {
 // for the current active program
 func (uni *Uniform) Location(gs *GLS) int32 {
 
-	loc := gs.Prog.GetUniformLocation(uni.name)
+	loc := gs.prog.GetUniformLocation(uni.name)
 	return loc
 }
 
@@ -36,7 +36,7 @@ func (uni *Uniform) LocationIdx(gs *GLS, idx int) int32 {
 		uni.idx = idx
 	}
 	//log.Debug("Location(%s, %d)", uni.name, idx)
-	loc := gs.Prog.GetUniformLocation(uni.nameidx)
+	loc := gs.prog.GetUniformLocation(uni.nameidx)
 	return loc
 }
 

+ 13 - 2
gls/vbo.go

@@ -11,7 +11,7 @@ import (
 
 // VBO abstracts an OpenGL Vertex Buffer Object
 type VBO struct {
-	gs      *GLS
+	gs      *GLS            // reference to GLS state
 	handle  uint32          // OpenGL handle for this VBO
 	usage   uint32          // Expected usage patter of the buffer
 	update  bool            // Update flag
@@ -77,6 +77,17 @@ func (vbo *VBO) AttribCount() int {
 	return len(vbo.attribs)
 }
 
+// Dispose disposes of this VBO OpenGL resources
+// As currently the VBO is used only by the Geometry object
+// it is not referenced counted.
+func (vbo *VBO) Dispose() {
+
+	if vbo.gs != nil {
+		vbo.gs.DeleteBuffers(vbo.handle)
+	}
+	vbo.gs = nil
+}
+
 // Sets the VBO buffer
 func (vbo *VBO) SetBuffer(buffer math32.ArrayF32) *VBO {
 
@@ -138,7 +149,7 @@ func (vbo *VBO) Transfer(gs *GLS) {
 		elsize := int32(unsafe.Sizeof(float32(0)))
 		for _, attrib := range vbo.attribs {
 			// Get attribute location in the current program
-			loc := gs.Prog.GetAttribLocation(attrib.Name)
+			loc := gs.prog.GetAttribLocation(attrib.Name)
 			if loc < 0 {
 				continue
 			}

+ 18 - 4
gui/control_folder.go

@@ -9,10 +9,9 @@ import (
 )
 
 type ControlFolder struct {
-	Folder                       // Embedded folder
-	tree    Tree                 // control tree
-	styles  *ControlFolderStyles // Pointer to styles
-	current interface{}
+	Folder                      // Embedded folder
+	tree   Tree                 // control tree
+	styles *ControlFolderStyles // Pointer to styles
 }
 
 type ControlFolderStyles struct {
@@ -54,6 +53,16 @@ func (f *ControlFolder) Clear() {
 	f.tree.Clear()
 }
 
+func (f *ControlFolder) RemoveAt(pos int) IPanel {
+
+	return f.tree.RemoveAt(pos)
+}
+
+func (f *ControlFolder) AddPanel(pan IPanel) {
+
+	f.tree.Add(pan)
+}
+
 func (f *ControlFolder) AddCheckBox(text string) *CheckRadio {
 
 	cb := NewCheckBox(text)
@@ -103,6 +112,11 @@ func (g *ControlFolderGroup) AddSlider(text string, sf, v float32) *Slider {
 	return slider
 }
 
+func (g *ControlFolderGroup) AddPanel(pan IPanel) {
+
+	g.node.Add(pan)
+}
+
 func (f *ControlFolder) newSlider(text string, sf, value float32) (IPanel, *Slider) {
 
 	// Creates container panel for the label and slider

+ 10 - 3
gui/list.go

@@ -134,10 +134,17 @@ func (li *List) InsertAt(pos int, item IPanel) {
 }
 
 // RemoveAt removes the list item from the specified position
-// Returns true if the item was successfuly removed
-func (li *List) RemoveAt(pos int) {
+func (li *List) RemoveAt(pos int) IPanel {
 
-	li.Scroller.RemoveAt(pos)
+	// Remove the list item from the internal scroller
+	pan := li.Scroller.RemoveAt(pos)
+	litem := pan.(*ListItem)
+
+	// Remove item from the list item children and disposes of the list item panel
+	item := litem.item
+	litem.Remove(item)
+	litem.Dispose()
+	return item
 }
 
 // Remove removes the specified item from the list

+ 2 - 1
gui/scroller.go

@@ -118,7 +118,7 @@ func (s *Scroller) InsertAt(pos int, item IPanel) {
 }
 
 // RemoveAt removes item from the specified position
-func (s *Scroller) RemoveAt(pos int) {
+func (s *Scroller) RemoveAt(pos int) IPanel {
 
 	// Validates position
 	if pos < 0 || pos >= len(s.items) {
@@ -137,6 +137,7 @@ func (s *Scroller) RemoveAt(pos int) {
 	s.Panel.Remove(item)
 	s.autoSize()
 	s.recalc()
+	return item
 }
 
 // Remove removes the specified item from the Scroller

+ 0 - 14
gui/tree.go

@@ -128,20 +128,6 @@ func (t *Tree) Remove(child IPanel) {
 	}
 }
 
-//// Clear removes all items from the tree
-//func (t *Tree) Clear() {
-//
-//	for t.List.Len() > 0 {
-//		curr := t.List.ItemAt(0)
-//		node, ok := curr.(*TreeNode)
-//		if ok {
-//			node.remove()
-//		} else {
-//			t.List.Remove(curr)
-//		}
-//	}
-//}
-
 // Selected returns the currently selected element or nil
 func (t *Tree) Selected() IPanel {
 

+ 74 - 0
util/stats/stats.go

@@ -0,0 +1,74 @@
+package stats
+
+import (
+	"github.com/g3n/engine/gls"
+	"runtime"
+	"time"
+)
+
+// Stats contains several statistics usefull for performance evaluation
+type Stats struct {
+	Glstats      gls.Stats // GLS statistics structure
+	UnilocHits   int       // Uniform location cache hits per frame
+	UnilocMiss   int       // Uniform location cache misses per frame
+	Unisets      int       // Uniform sets per frame
+	Drawcalls    int       // Draw calls per frame
+	Cgocalls     int       // Cgo calls per frame
+	prevGls      gls.Stats // previous gls statistics
+	prevCgocalls int64     // previous number of cgo calls
+	gs           *gls.GLS  // reference to gls state
+	frames       int       // frame counter
+	last         time.Time // last update time
+}
+
+// NewStats creates and returns a pointer to a new statistics object
+func NewStats(gs *gls.GLS) *Stats {
+
+	s := new(Stats)
+	s.gs = gs
+	s.last = time.Now()
+	return s
+}
+
+// Update should be called in the render loop with the desired update interval.
+// Returns true when the interval has elapsed and the statistics has been updated.
+func (s *Stats) Update(d time.Duration) bool {
+
+	// If the specified time duration has not elapsed from previous update,
+	// nothing to do.
+	now := time.Now()
+	s.frames++
+	if s.last.Add(d).After(now) {
+		return false
+	}
+
+	// Update GLS statistics
+	s.gs.Stats(&s.Glstats)
+
+	// Calculates uniform location cache hits per frame
+	unilochits := s.Glstats.UnilocHits - s.prevGls.UnilocHits
+	s.UnilocHits = int(float64(unilochits) / float64(s.frames))
+
+	// Calculates uniform location cache hits per frame
+	unilocmiss := s.Glstats.UnilocMiss - s.prevGls.UnilocMiss
+	s.UnilocMiss = int(float64(unilocmiss) / float64(s.frames))
+
+	// Calculates uniforms sets per frame
+	unisets := s.Glstats.Unisets - s.prevGls.Unisets
+	s.Unisets = int(float64(unisets) / float64(s.frames))
+
+	// Calculates draw calls per frame
+	drawcalls := s.Glstats.Drawcalls - s.prevGls.Drawcalls
+	s.Drawcalls = int(float64(drawcalls) / float64(s.frames))
+
+	// Calculates number of cgo calls per frame
+	current := runtime.NumCgoCall()
+	cgocalls := current - s.prevCgocalls
+	s.Cgocalls = int(float64(cgocalls) / float64(s.frames))
+	s.prevCgocalls = current
+
+	s.prevGls = s.Glstats
+	s.last = now
+	s.frames = 0
+	return true
+}

+ 76 - 0
util/stats/table.go

@@ -0,0 +1,76 @@
+package stats
+
+import (
+	"github.com/g3n/engine/gls"
+	"github.com/g3n/engine/gui"
+)
+
+// StatsTable is a gui.Table panel with statistics
+type StatsTable struct {
+	*gui.Table          // embedded table panel
+	fields     []*field // array of fields to show
+}
+
+type field struct {
+	id  string
+	row int
+}
+
+// NewStatsTable creates and returns a pointer to a new statistics table panel
+func NewStatsTable(width, height float32, gs *gls.GLS) *StatsTable {
+
+	// Creates table panel
+	st := new(StatsTable)
+	t, err := gui.NewTable(width, height, []gui.TableColumn{
+		{Id: "f", Header: "Stat", Width: 50, Minwidth: 32, Align: gui.AlignRight, Format: "%s", Resize: true, Expand: 2},
+		{Id: "v", Header: "Value", Width: 50, Minwidth: 32, Align: gui.AlignRight, Format: "%d", Resize: false, Expand: 1},
+	})
+	if err != nil {
+		panic(err)
+	}
+	st.Table = t
+	st.ShowHeader(false)
+
+	// Add rows
+	st.addRow("shaders", "Shaders:")
+	st.addRow("vaos", "Vaos:")
+	st.addRow("buffers", "Buffers:")
+	st.addRow("textures", "Textures:")
+	st.addRow("unisets", "Uniforms/frame:")
+	st.addRow("drawcalls", "Draw calls/frame:")
+	st.addRow("cgocalls", "CGO calls/frame:")
+	return st
+}
+
+// Update updates the table values from the specified stats table
+func (st *StatsTable) Update(s *Stats) {
+
+	for i := 0; i < len(st.fields); i++ {
+		f := st.fields[i]
+		switch f.id {
+		case "shaders":
+			st.Table.SetCell(f.row, "v", s.Glstats.Shaders)
+		case "vaos":
+			st.Table.SetCell(f.row, "v", s.Glstats.Vaos)
+		case "buffers":
+			st.Table.SetCell(f.row, "v", s.Glstats.Buffers)
+		case "textures":
+			st.Table.SetCell(f.row, "v", s.Glstats.Textures)
+		case "unisets":
+			st.Table.SetCell(f.row, "v", s.Unisets)
+		case "drawcalls":
+			st.Table.SetCell(f.row, "v", s.Drawcalls)
+		case "cgocalls":
+			st.Table.SetCell(f.row, "v", s.Cgocalls)
+		}
+	}
+}
+
+func (st *StatsTable) addRow(id, label string) {
+
+	f := new(field)
+	f.id = id
+	f.row = st.Table.RowCount()
+	st.Table.AddRow(map[string]interface{}{"f": label, "v": 0})
+	st.fields = append(st.fields, f)
+}