From 9bff33472a6bf683d848bd56bb9ad0896640f31e Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 22 Jun 2019 04:47:48 +0900 Subject: [PATCH] driver: Add (Graphics).HasHighPrecisionFlaot This enables to determine whether vertices should be adjusted or not. Fixes #879 --- internal/driver/graphics.go | 1 + internal/graphicscommand/command.go | 15 ++++++++------- internal/graphicsdriver/metal/driver.go | 4 ++++ internal/graphicsdriver/opengl/context.go | 13 +++++++++++++ internal/graphicsdriver/opengl/context_desktop.go | 6 ++++++ internal/graphicsdriver/opengl/context_js.go | 7 +++++++ internal/graphicsdriver/opengl/context_mobile.go | 6 ++++++ internal/graphicsdriver/opengl/driver.go | 4 ++++ 8 files changed, 49 insertions(+), 7 deletions(-) diff --git a/internal/driver/graphics.go b/internal/driver/graphics.go index 1621a374a..59654e4d0 100644 --- a/internal/driver/graphics.go +++ b/internal/driver/graphics.go @@ -35,6 +35,7 @@ type Graphics interface { VDirection() VDirection NeedsRestoring() bool IsGL() bool + HasHighPrecisionFloat() bool } type Image interface { diff --git a/internal/graphicscommand/command.go b/internal/graphicscommand/command.go index 343de435e..617d0415d 100644 --- a/internal/graphicscommand/command.go +++ b/internal/graphicscommand/command.go @@ -183,13 +183,14 @@ func (q *commandQueue) Flush() { fmt.Println("--") } - // Adjust texels. - // TODO: texelAdjustmentFactor can vary depends on the highp precisions (#879). - const texelAdjustmentFactor = 1.0 / 512.0 - for i := 0; i < q.nvertices/graphics.VertexFloatNum; i++ { - s := q.dstSizes[i] - vs[i*graphics.VertexFloatNum+6] -= 1.0 / s.width * texelAdjustmentFactor - vs[i*graphics.VertexFloatNum+7] -= 1.0 / s.height * texelAdjustmentFactor + if theGraphicsDriver.HasHighPrecisionFloat() { + // Adjust texels. + const texelAdjustmentFactor = 1.0 / 512.0 + for i := 0; i < q.nvertices/graphics.VertexFloatNum; i++ { + s := q.dstSizes[i] + vs[i*graphics.VertexFloatNum+6] -= 1.0 / s.width * texelAdjustmentFactor + vs[i*graphics.VertexFloatNum+7] -= 1.0 / s.height * texelAdjustmentFactor + } } theGraphicsDriver.Begin() diff --git a/internal/graphicsdriver/metal/driver.go b/internal/graphicsdriver/metal/driver.go index 7ed6bd170..5e8bf0467 100644 --- a/internal/graphicsdriver/metal/driver.go +++ b/internal/graphicsdriver/metal/driver.go @@ -703,6 +703,10 @@ func (d *Driver) IsGL() bool { return false } +func (d *Driver) HasHighPrecisionFloat() bool { + return true +} + type Image struct { driver *Driver width int diff --git a/internal/graphicsdriver/opengl/context.go b/internal/graphicsdriver/opengl/context.go index 660adef72..bc5822256 100644 --- a/internal/graphicsdriver/opengl/context.go +++ b/internal/graphicsdriver/opengl/context.go @@ -16,6 +16,7 @@ package opengl import ( "fmt" + "sync" "github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/thread" @@ -49,6 +50,8 @@ type context struct { lastViewportHeight int lastCompositeMode graphics.CompositeMode maxTextureSize int + highp bool + highpOnce sync.Once t *thread.Thread @@ -102,3 +105,13 @@ func (c *context) getMaxTextureSize() int { } return c.maxTextureSize } + +// highpPrecision represents an enough mantissa of float values in a shader. +const highpPrecision = 23 + +func (c *context) hasHighPrecisionFloat() bool { + c.highpOnce.Do(func() { + c.highp = c.getShaderPrecisionFormatPrecision() >= highpPrecision + }) + return c.highp +} diff --git a/internal/graphicsdriver/opengl/context_desktop.go b/internal/graphicsdriver/opengl/context_desktop.go index b3ff41d8a..f1d077e55 100644 --- a/internal/graphicsdriver/opengl/context_desktop.go +++ b/internal/graphicsdriver/opengl/context_desktop.go @@ -493,6 +493,12 @@ func (c *context) maxTextureSizeImpl() int { return size } +func (c *context) getShaderPrecisionFormatPrecision() int { + // glGetShaderPrecisionFormat is not defined at OpenGL 2.0. Assume that desktop environments always have + // enough highp precision. + return highpPrecision +} + func (c *context) flush() { _ = c.t.Call(func() error { gl.Flush() diff --git a/internal/graphicsdriver/opengl/context_js.go b/internal/graphicsdriver/opengl/context_js.go index d2d1c3e4a..d37dac709 100644 --- a/internal/graphicsdriver/opengl/context_js.go +++ b/internal/graphicsdriver/opengl/context_js.go @@ -73,6 +73,7 @@ var ( framebuffer_ = contextPrototype.Get("FRAMEBUFFER") framebufferBinding = contextPrototype.Get("FRAMEBUFFER_BINDING") framebufferComplete = contextPrototype.Get("FRAMEBUFFER_COMPLETE") + highFloat = contextPrototype.Get("HIGH_FLOAT") linkStatus = contextPrototype.Get("LINK_STATUS") maxTextureSize = contextPrototype.Get("MAX_TEXTURE_SIZE") nearest = contextPrototype.Get("NEAREST") @@ -451,6 +452,12 @@ func (c *context) maxTextureSizeImpl() int { return gl.Call("getParameter", maxTextureSize).Int() } +func (c *context) getShaderPrecisionFormatPrecision() int { + c.ensureGL() + gl := c.gl + return gl.Call("getShaderPrecisionFormat", js.ValueOf(int(fragmentShader)), highFloat).Get("precision").Int() +} + func (c *context) flush() { c.ensureGL() gl := c.gl diff --git a/internal/graphicsdriver/opengl/context_mobile.go b/internal/graphicsdriver/opengl/context_mobile.go index 6e5c457d3..6278bdbf8 100644 --- a/internal/graphicsdriver/opengl/context_mobile.go +++ b/internal/graphicsdriver/opengl/context_mobile.go @@ -377,6 +377,12 @@ func (c *context) maxTextureSizeImpl() int { return gl.GetInteger(mgl.MAX_TEXTURE_SIZE) } +func (c *context) getShaderPrecisionFormatPrecision() int { + gl := c.gl + _, _, p := gl.GetShaderPrecisionFormat(mgl.FRAGMENT_SHADER, mgl.HIGH_FLOAT) + return p +} + func (c *context) flush() { gl := c.gl gl.Flush() diff --git a/internal/graphicsdriver/opengl/driver.go b/internal/graphicsdriver/opengl/driver.go index a3f3d297b..f8486b664 100644 --- a/internal/graphicsdriver/opengl/driver.go +++ b/internal/graphicsdriver/opengl/driver.go @@ -138,3 +138,7 @@ func (d *Driver) NeedsRestoring() bool { func (d *Driver) IsGL() bool { return true } + +func (d *Driver) HasHighPrecisionFloat() bool { + return d.context.hasHighPrecisionFloat() +}