From e977019d2fd378c034910bfe532adc3f91d72694 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Fri, 9 Mar 2018 11:03:55 +0900 Subject: [PATCH] graphics: Detect maximum texture size for each environment Fixes #537, #539 See also #541 --- graphicscontext.go | 4 ++-- image.go | 6 ++++-- internal/graphics/command.go | 9 +++++---- internal/graphics/framebuffer.go | 8 ++------ internal/graphics/image.go | 26 +++++++++++++++++++++++--- internal/graphics/program.go | 1 + internal/opengl/context.go | 8 ++++++++ internal/opengl/context_desktop.go | 11 +++++++++++ internal/opengl/context_js.go | 5 +++++ internal/opengl/context_mobile.go | 5 +++++ 10 files changed, 66 insertions(+), 17 deletions(-) diff --git a/graphicscontext.go b/graphicscontext.go index 1d2b7fa2b..9e4728bc5 100644 --- a/graphicscontext.go +++ b/graphicscontext.go @@ -103,8 +103,8 @@ func (c *graphicsContext) Update(afterFrameUpdate func()) error { if c.offsetX > 0 || c.offsetY > 0 { op := &DrawImageOptions{} w, h := emptyImage.Size() - // graphics.MaxImageSize should be the maximum size of framebuffer. - op.GeoM.Scale(graphics.MaxImageSize/float64(w), graphics.MaxImageSize/float64(h)) + s := float64(graphics.MaxImageSize()) + op.GeoM.Scale(s/float64(w), s/float64(h)) op.CompositeMode = CompositeModeCopy c.screen.DrawImage(emptyImage, op) } diff --git a/image.go b/image.go index 0721da13f..57a3ad2cd 100644 --- a/image.go +++ b/image.go @@ -552,5 +552,7 @@ func newImageWithScreenFramebuffer(width, height int) *Image { return i } -// MaxImageSize represents the maximum width/height of an image. -const MaxImageSize = graphics.MaxImageSize +// MaxImageSize is deprecated as of 1.7.0-alpha. No replacement so far. +// +// TODO: Make this replacement (#541) +var MaxImageSize = 4096 diff --git a/internal/graphics/command.go b/internal/graphics/command.go index 12b6aeef8..cdd80d93b 100644 --- a/internal/graphics/command.go +++ b/internal/graphics/command.go @@ -332,11 +332,12 @@ func checkSize(width, height int) { if height < 1 { panic(fmt.Sprintf("graphics: height (%d) must be equal or more than 1.", height)) } - if width > MaxImageSize { - panic(fmt.Sprintf("graphics: width (%d) must be less than or equal to %d", width, MaxImageSize)) + m := MaxImageSize() + if width > m { + panic(fmt.Sprintf("graphics: width (%d) must be less than or equal to %d", width, m)) } - if height > MaxImageSize { - panic(fmt.Sprintf("graphics: height (%d) must be less than or equal to %d", height, MaxImageSize)) + if height > m { + panic(fmt.Sprintf("graphics: height (%d) must be less than or equal to %d", height, m)) } } diff --git a/internal/graphics/framebuffer.go b/internal/graphics/framebuffer.go index f27c91e5c..ced24be6e 100644 --- a/internal/graphics/framebuffer.go +++ b/internal/graphics/framebuffer.go @@ -66,11 +66,6 @@ func newScreenFramebuffer(width, height int) *framebuffer { } } -// defaultViewportSize is the default size (width or height) of viewport. -// -// defaultViewportSize also represents the maximum size of a framebuffer. -const defaultViewportSize = 4096 - // viewportSize returns the viewport size of the framebuffer. func (f *framebuffer) viewportSize() (int, int) { // On some browsers, viewport size must be within the framebuffer size. @@ -80,7 +75,8 @@ func (f *framebuffer) viewportSize() (int, int) { } // If possible, always use the same viewport size to reduce draw calls. - return defaultViewportSize, defaultViewportSize + m := MaxImageSize() + return m, m } // setAsViewport sets the framebuffer as the current viewport. diff --git a/internal/graphics/image.go b/internal/graphics/image.go index 300dc1ea2..de80ca578 100644 --- a/internal/graphics/image.go +++ b/internal/graphics/image.go @@ -18,8 +18,31 @@ import ( "github.com/hajimehoshi/ebiten/internal/affine" "github.com/hajimehoshi/ebiten/internal/math" "github.com/hajimehoshi/ebiten/internal/opengl" + "github.com/hajimehoshi/ebiten/internal/sync" ) +var ( + // maxTextureSize is the maximum texture size + // + // maxTextureSize also represents the default size (width or height) of viewport. + maxTextureSize = 0 + maxTextureSizeLock sync.Mutex +) + +// MaxImageSize returns the maximum of width/height of an image. +func MaxImageSize() int { + maxTextureSizeLock.Lock() + if maxTextureSize == 0 { + maxTextureSize = opengl.GetContext().MaxTextureSize() + if maxTextureSize == 0 { + panic("graphics: failed to get the max texture size") + } + } + s := maxTextureSize + maxTextureSizeLock.Unlock() + return s +} + // Image represents an image that is implemented with OpenGL. type Image struct { texture *texture @@ -28,9 +51,6 @@ type Image struct { height int } -// MaxImageSize is the maximum of width/height of an image. -const MaxImageSize = defaultViewportSize - func NewImage(width, height int) *Image { i := &Image{ width: width, diff --git a/internal/graphics/program.go b/internal/graphics/program.go index a3f272bb3..73dec8933 100644 --- a/internal/graphics/program.go +++ b/internal/graphics/program.go @@ -147,6 +147,7 @@ func (s *openGLState) reset() error { if err := opengl.GetContext().Reset(); err != nil { return err } + s.lastProgram = zeroProgram s.lastProjectionMatrix = nil s.lastColorMatrix = nil diff --git a/internal/opengl/context.go b/internal/opengl/context.go index a3d73a21f..af2c5e9b8 100644 --- a/internal/opengl/context.go +++ b/internal/opengl/context.go @@ -51,6 +51,7 @@ type Context struct { lastViewportWidth int lastViewportHeight int lastCompositeMode CompositeMode + maxTextureSize int context } @@ -93,3 +94,10 @@ func (c *Context) ResetViewportSize() { c.lastViewportWidth = 0 c.lastViewportHeight = 0 } + +func (c *Context) MaxTextureSize() int { + if c.maxTextureSize == 0 { + c.maxTextureSize = c.maxTextureSizeImpl() + } + return c.maxTextureSize +} diff --git a/internal/opengl/context_desktop.go b/internal/opengl/context_desktop.go index 4edd7c435..15f2017f8 100644 --- a/internal/opengl/context_desktop.go +++ b/internal/opengl/context_desktop.go @@ -494,6 +494,17 @@ func (c *Context) DrawElements(mode Mode, len int, offsetInBytes int) { }) } +func (c *Context) maxTextureSizeImpl() int { + size := 0 + _ = c.runOnContextThread(func() error { + s := int32(0) + gl.GetIntegerv(gl.MAX_TEXTURE_SIZE, &s) + size = int(s) + return nil + }) + return size +} + func (c *Context) Flush() { _ = c.runOnContextThread(func() error { gl.Flush() diff --git a/internal/opengl/context_js.go b/internal/opengl/context_js.go index d7caa36a7..168a43f9d 100644 --- a/internal/opengl/context_js.go +++ b/internal/opengl/context_js.go @@ -379,6 +379,11 @@ func (c *Context) DrawElements(mode Mode, len int, offsetInBytes int) { gl.DrawElements(int(mode), len, gl.UNSIGNED_SHORT, offsetInBytes) } +func (c *Context) maxTextureSizeImpl() int { + gl := c.gl + return gl.GetParameter(gl.MAX_TEXTURE_SIZE).Int() +} + func (c *Context) Flush() { gl := c.gl gl.Flush() diff --git a/internal/opengl/context_mobile.go b/internal/opengl/context_mobile.go index 804ef9a99..b4d715e1d 100644 --- a/internal/opengl/context_mobile.go +++ b/internal/opengl/context_mobile.go @@ -399,6 +399,11 @@ func (c *Context) DrawElements(mode Mode, len int, offsetInBytes int) { gl.DrawElements(mgl.Enum(mode), len, mgl.UNSIGNED_SHORT, offsetInBytes) } +func (c *Context) maxTextureSizeImpl() int { + gl := c.gl + return gl.GetInteger(mgl.MAX_TEXTURE_SIZE) +} + func (c *Context) Flush() { gl := c.gl gl.Flush()