texture.go (3798B)
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 "encoding/binary" 9 "image" 10 "image/color" 11 "image/draw" 12 13 "golang.org/x/exp/shiny/screen" 14 "golang.org/x/mobile/gl" 15 ) 16 17 type textureImpl struct { 18 w *windowImpl 19 id gl.Texture 20 fb gl.Framebuffer 21 size image.Point 22 } 23 24 func (t *textureImpl) Size() image.Point { return t.size } 25 func (t *textureImpl) Bounds() image.Rectangle { return image.Rectangle{Max: t.size} } 26 27 func (t *textureImpl) Release() { 28 t.w.glctxMu.Lock() 29 defer t.w.glctxMu.Unlock() 30 31 if t.fb.Value != 0 { 32 t.w.glctx.DeleteFramebuffer(t.fb) 33 t.fb = gl.Framebuffer{} 34 } 35 t.w.glctx.DeleteTexture(t.id) 36 t.id = gl.Texture{} 37 } 38 39 func (t *textureImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) { 40 buf := src.(*bufferImpl) 41 buf.preUpload() 42 43 // src2dst is added to convert from the src coordinate space to the dst 44 // coordinate space. It is subtracted to convert the other way. 45 src2dst := dp.Sub(sr.Min) 46 47 // Clip to the source. 48 sr = sr.Intersect(buf.Bounds()) 49 50 // Clip to the destination. 51 dr := sr.Add(src2dst) 52 dr = dr.Intersect(t.Bounds()) 53 if dr.Empty() { 54 return 55 } 56 57 // Bring dr.Min in dst-space back to src-space to get the pixel buffer offset. 58 pix := buf.rgba.Pix[buf.rgba.PixOffset(dr.Min.X-src2dst.X, dr.Min.Y-src2dst.Y):] 59 60 t.w.glctxMu.Lock() 61 defer t.w.glctxMu.Unlock() 62 63 t.w.glctx.BindTexture(gl.TEXTURE_2D, t.id) 64 65 width := dr.Dx() 66 if width*4 == buf.rgba.Stride { 67 t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, dr.Min.Y, width, dr.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pix) 68 return 69 } 70 // TODO: can we use GL_UNPACK_ROW_LENGTH with glPixelStorei for stride in 71 // ES 3.0, instead of uploading the pixels row-by-row? 72 for y, p := dr.Min.Y, 0; y < dr.Max.Y; y++ { 73 t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, y, width, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix[p:]) 74 p += buf.rgba.Stride 75 } 76 } 77 78 func (t *textureImpl) Fill(dr image.Rectangle, src color.Color, op draw.Op) { 79 minX := float64(dr.Min.X) 80 minY := float64(dr.Min.Y) 81 maxX := float64(dr.Max.X) 82 maxY := float64(dr.Max.Y) 83 mvp := calcMVP( 84 t.size.X, t.size.Y, 85 minX, minY, 86 maxX, minY, 87 minX, maxY, 88 ) 89 90 glctx := t.w.glctx 91 92 t.w.glctxMu.Lock() 93 defer t.w.glctxMu.Unlock() 94 95 create := t.fb.Value == 0 96 if create { 97 t.fb = glctx.CreateFramebuffer() 98 } 99 glctx.BindFramebuffer(gl.FRAMEBUFFER, t.fb) 100 if create { 101 glctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, t.id, 0) 102 } 103 104 glctx.Viewport(0, 0, t.size.X, t.size.Y) 105 doFill(t.w.s, t.w.glctx, mvp, src, op) 106 107 // We can't restore the GL state (i.e. bind the back buffer, also known as 108 // gl.Framebuffer{Value: 0}) right away, since we don't necessarily know 109 // the right viewport size yet. It is valid to call textureImpl.Fill before 110 // we've gotten our first size.Event. We bind it lazily instead. 111 t.w.backBufferBound = false 112 } 113 114 var quadCoords = f32Bytes(binary.LittleEndian, 115 0, 0, // top left 116 1, 0, // top right 117 0, 1, // bottom left 118 1, 1, // bottom right 119 ) 120 121 const textureVertexSrc = `#version 100 122 uniform mat3 mvp; 123 uniform mat3 uvp; 124 attribute vec3 pos; 125 attribute vec2 inUV; 126 varying vec2 uv; 127 void main() { 128 vec3 p = pos; 129 p.z = 1.0; 130 gl_Position = vec4(mvp * p, 1); 131 uv = (uvp * vec3(inUV, 1)).xy; 132 } 133 ` 134 135 const textureFragmentSrc = `#version 100 136 precision mediump float; 137 varying vec2 uv; 138 uniform sampler2D sample; 139 void main() { 140 gl_FragColor = texture2D(sample, uv); 141 } 142 ` 143 144 const fillVertexSrc = `#version 100 145 uniform mat3 mvp; 146 attribute vec3 pos; 147 void main() { 148 vec3 p = pos; 149 p.z = 1.0; 150 gl_Position = vec4(mvp * p, 1); 151 } 152 ` 153 154 const fillFragmentSrc = `#version 100 155 precision mediump float; 156 uniform vec4 color; 157 void main() { 158 gl_FragColor = color; 159 } 160 `