From bfe2d04c60317a97a3a463f097f35fa7cebb1f0f Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 30 Dec 2020 16:48:22 +0100 Subject: [PATCH] gpu,app,internal/glimpl: update GL backend for the compute renderer Modern graphics APIs have immutable objects, with mutable data. For example, a texture's dimensions are immutable, while the texture contents is not. Change the GPU API abstraction to match. Clearing a Texture is convenient to do with a plain []byte. Generalize Texture.Upload to take a plain byte slice and introduce a helper function for uploading *image.RGBA data. Add TextureFormatRGBA8 a format for the linear RGB colorspace. Add OpenGL ES 3.1 functions for compute programs. Signed-off-by: Elias Naur --- app/internal/d3d11/backend_windows.go | 55 +++++++--- app/internal/d3d11/d3d11_windows.go | 4 +- app/internal/srgb/srgb.go | 22 ++-- app/internal/window/d3d11_windows.go | 8 +- gpu/backend/backend.go | 58 ++++++++-- gpu/gl/backend.go | 151 ++++++++++++++++++++++---- gpu/gpu.go | 2 +- internal/glimpl/gl.go | 24 +++- internal/glimpl/gl_unix.go | 101 +++++++++++++++-- internal/glimpl/gl_windows.go | 44 +++++--- internal/glimpl/util.go | 20 ++++ 11 files changed, 400 insertions(+), 89 deletions(-) diff --git a/app/internal/d3d11/backend_windows.go b/app/internal/d3d11/backend_windows.go index 4ecb44ad..c8375ccb 100644 --- a/app/internal/d3d11/backend_windows.go +++ b/app/internal/d3d11/backend_windows.go @@ -121,12 +121,7 @@ func NewDevice() (*Device, error) { _IUnknownRelease(unsafe.Pointer(d3dctx), d3dctx.vtbl.Release) return nil, fmt.Errorf("d3d11: feature level too low: %d", featLvl) } - floatFormat, ok := detectFloatFormat(d3ddev) - if !ok { - _IUnknownRelease(unsafe.Pointer(d3ddev), d3ddev.vtbl.Release) - _IUnknownRelease(unsafe.Pointer(d3dctx), d3dctx.vtbl.Release) - return nil, fmt.Errorf("d3d11: no available floating point formats") - } + floatFormat, _ := detectFloatFormat(d3ddev) dev.floatFormat = floatFormat dev.depthStates = make(map[depthState]*_ID3D11DepthStencilState) dev.blendStates = make(map[blendState]*_ID3D11BlendState) @@ -253,6 +248,9 @@ func NewBackend(d *Device) (*Backend, error) { caps := backend.Caps{ MaxTextureSize: 2048, // 9.1 maximum } + if d.floatFormat != 0 { + caps.Features |= backend.FeatureFloatRenderTargets + } switch { case d.featLvl >= _D3D_FEATURE_LEVEL_11_0: caps.MaxTextureSize = 16384 @@ -524,6 +522,10 @@ func (b *Backend) NewImmutableBuffer(typ backend.BufferBinding, data []byte) (ba return &Buffer{backend: b, buf: buf, bind: bind, immutable: true}, nil } +func (b *Backend) NewComputeProgram(shader backend.ShaderSources) (backend.Program, error) { + panic("not implemented") +} + func (b *Backend) NewProgram(vertexShader, fragmentShader backend.ShaderSources) (backend.Program, error) { vs, err := b.dev.dev.CreateVertexShader(vertexShader.HLSL) if err != nil { @@ -667,17 +669,30 @@ func (b *Backend) BlendFunc(sfactor, dfactor backend.BlendFactor) { b.blendState.dfactor = dfactor } -func (t *Texture) Upload(img *image.RGBA) { - b := img.Bounds() - w := b.Dx() - if img.Stride != w*4 { - panic("unsupported stride") +func (b *Backend) BindImageTexture(unit int, tex backend.Texture, access backend.AccessBits, f backend.TextureFormat) { + panic("not implemented") +} + +func (b *Backend) MemoryBarrier() { + panic("not implemented") +} + +func (b *Backend) DispatchCompute(x, y, z int) { + panic("not implemented") +} + +func (t *Texture) Upload(offset, size image.Point, pixels []byte) { + stride := size.X * 4 + dst := &_D3D11_BOX{ + left: uint32(offset.X), + top: uint32(offset.Y), + right: uint32(offset.X + size.X), + bottom: uint32(offset.Y + size.Y), + front: 0, + back: 1, } - start := (b.Min.X + b.Min.Y*w) * 4 - end := (b.Max.X + (b.Max.Y-1)*w) * 4 - pixels := img.Pix[start:end] res := (*_ID3D11Resource)(unsafe.Pointer(t.tex)) - t.backend.dev.ctx.UpdateSubresource(res, uint32(img.Stride), uint32(len(pixels)), pixels) + t.backend.dev.ctx.UpdateSubresource(res, dst, uint32(stride), uint32(len(pixels)), pixels) } func (t *Texture) Release() { @@ -710,6 +725,10 @@ func (p *Program) Release() { p.frag.shader = nil } +func (p *Program) SetStorageBuffer(binding int, buffer backend.Buffer) { + panic("not implemented") +} + func (p *Program) SetVertexUniforms(buf backend.Buffer) { p.vert.uniforms = buf.(*Buffer) } @@ -726,8 +745,12 @@ func (b *Backend) BindIndexBuffer(buf backend.Buffer) { b.dev.ctx.IASetIndexBuffer(buf.(*Buffer).buf, _DXGI_FORMAT_R16_UINT, 0) } +func (b *Buffer) Download(data []byte) error { + panic("not implemented") +} + func (b *Buffer) Upload(data []byte) { - b.backend.dev.ctx.UpdateSubresource((*_ID3D11Resource)(unsafe.Pointer(b.buf)), 0, 0, data) + b.backend.dev.ctx.UpdateSubresource((*_ID3D11Resource)(unsafe.Pointer(b.buf)), nil, 0, 0, data) } func (b *Buffer) Release() { diff --git a/app/internal/d3d11/d3d11_windows.go b/app/internal/d3d11/d3d11_windows.go index 3dd21389..9226f219 100644 --- a/app/internal/d3d11/d3d11_windows.go +++ b/app/internal/d3d11/d3d11_windows.go @@ -1127,14 +1127,14 @@ func (c *_ID3D11DeviceContext) PSSetShader(s *_ID3D11PixelShader) { ) } -func (c *_ID3D11DeviceContext) UpdateSubresource(res *_ID3D11Resource, rowPitch, depthPitch uint32, data []byte) { +func (c *_ID3D11DeviceContext) UpdateSubresource(res *_ID3D11Resource, dstBox *_D3D11_BOX, rowPitch, depthPitch uint32, data []byte) { syscall.Syscall9( c.vtbl.UpdateSubresource, 7, uintptr(unsafe.Pointer(c)), uintptr(unsafe.Pointer(res)), 0, // DstSubresource - 0, // pDstBox + uintptr(unsafe.Pointer(dstBox)), uintptr(unsafe.Pointer(&data[0])), uintptr(rowPitch), uintptr(depthPitch), diff --git a/app/internal/srgb/srgb.go b/app/internal/srgb/srgb.go index fa2b6859..a9681101 100644 --- a/app/internal/srgb/srgb.go +++ b/app/internal/srgb/srgb.go @@ -71,14 +71,14 @@ func (s *FBO) Blit() { s.c.Uniform1i(s.c.GetUniformLocation(prog, "tex"), 0) s.quad = s.c.CreateBuffer() s.c.BindBuffer(glimpl.ARRAY_BUFFER, s.quad) - s.c.BufferData(glimpl.ARRAY_BUFFER, - unsafe.BytesView([]float32{ - -1, +1, 0, 1, - +1, +1, 1, 1, - -1, -1, 0, 0, - +1, -1, 1, 0, - }), - glimpl.STATIC_DRAW) + coords := unsafe.BytesView([]float32{ + -1, +1, 0, 1, + +1, +1, 1, 1, + -1, -1, 0, 0, + +1, -1, 1, 0, + }) + s.c.BufferData(glimpl.ARRAY_BUFFER, len(coords), glimpl.STATIC_DRAW) + s.c.BufferSubData(glimpl.ARRAY_BUFFER, 0, coords) s.blitted = true } s.c.BindFramebuffer(glimpl.FRAMEBUFFER, glimpl.Framebuffer{}) @@ -112,9 +112,9 @@ func (s *FBO) Refresh(w, h int) error { } s.c.BindTexture(glimpl.TEXTURE_2D, s.colorTex) if s.gl3 { - s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.SRGB8_ALPHA8, w, h, glimpl.RGBA, glimpl.UNSIGNED_BYTE, nil) + s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.SRGB8_ALPHA8, w, h, glimpl.RGBA, glimpl.UNSIGNED_BYTE) } else /* EXT_sRGB */ { - s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.SRGB_ALPHA_EXT, w, h, glimpl.SRGB_ALPHA_EXT, glimpl.UNSIGNED_BYTE, nil) + s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.SRGB_ALPHA_EXT, w, h, glimpl.SRGB_ALPHA_EXT, glimpl.UNSIGNED_BYTE) } currentRB := glimpl.Renderbuffer(s.c.GetBinding(glimpl.RENDERBUFFER_BINDING)) s.c.BindRenderbuffer(glimpl.RENDERBUFFER, s.depthBuffer) @@ -136,7 +136,7 @@ func (s *FBO) Refresh(w, h int) error { var pixel [4]byte s.c.ReadPixels(0, 0, 1, 1, glimpl.RGBA, glimpl.UNSIGNED_BYTE, pixel[:]) 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, nil) + s.c.TexImage2D(glimpl.TEXTURE_2D, 0, glimpl.RGBA, w, h, glimpl.RGBA, glimpl.UNSIGNED_BYTE) if st := s.c.CheckFramebufferStatus(glimpl.FRAMEBUFFER); st != glimpl.FRAMEBUFFER_COMPLETE { return fmt.Errorf("fallback RGBA framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) } diff --git a/app/internal/window/d3d11_windows.go b/app/internal/window/d3d11_windows.go index f1e06a6e..137505cd 100644 --- a/app/internal/window/d3d11_windows.go +++ b/app/internal/window/d3d11_windows.go @@ -94,8 +94,12 @@ func (c *d3d11Context) Release() { if c.fbo != nil { c.fbo.Release() } - c.swchain.Release() - c.Device.Release() + if c.swchain != nil { + c.swchain.Release() + } + if c.Device != nil { + c.Device.Release() + } c.fbo = nil c.swchain = nil c.Device = nil diff --git a/gpu/backend/backend.go b/gpu/backend/backend.go index 871eea49..7b1ce9b5 100644 --- a/gpu/backend/backend.go +++ b/gpu/backend/backend.go @@ -23,6 +23,7 @@ type Device interface { NewFramebuffer(tex Texture, depthBits int) (Framebuffer, error) NewImmutableBuffer(typ BufferBinding, data []byte) (Buffer, error) NewBuffer(typ BufferBinding, size int) (Buffer, error) + NewComputeProgram(shader ShaderSources) (Program, error) NewProgram(vertexShader, fragmentShader ShaderSources) (Program, error) NewInputLayout(vertexShader ShaderSources, layout []InputDesc) (InputLayout, error) @@ -43,17 +44,29 @@ type Device interface { BindTexture(unit int, t Texture) BindVertexBuffer(b Buffer, stride, offset int) BindIndexBuffer(b Buffer) + BindImageTexture(unit int, texture Texture, access AccessBits, format TextureFormat) + + MemoryBarrier() + DispatchCompute(x, y, z int) } type ShaderSources struct { - GLSL100ES string - GLSL300ES string - GLSL130 string - GLSL150 string - HLSL []byte - Uniforms UniformsReflection - Inputs []InputLocation - Textures []TextureBinding + Name string + GLSL100ES string + GLSL300ES string + GLSL310ES string + GLSL130 string + GLSL150 string + HLSL []byte + Uniforms UniformsReflection + Inputs []InputLocation + Textures []TextureBinding + StorageBuffers []StorageBufferBinding +} + +type StorageBufferBinding struct { + Binding int + BlockSize int } type UniformsReflection struct { @@ -105,6 +118,8 @@ type InputLayout interface { Release() } +type AccessBits uint8 + type BlendFactor uint8 type DrawMode uint8 @@ -127,6 +142,7 @@ type Caps struct { type Program interface { Release() + SetStorageBuffer(binding int, buf Buffer) SetVertexUniforms(buf Buffer) SetFragmentUniforms(buf Buffer) } @@ -134,6 +150,7 @@ type Program interface { type Buffer interface { Release() Upload(data []byte) + Download(data []byte) error } type Framebuffer interface { @@ -150,7 +167,7 @@ type Timer interface { } type Texture interface { - Upload(img *image.RGBA) + Upload(offset, size image.Point, pixels []byte) Release() } @@ -171,11 +188,18 @@ const ( BufferBindingUniforms BufferBindingTexture BufferBindingFramebuffer + BufferBindingShaderStorage ) const ( TextureFormatSRGB TextureFormat = iota TextureFormatFloat + TextureFormatRGBA8 +) + +const ( + AccessRead AccessBits = 1 + iota + AccessWrite ) const ( @@ -184,7 +208,9 @@ const ( ) const ( - FeatureTimers Features = iota + FeatureTimers Features = 1 << iota + FeatureFloatRenderTargets + FeatureCompute ) const ( @@ -202,3 +228,15 @@ const ( func (f Features) Has(feats Features) bool { return f&feats == feats } + +func UploadImage(t Texture, offset image.Point, img *image.RGBA) { + var pixels []byte + size := img.Bounds().Size() + if img.Stride != size.X*4 { + panic("unsupported stride") + } + start := img.PixOffset(0, 0) + end := img.PixOffset(size.X, size.Y-1) + pixels = img.Pix[start:end] + t.Upload(offset, size, pixels) +} diff --git a/gpu/gl/backend.go b/gpu/gl/backend.go index c1bfc592..28dd2a80 100644 --- a/gpu/gl/backend.go +++ b/gpu/gl/backend.go @@ -37,7 +37,7 @@ type glstate struct { // nattr is the current number of enabled vertex arrays. nattr int prog *gpuProgram - texUnits [2]*gpuTexture + texUnits [4]*gpuTexture layout *gpuInputLayout buffer bufferBinding } @@ -87,6 +87,7 @@ type gpuProgram struct { nattr int vertUniforms uniformsTracker fragUniforms uniformsTracker + storage [storageBindings]*gpuBuffer } type uniformsTracker struct { @@ -111,13 +112,17 @@ type gpuInputLayout struct { // textureTriple holds the type settings for // a TexImage2D call. type textureTriple struct { - internalFormat int + internalFormat glimpl.Enum format glimpl.Enum typ glimpl.Enum } type Context = glimpl.Context +const ( + storageBindings = 32 +) + // NewBackend returns a new Backend. // // Pass a WebGL context if GOOS is "js", otherwise pass nil for the current @@ -133,24 +138,28 @@ func NewBackend(ctx Context) (*Backend, error) { if err != nil { return nil, err } - floatTriple, err := floatTripleFor(f, ver, exts) - if err != nil { - return nil, err - } + floatTriple, ffboErr := floatTripleFor(f, ver, exts) srgbaTriple, err := srgbaTripleFor(ver, exts) if err != nil { return nil, err } - ubo := ver[0] >= 3 && gles + gles30 := gles && ver[0] >= 3 + gles31 := gles && (ver[0] > 3 || (ver[0] == 3 && ver[1] >= 1)) b := &Backend{ glver: ver, gles: gles, - ubo: ubo, + ubo: gles30, funcs: f, floatTriple: floatTriple, alphaTriple: alphaTripleFor(ver), srgbaTriple: srgbaTriple, } + if ffboErr == nil { + b.feats.Features |= backend.FeatureFloatRenderTargets + } + if gles31 { + b.feats.Features |= backend.FeatureCompute + } if hasExtension(exts, "GL_EXT_disjoint_timer_query_webgl2") || hasExtension(exts, "GL_EXT_disjoint_timer_query") { b.feats.Features |= backend.FeatureTimers } @@ -232,6 +241,8 @@ func (b *Backend) NewTexture(format backend.TextureFormat, width, height int, mi tex.triple = b.floatTriple case backend.TextureFormatSRGB: tex.triple = b.srgbaTriple + case backend.TextureFormatRGBA8: + tex.triple = textureTriple{glimpl.RGBA8, glimpl.RGBA, glimpl.UNSIGNED_BYTE} default: return nil, errors.New("unsupported texture format") } @@ -240,7 +251,12 @@ func (b *Backend) NewTexture(format backend.TextureFormat, width, height int, mi b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_MIN_FILTER, toTexFilter(minFilter)) b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_S, glimpl.CLAMP_TO_EDGE) b.funcs.TexParameteri(glimpl.TEXTURE_2D, glimpl.TEXTURE_WRAP_T, glimpl.CLAMP_TO_EDGE) - b.funcs.TexImage2D(glimpl.TEXTURE_2D, 0, tex.triple.internalFormat, width, height, tex.triple.format, tex.triple.typ, nil) + if b.gles && b.glver[0] >= 3 { + // Immutable textures are required for BindImageTexture, and can't hurt otherwise. + b.funcs.TexStorage2D(glimpl.TEXTURE_2D, 1, tex.triple.internalFormat, width, height) + } else { + b.funcs.TexImage2D(glimpl.TEXTURE_2D, 0, tex.triple.internalFormat, width, height, tex.triple.format, tex.triple.typ) + } if err := glErr(b.funcs); err != nil { tex.Release() return nil, err @@ -267,6 +283,9 @@ func (b *Backend) NewBuffer(typ backend.BufferBinding, size int) (backend.Buffer buf.Release() return nil, err } + firstBinding := firstBufferType(typ) + b.funcs.BindBuffer(firstBinding, buf.obj) + b.funcs.BufferData(firstBinding, size, glimpl.DYNAMIC_DRAW) } return buf, nil } @@ -275,6 +294,9 @@ func (b *Backend) NewImmutableBuffer(typ backend.BufferBinding, data []byte) (ba glErr(b.funcs) obj := b.funcs.CreateBuffer() buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true} + firstBinding := firstBufferType(typ) + b.funcs.BindBuffer(firstBinding, buf.obj) + b.funcs.BufferData(firstBinding, len(data), glimpl.STATIC_DRAW) buf.Upload(data) buf.immutable = true if err := glErr(b.funcs); err != nil { @@ -291,6 +313,40 @@ func glErr(f *glimpl.Functions) error { return nil } +func (b *Backend) MemoryBarrier() { + b.funcs.MemoryBarrier(glimpl.ALL_BARRIER_BITS) +} + +func (b *Backend) DispatchCompute(x, y, z int) { + if p := b.state.prog; p != nil { + for binding, buf := range p.storage { + if buf != nil { + b.funcs.BindBufferBase(glimpl.SHADER_STORAGE_BUFFER, binding, buf.obj) + } + } + } + b.funcs.DispatchCompute(x, y, z) +} + +func (b *Backend) BindImageTexture(unit int, tex backend.Texture, access backend.AccessBits, f backend.TextureFormat) { + t := tex.(*gpuTexture) + var acc glimpl.Enum + switch access { + case backend.AccessWrite: + acc = glimpl.WRITE_ONLY + default: + panic("unsupported access bits") + } + var format glimpl.Enum + switch f { + case backend.TextureFormatRGBA8: + format = glimpl.RGBA8 + default: + panic("unsupported format") + } + b.funcs.BindImageTexture(unit, t.obj, 0, false, 0, acc, format) +} + func (b *Backend) bindTexture(unit int, t *gpuTexture) { if b.state.texUnits[unit] != t { b.funcs.ActiveTexture(glimpl.TEXTURE0 + glimpl.Enum(unit)) @@ -433,6 +489,18 @@ func (b *Backend) NewInputLayout(vs backend.ShaderSources, layout []backend.Inpu }, nil } +func (b *Backend) NewComputeProgram(src backend.ShaderSources) (backend.Program, error) { + p, err := glimpl.CreateComputeProgram(b.funcs, src.GLSL310ES) + if err != nil { + return nil, fmt.Errorf("%s: %v", src.Name, err) + } + gpuProg := &gpuProgram{ + backend: b, + obj: p, + } + return gpuProg, nil +} + func (b *Backend) NewProgram(vertShader, fragShader backend.ShaderSources) (backend.Program, error) { attr := make([]string, len(vertShader.Inputs)) for _, inp := range vertShader.Inputs { @@ -503,6 +571,14 @@ func lookupUniform(funcs *glimpl.Functions, p glimpl.Program, loc backend.Unifor return uniformLocation{uniform: u, offset: loc.Offset, typ: loc.Type, size: loc.Size} } +func (p *gpuProgram) SetStorageBuffer(binding int, buffer backend.Buffer) { + buf := buffer.(*gpuBuffer) + if buf.typ&backend.BufferBindingShaderStorage == 0 { + panic("not a shader storage buffer") + } + p.storage[binding] = buf +} + func (p *gpuProgram) SetVertexUniforms(buffer backend.Buffer) { p.vertUniforms.setBuffer(buffer) } @@ -600,10 +676,31 @@ func (b *gpuBuffer) Upload(data []byte) { if b.hasBuffer { firstBinding := firstBufferType(b.typ) b.backend.funcs.BindBuffer(firstBinding, b.obj) - b.backend.funcs.BufferData(firstBinding, data, glimpl.STATIC_DRAW) + b.backend.funcs.BufferSubData(firstBinding, 0, data) } } +func (b *gpuBuffer) Download(data []byte) error { + if len(data) > b.size { + panic("buffer size overflow") + } + if !b.hasBuffer { + copy(data, b.data) + return nil + } + firstBinding := firstBufferType(b.typ) + b.backend.funcs.BindBuffer(firstBinding, b.obj) + bufferMap := b.backend.funcs.MapBufferRange(firstBinding, 0, len(data), glimpl.MAP_READ_BIT) + if bufferMap == nil { + return fmt.Errorf("MapBufferRange: error %#x", b.backend.funcs.GetError()) + } + copy(data, bufferMap) + if !b.backend.funcs.UnmapBuffer(firstBinding) { + return errors.New("buffer content lost") + } + return nil +} + func (b *gpuBuffer) Release() { if b.hasBuffer { b.backend.funcs.DeleteBuffer(b.obj) @@ -649,10 +746,20 @@ func (b *Backend) BindIndexBuffer(buf backend.Buffer) { b.funcs.BindBuffer(glimpl.ELEMENT_ARRAY_BUFFER, gbuf.obj) } +func (b *Backend) BlitFramebuffer(dst, src backend.Framebuffer, srect, drect image.Rectangle) { + b.funcs.BindFramebuffer(glimpl.DRAW_FRAMEBUFFER, dst.(*gpuFramebuffer).obj) + b.funcs.BindFramebuffer(glimpl.READ_FRAMEBUFFER, src.(*gpuFramebuffer).obj) + b.funcs.BlitFramebuffer( + srect.Min.X, srect.Min.Y, srect.Max.X, srect.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, + glimpl.NEAREST) +} + func (f *gpuFramebuffer) ReadPixels(src image.Rectangle, pixels []byte) error { glErr(f.backend.funcs) f.backend.BindFramebuffer(f) - if len(pixels) < src.Dx()*src.Dy() { + if len(pixels) < src.Dx()*src.Dy()*4 { 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) @@ -714,18 +821,12 @@ func (t *gpuTexture) Release() { t.backend.funcs.DeleteTexture(t.obj) } -func (t *gpuTexture) Upload(img *image.RGBA) { - t.backend.BindTexture(0, t) - var pixels []byte - b := img.Bounds() - w, h := b.Dx(), b.Dy() - if img.Stride != w*4 { - panic("unsupported stride") +func (t *gpuTexture) Upload(offset, size image.Point, pixels []byte) { + if min := size.X * size.Y * 4; min > len(pixels) { + panic(fmt.Errorf("size %d larger than data %d", min, len(pixels))) } - start := (b.Min.X + b.Min.Y*w) * 4 - end := (b.Max.X + (b.Max.Y-1)*w) * 4 - pixels = img.Pix[start:end] - t.backend.funcs.TexImage2D(glimpl.TEXTURE_2D, 0, t.triple.internalFormat, w, h, t.triple.format, t.triple.typ, pixels) + 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) } func (t *gpuTimer) Begin() { @@ -792,7 +893,7 @@ func floatTripleFor(f *glimpl.Functions, ver [2]int, exts []string) (textureTrip var attempts []string for _, tt := range triples { const size = 256 - f.TexImage2D(glimpl.TEXTURE_2D, 0, tt.internalFormat, size, size, tt.format, tt.typ, nil) + f.TexImage2D(glimpl.TEXTURE_2D, 0, tt.internalFormat, size, size, tt.format, tt.typ) f.FramebufferTexture2D(glimpl.FRAMEBUFFER, glimpl.COLOR_ATTACHMENT0, glimpl.TEXTURE_2D, tex, 0) st := f.CheckFramebufferStatus(glimpl.FRAMEBUFFER) if st == glimpl.FRAMEBUFFER_COMPLETE { @@ -815,7 +916,7 @@ func srgbaTripleFor(ver [2]int, exts []string) (textureTriple, error) { } func alphaTripleFor(ver [2]int) textureTriple { - intf, f := glimpl.R8, glimpl.Enum(glimpl.RED) + intf, f := glimpl.Enum(glimpl.R8), glimpl.Enum(glimpl.RED) if ver[0] < 3 { // R8, RED not supported on OpenGL ES 2.0. intf, f = glimpl.LUMINANCE, glimpl.Enum(glimpl.LUMINANCE) @@ -840,6 +941,8 @@ func firstBufferType(typ backend.BufferBinding) glimpl.Enum { return glimpl.ARRAY_BUFFER case typ&backend.BufferBindingUniforms != 0: return glimpl.UNIFORM_BUFFER + case typ&backend.BufferBindingShaderStorage != 0: + return glimpl.SHADER_STORAGE_BUFFER default: panic("unsupported buffer type") } diff --git a/gpu/gpu.go b/gpu/gpu.go index bb167565..547fefce 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -479,7 +479,7 @@ func (r *renderer) texHandle(cache *resourceCache, data imageOpData) backend.Tex if err != nil { panic(err) } - handle.Upload(data.src) + backend.UploadImage(handle, image.Pt(0, 0), data.src) tex.tex = handle return tex.tex } diff --git a/internal/glimpl/gl.go b/internal/glimpl/gl.go index cd421434..d6618de6 100644 --- a/internal/glimpl/gl.go +++ b/internal/glimpl/gl.go @@ -8,19 +8,24 @@ type ( ) const ( + ALL_BARRIER_BITS = 0xffffffff ARRAY_BUFFER = 0x8892 BLEND = 0xbe2 CLAMP_TO_EDGE = 0x812f COLOR_ATTACHMENT0 = 0x8ce0 COLOR_BUFFER_BIT = 0x4000 COMPILE_STATUS = 0x8b81 + COMPUTE_SHADER = 0x91B9 DEPTH_BUFFER_BIT = 0x100 DEPTH_ATTACHMENT = 0x8d00 DEPTH_COMPONENT16 = 0x81a5 DEPTH_COMPONENT24 = 0x81A6 DEPTH_COMPONENT32F = 0x8CAC DEPTH_TEST = 0xb71 + DRAW_FRAMEBUFFER = 0x8CA9 DST_COLOR = 0x306 + DYNAMIC_DRAW = 0x88E8 + DYNAMIC_READ = 0x88E9 ELEMENT_ARRAY_BUFFER = 0x8893 EXTENSIONS = 0x1f03 FALSE = 0 @@ -39,6 +44,7 @@ const ( LINEAR = 0x2601 LINK_STATUS = 0x8b82 LUMINANCE = 0x1909 + MAP_READ_BIT = 0x0001 MAX_TEXTURE_SIZE = 0xd33 NEAREST = 0x2600 NO_ERROR = 0x0 @@ -50,6 +56,8 @@ const ( R16F = 0x822d R8 = 0x8229 READ_FRAMEBUFFER = 0x8ca8 + READ_ONLY = 0x88B8 + READ_WRITE = 0x88BA RED = 0x1903 RENDERER = 0x1F01 RENDERBUFFER = 0x8d41 @@ -59,12 +67,14 @@ const ( RGB = 0x1907 RGBA = 0x1908 RGBA8 = 0x8058 + SHADER_STORAGE_BUFFER = 0x90D2 SHORT = 0x1402 SRGB = 0x8c40 SRGB_ALPHA_EXT = 0x8c42 SRGB8 = 0x8c41 SRGB8_ALPHA8 = 0x8c43 STATIC_DRAW = 0x88e4 + STENCIL_BUFFER_BIT = 0x00000400 TEXTURE_2D = 0xde1 TEXTURE_MAG_FILTER = 0x2800 TEXTURE_MIN_FILTER = 0x2801 @@ -81,6 +91,7 @@ const ( UNSIGNED_SHORT = 0x1403 VERSION = 0x1f02 VERTEX_SHADER = 0x8b31 + WRITE_ONLY = 0x88B9 ZERO = 0x0 // EXT_disjoint_timer_query @@ -96,11 +107,14 @@ var _ interface { BindBuffer(target Enum, b Buffer) BindBufferBase(target Enum, index int, buffer Buffer) BindFramebuffer(target Enum, fb Framebuffer) + BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) BindRenderbuffer(target Enum, fb Renderbuffer) BindTexture(target Enum, t Texture) BlendEquation(mode Enum) BlendFunc(sfactor, dfactor Enum) - BufferData(target Enum, src []byte, usage Enum) + BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) + BufferData(target Enum, size int, usage Enum) + BufferSubData(target Enum, offset int, src []byte) CheckFramebufferStatus(target Enum) Enum Clear(mask Enum) ClearColor(red, green, blue, alpha float32) @@ -124,6 +138,7 @@ var _ interface { DepthMask(mask bool) DisableVertexAttribArray(a Attrib) Disable(cap Enum) + DispatchCompute(x, y, z int) DrawArrays(mode Enum, first, count int) DrawElements(mode Enum, count int, ty Enum, offset int) Enable(cap Enum) @@ -144,11 +159,15 @@ var _ interface { GetUniformLocation(p Program, name string) Uniform InvalidateFramebuffer(target, attachment Enum) LinkProgram(p Program) + MapBufferRange(target Enum, offset, length int, access Enum) []byte + MemoryBarrier(barriers Enum) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) RenderbufferStorage(target, internalformat Enum, width, height int) ShaderSource(s Shader, src string) - TexImage2D(target Enum, level int, internalFormat int, width, height int, format, ty Enum, data []byte) + TexImage2D(target Enum, level int, internalFormat Enum, width, height int, format, ty Enum) TexParameteri(target, pname Enum, param int) + TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) + TexSubImage2D(target Enum, level, xoff, yoff int, width, height int, format, ty Enum, data []byte) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) Uniform1f(dst Uniform, v float32) Uniform1i(dst Uniform, v int) @@ -156,6 +175,7 @@ var _ interface { Uniform3f(dst Uniform, v0, v1, v2 float32) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) UseProgram(p Program) + UnmapBuffer(target Enum) bool VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) Viewport(x, y, width, height int) } = (*Functions)(nil) diff --git a/internal/glimpl/gl_unix.go b/internal/glimpl/gl_unix.go index 3a8d1fe2..30715eb0 100644 --- a/internal/glimpl/gl_unix.go +++ b/internal/glimpl/gl_unix.go @@ -51,6 +51,13 @@ static void (*_glEndQuery)(GLenum target); static void (*_glGenQueries)(GLsizei n, GLuint *ids); static void (*_glGetQueryObjectuiv)(GLuint id, GLenum pname, GLuint *params); static const GLubyte* (*_glGetStringi)(GLenum name, GLuint index); +static void (*_glMemoryBarrier)(GLbitfield barriers); +static void (*_glDispatchCompute)(GLuint x, GLuint y, GLuint z); +static void* (*_glMapBufferRange)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); +static GLboolean (*_glUnmapBuffer)(GLenum target); +static void (*_glBindImageTexture)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); +static void (*_glTexStorage2D)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); +static void (*_glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); // The pointer-free version of glVertexAttribPointer, to avoid the Cgo pointer checks. __attribute__ ((visibility ("hidden"))) void gio_glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, uintptr_t offset) { @@ -108,6 +115,34 @@ __attribute__ ((visibility ("hidden"))) void gio_glGetQueryObjectuiv(GLuint id, _glGetQueryObjectuiv(id, pname, params); } +__attribute__ ((visibility ("hidden"))) void gio_glMemoryBarrier(GLbitfield barriers) { + _glMemoryBarrier(barriers); +} + +__attribute__ ((visibility ("hidden"))) void gio_glDispatchCompute(GLuint x, GLuint y, GLuint z) { + _glDispatchCompute(x, y, z); +} + +__attribute__ ((visibility ("hidden"))) void *gio_glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) { + return _glMapBufferRange(target, offset, length, access); +} + +__attribute__ ((visibility ("hidden"))) GLboolean gio_glUnmapBuffer(GLenum target) { + return _glUnmapBuffer(target); +} + +__attribute__ ((visibility ("hidden"))) void gio_glBindImageTexture(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) { + _glBindImageTexture(unit, texture, level, layered, layer, access, format); +} + +__attribute__ ((visibility ("hidden"))) void gio_glTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) { + _glTexStorage2D(target, levels, internalFormat, width, height); +} + +__attribute__ ((visibility ("hidden"))) void gio_glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + _glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); +} + __attribute__((constructor)) static void gio_loadGLFunctions() { #ifdef __APPLE__ #if TARGET_OS_IPHONE @@ -122,6 +157,7 @@ __attribute__((constructor)) static void gio_loadGLFunctions() { _glGetUniformBlockIndex = glGetUniformBlockIndex; _glUniformBlockBinding = glUniformBlockBinding; _glGetStringi = glGetStringi; + _glTexStorage2D = glTexStorage2D; #else // Load libGLESv3 if available. dlopen("libGLESv3.so", RTLD_NOW | RTLD_GLOBAL); @@ -150,6 +186,14 @@ __attribute__((constructor)) static void gio_loadGLFunctions() { _glGetQueryObjectuiv = dlsym(RTLD_DEFAULT, "glGetQueryObjectuiv"); if (_glGetQueryObjectuiv == NULL) _glGetQueryObjectuiv = dlsym(RTLD_DEFAULT, "glGetQueryObjectuivEXT"); + + _glMemoryBarrier = dlsym(RTLD_DEFAULT, "glMemoryBarrier"); + _glDispatchCompute = dlsym(RTLD_DEFAULT, "glDispatchCompute"); + _glMapBufferRange = dlsym(RTLD_DEFAULT, "glMapBufferRange"); + _glUnmapBuffer = dlsym(RTLD_DEFAULT, "glUnmapBuffer"); + _glBindImageTexture = dlsym(RTLD_DEFAULT, "glBindImageTexture"); + _glTexStorage2D = dlsym(RTLD_DEFAULT, "glTexStorage2D"); + _glBlitFramebuffer = dlsym(RTLD_DEFAULT, "glBlitFramebuffer"); #endif } */ @@ -204,6 +248,14 @@ func (f *Functions) BindRenderbuffer(target Enum, fb Renderbuffer) { C.glBindRenderbuffer(C.GLenum(target), C.GLuint(fb.V)) } +func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) { + l := C.GLboolean(C.GL_FALSE) + if layered { + l = C.GL_TRUE + } + C.gio_glBindImageTexture(C.GLuint(unit), C.GLuint(t.V), C.GLint(level), l, C.GLint(layer), C.GLenum(access), C.GLenum(format)) +} + func (f *Functions) BindTexture(target Enum, t Texture) { C.glBindTexture(C.GLenum(target), C.GLuint(t.V)) } @@ -216,12 +268,24 @@ func (f *Functions) BlendFunc(sfactor, dfactor Enum) { C.glBlendFunc(C.GLenum(sfactor), C.GLenum(dfactor)) } -func (f *Functions) BufferData(target Enum, src []byte, usage Enum) { +func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) { + C.gio_glBlitFramebuffer( + C.GLint(sx0), C.GLint(sy0), C.GLint(sx1), C.GLint(sy1), + C.GLint(dx0), C.GLint(dy0), C.GLint(dx1), C.GLint(dy1), + C.GLenum(mask), C.GLenum(filter), + ) +} + +func (f *Functions) BufferData(target Enum, size int, usage Enum) { + C.glBufferData(C.GLenum(target), C.GLsizeiptr(size), nil, C.GLenum(usage)) +} + +func (f *Functions) BufferSubData(target Enum, offset int, src []byte) { var p unsafe.Pointer if len(src) > 0 { p = unsafe.Pointer(&src[0]) } - C.glBufferData(C.GLenum(target), C.GLsizeiptr(len(src)), p, C.GLenum(usage)) + C.glBufferSubData(C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(len(src)), p) } func (f *Functions) CheckFramebufferStatus(target Enum) Enum { @@ -338,6 +402,10 @@ func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) { C.gio_glDrawElements(C.GLenum(mode), C.GLsizei(count), C.GLenum(ty), C.uintptr_t(offset)) } +func (f *Functions) DispatchCompute(x, y, z int) { + C.gio_glDispatchCompute(C.GLuint(x), C.GLuint(y), C.GLuint(z)) +} + func (f *Functions) Enable(cap Enum) { C.glEnable(C.GLenum(cap)) } @@ -464,6 +532,18 @@ func (f *Functions) PixelStorei(pname Enum, param int32) { C.glPixelStorei(C.GLenum(pname), C.GLint(param)) } +func (f *Functions) MemoryBarrier(barriers Enum) { + C.gio_glMemoryBarrier(C.GLbitfield(barriers)) +} + +func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { + p := C.gio_glMapBufferRange(C.GLenum(target), C.GLintptr(offset), C.GLsizeiptr(length), C.GLbitfield(access)) + if p == nil { + return nil + } + return (*([1 << 30]byte))(p)[:length:length] +} + func (f *Functions) Scissor(x, y, width, height int32) { C.glScissor(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) } @@ -487,12 +567,12 @@ func (f *Functions) ShaderSource(s Shader, src string) { C.glShaderSource(C.GLuint(s.V), 1, &csrc, &strlen) } -func (f *Functions) TexImage2D(target Enum, level int, internalFormat int, width int, height int, format Enum, ty Enum, data []byte) { - var p unsafe.Pointer - if len(data) > 0 { - p = unsafe.Pointer(&data[0]) - } - C.glTexImage2D(C.GLenum(target), C.GLint(level), C.GLint(internalFormat), C.GLsizei(width), C.GLsizei(height), 0, C.GLenum(format), C.GLenum(ty), p) +func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width int, height int, format Enum, ty Enum) { + C.glTexImage2D(C.GLenum(target), C.GLint(level), C.GLint(internalFormat), C.GLsizei(width), C.GLsizei(height), 0, C.GLenum(format), C.GLenum(ty), nil) +} + +func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) { + C.gio_glTexStorage2D(C.GLenum(target), C.GLsizei(levels), C.GLenum(internalFormat), C.GLsizei(width), C.GLsizei(height)) } func (f *Functions) TexSubImage2D(target Enum, level int, x int, y int, width int, height int, format Enum, ty Enum, data []byte) { @@ -535,6 +615,11 @@ func (f *Functions) UseProgram(p Program) { C.glUseProgram(C.GLuint(p.V)) } +func (f *Functions) UnmapBuffer(target Enum) bool { + r := C.gio_glUnmapBuffer(C.GLenum(target)) + return r == C.GL_TRUE +} + func (f *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride int, offset int) { var n C.GLboolean = C.GL_FALSE if normalized { diff --git a/internal/glimpl/gl_windows.go b/internal/glimpl/gl_windows.go index 7e1d5417..1a4801c6 100644 --- a/internal/glimpl/gl_windows.go +++ b/internal/glimpl/gl_windows.go @@ -27,6 +27,7 @@ var ( _glBlendEquation = LibGLESv2.NewProc("glBlendEquation") _glBlendFunc = LibGLESv2.NewProc("glBlendFunc") _glBufferData = LibGLESv2.NewProc("glBufferData") + _glBufferSubData = LibGLESv2.NewProc("glBufferSubData") _glCheckFramebufferStatus = LibGLESv2.NewProc("glCheckFramebufferStatus") _glClear = LibGLESv2.NewProc("glClear") _glClearColor = LibGLESv2.NewProc("glClearColor") @@ -78,6 +79,7 @@ var ( _glScissor = LibGLESv2.NewProc("glScissor") _glShaderSource = LibGLESv2.NewProc("glShaderSource") _glTexImage2D = LibGLESv2.NewProc("glTexImage2D") + _glTexStorage2D = LibGLESv2.NewProc("glTexStorage2D") _glTexSubImage2D = LibGLESv2.NewProc("glTexSubImage2D") _glTexParameteri = LibGLESv2.NewProc("glTexParameteri") _glUniformBlockBinding = LibGLESv2.NewProc("glUniformBlockBinding") @@ -132,6 +134,9 @@ func (c *Functions) BindFramebuffer(target Enum, fb Framebuffer) { func (c *Functions) BindRenderbuffer(target Enum, rb Renderbuffer) { syscall.Syscall(_glBindRenderbuffer.Addr(), 2, uintptr(target), uintptr(rb.V), 0) } +func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) { + panic("not implemented") +} func (c *Functions) BindTexture(target Enum, t Texture) { syscall.Syscall(_glBindTexture.Addr(), 2, uintptr(target), uintptr(t.V), 0) } @@ -141,12 +146,16 @@ func (c *Functions) BlendEquation(mode Enum) { func (c *Functions) BlendFunc(sfactor, dfactor Enum) { syscall.Syscall(_glBlendFunc.Addr(), 2, uintptr(sfactor), uintptr(dfactor), 0) } -func (c *Functions) BufferData(target Enum, src []byte, usage Enum) { - if n := len(src); n == 0 { - syscall.Syscall6(_glBufferData.Addr(), 4, uintptr(target), 0, 0, uintptr(usage), 0, 0) - } else { +func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) { + panic("not implemented") +} +func (c *Functions) BufferData(target Enum, size int, usage Enum) { + syscall.Syscall6(_glBufferData.Addr(), 4, uintptr(target), uintptr(size), 0, uintptr(usage), 0, 0) +} +func (f *Functions) BufferSubData(target Enum, offset int, src []byte) { + if n := len(src); n > 0 { s0 := &src[0] - syscall.Syscall6(_glBufferData.Addr(), 4, uintptr(target), uintptr(n), uintptr(unsafe.Pointer(s0)), uintptr(usage), 0, 0) + syscall.Syscall6(_glBufferSubData.Addr(), 4, uintptr(target), uintptr(offset), uintptr(n), uintptr(unsafe.Pointer(s0)), 0, 0) issue34474KeepAlive(s0) } } @@ -242,6 +251,9 @@ func (c *Functions) DrawArrays(mode Enum, first, count int) { func (c *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) { syscall.Syscall6(_glDrawElements.Addr(), 4, uintptr(mode), uintptr(count), uintptr(ty), uintptr(offset), 0, 0) } +func (f *Functions) DispatchCompute(x, y, z int) { + panic("not implemented") +} func (c *Functions) Enable(cap Enum) { syscall.Syscall(_glEnable.Addr(), 1, uintptr(cap), 0, 0) } @@ -335,6 +347,12 @@ func (c *Functions) LinkProgram(p Program) { func (c *Functions) PixelStorei(pname Enum, param int32) { syscall.Syscall(_glPixelStorei.Addr(), 2, uintptr(pname), uintptr(param), 0) } +func (f *Functions) MemoryBarrier(barriers Enum) { + panic("not implemented") +} +func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { + panic("not implemented") +} func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { d0 := &data[0] syscall.Syscall9(_glReadPixels.Addr(), 7, uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(format), uintptr(ty), uintptr(unsafe.Pointer(d0)), 0, 0) @@ -352,14 +370,11 @@ func (c *Functions) ShaderSource(s Shader, src string) { syscall.Syscall6(_glShaderSource.Addr(), 4, uintptr(s.V), 1, uintptr(unsafe.Pointer(psrc)), uintptr(unsafe.Pointer(&n)), 0, 0) issue34474KeepAlive(psrc) } -func (c *Functions) TexImage2D(target Enum, level int, internalFormat int, width, height int, format, ty Enum, data []byte) { - if len(data) == 0 { - syscall.Syscall9(_glTexImage2D.Addr(), 9, uintptr(target), uintptr(level), uintptr(internalFormat), uintptr(width), uintptr(height), 0, uintptr(format), uintptr(ty), 0) - } else { - d0 := &data[0] - syscall.Syscall9(_glTexImage2D.Addr(), 9, uintptr(target), uintptr(level), uintptr(internalFormat), uintptr(width), uintptr(height), 0, uintptr(format), uintptr(ty), uintptr(unsafe.Pointer(d0))) - issue34474KeepAlive(d0) - } +func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width int, height int, format Enum, ty Enum) { + syscall.Syscall9(_glTexImage2D.Addr(), 9, uintptr(target), uintptr(level), uintptr(internalFormat), uintptr(width), uintptr(height), 0, uintptr(format), uintptr(ty), 0) +} +func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) { + syscall.Syscall6(_glTexStorage2D.Addr(), 5, uintptr(target), uintptr(levels), uintptr(internalFormat), uintptr(width), uintptr(height), 0) } func (c *Functions) TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte) { d0 := &data[0] @@ -390,6 +405,9 @@ func (c *Functions) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) { func (c *Functions) UseProgram(p Program) { syscall.Syscall(_glUseProgram.Addr(), 1, uintptr(p.V), 0, 0) } +func (f *Functions) UnmapBuffer(target Enum) bool { + panic("not implemented") +} func (c *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) { var norm uintptr if normalized { diff --git a/internal/glimpl/util.go b/internal/glimpl/util.go index f032642e..133222ac 100644 --- a/internal/glimpl/util.go +++ b/internal/glimpl/util.go @@ -37,6 +37,26 @@ func CreateProgram(ctx *Functions, vsSrc, fsSrc string, attribs []string) (Progr return prog, nil } +func CreateComputeProgram(ctx *Functions, src string) (Program, error) { + cs, err := createShader(ctx, COMPUTE_SHADER, src) + if err != nil { + return Program{}, err + } + defer ctx.DeleteShader(cs) + prog := ctx.CreateProgram() + if !prog.Valid() { + return Program{}, errors.New("glCreateProgram failed") + } + ctx.AttachShader(prog, cs) + ctx.LinkProgram(prog) + if ctx.GetProgrami(prog, LINK_STATUS) == 0 { + log := ctx.GetProgramInfoLog(prog) + ctx.DeleteProgram(prog) + return Program{}, fmt.Errorf("program link failed: %s", strings.TrimSpace(log)) + } + return prog, nil +} + func createShader(ctx *Functions, typ Enum, src string) (Shader, error) { sh := ctx.CreateShader(typ) if !sh.Valid() {