From 504664e01497a60f063c8fc4b257a0d9b6886fc2 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 8 Jun 2020 16:25:47 +0200 Subject: [PATCH] gpu: saturate instead of overflowing depth buffer Use greater-than-or-equal test and saturate the z depth buffer when more than 65k objects are drawn. Fixes gio#127 Signed-off-by: Elias Naur --- app/internal/d3d11/backend_windows.go | 2 ++ app/internal/d3d11/d3d11_windows.go | 3 ++- gpu/backend/backend.go | 1 + gpu/gl/backend.go | 2 ++ gpu/gl/gl.go | 1 + gpu/gpu.go | 15 ++++++++------- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/internal/d3d11/backend_windows.go b/app/internal/d3d11/backend_windows.go index 5977ff4b..c35a6252 100644 --- a/app/internal/d3d11/backend_windows.go +++ b/app/internal/d3d11/backend_windows.go @@ -605,6 +605,8 @@ func (b *Backend) prepareDraw(mode backend.DrawMode) { switch b.depthState.fn { case backend.DepthFuncGreater: desc.DepthFunc = _D3D11_COMPARISON_GREATER + case backend.DepthFuncGreaterEqual: + desc.DepthFunc = _D3D11_COMPARISON_GREATER_EQUAL default: panic("unsupported depth func") } diff --git a/app/internal/d3d11/d3d11_windows.go b/app/internal/d3d11/d3d11_windows.go index 5c1e36bc..3dd21389 100644 --- a/app/internal/d3d11/d3d11_windows.go +++ b/app/internal/d3d11/d3d11_windows.go @@ -621,7 +621,8 @@ const ( _D3D11_DEPTH_WRITE_MASK_ALL = 1 - _D3D11_COMPARISON_GREATER = 5 + _D3D11_COMPARISON_GREATER = 5 + _D3D11_COMPARISON_GREATER_EQUAL = 7 _D3D11_BLEND_OP_ADD = 1 _D3D11_BLEND_ONE = 2 diff --git a/gpu/backend/backend.go b/gpu/backend/backend.go index 9ece5510..871eea49 100644 --- a/gpu/backend/backend.go +++ b/gpu/backend/backend.go @@ -156,6 +156,7 @@ type Texture interface { const ( DepthFuncGreater DepthFunc = iota + DepthFuncGreaterEqual ) const ( diff --git a/gpu/gl/backend.go b/gpu/gl/backend.go index 0a785db4..02037c34 100644 --- a/gpu/gl/backend.go +++ b/gpu/gl/backend.go @@ -399,6 +399,8 @@ func (b *Backend) DepthFunc(f backend.DepthFunc) { switch f { case backend.DepthFuncGreater: glfunc = GREATER + case backend.DepthFuncGreaterEqual: + glfunc = GEQUAL default: panic("unsupported depth func") } diff --git a/gpu/gl/gl.go b/gpu/gl/gl.go index 1106bf73..350f60f8 100644 --- a/gpu/gl/gl.go +++ b/gpu/gl/gl.go @@ -35,6 +35,7 @@ const ( INFO_LOG_LENGTH = 0x8B84 INVALID_INDEX = ^uint(0) GREATER = 0x204 + GEQUAL = 0x206 LINEAR = 0x2601 LINK_STATUS = 0x8b82 LUMINANCE = 0x1909 diff --git a/gpu/gpu.go b/gpu/gpu.go index 56d18863..1f1ff1ab 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -71,7 +71,7 @@ type drawState struct { t op.TransformOp cpath *pathOp rect bool - z int + z uint16 matType materialType // Current paint.ImageOp @@ -335,7 +335,8 @@ func (g *GPU) BeginFrame() { g.zopsTimer.begin() } g.ctx.BindFramebuffer(g.defFBO) - g.ctx.DepthFunc(backend.DepthFuncGreater) + // Equal because of depth saturation. + g.ctx.DepthFunc(backend.DepthFuncGreaterEqual) g.ctx.ClearDepth(0.0) g.ctx.Clear(g.drawOps.clearColor.Float32()) g.ctx.Viewport(0, 0, viewport.X, viewport.Y) @@ -680,7 +681,7 @@ func (d *drawOps) newPathOp() *pathOp { return &d.pathOpCache[len(d.pathOpCache)-1] } -func (d *drawOps) collectOps(r *ops.Reader, state drawState) int { +func (d *drawOps) collectOps(r *ops.Reader, state drawState) uint16 { var aux []byte var auxKey ops.Key loop: @@ -749,10 +750,10 @@ loop: d.clearColor = mat.color.Opaque() continue } - state.z++ - if state.z != int(uint16(state.z)) { - // TODO(eliasnaur) gioui.org/issue/127. - panic("more than 65k paint objects not supported") + // It's ok to saturate the depth value because we're using + // the >= depth comparison function. + if state.z < 0xffff { + state.z++ } // Assume 16-bit depth buffer. const zdepth = 1 << 16