shareable: Add Shader

This commit is contained in:
Hajime Hoshi 2020-05-26 22:26:55 +09:00
parent 1c980a16f5
commit 9c637c65be
4 changed files with 96 additions and 15 deletions

View File

@ -150,7 +150,7 @@ func (m *Mipmap) DrawImage(src *Mipmap, bounds image.Rectangle, geom GeoM, color
if level == 0 { if level == 0 {
vs := quadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca, screen) vs := quadVertices(bounds.Min.X, bounds.Min.Y, bounds.Max.X, bounds.Max.Y, a, b, c, d, tx, ty, cr, cg, cb, ca, screen)
is := graphics.QuadIndices() is := graphics.QuadIndices()
m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressClampToZero) m.orig.DrawTriangles(src.orig, vs, is, colorm, mode, filter, driver.AddressClampToZero, nil, nil)
} else if buf := src.level(bounds, level); buf != nil { } else if buf := src.level(bounds, level); buf != nil {
w, h := sizeForLevel(bounds.Dx(), bounds.Dy(), level) w, h := sizeForLevel(bounds.Dx(), bounds.Dy(), level)
s := pow2(level) s := pow2(level)
@ -160,7 +160,7 @@ func (m *Mipmap) DrawImage(src *Mipmap, bounds image.Rectangle, geom GeoM, color
d *= s d *= s
vs := quadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca, false) vs := quadVertices(0, 0, w, h, a, b, c, d, tx, ty, cr, cg, cb, ca, false)
is := graphics.QuadIndices() is := graphics.QuadIndices()
m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressClampToZero) m.orig.DrawTriangles(buf, vs, is, colorm, mode, filter, driver.AddressClampToZero, nil, nil)
} }
m.disposeMipmaps() m.disposeMipmaps()
} }
@ -183,7 +183,7 @@ func (m *Mipmap) DrawTriangles(src *Mipmap, vertices []float32, indices []uint16
vertices[i*n+11] *= ca vertices[i*n+11] *= ca
} }
} }
m.orig.DrawTriangles(src.orig, vertices, indices, colorm, mode, filter, address) m.orig.DrawTriangles(src.orig, vertices, indices, colorm, mode, filter, address, nil, nil)
m.disposeMipmaps() m.disposeMipmaps()
} }
@ -246,7 +246,7 @@ func (m *Mipmap) level(r image.Rectangle, level int) *shareable.Image {
return nil return nil
} }
s := shareable.NewImage(w2, h2, m.volatile) s := shareable.NewImage(w2, h2, m.volatile)
s.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressClampToZero) s.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, filter, driver.AddressClampToZero, nil, nil)
imgs[level] = s imgs[level] = s
return imgs[level] return imgs[level]

View File

@ -282,7 +282,7 @@ func (i *Image) region() (x, y, width, height int) {
// 9: Color G // 9: Color G
// 10: Color B // 10: Color B
// 11: Color Y // 11: Color Y
func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address) { func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, shader *Shader, uniforms []interface{}) {
backendsM.Lock() backendsM.Lock()
// Do not use defer for performance. // Do not use defer for performance.
@ -316,7 +316,36 @@ func (i *Image) DrawTriangles(img *Image, vertices []float32, indices []uint16,
vertices[i*graphics.VertexFloatNum+7] += oyf vertices[i*graphics.VertexFloatNum+7] += oyf
} }
i.backend.restorable.DrawTriangles(img.backend.restorable, vertices, indices, colorm, mode, filter, address, nil, nil) var s *restorable.Shader
if shader != nil {
s = shader.shader
}
firstImage := true
us := make([]interface{}, len(uniforms))
for i := 0; i < len(uniforms); i++ {
switch v := us[i].(type) {
case *Image:
us[i] = v.backend.restorable
if !firstImage {
i++
pos := us[i].([]float32)
pos[0] += oxf
pos[1] += oyf
i++
region := us[i].([]float32)
region[0] += oxf
region[1] += oyf
region[2] += oxf
region[3] += oyf
}
firstImage = false
default:
us[i] = v
}
}
i.backend.restorable.DrawTriangles(img.backend.restorable, vertices, indices, colorm, mode, filter, address, s, us)
i.nonUpdatedCount = 0 i.nonUpdatedCount = 0
delete(imagesToMakeShared, i) delete(imagesToMakeShared, i)

View File

@ -89,7 +89,7 @@ func TestEnsureNotShared(t *testing.T) {
// img4.ensureNotShared() should be called. // img4.ensureNotShared() should be called.
vs := quadVertices(size/2, size/2, size/4, size/4, 1) vs := quadVertices(size/2, size/2, size/4, size/4, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
want := false want := false
if got := img4.IsSharedForTesting(); got != want { if got := img4.IsSharedForTesting(); got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
@ -119,7 +119,7 @@ func TestEnsureNotShared(t *testing.T) {
// Check further drawing doesn't cause panic. // Check further drawing doesn't cause panic.
// This bug was fixed by 03dcd948. // This bug was fixed by 03dcd948.
img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) img4.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
} }
func TestReshared(t *testing.T) { func TestReshared(t *testing.T) {
@ -159,7 +159,7 @@ func TestReshared(t *testing.T) {
// Use img1 as a render target. // Use img1 as a render target.
vs := quadVertices(size, size, 0, 0, 1) vs := quadVertices(size, size, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
img1.DrawTriangles(img2, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) img1.DrawTriangles(img2, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
if got, want := img1.IsSharedForTesting(), false; got != want { if got, want := img1.IsSharedForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -169,7 +169,7 @@ func TestReshared(t *testing.T) {
if err := MakeImagesSharedForTesting(); err != nil { if err := MakeImagesSharedForTesting(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
if got, want := img1.IsSharedForTesting(), false; got != want { if got, want := img1.IsSharedForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -196,7 +196,7 @@ func TestReshared(t *testing.T) {
} }
} }
img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) img0.DrawTriangles(img1, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
if got, want := img1.IsSharedForTesting(), true; got != want { if got, want := img1.IsSharedForTesting(), true; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -224,7 +224,7 @@ func TestReshared(t *testing.T) {
if err := MakeImagesSharedForTesting(); err != nil { if err := MakeImagesSharedForTesting(); err != nil {
t.Fatal(err) t.Fatal(err)
} }
img0.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) img0.DrawTriangles(img3, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
if got, want := img3.IsSharedForTesting(), false; got != want { if got, want := img3.IsSharedForTesting(), false; got != want {
t.Errorf("got: %v, want: %v", got, want) t.Errorf("got: %v, want: %v", got, want)
} }
@ -319,7 +319,7 @@ func TestReplacePixelsAfterDrawTriangles(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeCopy, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
dst.ReplacePixels(pix) dst.ReplacePixels(pix)
pix, err := dst.Pixels(0, 0, w, h) pix, err := dst.Pixels(0, 0, w, h)
@ -361,7 +361,7 @@ func TestSmallImages(t *testing.T) {
vs := quadVertices(w, h, 0, 0, 1) vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
pix, err := dst.Pixels(0, 0, w, h) pix, err := dst.Pixels(0, 0, w, h)
if err != nil { if err != nil {
@ -403,7 +403,7 @@ func TestLongImages(t *testing.T) {
const scale = 120 const scale = 120
vs := quadVertices(w, h, 0, 0, scale) vs := quadVertices(w, h, 0, 0, scale)
is := graphics.QuadIndices() is := graphics.QuadIndices()
dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero) dst.DrawTriangles(src, vs, is, nil, driver.CompositeModeSourceOver, driver.FilterNearest, driver.AddressClampToZero, nil, nil)
pix, err := dst.Pixels(0, 0, dstW, dstH) pix, err := dst.Pixels(0, 0, dstW, dstH)
if err != nil { if err != nil {

View File

@ -0,0 +1,52 @@
// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shareable
import (
"runtime"
"github.com/hajimehoshi/ebiten/internal/restorable"
"github.com/hajimehoshi/ebiten/internal/shaderir"
)
type Shader struct {
shader *restorable.Shader
}
func NewShader(program *shaderir.Program) *Shader {
s := &Shader{
shader: restorable.NewShader(program),
}
runtime.SetFinalizer(s, (*Shader).MarkDisposed)
return s
}
// MarkDisposed marks the shader as disposed. The actual operation is deferred.
// MarkDisposed can be called from finalizers.
//
// A function from finalizer must not be blocked, but disposing operation can be blocked.
// Defer this operation until it becomes safe. (#913)
func (s *Shader) MarkDisposed() {
deferredM.Lock()
deferred = append(deferred, func() {
s.dispose()
})
deferredM.Unlock()
}
func (s *Shader) dispose() {
s.shader.Dispose()
s.shader = nil
}