internal/gl: rename internal/glimpl

Now that the OpenGL driver package is named "opengl", we can finally get
rid of the ugly "glimpl" name.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-03-06 10:31:35 +01:00
parent a722768da9
commit 7bc0603d7e
17 changed files with 221 additions and 221 deletions
+22 -22
View File
@@ -22,17 +22,17 @@ import (
"fmt" "fmt"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
) )
type context struct { type context struct {
owner *window owner *window
c *glimpl.Functions c *gl.Functions
ctx C.CFTypeRef ctx C.CFTypeRef
layer C.CFTypeRef layer C.CFTypeRef
init bool init bool
frameBuffer glimpl.Framebuffer frameBuffer gl.Framebuffer
colorBuffer, depthBuffer glimpl.Renderbuffer colorBuffer, depthBuffer gl.Renderbuffer
} }
func init() { func init() {
@@ -50,7 +50,7 @@ func newContext(w *window) (*context, error) {
ctx: ctx, ctx: ctx,
owner: w, owner: w,
layer: C.CFTypeRef(w.contextLayer()), layer: C.CFTypeRef(w.contextLayer()),
c: new(glimpl.Functions), c: new(gl.Functions),
} }
return c, nil return c, nil
} }
@@ -63,7 +63,7 @@ func (c *context) Release() {
if c.ctx == 0 { if c.ctx == 0 {
return return
} }
C.gio_renderbufferStorage(c.ctx, 0, C.GLenum(glimpl.RENDERBUFFER)) C.gio_renderbufferStorage(c.ctx, 0, C.GLenum(gl.RENDERBUFFER))
c.c.DeleteFramebuffer(c.frameBuffer) c.c.DeleteFramebuffer(c.frameBuffer)
c.c.DeleteRenderbuffer(c.colorBuffer) c.c.DeleteRenderbuffer(c.colorBuffer)
c.c.DeleteRenderbuffer(c.depthBuffer) c.c.DeleteRenderbuffer(c.depthBuffer)
@@ -78,10 +78,10 @@ func (c *context) Present() error {
} }
// Discard depth buffer as recommended in // Discard depth buffer as recommended in
// https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html // https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/WorkingwithEAGLContexts/WorkingwithEAGLContexts.html
c.c.BindFramebuffer(glimpl.FRAMEBUFFER, c.frameBuffer) c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer)
c.c.InvalidateFramebuffer(glimpl.FRAMEBUFFER, glimpl.DEPTH_ATTACHMENT) c.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
c.c.BindRenderbuffer(glimpl.RENDERBUFFER, c.colorBuffer) c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer)
if C.gio_presentRenderbuffer(c.ctx, C.GLenum(glimpl.RENDERBUFFER)) == 0 { if C.gio_presentRenderbuffer(c.ctx, C.GLenum(gl.RENDERBUFFER)) == 0 {
return errors.New("presentRenderBuffer failed") return errors.New("presentRenderBuffer failed")
} }
return nil return nil
@@ -108,20 +108,20 @@ func (c *context) MakeCurrent() error {
c.c.Finish() c.c.Finish()
return nil return nil
} }
currentRB := glimpl.Renderbuffer{uint(c.c.GetInteger(glimpl.RENDERBUFFER_BINDING))} currentRB := gl.Renderbuffer{uint(c.c.GetInteger(gl.RENDERBUFFER_BINDING))}
c.c.BindRenderbuffer(glimpl.RENDERBUFFER, c.colorBuffer) c.c.BindRenderbuffer(gl.RENDERBUFFER, c.colorBuffer)
if C.gio_renderbufferStorage(c.ctx, c.layer, C.GLenum(glimpl.RENDERBUFFER)) == 0 { if C.gio_renderbufferStorage(c.ctx, c.layer, C.GLenum(gl.RENDERBUFFER)) == 0 {
return errors.New("renderbufferStorage failed") return errors.New("renderbufferStorage failed")
} }
w := c.c.GetRenderbufferParameteri(glimpl.RENDERBUFFER, glimpl.RENDERBUFFER_WIDTH) w := c.c.GetRenderbufferParameteri(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH)
h := c.c.GetRenderbufferParameteri(glimpl.RENDERBUFFER, glimpl.RENDERBUFFER_HEIGHT) h := c.c.GetRenderbufferParameteri(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT)
c.c.BindRenderbuffer(glimpl.RENDERBUFFER, c.depthBuffer) c.c.BindRenderbuffer(gl.RENDERBUFFER, c.depthBuffer)
c.c.RenderbufferStorage(glimpl.RENDERBUFFER, glimpl.DEPTH_COMPONENT16, w, h) c.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h)
c.c.BindRenderbuffer(glimpl.RENDERBUFFER, currentRB) c.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
c.c.BindFramebuffer(glimpl.FRAMEBUFFER, c.frameBuffer) c.c.BindFramebuffer(gl.FRAMEBUFFER, c.frameBuffer)
c.c.FramebufferRenderbuffer(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0, glimpl.RENDERBUFFER, c.colorBuffer) c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, c.colorBuffer)
c.c.FramebufferRenderbuffer(glimpl.FRAMEBUFFER, glimpl.DEPTH_ATTACHMENT, glimpl.RENDERBUFFER, c.depthBuffer) c.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, c.depthBuffer)
if st := c.c.CheckFramebufferStatus(glimpl.FRAMEBUFFER); st != glimpl.FRAMEBUFFER_COMPLETE { if st := c.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
return fmt.Errorf("framebuffer incomplete, status: %#x\n", st) return fmt.Errorf("framebuffer incomplete, status: %#x\n", st)
} }
return nil return nil
+4 -4
View File
@@ -6,9 +6,9 @@ import (
"errors" "errors"
"syscall/js" "syscall/js"
"gioui.org/internal/srgb"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
"gioui.org/internal/srgb"
) )
type context struct { type context struct {
@@ -39,7 +39,7 @@ func newContext(w *window) (*context, error) {
} }
func (c *context) API() gpu.API { func (c *context) API() gpu.API {
return gpu.OpenGL{Context: glimpl.Context(c.ctx)} return gpu.OpenGL{Context: gl.Context(c.ctx)}
} }
func (c *context) Release() { func (c *context) Release() {
@@ -69,7 +69,7 @@ func (c *context) Unlock() {}
func (c *context) MakeCurrent() error { func (c *context) MakeCurrent() error {
if c.srgbFBO == nil { if c.srgbFBO == nil {
var err error var err error
c.srgbFBO, err = srgb.New(glimpl.Context(c.ctx)) c.srgbFBO, err = srgb.New(gl.Context(c.ctx))
if err != nil { if err != nil {
c.Release() c.Release()
c.srgbFBO = nil c.srgbFBO = nil
+2 -2
View File
@@ -6,7 +6,7 @@ package window
import ( import (
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
) )
/* /*
@@ -26,7 +26,7 @@ __attribute__ ((visibility ("hidden"))) void gio_unlockContext(CFTypeRef ctxRef)
import "C" import "C"
type context struct { type context struct {
c *glimpl.Functions c *gl.Functions
ctx C.CFTypeRef ctx C.CFTypeRef
view C.CFTypeRef view C.CFTypeRef
} }
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"syscall/js" "syscall/js"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
) )
type jsContext struct { type jsContext struct {
@@ -31,7 +31,7 @@ func newGLContext() (context, error) {
} }
func (c *jsContext) API() gpu.API { func (c *jsContext) API() gpu.API {
return gpu.OpenGL{Context: glimpl.Context(c.ctx)} return gpu.OpenGL{Context: gl.Context(c.ctx)}
} }
func (c *jsContext) Release() { func (c *jsContext) Release() {
+2 -2
View File
@@ -6,7 +6,7 @@ import (
"fmt" "fmt"
"unsafe" "unsafe"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
) )
// See gpu/api.go for documentation for the API types // See gpu/api.go for documentation for the API types
@@ -19,7 +19,7 @@ type OpenGL struct {
// Context contains the WebGL context for WebAssembly platforms. It is // Context contains the WebGL context for WebAssembly platforms. It is
// empty for all other platforms; an OpenGL context is assumed current when // empty for all other platforms; an OpenGL context is assumed current when
// calling NewDevice. // calling NewDevice.
Context glimpl.Context Context gl.Context
} }
type Direct3D11 struct { type Direct3D11 struct {
@@ -114,7 +114,7 @@ type InputDesc struct {
Offset int Offset int
} }
// InputLayout is the backend specific representation of the mapping // InputLayout is the driver specific representation of the mapping
// between Buffers and shader attributes. // between Buffers and shader attributes.
type InputLayout interface { type InputLayout interface {
Release() Release()
+128 -128
View File
@@ -11,12 +11,12 @@ import (
"unsafe" "unsafe"
"gioui.org/gpu/internal/driver" "gioui.org/gpu/internal/driver"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
) )
// Backend implements driver.Device. // Backend implements driver.Device.
type Backend struct { type Backend struct {
funcs *glimpl.Functions funcs *gl.Functions
state glstate state glstate
@@ -49,13 +49,13 @@ type bufferBinding struct {
} }
type gpuTimer struct { type gpuTimer struct {
funcs *glimpl.Functions funcs *gl.Functions
obj glimpl.Query obj gl.Query
} }
type gpuTexture struct { type gpuTexture struct {
backend *Backend backend *Backend
obj glimpl.Texture obj gl.Texture
triple textureTriple triple textureTriple
width int width int
height int height int
@@ -63,16 +63,16 @@ type gpuTexture struct {
type gpuFramebuffer struct { type gpuFramebuffer struct {
backend *Backend backend *Backend
obj glimpl.Framebuffer obj gl.Framebuffer
hasDepth bool hasDepth bool
depthBuf glimpl.Renderbuffer depthBuf gl.Renderbuffer
foreign bool foreign bool
} }
type gpuBuffer struct { type gpuBuffer struct {
backend *Backend backend *Backend
hasBuffer bool hasBuffer bool
obj glimpl.Buffer obj gl.Buffer
typ driver.BufferBinding typ driver.BufferBinding
size int size int
immutable bool immutable bool
@@ -83,7 +83,7 @@ type gpuBuffer struct {
type gpuProgram struct { type gpuProgram struct {
backend *Backend backend *Backend
obj glimpl.Program obj gl.Program
nattr int nattr int
vertUniforms uniformsTracker vertUniforms uniformsTracker
fragUniforms uniformsTracker fragUniforms uniformsTracker
@@ -98,7 +98,7 @@ type uniformsTracker struct {
} }
type uniformLocation struct { type uniformLocation struct {
uniform glimpl.Uniform uniform gl.Uniform
offset int offset int
typ driver.DataType typ driver.DataType
size int size int
@@ -112,12 +112,12 @@ type gpuInputLayout struct {
// textureTriple holds the type settings for // textureTriple holds the type settings for
// a TexImage2D call. // a TexImage2D call.
type textureTriple struct { type textureTriple struct {
internalFormat glimpl.Enum internalFormat gl.Enum
format glimpl.Enum format gl.Enum
typ glimpl.Enum typ gl.Enum
} }
type Context = glimpl.Context type Context = gl.Context
const ( const (
storageBindings = 32 storageBindings = 32
@@ -128,13 +128,13 @@ func init() {
} }
func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) { func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
f, err := glimpl.NewFunctions(api.Context) f, err := gl.NewFunctions(api.Context)
if err != nil { if err != nil {
return nil, err return nil, err
} }
exts := strings.Split(f.GetString(glimpl.EXTENSIONS), " ") exts := strings.Split(f.GetString(gl.EXTENSIONS), " ")
glVer := f.GetString(glimpl.VERSION) glVer := f.GetString(gl.VERSION)
ver, gles, err := glimpl.ParseGLVersion(glVer) ver, gles, err := gl.ParseGLVersion(glVer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -163,19 +163,19 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
if hasExtension(exts, "GL_EXT_disjoint_timer_query_webgl2") || hasExtension(exts, "GL_EXT_disjoint_timer_query") { if hasExtension(exts, "GL_EXT_disjoint_timer_query_webgl2") || hasExtension(exts, "GL_EXT_disjoint_timer_query") {
b.feats.Features |= driver.FeatureTimers b.feats.Features |= driver.FeatureTimers
} }
b.feats.MaxTextureSize = f.GetInteger(glimpl.MAX_TEXTURE_SIZE) b.feats.MaxTextureSize = f.GetInteger(gl.MAX_TEXTURE_SIZE)
return b, nil return b, nil
} }
func (b *Backend) BeginFrame() driver.Framebuffer { func (b *Backend) BeginFrame() driver.Framebuffer {
// Assume GL state is reset between frames. // Assume GL state is reset between frames.
b.state = glstate{} b.state = glstate{}
fboID := glimpl.Framebuffer(b.funcs.GetBinding(glimpl.FRAMEBUFFER_BINDING)) fboID := gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING))
return &gpuFramebuffer{backend: b, obj: fboID, foreign: true} return &gpuFramebuffer{backend: b, obj: fboID, foreign: true}
} }
func (b *Backend) EndFrame() { func (b *Backend) EndFrame() {
b.funcs.ActiveTexture(glimpl.TEXTURE0) b.funcs.ActiveTexture(gl.TEXTURE0)
} }
func (b *Backend) Caps() driver.Caps { func (b *Backend) Caps() driver.Caps {
@@ -190,7 +190,7 @@ func (b *Backend) NewTimer() driver.Timer {
} }
func (b *Backend) IsTimeContinuous() bool { func (b *Backend) IsTimeContinuous() bool {
return b.funcs.GetInteger(glimpl.GPU_DISJOINT_EXT) == glimpl.FALSE return b.funcs.GetInteger(gl.GPU_DISJOINT_EXT) == gl.FALSE
} }
func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Framebuffer, error) { func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Framebuffer, error) {
@@ -203,19 +203,19 @@ func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Fram
fbo.Release() fbo.Release()
return nil, err return nil, err
} }
b.funcs.FramebufferTexture2D(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0, glimpl.TEXTURE_2D, gltex.obj, 0) b.funcs.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, gltex.obj, 0)
if depthBits > 0 { if depthBits > 0 {
size := glimpl.Enum(glimpl.DEPTH_COMPONENT16) size := gl.Enum(gl.DEPTH_COMPONENT16)
switch { switch {
case depthBits > 24: case depthBits > 24:
size = glimpl.DEPTH_COMPONENT32F size = gl.DEPTH_COMPONENT32F
case depthBits > 16: case depthBits > 16:
size = glimpl.DEPTH_COMPONENT24 size = gl.DEPTH_COMPONENT24
} }
depthBuf := b.funcs.CreateRenderbuffer() depthBuf := b.funcs.CreateRenderbuffer()
b.funcs.BindRenderbuffer(glimpl.RENDERBUFFER, depthBuf) b.funcs.BindRenderbuffer(gl.RENDERBUFFER, depthBuf)
b.funcs.RenderbufferStorage(glimpl.RENDERBUFFER, size, gltex.width, gltex.height) b.funcs.RenderbufferStorage(gl.RENDERBUFFER, size, gltex.width, gltex.height)
b.funcs.FramebufferRenderbuffer(glimpl.FRAMEBUFFER, glimpl.DEPTH_ATTACHMENT, glimpl.RENDERBUFFER, depthBuf) b.funcs.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuf)
fbo.depthBuf = depthBuf fbo.depthBuf = depthBuf
fbo.hasDepth = true fbo.hasDepth = true
if err := glErr(b.funcs); err != nil { if err := glErr(b.funcs); err != nil {
@@ -223,7 +223,7 @@ func (b *Backend) NewFramebuffer(tex driver.Texture, depthBits int) (driver.Fram
return nil, err return nil, err
} }
} }
if st := b.funcs.CheckFramebufferStatus(glimpl.FRAMEBUFFER); st != glimpl.FRAMEBUFFER_COMPLETE { if st := b.funcs.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
fbo.Release() fbo.Release()
return nil, fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError()) return nil, fmt.Errorf("incomplete framebuffer, status = 0x%x, err = %d", st, b.funcs.GetError())
} }
@@ -239,20 +239,20 @@ func (b *Backend) NewTexture(format driver.TextureFormat, width, height int, min
case driver.TextureFormatSRGB: case driver.TextureFormatSRGB:
tex.triple = b.srgbaTriple tex.triple = b.srgbaTriple
case driver.TextureFormatRGBA8: case driver.TextureFormatRGBA8:
tex.triple = textureTriple{glimpl.RGBA8, glimpl.RGBA, glimpl.UNSIGNED_BYTE} tex.triple = textureTriple{gl.RGBA8, gl.RGBA, gl.UNSIGNED_BYTE}
default: default:
return nil, errors.New("unsupported texture format") return nil, errors.New("unsupported texture format")
} }
b.BindTexture(0, tex) b.BindTexture(0, tex)
b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MAG_FILTER, toTexFilter(magFilter)) b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, toTexFilter(magFilter))
b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MIN_FILTER, toTexFilter(minFilter)) b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, toTexFilter(minFilter))
b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_S, glimpl.CLAMP_TO_EDGE) b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_T, glimpl.CLAMP_TO_EDGE) b.funcs.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
if b.gles && b.glver[0] >= 3 { if b.gles && b.glver[0] >= 3 {
// Immutable textures are required for BindImageTexture, and can't hurt otherwise. // Immutable textures are required for BindImageTexture, and can't hurt otherwise.
b.funcs.TexStorage2D(glimpl.TEXTURE_2D, 1, tex.triple.internalFormat, width, height) b.funcs.TexStorage2D(gl.TEXTURE_2D, 1, tex.triple.internalFormat, width, height)
} else { } else {
b.funcs.TexImage2D(glimpl.TEXTURE_2D, 0, tex.triple.internalFormat, width, height, tex.triple.format, tex.triple.typ) b.funcs.TexImage2D(gl.TEXTURE_2D, 0, tex.triple.internalFormat, width, height, tex.triple.format, tex.triple.typ)
} }
if err := glErr(b.funcs); err != nil { if err := glErr(b.funcs); err != nil {
tex.Release() tex.Release()
@@ -282,7 +282,7 @@ func (b *Backend) NewBuffer(typ driver.BufferBinding, size int) (driver.Buffer,
} }
firstBinding := firstBufferType(typ) firstBinding := firstBufferType(typ)
b.funcs.BindBuffer(firstBinding, buf.obj) b.funcs.BindBuffer(firstBinding, buf.obj)
b.funcs.BufferData(firstBinding, size, glimpl.DYNAMIC_DRAW) b.funcs.BufferData(firstBinding, size, gl.DYNAMIC_DRAW)
} }
return buf, nil return buf, nil
} }
@@ -293,7 +293,7 @@ func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (dri
buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true} buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true}
firstBinding := firstBufferType(typ) firstBinding := firstBufferType(typ)
b.funcs.BindBuffer(firstBinding, buf.obj) b.funcs.BindBuffer(firstBinding, buf.obj)
b.funcs.BufferData(firstBinding, len(data), glimpl.STATIC_DRAW) b.funcs.BufferData(firstBinding, len(data), gl.STATIC_DRAW)
buf.Upload(data) buf.Upload(data)
buf.immutable = true buf.immutable = true
if err := glErr(b.funcs); err != nil { if err := glErr(b.funcs); err != nil {
@@ -303,8 +303,8 @@ func (b *Backend) NewImmutableBuffer(typ driver.BufferBinding, data []byte) (dri
return buf, nil return buf, nil
} }
func glErr(f *glimpl.Functions) error { func glErr(f *gl.Functions) error {
if st := f.GetError(); st != glimpl.NO_ERROR { if st := f.GetError(); st != gl.NO_ERROR {
return fmt.Errorf("glGetError: %#x", st) return fmt.Errorf("glGetError: %#x", st)
} }
return nil return nil
@@ -314,14 +314,14 @@ func (b *Backend) Release() {
} }
func (b *Backend) MemoryBarrier() { func (b *Backend) MemoryBarrier() {
b.funcs.MemoryBarrier(glimpl.ALL_BARRIER_BITS) b.funcs.MemoryBarrier(gl.ALL_BARRIER_BITS)
} }
func (b *Backend) DispatchCompute(x, y, z int) { func (b *Backend) DispatchCompute(x, y, z int) {
if p := b.state.prog; p != nil { if p := b.state.prog; p != nil {
for binding, buf := range p.storage { for binding, buf := range p.storage {
if buf != nil { if buf != nil {
b.funcs.BindBufferBase(glimpl.SHADER_STORAGE_BUFFER, binding, buf.obj) b.funcs.BindBufferBase(gl.SHADER_STORAGE_BUFFER, binding, buf.obj)
} }
} }
} }
@@ -330,19 +330,19 @@ func (b *Backend) DispatchCompute(x, y, z int) {
func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.AccessBits, f driver.TextureFormat) { func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.AccessBits, f driver.TextureFormat) {
t := tex.(*gpuTexture) t := tex.(*gpuTexture)
var acc glimpl.Enum var acc gl.Enum
switch access { switch access {
case driver.AccessWrite: case driver.AccessWrite:
acc = glimpl.WRITE_ONLY acc = gl.WRITE_ONLY
case driver.AccessRead: case driver.AccessRead:
acc = glimpl.READ_ONLY acc = gl.READ_ONLY
default: default:
panic("unsupported access bits") panic("unsupported access bits")
} }
var format glimpl.Enum var format gl.Enum
switch f { switch f {
case driver.TextureFormatRGBA8: case driver.TextureFormatRGBA8:
format = glimpl.RGBA8 format = gl.RGBA8
default: default:
panic("unsupported format") panic("unsupported format")
} }
@@ -351,8 +351,8 @@ func (b *Backend) BindImageTexture(unit int, tex driver.Texture, access driver.A
func (b *Backend) bindTexture(unit int, t *gpuTexture) { func (b *Backend) bindTexture(unit int, t *gpuTexture) {
if b.state.texUnits[unit] != t { if b.state.texUnits[unit] != t {
b.funcs.ActiveTexture(glimpl.TEXTURE0 + glimpl.Enum(unit)) b.funcs.ActiveTexture(gl.TEXTURE0 + gl.Enum(unit))
b.funcs.BindTexture(glimpl.TEXTURE_2D, t.obj) b.funcs.BindTexture(gl.TEXTURE_2D, t.obj)
b.state.texUnits[unit] = t b.state.texUnits[unit] = t
} }
} }
@@ -367,20 +367,20 @@ func (b *Backend) useProgram(p *gpuProgram) {
func (b *Backend) enableVertexArrays(n int) { func (b *Backend) enableVertexArrays(n int) {
// Enable needed arrays. // Enable needed arrays.
for i := b.state.nattr; i < n; i++ { for i := b.state.nattr; i < n; i++ {
b.funcs.EnableVertexAttribArray(glimpl.Attrib(i)) b.funcs.EnableVertexAttribArray(gl.Attrib(i))
} }
// Disable extra arrays. // Disable extra arrays.
for i := n; i < b.state.nattr; i++ { for i := n; i < b.state.nattr; i++ {
b.funcs.DisableVertexAttribArray(glimpl.Attrib(i)) b.funcs.DisableVertexAttribArray(gl.Attrib(i))
} }
b.state.nattr = n b.state.nattr = n
} }
func (b *Backend) SetDepthTest(enable bool) { func (b *Backend) SetDepthTest(enable bool) {
if enable { if enable {
b.funcs.Enable(glimpl.DEPTH_TEST) b.funcs.Enable(gl.DEPTH_TEST)
} else { } else {
b.funcs.Disable(glimpl.DEPTH_TEST) b.funcs.Disable(gl.DEPTH_TEST)
} }
} }
@@ -388,16 +388,16 @@ func (b *Backend) BlendFunc(sfactor, dfactor driver.BlendFactor) {
b.funcs.BlendFunc(toGLBlendFactor(sfactor), toGLBlendFactor(dfactor)) b.funcs.BlendFunc(toGLBlendFactor(sfactor), toGLBlendFactor(dfactor))
} }
func toGLBlendFactor(f driver.BlendFactor) glimpl.Enum { func toGLBlendFactor(f driver.BlendFactor) gl.Enum {
switch f { switch f {
case driver.BlendFactorOne: case driver.BlendFactorOne:
return glimpl.ONE return gl.ONE
case driver.BlendFactorOneMinusSrcAlpha: case driver.BlendFactorOneMinusSrcAlpha:
return glimpl.ONE_MINUS_SRC_ALPHA return gl.ONE_MINUS_SRC_ALPHA
case driver.BlendFactorZero: case driver.BlendFactorZero:
return glimpl.ZERO return gl.ZERO
case driver.BlendFactorDstColor: case driver.BlendFactorDstColor:
return glimpl.DST_COLOR return gl.DST_COLOR
default: default:
panic("unsupported blend factor") panic("unsupported blend factor")
} }
@@ -409,9 +409,9 @@ func (b *Backend) DepthMask(mask bool) {
func (b *Backend) SetBlend(enable bool) { func (b *Backend) SetBlend(enable bool) {
if enable { if enable {
b.funcs.Enable(glimpl.BLEND) b.funcs.Enable(gl.BLEND)
} else { } else {
b.funcs.Disable(glimpl.BLEND) b.funcs.Disable(gl.BLEND)
} }
} }
@@ -419,7 +419,7 @@ func (b *Backend) DrawElements(mode driver.DrawMode, off, count int) {
b.prepareDraw() b.prepareDraw()
// off is in 16-bit indices, but DrawElements take a byte offset. // off is in 16-bit indices, but DrawElements take a byte offset.
byteOff := off * 2 byteOff := off * 2
b.funcs.DrawElements(toGLDrawMode(mode), count, glimpl.UNSIGNED_SHORT, byteOff) b.funcs.DrawElements(toGLDrawMode(mode), count, gl.UNSIGNED_SHORT, byteOff)
} }
func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) { func (b *Backend) DrawArrays(mode driver.DrawMode, off, count int) {
@@ -438,12 +438,12 @@ func (b *Backend) prepareDraw() {
} }
} }
func toGLDrawMode(mode driver.DrawMode) glimpl.Enum { func toGLDrawMode(mode driver.DrawMode) gl.Enum {
switch mode { switch mode {
case driver.DrawModeTriangleStrip: case driver.DrawModeTriangleStrip:
return glimpl.TRIANGLE_STRIP return gl.TRIANGLE_STRIP
case driver.DrawModeTriangles: case driver.DrawModeTriangles:
return glimpl.TRIANGLES return gl.TRIANGLES
default: default:
panic("unsupported draw mode") panic("unsupported draw mode")
} }
@@ -455,21 +455,21 @@ func (b *Backend) Viewport(x, y, width, height int) {
func (b *Backend) Clear(colR, colG, colB, colA float32) { func (b *Backend) Clear(colR, colG, colB, colA float32) {
b.funcs.ClearColor(colR, colG, colB, colA) b.funcs.ClearColor(colR, colG, colB, colA)
b.funcs.Clear(glimpl.COLOR_BUFFER_BIT) b.funcs.Clear(gl.COLOR_BUFFER_BIT)
} }
func (b *Backend) ClearDepth(d float32) { func (b *Backend) ClearDepth(d float32) {
b.funcs.ClearDepthf(d) b.funcs.ClearDepthf(d)
b.funcs.Clear(glimpl.DEPTH_BUFFER_BIT) b.funcs.Clear(gl.DEPTH_BUFFER_BIT)
} }
func (b *Backend) DepthFunc(f driver.DepthFunc) { func (b *Backend) DepthFunc(f driver.DepthFunc) {
var glfunc glimpl.Enum var glfunc gl.Enum
switch f { switch f {
case driver.DepthFuncGreater: case driver.DepthFuncGreater:
glfunc = glimpl.GREATER glfunc = gl.GREATER
case driver.DepthFuncGreaterEqual: case driver.DepthFuncGreaterEqual:
glfunc = glimpl.GEQUAL glfunc = gl.GEQUAL
default: default:
panic("unsupported depth func") panic("unsupported depth func")
} }
@@ -492,7 +492,7 @@ func (b *Backend) NewInputLayout(vs driver.ShaderSources, layout []driver.InputD
} }
func (b *Backend) NewComputeProgram(src driver.ShaderSources) (driver.Program, error) { func (b *Backend) NewComputeProgram(src driver.ShaderSources) (driver.Program, error) {
p, err := glimpl.CreateComputeProgram(b.funcs, src.GLSL310ES) p, err := gl.CreateComputeProgram(b.funcs, src.GLSL310ES)
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: %v", src.Name, err) return nil, fmt.Errorf("%s: %v", src.Name, err)
} }
@@ -521,7 +521,7 @@ func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (drive
vsrc, fsrc = vertShader.GLSL130, fragShader.GLSL130 vsrc, fsrc = vertShader.GLSL130, fragShader.GLSL130
} }
} }
p, err := glimpl.CreateProgram(b.funcs, vsrc, fsrc, attr) p, err := gl.CreateProgram(b.funcs, vsrc, fsrc, attr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -547,7 +547,7 @@ func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (drive
if b.ubo { if b.ubo {
for _, block := range vertShader.Uniforms.Blocks { for _, block := range vertShader.Uniforms.Blocks {
blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name) blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
if blockIdx != glimpl.INVALID_INDEX { if blockIdx != gl.INVALID_INDEX {
b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding)) b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding))
} }
} }
@@ -557,7 +557,7 @@ func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (drive
off := len(vertShader.Uniforms.Blocks) off := len(vertShader.Uniforms.Blocks)
for _, block := range fragShader.Uniforms.Blocks { for _, block := range fragShader.Uniforms.Blocks {
blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name) blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
if blockIdx != glimpl.INVALID_INDEX { if blockIdx != gl.INVALID_INDEX {
b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding+off)) b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding+off))
} }
} }
@@ -568,7 +568,7 @@ func (b *Backend) NewProgram(vertShader, fragShader driver.ShaderSources) (drive
return gpuProg, nil return gpuProg, nil
} }
func lookupUniform(funcs *glimpl.Functions, p glimpl.Program, loc driver.UniformLocation) uniformLocation { func lookupUniform(funcs *gl.Functions, p gl.Program, loc driver.UniformLocation) uniformLocation {
u := funcs.GetUniformLocation(p, loc.Name) u := funcs.GetUniformLocation(p, loc.Name)
return uniformLocation{uniform: u, offset: loc.Offset, typ: loc.Type, size: loc.Size} return uniformLocation{uniform: u, offset: loc.Offset, typ: loc.Type, size: loc.Size}
} }
@@ -593,10 +593,10 @@ func (p *gpuProgram) updateUniforms() {
f := p.backend.funcs f := p.backend.funcs
if p.backend.ubo { if p.backend.ubo {
if b := p.vertUniforms.buf; b != nil { if b := p.vertUniforms.buf; b != nil {
f.BindBufferBase(glimpl.UNIFORM_BUFFER, 0, b.obj) f.BindBufferBase(gl.UNIFORM_BUFFER, 0, b.obj)
} }
if b := p.fragUniforms.buf; b != nil { if b := p.fragUniforms.buf; b != nil {
f.BindBufferBase(glimpl.UNIFORM_BUFFER, 1, b.obj) f.BindBufferBase(gl.UNIFORM_BUFFER, 1, b.obj)
} }
} else { } else {
p.vertUniforms.update(f) p.vertUniforms.update(f)
@@ -613,7 +613,7 @@ func (p *gpuProgram) Release() {
p.backend.funcs.DeleteProgram(p.obj) p.backend.funcs.DeleteProgram(p.obj)
} }
func (u *uniformsTracker) setup(funcs *glimpl.Functions, p glimpl.Program, uniformSize int, uniforms []driver.UniformLocation) { func (u *uniformsTracker) setup(funcs *gl.Functions, p gl.Program, uniformSize int, uniforms []driver.UniformLocation) {
u.locs = make([]uniformLocation, len(uniforms)) u.locs = make([]uniformLocation, len(uniforms))
for i, uniform := range uniforms { for i, uniform := range uniforms {
u.locs[i] = lookupUniform(funcs, p, uniform) u.locs[i] = lookupUniform(funcs, p, uniform)
@@ -634,7 +634,7 @@ func (u *uniformsTracker) setBuffer(buffer driver.Buffer) {
u.version = buf.version - 1 u.version = buf.version - 1
} }
func (p *uniformsTracker) update(funcs *glimpl.Functions) { func (p *uniformsTracker) update(funcs *gl.Functions) {
b := p.buf b := p.buf
if b == nil || b.version == p.version { if b == nil || b.version == p.version {
return return
@@ -682,7 +682,7 @@ func (b *gpuBuffer) Upload(data []byte) {
// the iOS GL implementation doesn't recognize when BufferSubData // the iOS GL implementation doesn't recognize when BufferSubData
// clears the entire buffer. Tell it and avoid GPU stalls. // clears the entire buffer. Tell it and avoid GPU stalls.
// See also https://github.com/godotengine/godot/issues/23956. // See also https://github.com/godotengine/godot/issues/23956.
b.backend.funcs.BufferData(firstBinding, b.size, glimpl.DYNAMIC_DRAW) b.backend.funcs.BufferData(firstBinding, b.size, gl.DYNAMIC_DRAW)
} }
b.backend.funcs.BufferSubData(firstBinding, 0, data) b.backend.funcs.BufferSubData(firstBinding, 0, data)
} }
@@ -698,7 +698,7 @@ func (b *gpuBuffer) Download(data []byte) error {
} }
firstBinding := firstBufferType(b.typ) firstBinding := firstBufferType(b.typ)
b.backend.funcs.BindBuffer(firstBinding, b.obj) b.backend.funcs.BindBuffer(firstBinding, b.obj)
bufferMap := b.backend.funcs.MapBufferRange(firstBinding, 0, len(data), glimpl.MAP_READ_BIT) bufferMap := b.backend.funcs.MapBufferRange(firstBinding, 0, len(data), gl.MAP_READ_BIT)
if bufferMap == nil { if bufferMap == nil {
return fmt.Errorf("MapBufferRange: error %#x", b.backend.funcs.GetError()) return fmt.Errorf("MapBufferRange: error %#x", b.backend.funcs.GetError())
} }
@@ -730,19 +730,19 @@ func (b *Backend) setupVertexArrays() {
return return
} }
buf := b.state.buffer buf := b.state.buffer
b.funcs.BindBuffer(glimpl.ARRAY_BUFFER, buf.buf.obj) b.funcs.BindBuffer(gl.ARRAY_BUFFER, buf.buf.obj)
for i, inp := range layout.inputs { for i, inp := range layout.inputs {
l := layout.layout[i] l := layout.layout[i]
var gltyp glimpl.Enum var gltyp gl.Enum
switch l.Type { switch l.Type {
case driver.DataTypeFloat: case driver.DataTypeFloat:
gltyp = glimpl.FLOAT gltyp = gl.FLOAT
case driver.DataTypeShort: case driver.DataTypeShort:
gltyp = glimpl.SHORT gltyp = gl.SHORT
default: default:
panic("unsupported data type") panic("unsupported data type")
} }
b.funcs.VertexAttribPointer(glimpl.Attrib(inp.Location), l.Size, gltyp, false, buf.stride, buf.offset+l.Offset) b.funcs.VertexAttribPointer(gl.Attrib(inp.Location), l.Size, gltyp, false, buf.stride, buf.offset+l.Offset)
} }
} }
@@ -751,17 +751,17 @@ func (b *Backend) BindIndexBuffer(buf driver.Buffer) {
if gbuf.typ&driver.BufferBindingIndices == 0 { if gbuf.typ&driver.BufferBindingIndices == 0 {
panic("not an index buffer") panic("not an index buffer")
} }
b.funcs.BindBuffer(glimpl.ELEMENT_ARRAY_BUFFER, gbuf.obj) b.funcs.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, gbuf.obj)
} }
func (b *Backend) BlitFramebuffer(dst, src driver.Framebuffer, srect, drect image.Rectangle) { func (b *Backend) BlitFramebuffer(dst, src driver.Framebuffer, srect, drect image.Rectangle) {
b.funcs.BindFramebuffer(glimpl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj) b.funcs.BindFramebuffer(gl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj)
b.funcs.BindFramebuffer(glimpl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj) b.funcs.BindFramebuffer(gl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj)
b.funcs.BlitFramebuffer( b.funcs.BlitFramebuffer(
srect.Min.X, srect.Min.Y, srect.Max.X, srect.Max.Y, srect.Min.X, srect.Min.Y, srect.Max.X, srect.Max.Y,
drect.Min.X, drect.Min.Y, drect.Max.X, drect.Max.Y, drect.Min.X, drect.Min.Y, drect.Max.X, drect.Max.Y,
glimpl.COLOR_BUFFER_BIT|glimpl.DEPTH_BUFFER_BIT|glimpl.STENCIL_BUFFER_BIT, gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT|gl.STENCIL_BUFFER_BIT,
glimpl.NEAREST) gl.NEAREST)
} }
func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error { func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
@@ -770,7 +770,7 @@ func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error {
if len(pixels) < src.Dx()*src.Dy()*4 { if len(pixels) < src.Dx()*src.Dy()*4 {
return errors.New("unexpected RGBA size") return errors.New("unexpected RGBA size")
} }
f.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, src.Dx(), src.Dy(), glimpl.RGBA, glimpl.UNSIGNED_BYTE, pixels) f.backend.funcs.ReadPixels(src.Min.X, src.Min.Y, src.Dx(), src.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pixels)
// OpenGL origin is in the lower-left corner. Flip the image to // OpenGL origin is in the lower-left corner. Flip the image to
// match. // match.
flipImageY(src.Dx()*4, src.Dy(), pixels) flipImageY(src.Dx()*4, src.Dy(), pixels)
@@ -792,12 +792,12 @@ func flipImageY(stride int, height int, pixels []byte) {
} }
func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) { func (b *Backend) BindFramebuffer(fbo driver.Framebuffer) {
b.funcs.BindFramebuffer(glimpl.FRAMEBUFFER, fbo.(*gpuFramebuffer).obj) b.funcs.BindFramebuffer(gl.FRAMEBUFFER, fbo.(*gpuFramebuffer).obj)
} }
func (f *gpuFramebuffer) Invalidate() { func (f *gpuFramebuffer) Invalidate() {
f.backend.BindFramebuffer(f) f.backend.BindFramebuffer(f)
f.backend.funcs.InvalidateFramebuffer(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0) f.backend.funcs.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
} }
func (f *gpuFramebuffer) Release() { func (f *gpuFramebuffer) Release() {
@@ -813,9 +813,9 @@ func (f *gpuFramebuffer) Release() {
func toTexFilter(f driver.TextureFilter) int { func toTexFilter(f driver.TextureFilter) int {
switch f { switch f {
case driver.FilterNearest: case driver.FilterNearest:
return glimpl.NEAREST return gl.NEAREST
case driver.FilterLinear: case driver.FilterLinear:
return glimpl.LINEAR return gl.LINEAR
default: default:
panic("unsupported texture filter") panic("unsupported texture filter")
} }
@@ -834,19 +834,19 @@ func (t *gpuTexture) Upload(offset, size image.Point, pixels []byte) {
panic(fmt.Errorf("size %d larger than data %d", min, len(pixels))) panic(fmt.Errorf("size %d larger than data %d", min, len(pixels)))
} }
t.backend.BindTexture(0, t) t.backend.BindTexture(0, t)
t.backend.funcs.TexSubImage2D(glimpl.TEXTURE_2D, 0, offset.X, offset.Y, size.X, size.Y, t.triple.format, t.triple.typ, pixels) t.backend.funcs.TexSubImage2D(gl.TEXTURE_2D, 0, offset.X, offset.Y, size.X, size.Y, t.triple.format, t.triple.typ, pixels)
} }
func (t *gpuTimer) Begin() { func (t *gpuTimer) Begin() {
t.funcs.BeginQuery(glimpl.TIME_ELAPSED_EXT, t.obj) t.funcs.BeginQuery(gl.TIME_ELAPSED_EXT, t.obj)
} }
func (t *gpuTimer) End() { func (t *gpuTimer) End() {
t.funcs.EndQuery(glimpl.TIME_ELAPSED_EXT) t.funcs.EndQuery(gl.TIME_ELAPSED_EXT)
} }
func (t *gpuTimer) ready() bool { func (t *gpuTimer) ready() bool {
return t.funcs.GetQueryObjectuiv(t.obj, glimpl.QUERY_RESULT_AVAILABLE) == glimpl.TRUE return t.funcs.GetQueryObjectuiv(t.obj, gl.QUERY_RESULT_AVAILABLE) == gl.TRUE
} }
func (t *gpuTimer) Release() { func (t *gpuTimer) Release() {
@@ -857,7 +857,7 @@ func (t *gpuTimer) Duration() (time.Duration, bool) {
if !t.ready() { if !t.ready() {
return 0, false return 0, false
} }
nanos := t.funcs.GetQueryObjectuiv(t.obj, glimpl.QUERY_RESULT) nanos := t.funcs.GetQueryObjectuiv(t.obj, gl.QUERY_RESULT)
return time.Duration(nanos), true return time.Duration(nanos), true
} }
@@ -868,10 +868,10 @@ func (b *Backend) BindInputLayout(l driver.InputLayout) {
func (l *gpuInputLayout) Release() {} func (l *gpuInputLayout) Release() {}
// floatTripleFor determines the best texture triple for floating point FBOs. // floatTripleFor determines the best texture triple for floating point FBOs.
func floatTripleFor(f *glimpl.Functions, ver [2]int, exts []string) (textureTriple, error) { func floatTripleFor(f *gl.Functions, ver [2]int, exts []string) (textureTriple, error) {
var triples []textureTriple var triples []textureTriple
if ver[0] >= 3 { if ver[0] >= 3 {
triples = append(triples, textureTriple{glimpl.R16F, glimpl.Enum(glimpl.RED), glimpl.Enum(glimpl.HALF_FLOAT)}) triples = append(triples, textureTriple{gl.R16F, gl.Enum(gl.RED), gl.Enum(gl.HALF_FLOAT)})
} }
// According to the OES_texture_half_float specification, EXT_color_buffer_half_float is needed to // According to the OES_texture_half_float specification, EXT_color_buffer_half_float is needed to
// render to FBOs. However, the Safari WebGL1 implementation does support half-float FBOs but does not // render to FBOs. However, the Safari WebGL1 implementation does support half-float FBOs but does not
@@ -879,32 +879,32 @@ func floatTripleFor(f *glimpl.Functions, ver [2]int, exts []string) (textureTrip
// wrong. // wrong.
if hasExtension(exts, "GL_OES_texture_half_float") || hasExtension(exts, "GL_EXT_color_buffer_half_float") { if hasExtension(exts, "GL_OES_texture_half_float") || hasExtension(exts, "GL_EXT_color_buffer_half_float") {
// Try single channel. // Try single channel.
triples = append(triples, textureTriple{glimpl.LUMINANCE, glimpl.Enum(glimpl.LUMINANCE), glimpl.Enum(glimpl.HALF_FLOAT_OES)}) triples = append(triples, textureTriple{gl.LUMINANCE, gl.Enum(gl.LUMINANCE), gl.Enum(gl.HALF_FLOAT_OES)})
// Fallback to 4 channels. // Fallback to 4 channels.
triples = append(triples, textureTriple{glimpl.RGBA, glimpl.Enum(glimpl.RGBA), glimpl.Enum(glimpl.HALF_FLOAT_OES)}) triples = append(triples, textureTriple{gl.RGBA, gl.Enum(gl.RGBA), gl.Enum(gl.HALF_FLOAT_OES)})
} }
if hasExtension(exts, "GL_OES_texture_float") || hasExtension(exts, "GL_EXT_color_buffer_float") { if hasExtension(exts, "GL_OES_texture_float") || hasExtension(exts, "GL_EXT_color_buffer_float") {
triples = append(triples, textureTriple{glimpl.RGBA, glimpl.Enum(glimpl.RGBA), glimpl.Enum(glimpl.FLOAT)}) triples = append(triples, textureTriple{gl.RGBA, gl.Enum(gl.RGBA), gl.Enum(gl.FLOAT)})
} }
tex := f.CreateTexture() tex := f.CreateTexture()
defer f.DeleteTexture(tex) defer f.DeleteTexture(tex)
f.BindTexture(glimpl.TEXTURE_2D, tex) f.BindTexture(gl.TEXTURE_2D, tex)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_S, glimpl.CLAMP_TO_EDGE) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_T, glimpl.CLAMP_TO_EDGE) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MAG_FILTER, glimpl.NEAREST) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MIN_FILTER, glimpl.NEAREST) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
fbo := f.CreateFramebuffer() fbo := f.CreateFramebuffer()
defer f.DeleteFramebuffer(fbo) defer f.DeleteFramebuffer(fbo)
defFBO := glimpl.Framebuffer(f.GetBinding(glimpl.FRAMEBUFFER_BINDING)) defFBO := gl.Framebuffer(f.GetBinding(gl.FRAMEBUFFER_BINDING))
f.BindFramebuffer(glimpl.FRAMEBUFFER, fbo) f.BindFramebuffer(gl.FRAMEBUFFER, fbo)
defer f.BindFramebuffer(glimpl.FRAMEBUFFER, defFBO) defer f.BindFramebuffer(gl.FRAMEBUFFER, defFBO)
var attempts []string var attempts []string
for _, tt := range triples { for _, tt := range triples {
const size = 256 const size = 256
f.TexImage2D(glimpl.TEXTURE_2D, 0, tt.internalFormat, size, size, tt.format, tt.typ) f.TexImage2D(gl.TEXTURE_2D, 0, tt.internalFormat, size, size, tt.format, tt.typ)
f.FramebufferTexture2D(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0, glimpl.TEXTURE_2D, tex, 0) f.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0)
st := f.CheckFramebufferStatus(glimpl.FRAMEBUFFER) st := f.CheckFramebufferStatus(gl.FRAMEBUFFER)
if st == glimpl.FRAMEBUFFER_COMPLETE { if st == gl.FRAMEBUFFER_COMPLETE {
return tt, nil return tt, nil
} }
attempts = append(attempts, fmt.Sprintf("(0x%x, 0x%x, 0x%x): 0x%x", tt.internalFormat, tt.format, tt.typ, st)) attempts = append(attempts, fmt.Sprintf("(0x%x, 0x%x, 0x%x): 0x%x", tt.internalFormat, tt.format, tt.typ, st))
@@ -915,21 +915,21 @@ func floatTripleFor(f *glimpl.Functions, ver [2]int, exts []string) (textureTrip
func srgbaTripleFor(ver [2]int, exts []string) (textureTriple, error) { func srgbaTripleFor(ver [2]int, exts []string) (textureTriple, error) {
switch { switch {
case ver[0] >= 3: case ver[0] >= 3:
return textureTriple{glimpl.SRGB8_ALPHA8, glimpl.Enum(glimpl.RGBA), glimpl.Enum(glimpl.UNSIGNED_BYTE)}, nil return textureTriple{gl.SRGB8_ALPHA8, gl.Enum(gl.RGBA), gl.Enum(gl.UNSIGNED_BYTE)}, nil
case hasExtension(exts, "GL_EXT_sRGB"): case hasExtension(exts, "GL_EXT_sRGB"):
return textureTriple{glimpl.SRGB_ALPHA_EXT, glimpl.Enum(glimpl.SRGB_ALPHA_EXT), glimpl.Enum(glimpl.UNSIGNED_BYTE)}, nil return textureTriple{gl.SRGB_ALPHA_EXT, gl.Enum(gl.SRGB_ALPHA_EXT), gl.Enum(gl.UNSIGNED_BYTE)}, nil
default: default:
return textureTriple{}, errors.New("no sRGB texture formats found") return textureTriple{}, errors.New("no sRGB texture formats found")
} }
} }
func alphaTripleFor(ver [2]int) textureTriple { func alphaTripleFor(ver [2]int) textureTriple {
intf, f := glimpl.Enum(glimpl.R8), glimpl.Enum(glimpl.RED) intf, f := gl.Enum(gl.R8), gl.Enum(gl.RED)
if ver[0] < 3 { if ver[0] < 3 {
// R8, RED not supported on OpenGL ES 2.0. // R8, RED not supported on OpenGL ES 2.0.
intf, f = glimpl.LUMINANCE, glimpl.Enum(glimpl.LUMINANCE) intf, f = gl.LUMINANCE, gl.Enum(gl.LUMINANCE)
} }
return textureTriple{intf, f, glimpl.UNSIGNED_BYTE} return textureTriple{intf, f, gl.UNSIGNED_BYTE}
} }
func hasExtension(exts []string, ext string) bool { func hasExtension(exts []string, ext string) bool {
@@ -941,16 +941,16 @@ func hasExtension(exts []string, ext string) bool {
return false return false
} }
func firstBufferType(typ driver.BufferBinding) glimpl.Enum { func firstBufferType(typ driver.BufferBinding) gl.Enum {
switch { switch {
case typ&driver.BufferBindingIndices != 0: case typ&driver.BufferBindingIndices != 0:
return glimpl.ELEMENT_ARRAY_BUFFER return gl.ELEMENT_ARRAY_BUFFER
case typ&driver.BufferBindingVertices != 0: case typ&driver.BufferBindingVertices != 0:
return glimpl.ARRAY_BUFFER return gl.ARRAY_BUFFER
case typ&driver.BufferBindingUniforms != 0: case typ&driver.BufferBindingUniforms != 0:
return glimpl.UNIFORM_BUFFER return gl.UNIFORM_BUFFER
case typ&driver.BufferBindingShaderStorage != 0: case typ&driver.BufferBindingShaderStorage != 0:
return glimpl.SHADER_STORAGE_BUFFER return gl.SHADER_STORAGE_BUFFER
default: default:
panic("unsupported buffer type") panic("unsupported buffer type")
} }
+3 -3
View File
@@ -11,12 +11,12 @@ import (
"strings" "strings"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
"gioui.org/internal/srgb" "gioui.org/internal/srgb"
) )
type Context struct { type Context struct {
c *glimpl.Functions c *gl.Functions
disp _EGLDisplay disp _EGLDisplay
eglCtx *eglContext eglCtx *eglContext
eglSurf _EGLSurface eglSurf _EGLSurface
@@ -105,7 +105,7 @@ func NewContext(disp NativeDisplayType) (*Context, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
f, err := glimpl.NewFunctions(nil) f, err := gl.NewFunctions(nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+2 -2
View File
@@ -10,7 +10,7 @@ import (
syscall "golang.org/x/sys/windows" syscall "golang.org/x/sys/windows"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
gunsafe "gioui.org/internal/unsafe" gunsafe "gioui.org/internal/unsafe"
) )
@@ -57,7 +57,7 @@ func loadDLLs() error {
if err := loadDLL(libEGL, "libEGL.dll"); err != nil { if err := loadDLL(libEGL, "libEGL.dll"); err != nil {
return err return err
} }
if err := loadDLL(glimpl.LibGLESv2, "libGLESv2.dll"); err != nil { if err := loadDLL(gl.LibGLESv2, "libGLESv2.dll"); err != nil {
return err return err
} }
// d3dcompiler_47.dll is needed internally for shader compilation to function. // d3dcompiler_47.dll is needed internally for shader compilation to function.
+1 -1
View File
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package glimpl package gl
type ( type (
Attrib uint Attrib uint
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package glimpl package gl
import ( import (
"errors" "errors"
@@ -2,7 +2,7 @@
// +build darwin linux freebsd openbsd // +build darwin linux freebsd openbsd
package glimpl package gl
import ( import (
"runtime" "runtime"
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package glimpl package gl
import ( import (
"math" "math"
@@ -1,6 +1,6 @@
// +build !js // +build !js
package glimpl package gl
type ( type (
Buffer struct{ V uint } Buffer struct{ V uint }
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package glimpl package gl
import "syscall/js" import "syscall/js"
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package glimpl package gl
import ( import (
"errors" "errors"
+48 -48
View File
@@ -7,7 +7,7 @@ import (
"runtime" "runtime"
"strings" "strings"
"gioui.org/internal/glimpl" "gioui.org/internal/gl"
"gioui.org/internal/unsafe" "gioui.org/internal/unsafe"
) )
@@ -15,32 +15,32 @@ import (
// for gamma-correct rendering on platforms without // for gamma-correct rendering on platforms without
// sRGB enabled native framebuffers. // sRGB enabled native framebuffers.
type FBO struct { type FBO struct {
c *glimpl.Functions c *gl.Functions
width, height int width, height int
frameBuffer glimpl.Framebuffer frameBuffer gl.Framebuffer
depthBuffer glimpl.Renderbuffer depthBuffer gl.Renderbuffer
colorTex glimpl.Texture colorTex gl.Texture
blitted bool blitted bool
quad glimpl.Buffer quad gl.Buffer
prog glimpl.Program prog gl.Program
gl3 bool gl3 bool
} }
func New(ctx glimpl.Context) (*FBO, error) { func New(ctx gl.Context) (*FBO, error) {
f, err := glimpl.NewFunctions(ctx) f, err := gl.NewFunctions(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var gl3 bool var gl3 bool
glVer := f.GetString(glimpl.VERSION) glVer := f.GetString(gl.VERSION)
ver, _, err := glimpl.ParseGLVersion(glVer) ver, _, err := gl.ParseGLVersion(glVer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ver[0] >= 3 { if ver[0] >= 3 {
gl3 = true gl3 = true
} else { } else {
exts := f.GetString(glimpl.EXTENSIONS) exts := f.GetString(gl.EXTENSIONS)
if !strings.Contains(exts, "EXT_sRGB") { if !strings.Contains(exts, "EXT_sRGB") {
return nil, fmt.Errorf("no support for OpenGL ES 3 nor EXT_sRGB") return nil, fmt.Errorf("no support for OpenGL ES 3 nor EXT_sRGB")
} }
@@ -52,17 +52,17 @@ func New(ctx glimpl.Context) (*FBO, error) {
colorTex: f.CreateTexture(), colorTex: f.CreateTexture(),
depthBuffer: f.CreateRenderbuffer(), depthBuffer: f.CreateRenderbuffer(),
} }
f.BindTexture(glimpl.TEXTURE_2D, s.colorTex) f.BindTexture(gl.TEXTURE_2D, s.colorTex)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_S, glimpl.CLAMP_TO_EDGE) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_T, glimpl.CLAMP_TO_EDGE) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MAG_FILTER, glimpl.NEAREST) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
f.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MIN_FILTER, glimpl.NEAREST) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
return s, nil return s, nil
} }
func (s *FBO) Blit() { func (s *FBO) Blit() {
if !s.blitted { if !s.blitted {
prog, err := glimpl.CreateProgram(s.c, blitVSrc, blitFSrc, []string{"pos", "uv"}) prog, err := gl.CreateProgram(s.c, blitVSrc, blitFSrc, []string{"pos", "uv"})
if err != nil { if err != nil {
panic(err) panic(err)
} }
@@ -70,39 +70,39 @@ func (s *FBO) Blit() {
s.c.UseProgram(prog) s.c.UseProgram(prog)
s.c.Uniform1i(s.c.GetUniformLocation(prog, "tex"), 0) s.c.Uniform1i(s.c.GetUniformLocation(prog, "tex"), 0)
s.quad = s.c.CreateBuffer() s.quad = s.c.CreateBuffer()
s.c.BindBuffer(glimpl.ARRAY_BUFFER, s.quad) s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
coords := unsafe.BytesView([]float32{ coords := unsafe.BytesView([]float32{
-1, +1, 0, 1, -1, +1, 0, 1,
+1, +1, 1, 1, +1, +1, 1, 1,
-1, -1, 0, 0, -1, -1, 0, 0,
+1, -1, 1, 0, +1, -1, 1, 0,
}) })
s.c.BufferData(glimpl.ARRAY_BUFFER, len(coords), glimpl.STATIC_DRAW) s.c.BufferData(gl.ARRAY_BUFFER, len(coords), gl.STATIC_DRAW)
s.c.BufferSubData(glimpl.ARRAY_BUFFER, 0, coords) s.c.BufferSubData(gl.ARRAY_BUFFER, 0, coords)
s.blitted = true s.blitted = true
} }
s.c.BindFramebuffer(glimpl.FRAMEBUFFER, glimpl.Framebuffer{}) s.c.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{})
s.c.UseProgram(s.prog) s.c.UseProgram(s.prog)
s.c.BindTexture(glimpl.TEXTURE_2D, s.colorTex) s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
s.c.BindBuffer(glimpl.ARRAY_BUFFER, s.quad) s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
s.c.VertexAttribPointer(0 /* pos */, 2, glimpl.FLOAT, false, 4*4, 0) s.c.VertexAttribPointer(0 /* pos */, 2, gl.FLOAT, false, 4*4, 0)
s.c.VertexAttribPointer(1 /* uv */, 2, glimpl.FLOAT, false, 4*4, 4*2) s.c.VertexAttribPointer(1 /* uv */, 2, gl.FLOAT, false, 4*4, 4*2)
s.c.EnableVertexAttribArray(0) s.c.EnableVertexAttribArray(0)
s.c.EnableVertexAttribArray(1) s.c.EnableVertexAttribArray(1)
s.c.DrawArrays(glimpl.TRIANGLE_STRIP, 0, 4) s.c.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
s.c.BindTexture(glimpl.TEXTURE_2D, glimpl.Texture{}) s.c.BindTexture(gl.TEXTURE_2D, gl.Texture{})
s.c.DisableVertexAttribArray(0) s.c.DisableVertexAttribArray(0)
s.c.DisableVertexAttribArray(1) s.c.DisableVertexAttribArray(1)
s.c.BindFramebuffer(glimpl.FRAMEBUFFER, s.frameBuffer) s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
s.c.InvalidateFramebuffer(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0) s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
s.c.InvalidateFramebuffer(glimpl.FRAMEBUFFER, glimpl.DEPTH_ATTACHMENT) s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
// The Android emulator requires framebuffer 0 bound at eglSwapBuffer time. // The Android emulator requires framebuffer 0 bound at eglSwapBuffer time.
// Bind the sRGB framebuffer again in afterPresent. // Bind the sRGB framebuffer again in afterPresent.
s.c.BindFramebuffer(glimpl.FRAMEBUFFER, glimpl.Framebuffer{}) s.c.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{})
} }
func (s *FBO) AfterPresent() { func (s *FBO) AfterPresent() {
s.c.BindFramebuffer(glimpl.FRAMEBUFFER, s.frameBuffer) s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
} }
func (s *FBO) Refresh(w, h int) error { func (s *FBO) Refresh(w, h int) error {
@@ -110,20 +110,20 @@ func (s *FBO) Refresh(w, h int) error {
if w == 0 || h == 0 { if w == 0 || h == 0 {
return nil return nil
} }
s.c.BindTexture(glimpl.TEXTURE_2D, s.colorTex) s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
if s.gl3 { if s.gl3 {
s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.SRGB8_ALPHA8, w, h, glimpl.RGBA, glimpl.UNSIGNED_BYTE) s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, w, h, gl.RGBA, gl.UNSIGNED_BYTE)
} else /* EXT_sRGB */ { } else /* EXT_sRGB */ {
s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.SRGB_ALPHA_EXT, w, h, glimpl.SRGB_ALPHA_EXT, glimpl.UNSIGNED_BYTE) s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB_ALPHA_EXT, w, h, gl.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE)
} }
currentRB := glimpl.Renderbuffer(s.c.GetBinding(glimpl.RENDERBUFFER_BINDING)) currentRB := gl.Renderbuffer(s.c.GetBinding(gl.RENDERBUFFER_BINDING))
s.c.BindRenderbuffer(glimpl.RENDERBUFFER, s.depthBuffer) s.c.BindRenderbuffer(gl.RENDERBUFFER, s.depthBuffer)
s.c.RenderbufferStorage(glimpl.RENDERBUFFER, glimpl.DEPTH_COMPONENT16, w, h) s.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h)
s.c.BindRenderbuffer(glimpl.RENDERBUFFER, currentRB) s.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
s.c.BindFramebuffer(glimpl.FRAMEBUFFER, s.frameBuffer) s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
s.c.FramebufferTexture2D(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0, glimpl.TEXTURE_2D, s.colorTex, 0) s.c.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, s.colorTex, 0)
s.c.FramebufferRenderbuffer(glimpl.FRAMEBUFFER, glimpl.DEPTH_ATTACHMENT, glimpl.RENDERBUFFER, s.depthBuffer) s.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, s.depthBuffer)
if st := s.c.CheckFramebufferStatus(glimpl.FRAMEBUFFER); st != glimpl.FRAMEBUFFER_COMPLETE { if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
return fmt.Errorf("sRGB framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) return fmt.Errorf("sRGB framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError())
} }
@@ -132,12 +132,12 @@ func (s *FBO) Refresh(w, h int) error {
// texture result in twice gamma corrected colors. Using a plain RGBA // texture result in twice gamma corrected colors. Using a plain RGBA
// texture seems to work. // texture seems to work.
s.c.ClearColor(.5, .5, .5, 1.0) s.c.ClearColor(.5, .5, .5, 1.0)
s.c.Clear(glimpl.COLOR_BUFFER_BIT) s.c.Clear(gl.COLOR_BUFFER_BIT)
var pixel [4]byte var pixel [4]byte
s.c.ReadPixels(0, 0, 1, 1, glimpl.RGBA, glimpl.UNSIGNED_BYTE, pixel[:]) s.c.ReadPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel[:])
if pixel[0] == 128 { // Correct sRGB color value is ~188 if pixel[0] == 128 { // Correct sRGB color value is ~188
s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.RGBA, w, h, glimpl.RGBA, glimpl.UNSIGNED_BYTE) s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, gl.RGBA, gl.UNSIGNED_BYTE)
if st := s.c.CheckFramebufferStatus(glimpl.FRAMEBUFFER); st != glimpl.FRAMEBUFFER_COMPLETE { if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
return fmt.Errorf("fallback RGBA framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) return fmt.Errorf("fallback RGBA framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError())
} }
} }