mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-27 20:28:54 +01:00
Compare commits
7 Commits
5ec07dc19b
...
363020fa65
Author | SHA1 | Date | |
---|---|---|---|
|
363020fa65 | ||
|
f6927232f2 | ||
|
6eee7ccc5f | ||
|
577664c1cb | ||
|
c247da0f05 | ||
|
9003692630 | ||
|
32b5e3edd8 |
131
examples/mrt/main.go
Normal file
131
examples/mrt/main.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// Copyright 2024 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
_ "image/jpeg"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
dstSize = 128
|
||||||
|
screenWidth = dstSize * 2
|
||||||
|
screenHeight = dstSize * 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dsts = [4]*ebiten.Image{
|
||||||
|
/*ebiten.NewImage(dstSize, dstSize),
|
||||||
|
ebiten.NewImage(dstSize, dstSize),
|
||||||
|
ebiten.NewImage(dstSize, dstSize),
|
||||||
|
ebiten.NewImage(dstSize, dstSize),*/
|
||||||
|
ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{
|
||||||
|
Unmanaged: true,
|
||||||
|
}),
|
||||||
|
ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{
|
||||||
|
Unmanaged: true,
|
||||||
|
}),
|
||||||
|
ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{
|
||||||
|
Unmanaged: true,
|
||||||
|
}),
|
||||||
|
ebiten.NewImageWithOptions(image.Rect(0, 0, dstSize, dstSize), &ebiten.NewImageOptions{
|
||||||
|
Unmanaged: true,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
shaderSrc = []byte(
|
||||||
|
`
|
||||||
|
//kage:units pixels
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func Fragment(dst vec4, src vec2, color vec4) (vec4, vec4, vec4, vec4) {
|
||||||
|
return vec4(1,0,0,1), vec4(0,1,0,1), vec4(0,0,1,1), vec4(1,0,1,1)
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
s *ebiten.Shader
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
s, err = ebiten.NewShader(shaderSrc)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Update() error {
|
||||||
|
g.count++
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
|
vertices := []ebiten.Vertex{
|
||||||
|
{
|
||||||
|
DstX: 0,
|
||||||
|
DstY: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: dstSize,
|
||||||
|
DstY: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: 0,
|
||||||
|
DstY: dstSize,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
DstX: dstSize,
|
||||||
|
DstY: dstSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
indices := []uint16{0, 1, 2, 1, 2, 3}
|
||||||
|
ebiten.DrawTrianglesShaderMRT(dsts, vertices, indices, s, nil)
|
||||||
|
// Dst 0
|
||||||
|
screen.DrawImage(dsts[0], nil)
|
||||||
|
// Dst 1
|
||||||
|
opts := &ebiten.DrawImageOptions{}
|
||||||
|
opts.GeoM.Translate(dstSize, 0)
|
||||||
|
screen.DrawImage(dsts[1], opts)
|
||||||
|
// Dst 2
|
||||||
|
opts.GeoM.Reset()
|
||||||
|
opts.GeoM.Translate(0, dstSize)
|
||||||
|
screen.DrawImage(dsts[2], opts)
|
||||||
|
// Dst 3
|
||||||
|
opts.GeoM.Reset()
|
||||||
|
opts.GeoM.Translate(dstSize, dstSize)
|
||||||
|
screen.DrawImage(dsts[3], opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||||
|
return screenWidth, screenHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||||
|
ebiten.SetWindowTitle("MRT (Ebitengine Demo)")
|
||||||
|
if err := ebiten.RunGameWithOptions(&Game{}, &ebiten.RunGameOptions{
|
||||||
|
GraphicsLibrary: ebiten.GraphicsLibraryDirectX,
|
||||||
|
}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
149
image.go
149
image.go
@ -247,7 +247,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
|||||||
graphics.QuadVertices(vs, float32(sx0), float32(sy0), float32(sx1), float32(sy1), a, b, c, d, tx, ty, cr, cg, cb, ca)
|
graphics.QuadVertices(vs, float32(sx0), float32(sy0), float32(sx1), float32(sy1), a, b, c, d, tx, ty, cr, cg, cb, ca)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*ui.Image{img.image}
|
srcs := [graphics.ShaderSrcImageCount]*ui.Image{img.image}
|
||||||
|
|
||||||
useColorM := !colorm.IsIdentity()
|
useColorM := !colorm.IsIdentity()
|
||||||
shader := builtinShader(filter, builtinshader.AddressUnsafe, useColorM)
|
shader := builtinShader(filter, builtinshader.AddressUnsafe, useColorM)
|
||||||
@ -262,7 +262,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillAll, canSkipMipmap(geoM, filter), false)
|
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillAll, canSkipMipmap(geoM, filter), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex represents a vertex passed to DrawTriangles.
|
// Vertex represents a vertex passed to DrawTriangles.
|
||||||
@ -500,7 +500,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
is[i] = uint32(indices[i])
|
is[i] = uint32(indices[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*ui.Image{img.image}
|
srcs := [graphics.ShaderSrcImageCount]*ui.Image{img.image}
|
||||||
|
|
||||||
useColorM := !colorm.IsIdentity()
|
useColorM := !colorm.IsIdentity()
|
||||||
shader := builtinShader(filter, address, useColorM)
|
shader := builtinShader(filter, address, useColorM)
|
||||||
@ -515,7 +515,7 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias)
|
i.image.DrawTriangles(srcs, vs, is, blend, i.adjustedBounds(), [graphics.ShaderSrcImageCount]image.Rectangle{img.adjustedBounds()}, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), filter != builtinshader.FilterLinear, options.AntiAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
// DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
|
||||||
@ -565,7 +565,7 @@ type DrawTrianglesShaderOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the number of images.
|
// Check the number of images.
|
||||||
var _ [len(DrawTrianglesShaderOptions{}.Images) - graphics.ShaderImageCount]struct{} = [0]struct{}{}
|
var _ [len(DrawTrianglesShaderOptions{}.Images) - graphics.ShaderSrcImageCount]struct{} = [0]struct{}{}
|
||||||
|
|
||||||
// DrawTrianglesShader draws triangles with the specified vertices and their indices with the specified shader.
|
// DrawTrianglesShader draws triangles with the specified vertices and their indices with the specified shader.
|
||||||
//
|
//
|
||||||
@ -650,7 +650,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
|||||||
is[i] = uint32(indices[i])
|
is[i] = uint32(indices[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]*ui.Image
|
var imgs [graphics.ShaderSrcImageCount]*ui.Image
|
||||||
var imgSize image.Point
|
var imgSize image.Point
|
||||||
for i, img := range options.Images {
|
for i, img := range options.Images {
|
||||||
if img == nil {
|
if img == nil {
|
||||||
@ -672,7 +672,7 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
|||||||
imgs[i] = img.image
|
imgs[i] = img.image
|
||||||
}
|
}
|
||||||
|
|
||||||
var srcRegions [graphics.ShaderImageCount]image.Rectangle
|
var srcRegions [graphics.ShaderSrcImageCount]image.Rectangle
|
||||||
for i, img := range options.Images {
|
for i, img := range options.Images {
|
||||||
if img == nil {
|
if img == nil {
|
||||||
continue
|
continue
|
||||||
@ -686,6 +686,135 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader
|
|||||||
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), true, options.AntiAlias)
|
i.image.DrawTriangles(imgs, vs, is, blend, i.adjustedBounds(), srcRegions, shader.shader, i.tmpUniforms, graphicsdriver.FillRule(options.FillRule), true, options.AntiAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DrawTrianglesShader draws triangles with the specified vertices and their indices with the specified shader.
|
||||||
|
//
|
||||||
|
// Vertex contains color values, which can be interpreted for any purpose by the shader.
|
||||||
|
//
|
||||||
|
// For the details about the shader, see https://ebitengine.org/en/documents/shader.html.
|
||||||
|
//
|
||||||
|
// If the shader unit is texels, one of the specified image is non-nil and its size is different from (width, height),
|
||||||
|
// DrawTrianglesShader panics.
|
||||||
|
// If one of the specified image is non-nil and is disposed, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// If len(vertices) is more than MaxVertexCount, the exceeding part is ignored.
|
||||||
|
//
|
||||||
|
// If len(indices) is not multiple of 3, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// If a value in indices is out of range of vertices, or not less than MaxVertexCount, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// When a specified image is non-nil and is disposed, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// If a specified uniform variable's length or type doesn't match with an expected one, DrawTrianglesShader panics.
|
||||||
|
//
|
||||||
|
// Even if a result is an invalid color as a premultiplied-alpha color, i.e. an alpha value exceeds other color values,
|
||||||
|
// the value is kept and is not clamped.
|
||||||
|
//
|
||||||
|
// When the image i is disposed, DrawTrianglesShader does nothing.
|
||||||
|
func DrawTrianglesShaderMRT(dsts [graphics.ShaderDstImageCount]*Image, vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) {
|
||||||
|
if dsts[0] == nil || dsts[0].isDisposed() {
|
||||||
|
panic("ebiten: the first destination image given to DrawTrianglesShaderMRT must not be nil or disposed")
|
||||||
|
}
|
||||||
|
var dstImgs [graphics.ShaderDstImageCount]*ui.Image
|
||||||
|
for i, dst := range dsts {
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dst.copyCheck()
|
||||||
|
if dst.isDisposed() {
|
||||||
|
panic("ebiten: the destination images given to DrawTrianglesShaderMRT must not be disposed")
|
||||||
|
}
|
||||||
|
dstImgs[i] = dst.image
|
||||||
|
}
|
||||||
|
|
||||||
|
if shader.isDisposed() {
|
||||||
|
panic("ebiten: the given shader to DrawTrianglesShaderMRT must not be disposed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vertices) > graphicscommand.MaxVertexCount {
|
||||||
|
// The last part cannot be specified by indices. Just omit them.
|
||||||
|
vertices = vertices[:graphicscommand.MaxVertexCount]
|
||||||
|
}
|
||||||
|
if len(indices)%3 != 0 {
|
||||||
|
panic("ebiten: len(indices) % 3 must be 0")
|
||||||
|
}
|
||||||
|
for i, idx := range indices {
|
||||||
|
if int(idx) >= len(vertices) {
|
||||||
|
panic(fmt.Sprintf("ebiten: indices[%d] must be less than len(vertices) (%d) but was %d", i, len(vertices), idx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if options == nil {
|
||||||
|
options = &DrawTrianglesShaderOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var blend graphicsdriver.Blend
|
||||||
|
if options.CompositeMode == CompositeModeCustom {
|
||||||
|
blend = options.Blend.internalBlend()
|
||||||
|
} else {
|
||||||
|
blend = options.CompositeMode.blend().internalBlend()
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := dsts[0]
|
||||||
|
vs := dst.ensureTmpVertices(len(vertices) * graphics.VertexFloatCount)
|
||||||
|
src := options.Images[0]
|
||||||
|
for i, v := range vertices {
|
||||||
|
dx, dy := dst.adjustPositionF32(v.DstX, v.DstY)
|
||||||
|
vs[i*graphics.VertexFloatCount] = dx
|
||||||
|
vs[i*graphics.VertexFloatCount+1] = dy
|
||||||
|
sx, sy := v.SrcX, v.SrcY
|
||||||
|
if src != nil {
|
||||||
|
sx, sy = src.adjustPositionF32(sx, sy)
|
||||||
|
}
|
||||||
|
vs[i*graphics.VertexFloatCount+2] = sx
|
||||||
|
vs[i*graphics.VertexFloatCount+3] = sy
|
||||||
|
vs[i*graphics.VertexFloatCount+4] = v.ColorR
|
||||||
|
vs[i*graphics.VertexFloatCount+5] = v.ColorG
|
||||||
|
vs[i*graphics.VertexFloatCount+6] = v.ColorB
|
||||||
|
vs[i*graphics.VertexFloatCount+7] = v.ColorA
|
||||||
|
}
|
||||||
|
|
||||||
|
is := make([]uint32, len(indices))
|
||||||
|
for i := range is {
|
||||||
|
is[i] = uint32(indices[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcImgs [graphics.ShaderSrcImageCount]*ui.Image
|
||||||
|
var imgSize image.Point
|
||||||
|
for i, img := range options.Images {
|
||||||
|
if img == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if img.isDisposed() {
|
||||||
|
panic("ebiten: the given image to DrawTrianglesShader must not be disposed")
|
||||||
|
}
|
||||||
|
if shader.unit == shaderir.Texels {
|
||||||
|
if i == 0 {
|
||||||
|
imgSize = img.Bounds().Size()
|
||||||
|
} else {
|
||||||
|
// TODO: Check imgw > 0 && imgh > 0
|
||||||
|
if img.Bounds().Size() != imgSize {
|
||||||
|
panic("ebiten: all the source images must be the same size with the rectangle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srcImgs[i] = img.image
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcRegions [graphics.ShaderSrcImageCount]image.Rectangle
|
||||||
|
for i, img := range options.Images {
|
||||||
|
if img == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcRegions[i] = img.adjustedBounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dst := range dsts {
|
||||||
|
dst.tmpUniforms = dst.tmpUniforms[:0]
|
||||||
|
dst.tmpUniforms = shader.appendUniforms(dst.tmpUniforms, options.Uniforms)
|
||||||
|
}
|
||||||
|
ui.DrawTrianglesMRT(dstImgs, srcImgs, vs, is, blend, dst.adjustedBounds(), srcRegions, shader.shader, dst.tmpUniforms, graphicsdriver.FillRule(options.FillRule), true, options.AntiAlias)
|
||||||
|
}
|
||||||
|
|
||||||
// DrawRectShaderOptions represents options for DrawRectShader.
|
// DrawRectShaderOptions represents options for DrawRectShader.
|
||||||
type DrawRectShaderOptions struct {
|
type DrawRectShaderOptions struct {
|
||||||
// GeoM is a geometry matrix to draw.
|
// GeoM is a geometry matrix to draw.
|
||||||
@ -724,7 +853,7 @@ type DrawRectShaderOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check the number of images.
|
// Check the number of images.
|
||||||
var _ [len(DrawRectShaderOptions{}.Images)]struct{} = [graphics.ShaderImageCount]struct{}{}
|
var _ [len(DrawRectShaderOptions{}.Images)]struct{} = [graphics.ShaderSrcImageCount]struct{}{}
|
||||||
|
|
||||||
// DrawRectShader draws a rectangle with the specified width and height with the specified shader.
|
// DrawRectShader draws a rectangle with the specified width and height with the specified shader.
|
||||||
//
|
//
|
||||||
@ -771,7 +900,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
|||||||
blend = options.CompositeMode.blend().internalBlend()
|
blend = options.CompositeMode.blend().internalBlend()
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]*ui.Image
|
var imgs [graphics.ShaderSrcImageCount]*ui.Image
|
||||||
for i, img := range options.Images {
|
for i, img := range options.Images {
|
||||||
if img == nil {
|
if img == nil {
|
||||||
continue
|
continue
|
||||||
@ -785,7 +914,7 @@ func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawR
|
|||||||
imgs[i] = img.image
|
imgs[i] = img.image
|
||||||
}
|
}
|
||||||
|
|
||||||
var srcRegions [graphics.ShaderImageCount]image.Rectangle
|
var srcRegions [graphics.ShaderSrcImageCount]image.Rectangle
|
||||||
for i, img := range options.Images {
|
for i, img := range options.Images {
|
||||||
if img == nil {
|
if img == nil {
|
||||||
if shader.unit == shaderir.Pixels && i == 0 {
|
if shader.unit == shaderir.Pixels && i == 0 {
|
||||||
|
@ -153,12 +153,12 @@ func (b *backend) extendIfNeeded(width, height int) {
|
|||||||
|
|
||||||
// Use DrawTriangles instead of WritePixels because the image i might be stale and not have its pixels
|
// Use DrawTriangles instead of WritePixels because the image i might be stale and not have its pixels
|
||||||
// information.
|
// information.
|
||||||
srcs := [graphics.ShaderImageCount]*graphicscommand.Image{b.image}
|
srcs := [graphics.ShaderSrcImageCount]*graphicscommand.Image{b.image}
|
||||||
sw, sh := b.image.InternalSize()
|
sw, sh := b.image.InternalSize()
|
||||||
vs := quadVertices(0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1)
|
vs := quadVertices(0, 0, float32(sw), float32(sh), 0, 0, float32(sw), float32(sh), 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, sw, sh)
|
dr := image.Rect(0, 0, sw, sh)
|
||||||
newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader.ensureShader(), nil, graphicsdriver.FillAll)
|
newImg.DrawTriangles(srcs, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader.ensureShader(), nil, graphicsdriver.FillAll)
|
||||||
b.image.Dispose()
|
b.image.Dispose()
|
||||||
|
|
||||||
b.image = newImg
|
b.image = newImg
|
||||||
@ -182,7 +182,7 @@ func newClearedImage(width, height int, screen bool) *graphicscommand.Image {
|
|||||||
func clearImage(i *graphicscommand.Image, region image.Rectangle) {
|
func clearImage(i *graphicscommand.Image, region image.Rectangle) {
|
||||||
vs := quadVertices(float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0)
|
vs := quadVertices(float32(region.Min.X), float32(region.Min.Y), float32(region.Max.X), float32(region.Max.Y), 0, 0, 0, 0, 0, 0, 0, 0)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
i.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderImageCount]image.Rectangle{}, clearShader.ensureShader(), nil, graphicsdriver.FillAll)
|
i.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendClear, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, clearShader.ensureShader(), nil, graphicsdriver.FillAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) clearPixels(region image.Rectangle) {
|
func (b *backend) clearPixels(region image.Rectangle) {
|
||||||
@ -355,7 +355,7 @@ func (i *Image) ensureIsolatedFromSource(backends []*backend) {
|
|||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, i.width, i.height)
|
dr := image.Rect(0, 0, i.width, i.height)
|
||||||
|
|
||||||
newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
|
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
newI.moveTo(i)
|
newI.moveTo(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ func (i *Image) putOnSourceBackend(graphicsDriver graphicsdriver.Graphics) {
|
|||||||
graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
graphics.QuadVertices(vs, 0, 0, w, h, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, i.width, i.height)
|
dr := image.Rect(0, 0, i.width, i.height)
|
||||||
newI.drawTriangles([graphics.ShaderImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
|
newI.drawTriangles([graphics.ShaderSrcImageCount]*Image{i}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
newI.moveTo(i)
|
newI.moveTo(i)
|
||||||
i.usedAsSourceCount = 0
|
i.usedAsSourceCount = 0
|
||||||
@ -417,7 +417,7 @@ func (i *Image) regionWithPadding() image.Rectangle {
|
|||||||
// 5: Color G
|
// 5: Color G
|
||||||
// 6: Color B
|
// 6: Color B
|
||||||
// 7: Color Y
|
// 7: Color Y
|
||||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
backendsM.Lock()
|
backendsM.Lock()
|
||||||
defer backendsM.Unlock()
|
defer backendsM.Unlock()
|
||||||
|
|
||||||
@ -438,7 +438,28 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
i.drawTriangles(srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
func DrawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
|
backendsM.Lock()
|
||||||
|
defer backendsM.Unlock()
|
||||||
|
|
||||||
|
if !inFrame {
|
||||||
|
vs := make([]float32, len(vertices))
|
||||||
|
copy(vs, vertices)
|
||||||
|
is := make([]uint32, len(indices))
|
||||||
|
copy(is, indices)
|
||||||
|
us := make([]uint32, len(uniforms))
|
||||||
|
copy(us, uniforms)
|
||||||
|
|
||||||
|
appendDeferred(func() {
|
||||||
|
drawTrianglesMRT(dsts, srcs, vs, is, blend, dstRegion, srcRegions, shader, us, fillRule)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
drawTrianglesMRT(dsts, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Image) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
if len(vertices) == 0 {
|
if len(vertices) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -515,7 +536,7 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
srcRegions[i] = srcRegions[i].Add(r.Min)
|
srcRegions[i] = srcRegions[i].Add(r.Min)
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]*graphicscommand.Image
|
var imgs [graphics.ShaderSrcImageCount]*graphicscommand.Image
|
||||||
for i, src := range srcs {
|
for i, src := range srcs {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
continue
|
continue
|
||||||
@ -536,6 +557,113 @@ func (i *Image) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func drawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
|
if len(vertices) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
backends := make([]*backend, 0, len(srcs))
|
||||||
|
for _, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if src.backend == nil {
|
||||||
|
// It is possible to spcify i.backend as a forbidden backend, but this might prevent a good allocation for a source image.
|
||||||
|
// If the backend becomes the same as i's, i's backend will be changed at ensureIsolatedFromSource.
|
||||||
|
src.allocate(nil, true)
|
||||||
|
}
|
||||||
|
backends = append(backends, src.backend)
|
||||||
|
src.backend.sourceInThisFrame = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var dstImgs [graphics.ShaderDstImageCount]*graphicscommand.Image
|
||||||
|
for i, dst := range dsts {
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dst.ensureIsolatedFromSource(backends)
|
||||||
|
dstImgs[i] = dst.backend.image
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, src := range srcs {
|
||||||
|
// Compare i and source images after ensuring i is not on an atlas, or
|
||||||
|
// i and a source image might share the same atlas even though i != src.
|
||||||
|
for _, dst := range dsts {
|
||||||
|
if src != nil && dst != nil && dst.backend.image == src.backend.image {
|
||||||
|
panic("atlas: Image.DrawTriangles: source must be different from the receiver")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r := dsts[0].regionWithPadding()
|
||||||
|
// TODO: Check if dstRegion does not to violate the region.
|
||||||
|
dstRegion = dstRegion.Add(r.Min)
|
||||||
|
|
||||||
|
dx, dy := float32(r.Min.X), float32(r.Min.Y)
|
||||||
|
|
||||||
|
var oxf, oyf float32
|
||||||
|
if srcs[0] != nil {
|
||||||
|
r := srcs[0].regionWithPadding()
|
||||||
|
oxf, oyf = float32(r.Min.X), float32(r.Min.Y)
|
||||||
|
n := len(vertices)
|
||||||
|
for i := 0; i < n; i += graphics.VertexFloatCount {
|
||||||
|
vertices[i] += dx
|
||||||
|
vertices[i+1] += dy
|
||||||
|
vertices[i+2] += oxf
|
||||||
|
vertices[i+3] += oyf
|
||||||
|
}
|
||||||
|
if shader.ir.Unit == shaderir.Texels {
|
||||||
|
sw, sh := srcs[0].backend.image.InternalSize()
|
||||||
|
swf, shf := float32(sw), float32(sh)
|
||||||
|
for i := 0; i < n; i += graphics.VertexFloatCount {
|
||||||
|
vertices[i+2] /= swf
|
||||||
|
vertices[i+3] /= shf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n := len(vertices)
|
||||||
|
for i := 0; i < n; i += graphics.VertexFloatCount {
|
||||||
|
vertices[i] += dx
|
||||||
|
vertices[i+1] += dy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// A source region can be deliberately empty when this is not needed in order to avoid unexpected
|
||||||
|
// performance issue (#1293).
|
||||||
|
if srcRegions[i].Empty() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r := src.regionWithPadding()
|
||||||
|
srcRegions[i] = srcRegions[i].Add(r.Min)
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcImgs [graphics.ShaderSrcImageCount]*graphicscommand.Image
|
||||||
|
for i, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcImgs[i] = src.backend.image
|
||||||
|
}
|
||||||
|
|
||||||
|
graphicscommand.DrawTrianglesMRT(dstImgs, srcImgs, vertices, indices, blend, dstRegion, srcRegions, shader.ensureShader(), uniforms, fillRule)
|
||||||
|
|
||||||
|
for _, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !src.isOnSourceBackend() && src.canBePutOnAtlas() {
|
||||||
|
// src might already registered, but assigning it again is not harmful.
|
||||||
|
imagesToPutOnSourceBackend.add(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WritePixels replaces the pixels on the image.
|
// WritePixels replaces the pixels on the image.
|
||||||
func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
||||||
backendsM.Lock()
|
backendsM.Lock()
|
||||||
|
@ -105,7 +105,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
|
|||||||
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()
|
||||||
dr := image.Rect(0, 0, size, size)
|
dr := image.Rect(0, 0, size, size)
|
||||||
img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img4.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img4.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ func TestEnsureIsolatedFromSourceBackend(t *testing.T) {
|
|||||||
// img5 is not allocated now, but is allocated at DrawTriangles.
|
// img5 is not allocated now, but is allocated at DrawTriangles.
|
||||||
vs = quadVertices(0, 0, size/2, size/2, 1)
|
vs = quadVertices(0, 0, size/2, size/2, 1)
|
||||||
dr = image.Rect(0, 0, size/2, size/2)
|
dr = image.Rect(0, 0, size/2, size/2)
|
||||||
img3.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img3.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img5}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ func TestEnsureIsolatedFromSourceBackend(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.
|
||||||
vs = quadVertices(0, 0, size/2, size/2, 1)
|
vs = quadVertices(0, 0, size/2, size/2, 1)
|
||||||
img4.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img4.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReputOnSourceBackend(t *testing.T) {
|
func TestReputOnSourceBackend(t *testing.T) {
|
||||||
@ -191,7 +191,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
// Render onto img1. The count should not matter.
|
// Render onto img1. The count should not matter.
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
|
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
// Finally, img1 is on a source backend.
|
// Finally, img1 is on a source backend.
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vs = quadVertices(size, size, 0, 0, 1)
|
vs = quadVertices(size, size, 0, 0, 1)
|
||||||
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), true; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -270,7 +270,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
// Use img1 as a render target again. The count should not matter.
|
// Use img1 as a render target again. The count should not matter.
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
img1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -282,7 +282,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
|
img1.WritePixels(make([]byte, 4*size*size), image.Rect(0, 0, size, size))
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -291,7 +291,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
|
|
||||||
// img1 is not on an atlas due to WritePixels.
|
// img1 is not on an atlas due to WritePixels.
|
||||||
vs = quadVertices(size, size, 0, 0, 1)
|
vs = quadVertices(size, size, 0, 0, 1)
|
||||||
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img1.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -300,7 +300,7 @@ func TestReputOnSourceBackend(t *testing.T) {
|
|||||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
|
for i := 0; i < atlas.BaseCountToPutOnSourceBackend*2; i++ {
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
img0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{img3}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := img3.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -403,7 +403,7 @@ func TestWritePixelsAfterDrawTriangles(t *testing.T) {
|
|||||||
vs := quadVertices(w, h, 0, 0, 1)
|
vs := quadVertices(w, h, 0, 0, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
dst.WritePixels(pix, image.Rect(0, 0, w, h))
|
dst.WritePixels(pix, image.Rect(0, 0, w, h))
|
||||||
|
|
||||||
pix = make([]byte, 4*w*h)
|
pix = make([]byte, 4*w*h)
|
||||||
@ -450,7 +450,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()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
pix = make([]byte, 4*w*h)
|
pix = make([]byte, 4*w*h)
|
||||||
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h))
|
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h))
|
||||||
@ -497,7 +497,7 @@ func TestLongImages(t *testing.T) {
|
|||||||
vs := quadVertices(w, h, 0, 0, scale)
|
vs := quadVertices(w, h, 0, 0, scale)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, dstW, dstH)
|
dr := image.Rect(0, 0, dstW, dstH)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
pix = make([]byte, 4*dstW*dstH)
|
pix = make([]byte, 4*dstW*dstH)
|
||||||
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH))
|
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, dstW, dstH))
|
||||||
@ -613,7 +613,7 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
|
|||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, size, size)
|
dr := image.Rect(0, 0, size, size)
|
||||||
src.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
src.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -622,7 +622,7 @@ func TestDeallocatedAndReputOnSourceBackend(t *testing.T) {
|
|||||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ {
|
for i := 0; i < atlas.BaseCountToPutOnSourceBackend/2; i++ {
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := src.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -656,7 +656,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
|
|||||||
// Call DrawTriangles multiple times.
|
// Call DrawTriangles multiple times.
|
||||||
// The number of DrawTriangles doesn't matter as long as these are called in one frame.
|
// The number of DrawTriangles doesn't matter as long as these are called in one frame.
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
src2.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
src2.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
}
|
}
|
||||||
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
@ -675,7 +675,7 @@ func TestImageIsNotReputOnSourceBackendWithoutUsingAsSource(t *testing.T) {
|
|||||||
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
|
for i := 0; i < atlas.BaseCountToPutOnSourceBackend; i++ {
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
vs := quadVertices(size, size, 0, 0, 1)
|
vs := quadVertices(size, size, 0, 0, 1)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src2}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
|
if got, want := src2.IsOnSourceBackendForTesting(), false; got != want {
|
||||||
t.Errorf("got: %v, want: %v", got, want)
|
t.Errorf("got: %v, want: %v", got, want)
|
||||||
}
|
}
|
||||||
@ -801,14 +801,14 @@ func TestDestinationCountOverflow(t *testing.T) {
|
|||||||
|
|
||||||
// Use dst0 as a destination for a while.
|
// Use dst0 as a destination for a while.
|
||||||
for i := 0; i < 31; i++ {
|
for i := 0; i < 31; i++ {
|
||||||
dst0.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst0.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use dst0 as a source for a while.
|
// Use dst0 as a source for a while.
|
||||||
// As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend.
|
// As dst0 is used as a destination too many times (31 is a maximum), dst0's backend should never be a source backend.
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
dst1.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst1.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{dst0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
if dst0.IsOnSourceBackendForTesting() {
|
if dst0.IsOnSourceBackendForTesting() {
|
||||||
t.Errorf("dst0 cannot be on a source backend: %d", i)
|
t.Errorf("dst0 cannot be on a source backend: %d", i)
|
||||||
@ -834,7 +834,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
|
|||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
for _, img := range srcs {
|
for _, img := range srcs {
|
||||||
img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
img.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
}
|
}
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
|
|
||||||
@ -842,7 +842,7 @@ func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
|
|||||||
// Check iterating the registered image works correctly.
|
// Check iterating the registered image works correctly.
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
for _, src := range srcs {
|
for _, src := range srcs {
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
}
|
}
|
||||||
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
atlas.PutImagesOnSourceBackendForTesting(ui.Get().GraphicsDriverForTesting())
|
||||||
}
|
}
|
||||||
|
@ -37,12 +37,12 @@ func TestShaderFillTwice(t *testing.T) {
|
|||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
g := ui.Get().GraphicsDriverForTesting()
|
g := ui.Get().GraphicsDriverForTesting()
|
||||||
s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff))
|
s0 := atlas.NewShader(etesting.ShaderProgramFill(0xff, 0xff, 0xff, 0xff))
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s0, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s0, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
// Vertices must be recreated (#1755)
|
// Vertices must be recreated (#1755)
|
||||||
vs = quadVertices(w, h, 0, 0, 1)
|
vs = quadVertices(w, h, 0, 0, 1)
|
||||||
s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff))
|
s1 := atlas.NewShader(etesting.ShaderProgramFill(0x80, 0x80, 0x80, 0xff))
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s1, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s1, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
pix := make([]byte, 4*w*h)
|
pix := make([]byte, 4*w*h)
|
||||||
ok, err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h))
|
ok, err := dst.ReadPixels(g, pix, image.Rect(0, 0, w, h))
|
||||||
@ -69,11 +69,11 @@ func TestImageDrawTwice(t *testing.T) {
|
|||||||
vs := quadVertices(w, h, 0, 0, 1)
|
vs := quadVertices(w, h, 0, 0, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src0}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
// Vertices must be recreated (#1755)
|
// Vertices must be recreated (#1755)
|
||||||
vs = quadVertices(w, h, 0, 0, 1)
|
vs = quadVertices(w, h, 0, 0, 1)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{src1}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
pix := make([]byte, 4*w*h)
|
pix := make([]byte, 4*w*h)
|
||||||
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h))
|
ok, err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), pix, image.Rect(0, 0, w, h))
|
||||||
@ -97,7 +97,7 @@ func TestGCShader(t *testing.T) {
|
|||||||
vs := quadVertices(w, h, 0, 0, 1)
|
vs := quadVertices(w, h, 0, 0, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*atlas.Image{}, vs, is, graphicsdriver.BlendCopy, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
// Ensure other objects are GCed, as GC appends deferred functions for collected objects.
|
// Ensure other objects are GCed, as GC appends deferred functions for collected objects.
|
||||||
ensureGC()
|
ensureGC()
|
||||||
|
@ -183,7 +183,7 @@ func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
|||||||
// DrawTriangles draws the src image with the given vertices.
|
// DrawTriangles draws the src image with the given vertices.
|
||||||
//
|
//
|
||||||
// Copying vertices and indices is the caller's responsibility.
|
// Copying vertices and indices is the caller's responsibility.
|
||||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
for _, src := range srcs {
|
for _, src := range srcs {
|
||||||
if i == src {
|
if i == src {
|
||||||
panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
|
panic("buffered: Image.DrawTriangles: source images must be different from the receiver")
|
||||||
@ -197,7 +197,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
|
|
||||||
i.syncPixelsIfNeeded()
|
i.syncPixelsIfNeeded()
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]*atlas.Image
|
var imgs [graphics.ShaderSrcImageCount]*atlas.Image
|
||||||
for i, img := range srcs {
|
for i, img := range srcs {
|
||||||
if img == nil {
|
if img == nil {
|
||||||
continue
|
continue
|
||||||
@ -211,6 +211,45 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
i.pixels = nil
|
i.pixels = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DrawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
|
for _, src := range srcs {
|
||||||
|
for _, dst := range dsts {
|
||||||
|
if dst == src {
|
||||||
|
panic("buffered: DrawTrianglesMRT: source images must be different from the destination")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if src != nil {
|
||||||
|
// src's pixels have to be synced between CPU and GPU,
|
||||||
|
// but doesn't have to be cleared since src is not modified in this function.
|
||||||
|
src.syncPixelsIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dstImgs [graphics.ShaderDstImageCount]*atlas.Image
|
||||||
|
for i, dst := range dsts {
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dst.syncPixelsIfNeeded()
|
||||||
|
dstImgs[i] = dst.img
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcImgs [graphics.ShaderSrcImageCount]*atlas.Image
|
||||||
|
for i, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcImgs[i] = src.img
|
||||||
|
}
|
||||||
|
|
||||||
|
atlas.DrawTrianglesMRT(dstImgs, srcImgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
|
|
||||||
|
// After rendering, the pixel cache is no longer valid.
|
||||||
|
for _, dst := range dsts {
|
||||||
|
dst.pixels = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// syncPixelsIfNeeded syncs the pixels between CPU and GPU.
|
// syncPixelsIfNeeded syncs the pixels between CPU and GPU.
|
||||||
// After syncPixelsIfNeeded, dotsBuffer is cleared, but pixels might remain.
|
// After syncPixelsIfNeeded, dotsBuffer is cleared, but pixels might remain.
|
||||||
func (i *Image) syncPixelsIfNeeded() {
|
func (i *Image) syncPixelsIfNeeded() {
|
||||||
@ -289,10 +328,10 @@ func (i *Image) syncPixelsIfNeeded() {
|
|||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*atlas.Image{whiteImage.img}
|
srcs := [graphics.ShaderSrcImageCount]*atlas.Image{whiteImage.img}
|
||||||
dr := image.Rect(0, 0, i.width, i.height)
|
dr := image.Rect(0, 0, i.width, i.height)
|
||||||
blend := graphicsdriver.BlendCopy
|
blend := graphicsdriver.BlendCopy
|
||||||
i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
i.img.DrawTriangles(srcs, vs, is, blend, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
// TODO: Use clear if Go 1.21 is available.
|
// TODO: Use clear if Go 1.21 is available.
|
||||||
for pos := range i.dotsBuffer {
|
for pos := range i.dotsBuffer {
|
||||||
|
@ -55,8 +55,8 @@ func TestUnsyncedPixels(t *testing.T) {
|
|||||||
graphics.QuadVertices(vs, 0, 0, 16, 16, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
graphics.QuadVertices(vs, 0, 0, 16, 16, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, 16, 16)
|
dr := image.Rect(0, 0, 16, 16)
|
||||||
sr := [graphics.ShaderImageCount]image.Rectangle{image.Rect(0, 0, 16, 16)}
|
sr := [graphics.ShaderSrcImageCount]image.Rectangle{image.Rect(0, 0, 16, 16)}
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, sr, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, sr, atlas.NearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
// Check the result is correct.
|
// Check the result is correct.
|
||||||
var got [4]byte
|
var got [4]byte
|
||||||
|
@ -538,7 +538,7 @@ func (w *Window) SetOpacity(opacity float32) {
|
|||||||
C.glfwSetWindowOpacity(w.data, C.float(opacity))
|
C.glfwSetWindowOpacity(w.data, C.float(opacity))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequestWindowAttention funciton requests user attention to the specified
|
// RequestAttention function requests user attention to the specified
|
||||||
// window. On platforms where this is not supported, attention is requested to
|
// window. On platforms where this is not supported, attention is requested to
|
||||||
// the application as a whole.
|
// the application as a whole.
|
||||||
//
|
//
|
||||||
|
@ -89,9 +89,9 @@ var __imageSrcRegionSizes [%[1]d]vec2
|
|||||||
func imageSrcRegionOnTexture() (vec2, vec2) {
|
func imageSrcRegionOnTexture() (vec2, vec2) {
|
||||||
return __imageSrcRegionOrigins[0], __imageSrcRegionSizes[0]
|
return __imageSrcRegionOrigins[0], __imageSrcRegionSizes[0]
|
||||||
}
|
}
|
||||||
`, ShaderImageCount)
|
`, ShaderSrcImageCount)
|
||||||
|
|
||||||
for i := 0; i < ShaderImageCount; i++ {
|
for i := 0; i < ShaderSrcImageCount; i++ {
|
||||||
shaderSuffix += fmt.Sprintf(`
|
shaderSuffix += fmt.Sprintf(`
|
||||||
// imageSrc%[1]dOrigin returns the source image's region origin on its texture.
|
// imageSrc%[1]dOrigin returns the source image's region origin on its texture.
|
||||||
// The unit is the source texture's pixel or texel.
|
// The unit is the source texture's pixel or texel.
|
||||||
@ -179,7 +179,7 @@ func CompileShader(src []byte) (*shaderir.Program, error) {
|
|||||||
vert = "__vertex"
|
vert = "__vertex"
|
||||||
frag = "Fragment"
|
frag = "Fragment"
|
||||||
)
|
)
|
||||||
ir, err := shader.Compile(buf.Bytes(), vert, frag, ShaderImageCount)
|
ir, err := shader.Compile(buf.Bytes(), vert, frag, ShaderSrcImageCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
package graphics
|
package graphics
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ShaderImageCount = 4
|
ShaderSrcImageCount = 4
|
||||||
|
ShaderDstImageCount = 4
|
||||||
|
|
||||||
// PreservedUniformVariablesCount represents the number of preserved uniform variables.
|
// PreservedUniformVariablesCount represents the number of preserved uniform variables.
|
||||||
// Any shaders in Ebitengine must have these uniform variables.
|
// Any shaders in Ebitengine must have these uniform variables.
|
||||||
@ -30,11 +31,11 @@ const (
|
|||||||
ProjectionMatrixUniformVariableIndex = 6
|
ProjectionMatrixUniformVariableIndex = 6
|
||||||
|
|
||||||
PreservedUniformUint32Count = 2 + // the destination texture size
|
PreservedUniformUint32Count = 2 + // the destination texture size
|
||||||
2*ShaderImageCount + // the source texture sizes array
|
2*ShaderSrcImageCount + // the source texture sizes array
|
||||||
2 + // the destination image region origin
|
2 + // the destination image region origin
|
||||||
2 + // the destination image region size
|
2 + // the destination image region size
|
||||||
2*ShaderImageCount + // the source image region origins array
|
2*ShaderSrcImageCount + // the source image region origins array
|
||||||
2*ShaderImageCount + // the source image region sizes array
|
2*ShaderSrcImageCount + // the source image region sizes array
|
||||||
16 // the projection matrix
|
16 // the projection matrix
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -61,8 +61,8 @@ func (p *drawTrianglesCommandPool) put(v *drawTrianglesCommand) {
|
|||||||
|
|
||||||
// drawTrianglesCommand represents a drawing command to draw an image on another image.
|
// drawTrianglesCommand represents a drawing command to draw an image on another image.
|
||||||
type drawTrianglesCommand struct {
|
type drawTrianglesCommand struct {
|
||||||
dst *Image
|
dsts [graphics.ShaderDstImageCount]*Image
|
||||||
srcs [graphics.ShaderImageCount]*Image
|
srcs [graphics.ShaderSrcImageCount]*Image
|
||||||
vertices []float32
|
vertices []float32
|
||||||
blend graphicsdriver.Blend
|
blend graphicsdriver.Blend
|
||||||
dstRegions []graphicsdriver.DstRegion
|
dstRegions []graphicsdriver.DstRegion
|
||||||
@ -81,12 +81,19 @@ func (c *drawTrianglesCommand) String() string {
|
|||||||
c.blend.BlendOperationRGB,
|
c.blend.BlendOperationRGB,
|
||||||
c.blend.BlendOperationAlpha)
|
c.blend.BlendOperationAlpha)
|
||||||
|
|
||||||
dst := fmt.Sprintf("%d", c.dst.id)
|
var dststrs [graphics.ShaderDstImageCount]string
|
||||||
if c.dst.screen {
|
for i, dst := range c.dsts {
|
||||||
dst += " (screen)"
|
if dst == nil {
|
||||||
|
dststrs[i] = "(nil)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dststrs[i] = fmt.Sprintf("%d", dst.id)
|
||||||
|
if dst.screen {
|
||||||
|
dststrs[i] += " (screen)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var srcstrs [graphics.ShaderImageCount]string
|
var srcstrs [graphics.ShaderSrcImageCount]string
|
||||||
for i, src := range c.srcs {
|
for i, src := range c.srcs {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
srcstrs[i] = "(nil)"
|
srcstrs[i] = "(nil)"
|
||||||
@ -98,7 +105,7 @@ func (c *drawTrianglesCommand) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("draw-triangles: dst: %s <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, fill rule: %s, shader id: %d", dst, strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.fillRule, c.shader.id)
|
return fmt.Sprintf("draw-triangles: dst: [%s] <- src: [%s], num of dst regions: %d, num of indices: %d, blend: %s, fill rule: %s, shader id: %d", strings.Join(dststrs[:], ", "), strings.Join(srcstrs[:], ", "), len(c.dstRegions), c.numIndices(), blend, c.fillRule, c.shader.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exec executes the drawTrianglesCommand.
|
// Exec executes the drawTrianglesCommand.
|
||||||
@ -108,16 +115,25 @@ func (c *drawTrianglesCommand) Exec(commandQueue *commandQueue, graphicsDriver g
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]graphicsdriver.ImageID
|
var dsts [graphics.ShaderDstImageCount]graphicsdriver.ImageID
|
||||||
for i, src := range c.srcs {
|
for i, dst := range c.dsts {
|
||||||
if src == nil {
|
if dst == nil {
|
||||||
imgs[i] = graphicsdriver.InvalidImageID
|
dsts[i] = graphicsdriver.InvalidImageID
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
imgs[i] = src.image.ID()
|
dsts[i] = dst.image.ID()
|
||||||
}
|
}
|
||||||
|
|
||||||
return graphicsDriver.DrawTriangles(c.dst.image.ID(), imgs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.fillRule)
|
var srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID
|
||||||
|
for i, src := range c.srcs {
|
||||||
|
if src == nil {
|
||||||
|
srcs[i] = graphicsdriver.InvalidImageID
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srcs[i] = src.image.ID()
|
||||||
|
}
|
||||||
|
|
||||||
|
return graphicsDriver.DrawTriangles(dsts, srcs, c.shader.shader.ID(), c.dstRegions, indexOffset, c.blend, c.uniforms, c.fillRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *drawTrianglesCommand) NeedsSync() bool {
|
func (c *drawTrianglesCommand) NeedsSync() bool {
|
||||||
@ -142,7 +158,7 @@ func (c *drawTrianglesCommand) setVertices(vertices []float32) {
|
|||||||
|
|
||||||
// CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged
|
// CanMergeWithDrawTrianglesCommand returns a boolean value indicating whether the other drawTrianglesCommand can be merged
|
||||||
// with the drawTrianglesCommand c.
|
// with the drawTrianglesCommand c.
|
||||||
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) bool {
|
func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, blend graphicsdriver.Blend, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) bool {
|
||||||
if c.shader != shader {
|
if c.shader != shader {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -154,7 +170,7 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst *Image, srcs
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.dst != dst {
|
if c.dsts != dsts {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if c.srcs != srcs {
|
if c.srcs != srcs {
|
||||||
|
@ -105,7 +105,7 @@ func mustUseDifferentVertexBuffer(nextNumVertexFloats int) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnqueueDrawTrianglesCommand enqueues a drawing-image command.
|
// EnqueueDrawTrianglesCommand enqueues a drawing-image command.
|
||||||
func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
func (q *commandQueue) EnqueueDrawTrianglesCommand(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
if len(vertices) > maxVertexFloatCount {
|
if len(vertices) > maxVertexFloatCount {
|
||||||
panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", maxVertexFloatCount, len(vertices)))
|
panic(fmt.Sprintf("graphicscommand: len(vertices) must equal to or less than %d but was %d", maxVertexFloatCount, len(vertices)))
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
|
|||||||
// prependPreservedUniforms not only prepends values to the given slice but also creates a new slice.
|
// prependPreservedUniforms not only prepends values to the given slice but also creates a new slice.
|
||||||
// Allocating a new slice is necessary to make EnqueueDrawTrianglesCommand safe so far.
|
// Allocating a new slice is necessary to make EnqueueDrawTrianglesCommand safe so far.
|
||||||
// TODO: This might cause a performance issue (#2601).
|
// TODO: This might cause a performance issue (#2601).
|
||||||
uniforms = q.prependPreservedUniforms(uniforms, shader, dst, srcs, dstRegion, srcRegions)
|
uniforms = q.prependPreservedUniforms(uniforms, shader, dsts, srcs, dstRegion, srcRegions)
|
||||||
|
|
||||||
// Remove unused uniform variables so that more commands can be merged.
|
// Remove unused uniform variables so that more commands can be merged.
|
||||||
shader.ir.FilterUniformVariables(uniforms)
|
shader.ir.FilterUniformVariables(uniforms)
|
||||||
@ -133,7 +133,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
|
|||||||
// TODO: If dst is the screen, reorder the command to be the last.
|
// TODO: If dst is the screen, reorder the command to be the last.
|
||||||
if !split && 0 < len(q.commands) {
|
if !split && 0 < len(q.commands) {
|
||||||
if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok {
|
if last, ok := q.commands[len(q.commands)-1].(*drawTrianglesCommand); ok {
|
||||||
if last.CanMergeWithDrawTrianglesCommand(dst, srcs, vertices, blend, shader, uniforms, fillRule) {
|
if last.CanMergeWithDrawTrianglesCommand(dsts, srcs, vertices, blend, shader, uniforms, fillRule) {
|
||||||
last.setVertices(q.lastVertices(len(vertices) + last.numVertices()))
|
last.setVertices(q.lastVertices(len(vertices) + last.numVertices()))
|
||||||
if last.dstRegions[len(last.dstRegions)-1].Region == dstRegion {
|
if last.dstRegions[len(last.dstRegions)-1].Region == dstRegion {
|
||||||
last.dstRegions[len(last.dstRegions)-1].IndexCount += len(indices)
|
last.dstRegions[len(last.dstRegions)-1].IndexCount += len(indices)
|
||||||
@ -149,7 +149,7 @@ func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.Sh
|
|||||||
}
|
}
|
||||||
|
|
||||||
c := q.drawTrianglesCommandPool.get()
|
c := q.drawTrianglesCommandPool.get()
|
||||||
c.dst = dst
|
c.dsts = dsts
|
||||||
c.srcs = srcs
|
c.srcs = srcs
|
||||||
c.vertices = q.lastVertices(len(vertices))
|
c.vertices = q.lastVertices(len(vertices))
|
||||||
c.blend = blend
|
c.blend = blend
|
||||||
@ -324,18 +324,18 @@ func imageRectangleToRectangleF32(r image.Rectangle) rectangleF32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dst *Image, srcs [graphics.ShaderImageCount]*Image, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle) []uint32 {
|
func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shader, dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle) []uint32 {
|
||||||
origUniforms := uniforms
|
origUniforms := uniforms
|
||||||
uniforms = q.uint32sBuffer.alloc(len(origUniforms) + graphics.PreservedUniformUint32Count)
|
uniforms = q.uint32sBuffer.alloc(len(origUniforms) + graphics.PreservedUniformUint32Count)
|
||||||
copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms)
|
copy(uniforms[graphics.PreservedUniformUint32Count:], origUniforms)
|
||||||
|
|
||||||
// Set the destination texture size.
|
// Set the destination texture size.
|
||||||
dw, dh := dst.InternalSize()
|
dw, dh := dsts[0].InternalSize()
|
||||||
uniforms[0] = math.Float32bits(float32(dw))
|
uniforms[0] = math.Float32bits(float32(dw))
|
||||||
uniforms[1] = math.Float32bits(float32(dh))
|
uniforms[1] = math.Float32bits(float32(dh))
|
||||||
uniformIndex := 2
|
uniformIndex := 2
|
||||||
|
|
||||||
for i := 0; i < graphics.ShaderImageCount; i++ {
|
for i := 0; i < graphics.ShaderSrcImageCount; i++ {
|
||||||
var floatW, floatH uint32
|
var floatW, floatH uint32
|
||||||
if srcs[i] != nil {
|
if srcs[i] != nil {
|
||||||
w, h := srcs[i].InternalSize()
|
w, h := srcs[i].InternalSize()
|
||||||
@ -346,7 +346,7 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade
|
|||||||
uniforms[uniformIndex+i*2] = floatW
|
uniforms[uniformIndex+i*2] = floatW
|
||||||
uniforms[uniformIndex+1+i*2] = floatH
|
uniforms[uniformIndex+1+i*2] = floatH
|
||||||
}
|
}
|
||||||
uniformIndex += graphics.ShaderImageCount * 2
|
uniformIndex += graphics.ShaderSrcImageCount * 2
|
||||||
|
|
||||||
dr := imageRectangleToRectangleF32(dstRegion)
|
dr := imageRectangleToRectangleF32(dstRegion)
|
||||||
if shader.unit() == shaderir.Texels {
|
if shader.unit() == shaderir.Texels {
|
||||||
@ -366,7 +366,7 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade
|
|||||||
uniforms[uniformIndex+1] = math.Float32bits(dr.height)
|
uniforms[uniformIndex+1] = math.Float32bits(dr.height)
|
||||||
uniformIndex += 2
|
uniformIndex += 2
|
||||||
|
|
||||||
var srs [graphics.ShaderImageCount]rectangleF32
|
var srs [graphics.ShaderSrcImageCount]rectangleF32
|
||||||
for i, r := range srcRegions {
|
for i, r := range srcRegions {
|
||||||
srs[i] = imageRectangleToRectangleF32(r)
|
srs[i] = imageRectangleToRectangleF32(r)
|
||||||
}
|
}
|
||||||
@ -384,18 +384,18 @@ func (q *commandQueue) prependPreservedUniforms(uniforms []uint32, shader *Shade
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the source region origins.
|
// Set the source region origins.
|
||||||
for i := 0; i < graphics.ShaderImageCount; i++ {
|
for i := 0; i < graphics.ShaderSrcImageCount; i++ {
|
||||||
uniforms[uniformIndex+i*2] = math.Float32bits(srs[i].x)
|
uniforms[uniformIndex+i*2] = math.Float32bits(srs[i].x)
|
||||||
uniforms[uniformIndex+1+i*2] = math.Float32bits(srs[i].y)
|
uniforms[uniformIndex+1+i*2] = math.Float32bits(srs[i].y)
|
||||||
}
|
}
|
||||||
uniformIndex += graphics.ShaderImageCount * 2
|
uniformIndex += graphics.ShaderSrcImageCount * 2
|
||||||
|
|
||||||
// Set the source region sizes.
|
// Set the source region sizes.
|
||||||
for i := 0; i < graphics.ShaderImageCount; i++ {
|
for i := 0; i < graphics.ShaderSrcImageCount; i++ {
|
||||||
uniforms[uniformIndex+i*2] = math.Float32bits(srs[i].width)
|
uniforms[uniformIndex+i*2] = math.Float32bits(srs[i].width)
|
||||||
uniforms[uniformIndex+1+i*2] = math.Float32bits(srs[i].height)
|
uniforms[uniformIndex+1+i*2] = math.Float32bits(srs[i].height)
|
||||||
}
|
}
|
||||||
uniformIndex += graphics.ShaderImageCount * 2
|
uniformIndex += graphics.ShaderSrcImageCount * 2
|
||||||
|
|
||||||
// Set the projection matrix.
|
// Set the projection matrix.
|
||||||
uniforms[uniformIndex] = math.Float32bits(2 / float32(dw))
|
uniforms[uniformIndex] = math.Float32bits(2 / float32(dw))
|
||||||
@ -469,11 +469,11 @@ func (c *commandQueueManager) putCommandQueue(commandQueue *commandQueue) {
|
|||||||
c.pool.put(commandQueue)
|
c.pool.put(commandQueue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commandQueueManager) enqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
func (c *commandQueueManager) enqueueDrawTrianglesCommand(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
if c.current == nil {
|
if c.current == nil {
|
||||||
c.current, _ = c.pool.get()
|
c.current, _ = c.pool.get()
|
||||||
}
|
}
|
||||||
c.current.EnqueueDrawTrianglesCommand(dst, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
c.current.EnqueueDrawTrianglesCommand(dsts, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool) error {
|
func (c *commandQueueManager) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool) error {
|
||||||
|
@ -130,7 +130,7 @@ func (i *Image) InternalSize() (int, int) {
|
|||||||
//
|
//
|
||||||
// If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the
|
// If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the
|
||||||
// elements for the source image are not used.
|
// elements for the source image are not used.
|
||||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
for _, src := range srcs {
|
for _, src := range srcs {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
continue
|
continue
|
||||||
@ -142,7 +142,45 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
}
|
}
|
||||||
i.flushBufferedWritePixels()
|
i.flushBufferedWritePixels()
|
||||||
|
|
||||||
theCommandQueueManager.enqueueDrawTrianglesCommand(i, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
theCommandQueueManager.enqueueDrawTrianglesCommand([graphics.ShaderDstImageCount]*Image{i}, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrawTriangles draws triangles with the given image.
|
||||||
|
//
|
||||||
|
// The vertex floats are:
|
||||||
|
//
|
||||||
|
// 0: Destination X in pixels
|
||||||
|
// 1: Destination Y in pixels
|
||||||
|
// 2: Source X in texels
|
||||||
|
// 3: Source Y in texels
|
||||||
|
// 4: Color R [0.0-1.0]
|
||||||
|
// 5: Color G
|
||||||
|
// 6: Color B
|
||||||
|
// 7: Color Y
|
||||||
|
//
|
||||||
|
// src and shader are exclusive and only either is non-nil.
|
||||||
|
//
|
||||||
|
// The elements that index is in between 2 and 7 are used for the source images.
|
||||||
|
// The source image is 1) src argument if non-nil, or 2) an image value in the uniform variables if it exists.
|
||||||
|
// If there are multiple images in the uniform variables, the smallest ID's value is adopted.
|
||||||
|
//
|
||||||
|
// If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the
|
||||||
|
// elements for the source image are not used.
|
||||||
|
func DrawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule) {
|
||||||
|
for _, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if src.screen {
|
||||||
|
panic("graphicscommand: the screen image cannot be the rendering des")
|
||||||
|
}
|
||||||
|
src.flushBufferedWritePixels()
|
||||||
|
}
|
||||||
|
for _, dst := range dsts {
|
||||||
|
dst.flushBufferedWritePixels()
|
||||||
|
}
|
||||||
|
|
||||||
|
theCommandQueueManager.enqueueDrawTrianglesCommand(dsts, srcs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadPixels reads the image's pixels.
|
// ReadPixels reads the image's pixels.
|
||||||
|
@ -59,7 +59,7 @@ func TestClear(t *testing.T) {
|
|||||||
vs := quadVertices(w/2, h/2)
|
vs := quadVertices(w/2, h/2)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
pix := make([]byte, 4*w*h)
|
pix := make([]byte, 4*w*h)
|
||||||
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{
|
if err := dst.ReadPixels(ui.Get().GraphicsDriverForTesting(), []graphicsdriver.PixelsArgs{
|
||||||
@ -90,8 +90,8 @@ func TestWritePixelsPartAfterDrawTriangles(t *testing.T) {
|
|||||||
vs := quadVertices(w/2, h/2)
|
vs := quadVertices(w/2, h/2)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{src}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
bs := graphics.NewManagedBytes(4, func(bs []byte) {
|
bs := graphics.NewManagedBytes(4, func(bs []byte) {
|
||||||
for i := range bs {
|
for i := range bs {
|
||||||
bs[i] = 0
|
bs[i] = 0
|
||||||
@ -109,11 +109,11 @@ func TestShader(t *testing.T) {
|
|||||||
vs := quadVertices(w, h)
|
vs := quadVertices(w, h)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dr := image.Rect(0, 0, w, h)
|
dr := image.Rect(0, 0, w, h)
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{clr}, vs, is, graphicsdriver.BlendClear, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, nearestFilterShader, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
g := ui.Get().GraphicsDriverForTesting()
|
g := ui.Get().GraphicsDriverForTesting()
|
||||||
s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
|
s := graphicscommand.NewShader(etesting.ShaderProgramFill(0xff, 0, 0, 0xff))
|
||||||
dst.DrawTriangles([graphics.ShaderImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
|
dst.DrawTriangles([graphics.ShaderSrcImageCount]*graphicscommand.Image{}, vs, is, graphicsdriver.BlendSourceOver, dr, [graphics.ShaderSrcImageCount]image.Rectangle{}, s, nil, graphicsdriver.FillAll)
|
||||||
|
|
||||||
pix := make([]byte, 4*w*h)
|
pix := make([]byte, 4*w*h)
|
||||||
if err := dst.ReadPixels(g, []graphicsdriver.PixelsArgs{
|
if err := dst.ReadPixels(g, []graphicsdriver.PixelsArgs{
|
||||||
|
@ -515,14 +515,22 @@ func (g *graphics11) removeShader(s *shader11) {
|
|||||||
delete(g.shaders, s.id)
|
delete(g.shaders, s.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
func (g *graphics11) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||||
// Remove bound textures first. This is needed to avoid warnings on the debugger.
|
// Remove bound textures first. This is needed to avoid warnings on the debugger.
|
||||||
g.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{nil}, nil)
|
g.deviceContext.OMSetRenderTargets([]*_ID3D11RenderTargetView{nil}, nil)
|
||||||
srvs := [graphics.ShaderImageCount]*_ID3D11ShaderResourceView{}
|
srvs := [graphics.ShaderSrcImageCount]*_ID3D11ShaderResourceView{}
|
||||||
g.deviceContext.PSSetShaderResources(0, srvs[:])
|
g.deviceContext.PSSetShaderResources(0, srvs[:])
|
||||||
|
|
||||||
dst := g.images[dstID]
|
var dsts []*image11
|
||||||
var srcs [graphics.ShaderImageCount]*image11
|
for _, id := range dstIDs {
|
||||||
|
img := g.images[id]
|
||||||
|
if img == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dsts = append(dsts, img)
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcs [graphics.ShaderSrcImageCount]*image11
|
||||||
for i, id := range srcIDs {
|
for i, id := range srcIDs {
|
||||||
img := g.images[id]
|
img := g.images[id]
|
||||||
if img == nil {
|
if img == nil {
|
||||||
@ -531,7 +539,7 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
|||||||
srcs[i] = img
|
srcs[i] = img
|
||||||
}
|
}
|
||||||
|
|
||||||
w, h := dst.internalSize()
|
w, h := dsts[0].internalSize()
|
||||||
g.deviceContext.RSSetViewports([]_D3D11_VIEWPORT{
|
g.deviceContext.RSSetViewports([]_D3D11_VIEWPORT{
|
||||||
{
|
{
|
||||||
TopLeftX: 0,
|
TopLeftX: 0,
|
||||||
@ -543,7 +551,7 @@ func (g *graphics11) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphic
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := dst.setAsRenderTarget(fillRule != graphicsdriver.FillAll); err != nil {
|
if err := setAsRenderTargets(dsts, fillRule != graphicsdriver.FillAll); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,7 +1082,7 @@ func (g *graphics12) NewShader(program *shaderir.Program) (graphicsdriver.Shader
|
|||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
func (g *graphics12) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||||
if shaderID == graphicsdriver.InvalidShaderID {
|
if shaderID == graphicsdriver.InvalidShaderID {
|
||||||
return fmt.Errorf("directx: shader ID is invalid")
|
return fmt.Errorf("directx: shader ID is invalid")
|
||||||
}
|
}
|
||||||
@ -1103,13 +1103,13 @@ func (g *graphics12) DrawTriangles(dstID graphicsdriver.ImageID, srcs [graphics.
|
|||||||
g.pipelineStates.releaseConstantBuffers(g.frameIndex)
|
g.pipelineStates.releaseConstantBuffers(g.frameIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := g.images[dstID]
|
dst := g.images[dstIDs[0]] // TODO: handle array
|
||||||
var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition
|
var resourceBarriers []_D3D12_RESOURCE_BARRIER_Transition
|
||||||
if rb, ok := dst.transiteState(_D3D12_RESOURCE_STATE_RENDER_TARGET); ok {
|
if rb, ok := dst.transiteState(_D3D12_RESOURCE_STATE_RENDER_TARGET); ok {
|
||||||
resourceBarriers = append(resourceBarriers, rb)
|
resourceBarriers = append(resourceBarriers, rb)
|
||||||
}
|
}
|
||||||
|
|
||||||
var srcImages [graphics.ShaderImageCount]*image12
|
var srcImages [graphics.ShaderSrcImageCount]*image12
|
||||||
for i, srcID := range srcs {
|
for i, srcID := range srcs {
|
||||||
src := g.images[srcID]
|
src := g.images[srcID]
|
||||||
if src == nil {
|
if src == nil {
|
||||||
|
@ -204,6 +204,69 @@ func (i *image11) setAsRenderTarget(useStencil bool) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setAsRenderTargets(dsts []*image11, useStencil bool) error {
|
||||||
|
for _, i := range dsts {
|
||||||
|
if i.renderTargetView == nil {
|
||||||
|
rtv, err := i.graphics.device.CreateRenderTargetView(unsafe.Pointer(i.texture), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.renderTargetView = rtv
|
||||||
|
}
|
||||||
|
|
||||||
|
if !useStencil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.screen {
|
||||||
|
return fmt.Errorf("directx: a stencil buffer is not available for a screen image")
|
||||||
|
}
|
||||||
|
if i.stencilView == nil {
|
||||||
|
sv, err := i.graphics.device.CreateDepthStencilView(unsafe.Pointer(i.stencil), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.stencilView = sv
|
||||||
|
}
|
||||||
|
if i.stencil == nil {
|
||||||
|
w, h := i.internalSize()
|
||||||
|
s, err := i.graphics.device.CreateTexture2D(&_D3D11_TEXTURE2D_DESC{
|
||||||
|
Width: uint32(w),
|
||||||
|
Height: uint32(h),
|
||||||
|
MipLevels: 0,
|
||||||
|
ArraySize: 1,
|
||||||
|
Format: _DXGI_FORMAT_D24_UNORM_S8_UINT,
|
||||||
|
SampleDesc: _DXGI_SAMPLE_DESC{
|
||||||
|
Count: 1,
|
||||||
|
Quality: 0,
|
||||||
|
},
|
||||||
|
Usage: _D3D11_USAGE_DEFAULT,
|
||||||
|
BindFlags: uint32(_D3D11_BIND_DEPTH_STENCIL),
|
||||||
|
CPUAccessFlags: 0,
|
||||||
|
MiscFlags: 0,
|
||||||
|
}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i.stencil = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rtvs []*_ID3D11RenderTargetView
|
||||||
|
var dsvs []*_ID3D11DepthStencilView
|
||||||
|
for _, i := range dsts {
|
||||||
|
rtvs = append(rtvs, i.renderTargetView)
|
||||||
|
dsvs = append(dsvs, i.stencilView)
|
||||||
|
}
|
||||||
|
|
||||||
|
dsts[0].graphics.deviceContext.OMSetRenderTargets(rtvs, dsts[0].stencilView)
|
||||||
|
if useStencil {
|
||||||
|
dsts[0].graphics.deviceContext.ClearDepthStencilView(dsts[0].stencilView, uint8(_D3D11_CLEAR_STENCIL), 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (i *image11) getShaderResourceView() (*_ID3D11ShaderResourceView, error) {
|
func (i *image11) getShaderResourceView() (*_ID3D11ShaderResourceView, error) {
|
||||||
if i.shaderResourceView == nil {
|
if i.shaderResourceView == nil {
|
||||||
srv, err := i.graphics.device.CreateShaderResourceView(unsafe.Pointer(i.texture), nil)
|
srv, err := i.graphics.device.CreateShaderResourceView(unsafe.Pointer(i.texture), nil)
|
||||||
|
@ -128,7 +128,7 @@ type pipelineStates struct {
|
|||||||
constantBufferMaps [frameCount][]uintptr
|
constantBufferMaps [frameCount][]uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
const numConstantBufferAndSourceTextures = 1 + graphics.ShaderImageCount
|
const numConstantBufferAndSourceTextures = 1 + graphics.ShaderSrcImageCount
|
||||||
|
|
||||||
func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
||||||
// Create a CBV/SRV/UAV descriptor heap.
|
// Create a CBV/SRV/UAV descriptor heap.
|
||||||
@ -180,7 +180,7 @@ func (p *pipelineStates) initialize(device *_ID3D12Device) (ferr error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderImageCount]*image12, shader *shader12, dstRegions []graphicsdriver.DstRegion, uniforms []uint32, blend graphicsdriver.Blend, indexOffset int, fillRule graphicsdriver.FillRule) error {
|
func (p *pipelineStates) drawTriangles(device *_ID3D12Device, commandList *_ID3D12GraphicsCommandList, frameIndex int, screen bool, srcs [graphics.ShaderSrcImageCount]*image12, shader *shader12, dstRegions []graphicsdriver.DstRegion, uniforms []uint32, blend graphicsdriver.Blend, indexOffset int, fillRule graphicsdriver.FillRule) error {
|
||||||
idx := len(p.constantBuffers[frameIndex])
|
idx := len(p.constantBuffers[frameIndex])
|
||||||
if idx >= numDescriptorsPerFrame {
|
if idx >= numDescriptorsPerFrame {
|
||||||
return fmt.Errorf("directx: too many constant buffers")
|
return fmt.Errorf("directx: too many constant buffers")
|
||||||
@ -354,7 +354,7 @@ func (p *pipelineStates) ensureRootSignature(device *_ID3D12Device) (rootSignatu
|
|||||||
}
|
}
|
||||||
srv := _D3D12_DESCRIPTOR_RANGE{
|
srv := _D3D12_DESCRIPTOR_RANGE{
|
||||||
RangeType: _D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // t0
|
RangeType: _D3D12_DESCRIPTOR_RANGE_TYPE_SRV, // t0
|
||||||
NumDescriptors: graphics.ShaderImageCount,
|
NumDescriptors: graphics.ShaderSrcImageCount,
|
||||||
BaseShaderRegister: 0,
|
BaseShaderRegister: 0,
|
||||||
RegisterSpace: 0,
|
RegisterSpace: 0,
|
||||||
OffsetInDescriptorsFromTableStart: 1,
|
OffsetInDescriptorsFromTableStart: 1,
|
||||||
|
@ -78,7 +78,7 @@ func (s *shader11) disposeImpl() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderImageCount]*image11) error {
|
func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderSrcImageCount]*image11) error {
|
||||||
vs, err := s.ensureVertexShader()
|
vs, err := s.ensureVertexShader()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -114,7 +114,7 @@ func (s *shader11) use(uniforms []uint32, srcs [graphics.ShaderImageCount]*image
|
|||||||
s.graphics.deviceContext.Unmap(unsafe.Pointer(cb), 0)
|
s.graphics.deviceContext.Unmap(unsafe.Pointer(cb), 0)
|
||||||
|
|
||||||
// Set the render sources.
|
// Set the render sources.
|
||||||
var srvs [graphics.ShaderImageCount]*_ID3D11ShaderResourceView
|
var srvs [graphics.ShaderSrcImageCount]*_ID3D11ShaderResourceView
|
||||||
for i, src := range srcs {
|
for i, src := range srcs {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
continue
|
continue
|
||||||
|
@ -68,7 +68,7 @@ type Graphics interface {
|
|||||||
NewShader(program *shaderir.Program) (Shader, error)
|
NewShader(program *shaderir.Program) (Shader, error)
|
||||||
|
|
||||||
// DrawTriangles draws an image onto another image with the given parameters.
|
// DrawTriangles draws an image onto another image with the given parameters.
|
||||||
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error
|
DrawTriangles(dsts [graphics.ShaderDstImageCount]ImageID, srcs [graphics.ShaderSrcImageCount]ImageID, shader ShaderID, dstRegions []DstRegion, indexOffset int, blend Blend, uniforms []uint32, fillRule FillRule) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Resetter interface {
|
type Resetter interface {
|
||||||
|
@ -293,6 +293,14 @@ func (d *DebugContext) DisableVertexAttribArray(arg0 uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DebugContext) DrawBuffers(arg0 []uint32) {
|
||||||
|
d.Context.DrawBuffers(arg0)
|
||||||
|
fmt.Fprintln(os.Stderr, "DrawBuffers")
|
||||||
|
if e := d.Context.GetError(); e != NO_ERROR {
|
||||||
|
panic(fmt.Sprintf("gl: GetError() returned %d at DrawBuffers", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DebugContext) DrawElements(arg0 uint32, arg1 int32, arg2 uint32, arg3 int) {
|
func (d *DebugContext) DrawElements(arg0 uint32, arg1 int32, arg2 uint32, arg3 int) {
|
||||||
d.Context.DrawElements(arg0, arg1, arg2, arg3)
|
d.Context.DrawElements(arg0, arg1, arg2, arg3)
|
||||||
fmt.Fprintln(os.Stderr, "DrawElements")
|
fmt.Fprintln(os.Stderr, "DrawElements")
|
||||||
|
@ -51,6 +51,7 @@ type defaultContext struct {
|
|||||||
gpDeleteVertexArrays uintptr
|
gpDeleteVertexArrays uintptr
|
||||||
gpDisable uintptr
|
gpDisable uintptr
|
||||||
gpDisableVertexAttribArray uintptr
|
gpDisableVertexAttribArray uintptr
|
||||||
|
gpDrawBuffers uintptr
|
||||||
gpDrawElements uintptr
|
gpDrawElements uintptr
|
||||||
gpEnable uintptr
|
gpEnable uintptr
|
||||||
gpEnableVertexAttribArray uintptr
|
gpEnableVertexAttribArray uintptr
|
||||||
@ -269,6 +270,10 @@ func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, of
|
|||||||
purego.SyscallN(c.gpDrawElements, uintptr(mode), uintptr(count), uintptr(xtype), uintptr(offset))
|
purego.SyscallN(c.gpDrawElements, uintptr(mode), uintptr(count), uintptr(xtype), uintptr(offset))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *defaultContext) DrawBuffers(buffers []uint32) {
|
||||||
|
purego.SyscallN(c.gpDrawBuffers, uintptr(len(buffers)), uintptr(unsafe.Pointer(&buffers[0])))
|
||||||
|
}
|
||||||
|
|
||||||
func (c *defaultContext) Enable(cap uint32) {
|
func (c *defaultContext) Enable(cap uint32) {
|
||||||
purego.SyscallN(c.gpEnable, uintptr(cap))
|
purego.SyscallN(c.gpEnable, uintptr(cap))
|
||||||
}
|
}
|
||||||
@ -501,6 +506,7 @@ func (c *defaultContext) LoadFunctions() error {
|
|||||||
c.gpDeleteVertexArrays = g.get("glDeleteVertexArrays")
|
c.gpDeleteVertexArrays = g.get("glDeleteVertexArrays")
|
||||||
c.gpDisable = g.get("glDisable")
|
c.gpDisable = g.get("glDisable")
|
||||||
c.gpDisableVertexAttribArray = g.get("glDisableVertexAttribArray")
|
c.gpDisableVertexAttribArray = g.get("glDisableVertexAttribArray")
|
||||||
|
c.gpDrawBuffers = g.get("glDrawBuffers")
|
||||||
c.gpDrawElements = g.get("glDrawElements")
|
c.gpDrawElements = g.get("glDrawElements")
|
||||||
c.gpEnable = g.get("glEnable")
|
c.gpEnable = g.get("glEnable")
|
||||||
c.gpEnableVertexAttribArray = g.get("glEnableVertexAttribArray")
|
c.gpEnableVertexAttribArray = g.get("glEnableVertexAttribArray")
|
||||||
|
@ -60,6 +60,7 @@ type Context interface {
|
|||||||
Disable(cap uint32)
|
Disable(cap uint32)
|
||||||
DisableVertexAttribArray(index uint32)
|
DisableVertexAttribArray(index uint32)
|
||||||
DrawElements(mode uint32, count int32, xtype uint32, offset int)
|
DrawElements(mode uint32, count int32, xtype uint32, offset int)
|
||||||
|
DrawBuffers(buffers []uint32)
|
||||||
Enable(cap uint32)
|
Enable(cap uint32)
|
||||||
EnableVertexAttribArray(index uint32)
|
EnableVertexAttribArray(index uint32)
|
||||||
Flush()
|
Flush()
|
||||||
|
@ -47,6 +47,7 @@ type Graphics struct {
|
|||||||
|
|
||||||
uniformVariableNameCache map[int]string
|
uniformVariableNameCache map[int]string
|
||||||
textureVariableNameCache map[int]string
|
textureVariableNameCache map[int]string
|
||||||
|
colorBufferVariableNameCache map[int]string
|
||||||
|
|
||||||
uniformVars []uniformVariable
|
uniformVars []uniformVariable
|
||||||
|
|
||||||
@ -198,18 +199,45 @@ func (g *Graphics) uniformVariableName(idx int) string {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.ShaderImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
func (g *Graphics) DrawTriangles(dstIDs [graphics.ShaderDstImageCount]graphicsdriver.ImageID, srcIDs [graphics.ShaderSrcImageCount]graphicsdriver.ImageID, shaderID graphicsdriver.ShaderID, dstRegions []graphicsdriver.DstRegion, indexOffset int, blend graphicsdriver.Blend, uniforms []uint32, fillRule graphicsdriver.FillRule) error {
|
||||||
if shaderID == graphicsdriver.InvalidShaderID {
|
if shaderID == graphicsdriver.InvalidShaderID {
|
||||||
return fmt.Errorf("opengl: shader ID is invalid")
|
return fmt.Errorf("opengl: shader ID is invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
destination := g.images[dstID]
|
|
||||||
|
|
||||||
g.drawCalled = true
|
g.drawCalled = true
|
||||||
|
|
||||||
if err := destination.setViewport(); err != nil {
|
dstCount := 0
|
||||||
|
var destinations [graphics.ShaderDstImageCount]*Image
|
||||||
|
for i, dstID := range dstIDs {
|
||||||
|
if dstID == graphicsdriver.InvalidImageID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dst := g.images[dstIDs[i]]
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
destinations[i] = dst
|
||||||
|
dstCount++
|
||||||
|
}
|
||||||
|
if dstCount == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Only necessary for the same shared framebuffer
|
||||||
|
if err := destinations[0].setViewport(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Color attachments
|
||||||
|
var attached []uint32
|
||||||
|
for i, dst := range destinations {
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
attached = append(attached, uint32(gl.COLOR_ATTACHMENT0+i))
|
||||||
|
g.context.ctx.FramebufferTexture2D(gl.FRAMEBUFFER, uint32(gl.COLOR_ATTACHMENT0+i), gl.TEXTURE_2D, uint32(dst.texture), 0)
|
||||||
|
}
|
||||||
|
g.context.ctx.DrawBuffers(attached)
|
||||||
|
|
||||||
g.context.blend(blend)
|
g.context.blend(blend)
|
||||||
|
|
||||||
shader := g.shaders[shaderID]
|
shader := g.shaders[shaderID]
|
||||||
@ -232,7 +260,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// In OpenGL, the NDC's Y direction is upward, so flip the Y direction for the final framebuffer.
|
// In OpenGL, the NDC's Y direction is upward, so flip the Y direction for the final framebuffer.
|
||||||
if destination.screen {
|
if dstCount == 1 && destinations[0] != nil && destinations[0].screen {
|
||||||
const idx = graphics.ProjectionMatrixUniformVariableIndex
|
const idx = graphics.ProjectionMatrixUniformVariableIndex
|
||||||
// Invert the sign bits as float32 values.
|
// Invert the sign bits as float32 values.
|
||||||
g.uniformVars[idx].value[1] ^= 1 << 31
|
g.uniformVars[idx].value[1] ^= 1 << 31
|
||||||
@ -241,7 +269,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
g.uniformVars[idx].value[13] ^= 1 << 31
|
g.uniformVars[idx].value[13] ^= 1 << 31
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]textureVariable
|
var imgs [graphics.ShaderSrcImageCount]textureVariable
|
||||||
for i, srcID := range srcIDs {
|
for i, srcID := range srcIDs {
|
||||||
if srcID == graphicsdriver.InvalidImageID {
|
if srcID == graphicsdriver.InvalidImageID {
|
||||||
continue
|
continue
|
||||||
@ -260,9 +288,14 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
g.uniformVars = g.uniformVars[:0]
|
g.uniformVars = g.uniformVars[:0]
|
||||||
|
|
||||||
if fillRule != graphicsdriver.FillAll {
|
if fillRule != graphicsdriver.FillAll {
|
||||||
if err := destination.ensureStencilBuffer(); err != nil {
|
for _, dst := range destinations {
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := dst.ensureStencilBuffer(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
g.context.ctx.Enable(gl.STENCIL_TEST)
|
g.context.ctx.Enable(gl.STENCIL_TEST)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,6 +306,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
int32(dstRegion.Region.Dx()),
|
int32(dstRegion.Region.Dx()),
|
||||||
int32(dstRegion.Region.Dy()),
|
int32(dstRegion.Region.Dy()),
|
||||||
)
|
)
|
||||||
|
|
||||||
switch fillRule {
|
switch fillRule {
|
||||||
case graphicsdriver.NonZero:
|
case graphicsdriver.NonZero:
|
||||||
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||||
@ -280,6 +314,7 @@ func (g *Graphics) DrawTriangles(dstID graphicsdriver.ImageID, srcIDs [graphics.
|
|||||||
g.context.ctx.StencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP)
|
g.context.ctx.StencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP)
|
||||||
g.context.ctx.StencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP)
|
g.context.ctx.StencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP)
|
||||||
g.context.ctx.ColorMask(false, false, false, false)
|
g.context.ctx.ColorMask(false, false, false, false)
|
||||||
|
|
||||||
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
g.context.ctx.DrawElements(gl.TRIANGLES, int32(dstRegion.IndexCount), gl.UNSIGNED_INT, indexOffset*int(unsafe.Sizeof(uint32(0))))
|
||||||
case graphicsdriver.EvenOdd:
|
case graphicsdriver.EvenOdd:
|
||||||
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
g.context.ctx.Clear(gl.STENCIL_BUFFER_BIT)
|
||||||
|
@ -258,8 +258,20 @@ func (g *Graphics) textureVariableName(idx int) string {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *Graphics) colorBufferVariableName(idx int) string {
|
||||||
|
if v, ok := g.colorBufferVariableNameCache[idx]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if g.colorBufferVariableNameCache == nil {
|
||||||
|
g.colorBufferVariableNameCache = map[int]string{}
|
||||||
|
}
|
||||||
|
name := fmt.Sprintf("gl_FragData[%d]", idx)
|
||||||
|
g.colorBufferVariableNameCache[idx] = name
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
// useProgram uses the program (programTexture).
|
// useProgram uses the program (programTexture).
|
||||||
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderImageCount]textureVariable) error {
|
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderSrcImageCount]textureVariable) error {
|
||||||
if g.state.lastProgram != program {
|
if g.state.lastProgram != program {
|
||||||
g.context.ctx.UseProgram(uint32(program))
|
g.context.ctx.UseProgram(uint32(program))
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ func (m *Mipmap) ReadPixels(graphicsDriver graphicsdriver.Graphics, pixels []byt
|
|||||||
return m.orig.ReadPixels(graphicsDriver, pixels, region)
|
return m.orig.ReadPixels(graphicsDriver, pixels, region)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool) {
|
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool) {
|
||||||
if len(indices) == 0 {
|
if len(indices) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgs [graphics.ShaderImageCount]*buffered.Image
|
var imgs [graphics.ShaderSrcImageCount]*buffered.Image
|
||||||
for i, src := range srcs {
|
for i, src := range srcs {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
continue
|
continue
|
||||||
@ -127,6 +127,78 @@ func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageCount]*Mipmap, vertices
|
|||||||
m.deallocateMipmaps()
|
m.deallocateMipmaps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DrawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Mipmap, srcs [graphics.ShaderSrcImageCount]*Mipmap, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *atlas.Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool) {
|
||||||
|
if len(indices) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
level := 0
|
||||||
|
// TODO: Do we need to check all the sources' states of being volatile?
|
||||||
|
if !canSkipMipmap && srcs[0] != nil && canUseMipmap(srcs[0].imageType) {
|
||||||
|
level = math.MaxInt32
|
||||||
|
for i := 0; i < len(indices)/3; i++ {
|
||||||
|
const n = graphics.VertexFloatCount
|
||||||
|
dx0 := vertices[n*indices[3*i]+0]
|
||||||
|
dy0 := vertices[n*indices[3*i]+1]
|
||||||
|
sx0 := vertices[n*indices[3*i]+2]
|
||||||
|
sy0 := vertices[n*indices[3*i]+3]
|
||||||
|
dx1 := vertices[n*indices[3*i+1]+0]
|
||||||
|
dy1 := vertices[n*indices[3*i+1]+1]
|
||||||
|
sx1 := vertices[n*indices[3*i+1]+2]
|
||||||
|
sy1 := vertices[n*indices[3*i+1]+3]
|
||||||
|
dx2 := vertices[n*indices[3*i+2]+0]
|
||||||
|
dy2 := vertices[n*indices[3*i+2]+1]
|
||||||
|
sx2 := vertices[n*indices[3*i+2]+2]
|
||||||
|
sy2 := vertices[n*indices[3*i+2]+3]
|
||||||
|
if l := mipmapLevelFromDistance(dx0, dy0, dx1, dy1, sx0, sy0, sx1, sy1); level > l {
|
||||||
|
level = l
|
||||||
|
}
|
||||||
|
if l := mipmapLevelFromDistance(dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2); level > l {
|
||||||
|
level = l
|
||||||
|
}
|
||||||
|
if l := mipmapLevelFromDistance(dx2, dy2, dx0, dy0, sx2, sy2, sx0, sy0); level > l {
|
||||||
|
level = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if level == math.MaxInt32 {
|
||||||
|
panic("mipmap: level must be calculated at least once but not")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dstImgs [graphics.ShaderDstImageCount]*buffered.Image
|
||||||
|
for i, dst := range dsts {
|
||||||
|
if dst == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dstImgs[i] = dst.orig
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcImgs [graphics.ShaderSrcImageCount]*buffered.Image
|
||||||
|
for i, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if level != 0 {
|
||||||
|
if img := src.level(level); img != nil {
|
||||||
|
const n = graphics.VertexFloatCount
|
||||||
|
s := float32(pow2(level))
|
||||||
|
for i := 0; i < len(vertices)/n; i++ {
|
||||||
|
vertices[i*n+2] /= s
|
||||||
|
vertices[i*n+3] /= s
|
||||||
|
}
|
||||||
|
srcImgs[i] = img
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
srcImgs[i] = src.orig
|
||||||
|
}
|
||||||
|
|
||||||
|
buffered.DrawTrianglesMRT(dstImgs, srcImgs, vertices, indices, blend, dstRegion, srcRegions, shader, uniforms, fillRule)
|
||||||
|
for _, dst := range dsts {
|
||||||
|
dst.deallocateMipmaps()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Mipmap) setImg(level int, img *buffered.Image) {
|
func (m *Mipmap) setImg(level int, img *buffered.Image) {
|
||||||
if m.imgs == nil {
|
if m.imgs == nil {
|
||||||
m.imgs = map[int]*buffered.Image{}
|
m.imgs = map[int]*buffered.Image{}
|
||||||
@ -187,7 +259,7 @@ func (m *Mipmap) level(level int) *buffered.Image {
|
|||||||
s := buffered.NewImage(w2, h2, m.imageType)
|
s := buffered.NewImage(w2, h2, m.imageType)
|
||||||
|
|
||||||
dstRegion := image.Rect(0, 0, w2, h2)
|
dstRegion := image.Rect(0, 0, w2, h2)
|
||||||
s.DrawTriangles([graphics.ShaderImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, shader, nil, graphicsdriver.FillAll)
|
s.DrawTriangles([graphics.ShaderSrcImageCount]*buffered.Image{src}, vs, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, shader, nil, graphicsdriver.FillAll)
|
||||||
m.setImg(level, s)
|
m.setImg(level, s)
|
||||||
|
|
||||||
return m.imgs[level]
|
return m.imgs[level]
|
||||||
|
@ -215,6 +215,7 @@ func Compile(src []byte, vertexEntry, fragmentEntry string, textureCount int) (*
|
|||||||
// TODO: Make a call graph and reorder the elements.
|
// TODO: Make a call graph and reorder the elements.
|
||||||
|
|
||||||
s.ir.TextureCount = textureCount
|
s.ir.TextureCount = textureCount
|
||||||
|
|
||||||
return &s.ir, nil
|
return &s.ir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -741,8 +742,9 @@ func (cs *compileState) parseFuncParams(block *block, fname string, d *ast.FuncD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If there is only one returning value, it is treated as a returning value.
|
// If there is only one returning value, it is treated as a returning value.
|
||||||
|
// Only if not the fragment entrypoint.
|
||||||
// An array cannot be a returning value, especially for HLSL (#2923).
|
// An array cannot be a returning value, especially for HLSL (#2923).
|
||||||
if len(out) == 1 && out[0].name == "" && out[0].typ.Main != shaderir.Array {
|
if fname != cs.fragmentEntry && len(out) == 1 && out[0].name == "" && out[0].typ.Main != shaderir.Array {
|
||||||
ret = out[0].typ
|
ret = out[0].typ
|
||||||
out = nil
|
out = nil
|
||||||
}
|
}
|
||||||
@ -820,10 +822,13 @@ func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) (function, bool
|
|||||||
return function{}, false
|
return function{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(outParams) != 0 || returnType.Main != shaderir.Vec4 {
|
// The first out-param is treated as gl_FragColor in GLSL.
|
||||||
cs.addError(d.Pos(), "fragment entry point must have one returning vec4 value for a color")
|
if outParams[0].typ.Main != shaderir.Vec4 {
|
||||||
|
cs.addError(d.Pos(), "fragment entry point must have at least one returning vec4 value for a color")
|
||||||
return function{}, false
|
return function{}, false
|
||||||
}
|
}
|
||||||
|
// Adjust the number of textures to write to
|
||||||
|
cs.ir.ColorsOutCount = len(outParams)
|
||||||
|
|
||||||
if cs.varyingParsed {
|
if cs.varyingParsed {
|
||||||
checkVaryings(inParams[1:])
|
checkVaryings(inParams[1:])
|
||||||
|
@ -87,8 +87,7 @@ precision highp int;
|
|||||||
#define mediump
|
#define mediump
|
||||||
#define highp
|
#define highp
|
||||||
#endif
|
#endif
|
||||||
|
`
|
||||||
out vec4 fragColor;`
|
|
||||||
if version == GLSLVersionDefault {
|
if version == GLSLVersionDefault {
|
||||||
prelude += "\n\n" + utilFunctions
|
prelude += "\n\n" + utilFunctions
|
||||||
}
|
}
|
||||||
@ -420,7 +419,7 @@ func (c *compileContext) localVariableName(p *shaderir.Program, topBlock *shader
|
|||||||
case idx < nv+1:
|
case idx < nv+1:
|
||||||
return fmt.Sprintf("V%d", idx-1)
|
return fmt.Sprintf("V%d", idx-1)
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("l%d", idx-(nv+1))
|
return fmt.Sprintf("gl_FragData[%d]", idx-(nv+1))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("l%d", idx)
|
return fmt.Sprintf("l%d", idx)
|
||||||
@ -595,7 +594,7 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
|||||||
case shaderir.Return:
|
case shaderir.Return:
|
||||||
switch {
|
switch {
|
||||||
case topBlock == p.FragmentFunc.Block:
|
case topBlock == p.FragmentFunc.Block:
|
||||||
lines = append(lines, fmt.Sprintf("%sfragColor = %s;", idt, expr(&s.Exprs[0])))
|
lines = append(lines, fmt.Sprintf("%s%s;", idt, expr(&s.Exprs[0])))
|
||||||
// The 'return' statement is not required so far, as the fragment entrypoint has only one sentence so far. See adjustProgram implementation.
|
// The 'return' statement is not required so far, as the fragment entrypoint has only one sentence so far. See adjustProgram implementation.
|
||||||
case len(s.Exprs) == 0:
|
case len(s.Exprs) == 0:
|
||||||
lines = append(lines, idt+"return;")
|
lines = append(lines, idt+"return;")
|
||||||
@ -645,14 +644,19 @@ func adjustProgram(p *shaderir.Program) *shaderir.Program {
|
|||||||
Main: shaderir.Vec4, // gl_FragCoord
|
Main: shaderir.Vec4, // gl_FragCoord
|
||||||
}
|
}
|
||||||
copy(inParams[1:], newP.Varyings)
|
copy(inParams[1:], newP.Varyings)
|
||||||
|
// Out parameters of a fragment func are colors
|
||||||
|
outParams := make([]shaderir.Type, p.ColorsOutCount)
|
||||||
|
for i := range outParams {
|
||||||
|
outParams[i] = shaderir.Type{
|
||||||
|
Main: shaderir.Vec4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newP.FragmentFunc.Block.LocalVarIndexOffset += (p.ColorsOutCount-1)
|
||||||
|
|
||||||
newP.Funcs = append(newP.Funcs, shaderir.Func{
|
newP.Funcs = append(newP.Funcs, shaderir.Func{
|
||||||
Index: funcIdx,
|
Index: funcIdx,
|
||||||
InParams: inParams,
|
InParams: inParams,
|
||||||
OutParams: nil,
|
OutParams: outParams,
|
||||||
Return: shaderir.Type{
|
|
||||||
Main: shaderir.Vec4,
|
|
||||||
},
|
|
||||||
Block: newP.FragmentFunc.Block,
|
Block: newP.FragmentFunc.Block,
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -663,7 +667,7 @@ func adjustProgram(p *shaderir.Program) *shaderir.Program {
|
|||||||
Index: funcIdx,
|
Index: funcIdx,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i := 0; i < 1+len(newP.Varyings); i++ {
|
for i := 0; i < 1+len(newP.Varyings)+p.ColorsOutCount; i++ {
|
||||||
call = append(call, shaderir.Expr{
|
call = append(call, shaderir.Expr{
|
||||||
Type: shaderir.LocalVariable,
|
Type: shaderir.LocalVariable,
|
||||||
Index: i,
|
Index: i,
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
|
||||||
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -190,7 +191,15 @@ func Compile(p *shaderir.Program) (vertexShader, pixelShader string, offsets []i
|
|||||||
}
|
}
|
||||||
if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 {
|
if p.FragmentFunc.Block != nil && len(p.FragmentFunc.Block.Stmts) > 0 {
|
||||||
pslines = append(pslines, "")
|
pslines = append(pslines, "")
|
||||||
pslines = append(pslines, fmt.Sprintf("float4 PSMain(Varyings %s) : SV_TARGET {", vsOut))
|
pslines = append(pslines, "struct PS_OUTPUT")
|
||||||
|
pslines = append(pslines, "{")
|
||||||
|
for i := 0; i < graphics.ShaderDstImageCount; i++ {
|
||||||
|
pslines = append(pslines, fmt.Sprintf("\tfloat4 Color%d: SV_Target%d;", i, i))
|
||||||
|
}
|
||||||
|
pslines = append(pslines, "};")
|
||||||
|
pslines = append(pslines, "")
|
||||||
|
pslines = append(pslines, fmt.Sprintf("PS_OUTPUT PSMain(Varyings %s) {", vsOut))
|
||||||
|
pslines = append(pslines, "\tPS_OUTPUT output;")
|
||||||
pslines = append(pslines, c.block(p, p.FragmentFunc.Block, p.FragmentFunc.Block, 0)...)
|
pslines = append(pslines, c.block(p, p.FragmentFunc.Block, p.FragmentFunc.Block, 0)...)
|
||||||
pslines = append(pslines, "}")
|
pslines = append(pslines, "}")
|
||||||
}
|
}
|
||||||
@ -227,6 +236,8 @@ func Compile(p *shaderir.Program) (vertexShader, pixelShader string, offsets []i
|
|||||||
vertexShader = shaders[0]
|
vertexShader = shaders[0]
|
||||||
pixelShader = shaders[1]
|
pixelShader = shaders[1]
|
||||||
|
|
||||||
|
fmt.Println("PS:", pixelShader)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +364,7 @@ func (c *compileContext) localVariableName(p *shaderir.Program, topBlock *shader
|
|||||||
case idx < nv+1:
|
case idx < nv+1:
|
||||||
return fmt.Sprintf("%s.M%d", vsOut, idx-1)
|
return fmt.Sprintf("%s.M%d", vsOut, idx-1)
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("l%d", idx-(nv+1))
|
return fmt.Sprintf("output.Color%d", idx-(nv+1))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("l%d", idx)
|
return fmt.Sprintf("l%d", idx)
|
||||||
@ -393,9 +404,6 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
|||||||
}
|
}
|
||||||
|
|
||||||
var lines []string
|
var lines []string
|
||||||
for i := range block.LocalVars {
|
|
||||||
lines = append(lines, c.initVariable(p, topBlock, block, block.LocalVarIndexOffset+i, true, level)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
var expr func(e *shaderir.Expr) string
|
var expr func(e *shaderir.Expr) string
|
||||||
expr = func(e *shaderir.Expr) string {
|
expr = func(e *shaderir.Expr) string {
|
||||||
@ -502,7 +510,8 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
|||||||
case shaderir.Assign:
|
case shaderir.Assign:
|
||||||
lhs := s.Exprs[0]
|
lhs := s.Exprs[0]
|
||||||
rhs := s.Exprs[1]
|
rhs := s.Exprs[1]
|
||||||
if lhs.Type == shaderir.LocalVariable {
|
isOutput := strings.HasPrefix(expr(&lhs), "output.Color")
|
||||||
|
if !isOutput && lhs.Type == shaderir.LocalVariable {
|
||||||
if t := p.LocalVariableType(topBlock, block, lhs.Index); t.Main == shaderir.Array {
|
if t := p.LocalVariableType(topBlock, block, lhs.Index); t.Main == shaderir.Array {
|
||||||
for i := 0; i < t.Length; i++ {
|
for i := 0; i < t.Length; i++ {
|
||||||
lines = append(lines, fmt.Sprintf("%[1]s%[2]s[%[3]d] = %[4]s[%[3]d];", idt, expr(&lhs), i, expr(&rhs)))
|
lines = append(lines, fmt.Sprintf("%[1]s%[2]s[%[3]d] = %[4]s[%[3]d];", idt, expr(&lhs), i, expr(&rhs)))
|
||||||
@ -564,7 +573,7 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
|||||||
case topBlock == p.VertexFunc.Block:
|
case topBlock == p.VertexFunc.Block:
|
||||||
lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, vsOut))
|
lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, vsOut))
|
||||||
case len(s.Exprs) == 0:
|
case len(s.Exprs) == 0:
|
||||||
lines = append(lines, idt+"return;")
|
lines = append(lines, idt+"return output;")
|
||||||
default:
|
default:
|
||||||
lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, expr(&s.Exprs[0])))
|
lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, expr(&s.Exprs[0])))
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ type Program struct {
|
|||||||
UniformNames []string
|
UniformNames []string
|
||||||
Uniforms []Type
|
Uniforms []Type
|
||||||
TextureCount int
|
TextureCount int
|
||||||
|
ColorsOutCount int
|
||||||
Attributes []Type
|
Attributes []Type
|
||||||
Varyings []Type
|
Varyings []Type
|
||||||
Funcs []Func
|
Funcs []Func
|
||||||
|
@ -77,7 +77,7 @@ func (i *Image) Deallocate() {
|
|||||||
i.mipmap.Deallocate()
|
i.mipmap.Deallocate()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
|
func (i *Image) DrawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
|
||||||
if i.modifyCallback != nil {
|
if i.modifyCallback != nil {
|
||||||
i.modifyCallback()
|
i.modifyCallback()
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
|
|
||||||
i.flushBufferIfNeeded()
|
i.flushBufferIfNeeded()
|
||||||
|
|
||||||
var srcMipmaps [graphics.ShaderImageCount]*mipmap.Mipmap
|
var srcMipmaps [graphics.ShaderSrcImageCount]*mipmap.Mipmap
|
||||||
for i, src := range srcs {
|
for i, src := range srcs {
|
||||||
if src == nil {
|
if src == nil {
|
||||||
continue
|
continue
|
||||||
@ -116,6 +116,30 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices [
|
|||||||
i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule, canSkipMipmap)
|
i.mipmap.DrawTriangles(srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule, canSkipMipmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DrawTrianglesMRT(dsts [graphics.ShaderDstImageCount]*Image, srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
|
||||||
|
var dstMipmaps [graphics.ShaderDstImageCount]*mipmap.Mipmap
|
||||||
|
for i, dst := range dsts {
|
||||||
|
if dst.modifyCallback != nil {
|
||||||
|
dst.modifyCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.lastBlend = blend
|
||||||
|
dst.flushBufferIfNeeded()
|
||||||
|
dstMipmaps[i] = dst.mipmap
|
||||||
|
}
|
||||||
|
|
||||||
|
var srcMipmaps [graphics.ShaderSrcImageCount]*mipmap.Mipmap
|
||||||
|
for i, src := range srcs {
|
||||||
|
if src == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
src.flushBufferIfNeeded()
|
||||||
|
srcMipmaps[i] = src.mipmap
|
||||||
|
}
|
||||||
|
|
||||||
|
mipmap.DrawTrianglesMRT(dstMipmaps, srcMipmaps, vertices, indices, blend, dstRegion, srcRegions, shader.shader, uniforms, fillRule, canSkipMipmap)
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
func (i *Image) WritePixels(pix []byte, region image.Rectangle) {
|
||||||
if i.modifyCallback != nil {
|
if i.modifyCallback != nil {
|
||||||
i.modifyCallback()
|
i.modifyCallback()
|
||||||
@ -175,7 +199,7 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) {
|
|||||||
r, g, b, a)
|
r, g, b, a)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*Image{i.ui.whiteImage}
|
srcs := [graphics.ShaderSrcImageCount]*Image{i.ui.whiteImage}
|
||||||
|
|
||||||
blend := graphicsdriver.BlendCopy
|
blend := graphicsdriver.BlendCopy
|
||||||
// If possible, use BlendSourceOver to encourage batching (#2817).
|
// If possible, use BlendSourceOver to encourage batching (#2817).
|
||||||
@ -183,7 +207,7 @@ func (i *Image) Fill(r, g, b, a float32, region image.Rectangle) {
|
|||||||
blend = graphicsdriver.BlendSourceOver
|
blend = graphicsdriver.BlendSourceOver
|
||||||
}
|
}
|
||||||
// i.lastBlend is updated in DrawTriangles.
|
// i.lastBlend is updated in DrawTriangles.
|
||||||
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll, true, false)
|
i.DrawTriangles(srcs, i.tmpVerticesForFill, is, blend, region, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
type bigOffscreenImage struct {
|
type bigOffscreenImage struct {
|
||||||
@ -217,7 +241,7 @@ func (i *bigOffscreenImage) deallocate() {
|
|||||||
i.dirty = false
|
i.dirty = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
|
func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderSrcImageCount]*Image, vertices []float32, indices []uint32, blend graphicsdriver.Blend, dstRegion image.Rectangle, srcRegions [graphics.ShaderSrcImageCount]image.Rectangle, shader *Shader, uniforms []uint32, fillRule graphicsdriver.FillRule, canSkipMipmap bool, antialias bool) {
|
||||||
if i.blend != blend {
|
if i.blend != blend {
|
||||||
i.flush()
|
i.flush()
|
||||||
}
|
}
|
||||||
@ -240,7 +264,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image
|
|||||||
|
|
||||||
// Copy the current rendering result to get the correct blending result.
|
// Copy the current rendering result to get the correct blending result.
|
||||||
if blend != graphicsdriver.BlendSourceOver && !i.dirty {
|
if blend != graphicsdriver.BlendSourceOver && !i.dirty {
|
||||||
srcs := [graphics.ShaderImageCount]*Image{i.orig}
|
srcs := [graphics.ShaderSrcImageCount]*Image{i.orig}
|
||||||
if len(i.tmpVerticesForCopying) < 4*graphics.VertexFloatCount {
|
if len(i.tmpVerticesForCopying) < 4*graphics.VertexFloatCount {
|
||||||
i.tmpVerticesForCopying = make([]float32, 4*graphics.VertexFloatCount)
|
i.tmpVerticesForCopying = make([]float32, 4*graphics.VertexFloatCount)
|
||||||
}
|
}
|
||||||
@ -252,7 +276,7 @@ func (i *bigOffscreenImage) drawTriangles(srcs [graphics.ShaderImageCount]*Image
|
|||||||
1, 1, 1, 1)
|
1, 1, 1, 1)
|
||||||
is := graphics.QuadIndices()
|
is := graphics.QuadIndices()
|
||||||
dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale)
|
dstRegion := image.Rect(0, 0, i.region.Dx()*bigOffscreenScale, i.region.Dy()*bigOffscreenScale)
|
||||||
i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll, true, false)
|
i.image.DrawTriangles(srcs, i.tmpVerticesForCopying, is, graphicsdriver.BlendCopy, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, NearestFilterShader, nil, graphicsdriver.FillAll, true, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount {
|
for idx := 0; idx < len(vertices); idx += graphics.VertexFloatCount {
|
||||||
@ -284,7 +308,7 @@ func (i *bigOffscreenImage) flush() {
|
|||||||
// Mark the offscreen clean earlier to avoid recursive calls.
|
// Mark the offscreen clean earlier to avoid recursive calls.
|
||||||
i.dirty = false
|
i.dirty = false
|
||||||
|
|
||||||
srcs := [graphics.ShaderImageCount]*Image{i.image}
|
srcs := [graphics.ShaderSrcImageCount]*Image{i.image}
|
||||||
if len(i.tmpVerticesForFlushing) < 4*graphics.VertexFloatCount {
|
if len(i.tmpVerticesForFlushing) < 4*graphics.VertexFloatCount {
|
||||||
i.tmpVerticesForFlushing = make([]float32, 4*graphics.VertexFloatCount)
|
i.tmpVerticesForFlushing = make([]float32, 4*graphics.VertexFloatCount)
|
||||||
}
|
}
|
||||||
@ -300,7 +324,7 @@ func (i *bigOffscreenImage) flush() {
|
|||||||
if i.blend != graphicsdriver.BlendSourceOver {
|
if i.blend != graphicsdriver.BlendSourceOver {
|
||||||
blend = graphicsdriver.BlendCopy
|
blend = graphicsdriver.BlendCopy
|
||||||
}
|
}
|
||||||
i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderImageCount]image.Rectangle{}, LinearFilterShader, nil, graphicsdriver.FillAll, true, false)
|
i.orig.DrawTriangles(srcs, i.tmpVerticesForFlushing, is, blend, dstRegion, [graphics.ShaderSrcImageCount]image.Rectangle{}, LinearFilterShader, nil, graphicsdriver.FillAll, true, false)
|
||||||
|
|
||||||
i.image.clear()
|
i.image.clear()
|
||||||
i.dirty = false
|
i.dirty = false
|
||||||
|
@ -168,7 +168,7 @@ func (t Tag) String() string {
|
|||||||
return string([]byte{byte(t >> 24), byte(t >> 16), byte(t >> 8), byte(t)})
|
return string([]byte{byte(t >> 24), byte(t >> 16), byte(t >> 8), byte(t)})
|
||||||
}
|
}
|
||||||
|
|
||||||
// PraseTag converts a string to Tag.
|
// ParseTag converts a string to Tag.
|
||||||
func ParseTag(str string) (Tag, error) {
|
func ParseTag(str string) (Tag, error) {
|
||||||
if len(str) != 4 {
|
if len(str) != 4 {
|
||||||
return 0, fmt.Errorf("text: a string's length must be 4 but was %d at ParseTag", len(str))
|
return 0, fmt.Errorf("text: a string's length must be 4 but was %d at ParseTag", len(str))
|
||||||
@ -176,7 +176,7 @@ func ParseTag(str string) (Tag, error) {
|
|||||||
return Tag((uint32(str[0]) << 24) | (uint32(str[1]) << 16) | (uint32(str[2]) << 8) | uint32(str[3])), nil
|
return Tag((uint32(str[0]) << 24) | (uint32(str[1]) << 16) | (uint32(str[2]) << 8) | uint32(str[3])), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustPraseTag converts a string to Tag.
|
// MustParseTag converts a string to Tag.
|
||||||
// If parsing fails, MustParseTag panics.
|
// If parsing fails, MustParseTag panics.
|
||||||
func MustParseTag(str string) Tag {
|
func MustParseTag(str string) Tag {
|
||||||
t, err := ParseTag(str)
|
t, err := ParseTag(str)
|
||||||
|
Loading…
Reference in New Issue
Block a user