github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/gldriver/screen.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gldriver
     6  
     7  import (
     8  	"fmt"
     9  	"image"
    10  	"sync"
    11  
    12  	"golang.org/x/exp/shiny/driver/internal/pump"
    13  	"golang.org/x/exp/shiny/screen"
    14  	"golang.org/x/mobile/gl"
    15  )
    16  
    17  var theScreen = &screenImpl{
    18  	windows: make(map[uintptr]*windowImpl),
    19  }
    20  
    21  type screenImpl struct {
    22  	texture struct {
    23  		program gl.Program
    24  		pos     gl.Attrib
    25  		mvp     gl.Uniform
    26  		uvp     gl.Uniform
    27  		inUV    gl.Attrib
    28  		sample  gl.Uniform
    29  		quad    gl.Buffer
    30  	}
    31  	fill struct {
    32  		program gl.Program
    33  		pos     gl.Attrib
    34  		mvp     gl.Uniform
    35  		color   gl.Uniform
    36  		quad    gl.Buffer
    37  	}
    38  
    39  	mu      sync.Mutex
    40  	windows map[uintptr]*windowImpl
    41  }
    42  
    43  func (s *screenImpl) NewBuffer(size image.Point) (retBuf screen.Buffer, retErr error) {
    44  	return &bufferImpl{
    45  		rgba: image.NewRGBA(image.Rectangle{Max: size}),
    46  		size: size,
    47  	}, nil
    48  }
    49  
    50  func (s *screenImpl) NewTexture(size image.Point) (screen.Texture, error) {
    51  	// TODO: can we compile these programs eagerly instead of lazily?
    52  
    53  	// Find a GL context for this texture.
    54  	// TODO: this might be correct. Some GL objects can be shared
    55  	// across contexts. But this needs a review of the spec to make
    56  	// sure it's correct, and some testing would be nice.
    57  	var w *windowImpl
    58  
    59  	s.mu.Lock()
    60  	for _, window := range s.windows {
    61  		w = window
    62  		break
    63  	}
    64  	s.mu.Unlock()
    65  
    66  	if w == nil {
    67  		return nil, fmt.Errorf("gldriver: no window available")
    68  	}
    69  
    70  	w.glctxMu.Lock()
    71  	defer w.glctxMu.Unlock()
    72  	glctx := w.glctx
    73  	if glctx == nil {
    74  		return nil, fmt.Errorf("gldriver: no GL context available")
    75  	}
    76  
    77  	if !glctx.IsProgram(s.texture.program) {
    78  		p, err := compileProgram(glctx, textureVertexSrc, textureFragmentSrc)
    79  		if err != nil {
    80  			return nil, err
    81  		}
    82  		s.texture.program = p
    83  		s.texture.pos = glctx.GetAttribLocation(p, "pos")
    84  		s.texture.mvp = glctx.GetUniformLocation(p, "mvp")
    85  		s.texture.uvp = glctx.GetUniformLocation(p, "uvp")
    86  		s.texture.inUV = glctx.GetAttribLocation(p, "inUV")
    87  		s.texture.sample = glctx.GetUniformLocation(p, "sample")
    88  		s.texture.quad = glctx.CreateBuffer()
    89  
    90  		glctx.BindBuffer(gl.ARRAY_BUFFER, s.texture.quad)
    91  		glctx.BufferData(gl.ARRAY_BUFFER, quadCoords, gl.STATIC_DRAW)
    92  	}
    93  
    94  	t := &textureImpl{
    95  		w:    w,
    96  		id:   glctx.CreateTexture(),
    97  		size: size,
    98  	}
    99  
   100  	glctx.BindTexture(gl.TEXTURE_2D, t.id)
   101  	glctx.TexImage2D(gl.TEXTURE_2D, 0, size.X, size.Y, gl.RGBA, gl.UNSIGNED_BYTE, nil)
   102  	glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
   103  	glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
   104  	glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
   105  	glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
   106  
   107  	return t, nil
   108  }
   109  
   110  func (s *screenImpl) NewWindow(opts *screen.NewWindowOptions) (screen.Window, error) {
   111  	width, height := 1024, 768
   112  	if opts != nil {
   113  		if opts.Width > 0 {
   114  			width = opts.Width
   115  		}
   116  		if opts.Height > 0 {
   117  			height = opts.Height
   118  		}
   119  	}
   120  
   121  	id := newWindow(int32(width), int32(height))
   122  	w := &windowImpl{
   123  		s:           s,
   124  		id:          id,
   125  		pump:        pump.Make(),
   126  		publish:     make(chan struct{}),
   127  		publishDone: make(chan screen.PublishResult),
   128  		drawDone:    make(chan struct{}),
   129  	}
   130  
   131  	s.mu.Lock()
   132  	s.windows[id] = w
   133  	s.mu.Unlock()
   134  
   135  	showWindow(w)
   136  
   137  	return w, nil
   138  }