Remove 'default framebuffer' and add 'screen framebuffer' for iOS

This commit is contained in:
Hajime Hoshi 2016-06-18 04:46:33 +09:00
parent 0b8fe25350
commit 5eb77d2fb5
9 changed files with 101 additions and 59 deletions

View File

@ -28,29 +28,29 @@ func newGraphicsContext(f func(*Image) error) *graphicsContext {
type graphicsContext struct {
f func(*Image) error
offscreen *Image
screen *Image
defaultRenderTarget *Image
screenScale int
initialized bool
}
func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) error {
if c.defaultRenderTarget != nil {
c.defaultRenderTarget.Dispose()
}
if c.screen != nil {
c.screen.Dispose()
}
screen, err := NewImage(screenWidth, screenHeight, FilterNearest)
if c.offscreen != nil {
c.offscreen.Dispose()
}
offscreen, err := NewImage(screenWidth, screenHeight, FilterNearest)
if err != nil {
return err
}
c.defaultRenderTarget, err = newImageWithZeroFramebuffer(screenWidth*screenScale, screenHeight*screenScale)
c.screen, err = newImageWithScreenFramebuffer(screenWidth*screenScale, screenHeight*screenScale)
if err != nil {
return err
}
c.defaultRenderTarget.Clear()
c.screen = screen
c.screen.Clear()
c.offscreen = offscreen
c.screenScale = screenScale
return nil
}
@ -58,11 +58,11 @@ func (c *graphicsContext) SetSize(screenWidth, screenHeight, screenScale int) er
func (c *graphicsContext) needsRestoring(context *opengl.Context) (bool, error) {
imageM.Lock()
defer imageM.Unlock()
// FlushCommands is required because c.screen.impl might not have an actual texture.
// FlushCommands is required because c.offscreen.impl might not have an actual texture.
if err := graphics.FlushCommands(ui.GLContext()); err != nil {
return false, err
}
return c.screen.impl.isInvalidated(context), nil
return c.offscreen.impl.isInvalidated(context), nil
}
func (c *graphicsContext) initializeIfNeeded() error {
@ -85,13 +85,13 @@ func (c *graphicsContext) initializeIfNeeded() error {
}
func (c *graphicsContext) drawToDefaultRenderTarget() error {
if err := c.defaultRenderTarget.Clear(); err != nil {
if err := c.screen.Clear(); err != nil {
return err
}
scale := float64(c.screenScale)
options := &DrawImageOptions{}
options.GeoM.Scale(scale, scale)
if err := c.defaultRenderTarget.DrawImage(c.screen, options); err != nil {
if err := c.screen.DrawImage(c.offscreen, options); err != nil {
return err
}
if err := c.flush(); err != nil {
@ -104,10 +104,10 @@ func (c *graphicsContext) UpdateAndDraw() error {
if err := c.initializeIfNeeded(); err != nil {
return err
}
if err := c.screen.Clear(); err != nil {
if err := c.offscreen.Clear(); err != nil {
return err
}
if err := c.f(c.screen); err != nil {
if err := c.f(c.offscreen); err != nil {
return err
}
if IsRunningSlowly() {
@ -117,8 +117,8 @@ func (c *graphicsContext) UpdateAndDraw() error {
return err
}
exceptions := map[*imageImpl]struct{}{
c.offscreen.impl: {},
c.screen.impl: {},
c.defaultRenderTarget.impl: {},
}
if err := theImages.savePixels(ui.GLContext(), exceptions); err != nil {
return err

View File

@ -78,7 +78,7 @@ func (i *images) restorePixels(context *opengl.Context) error {
i.m.Lock()
defer i.m.Unlock()
for img := range i.images {
if img.defaultFramebuffer {
if img.screen {
continue
}
if img.isDisposed() {
@ -192,7 +192,7 @@ func (i *Image) ReplacePixels(p []uint8) error {
type imageImpl struct {
image *graphics.Image
defaultFramebuffer bool
screen bool
disposed bool
width int
height int
@ -285,7 +285,7 @@ func (i *imageImpl) savePixels(context *opengl.Context) error {
}
func (i *imageImpl) restorePixels(context *opengl.Context) error {
if i.defaultFramebuffer {
if i.screen {
return nil
}
if i.disposed {
@ -433,10 +433,10 @@ func NewImageFromImage(source image.Image, filter Filter) (*Image, error) {
return eimg, nil
}
func newImageWithZeroFramebuffer(width, height int) (*Image, error) {
func newImageWithScreenFramebuffer(width, height int) (*Image, error) {
imageM.Lock()
defer imageM.Unlock()
i, err := graphics.NewZeroFramebufferImage(width, height)
i, err := graphics.NewScreenFramebufferImage(width, height)
if err != nil {
return nil, err
}
@ -444,7 +444,7 @@ func newImageWithZeroFramebuffer(width, height int) (*Image, error) {
image: i,
width: width,
height: height,
defaultFramebuffer: true,
screen: true,
}
eimg, err := theImages.add(img)
if err != nil {

View File

@ -151,7 +151,7 @@ type disposeCommand struct {
}
func (c *disposeCommand) Exec(context *opengl.Context) error {
if c.target.framebuffer != nil && c.target.framebuffer.native != opengl.ZeroFramebuffer {
if c.target.framebuffer != nil && c.target.framebuffer.native != context.ScreenFramebuffer() {
context.DeleteFramebuffer(c.target.framebuffer.native)
}
if c.target.texture != nil {
@ -245,3 +245,26 @@ func (c *newImageCommand) Exec(context *opengl.Context) error {
}
return nil
}
type newScreenFramebufferImageCommand struct {
result *Image
width int
height int
}
func (c *newScreenFramebufferImageCommand) Exec(context *opengl.Context) error {
if c.width < 4 {
return errors.New("graphics: width must be equal or more than 4.")
}
if c.height < 4 {
return errors.New("graphics: height must be equal or more than 4.")
}
f := &framebuffer{
native: context.ScreenFramebuffer(),
width: c.width,
height: c.height,
flipY: true,
}
c.result.framebuffer = f
return nil
}

View File

@ -49,15 +49,15 @@ func NewImageFromImage(img *image.RGBA, filter opengl.Filter) (*Image, error) {
return i, nil
}
func NewZeroFramebufferImage(width, height int) (*Image, error) {
f := &framebuffer{
func NewScreenFramebufferImage(width, height int) (*Image, error) {
i := &Image{}
c := &newScreenFramebufferImageCommand{
result: i,
width: width,
height: height,
flipY: true,
}
return &Image{
framebuffer: f,
}, nil
theCommandQueue.Enqueue(c)
return i, nil
}
func (i *Image) Dispose() error {

View File

@ -14,8 +14,6 @@
package opengl
var ZeroFramebuffer Framebuffer
type Context struct {
Nearest Filter
Linear Filter
@ -34,6 +32,7 @@ type Context struct {
oneMinusSrcAlpha operation
oneMinusDstAlpha operation
locationCache *locationCache
screenFramebuffer Framebuffer // This might not be the default frame buffer '0' (e.g. iOS).
lastFramebuffer Framebuffer
lastViewportWidth int
lastViewportHeight int
@ -48,3 +47,7 @@ func (c *Context) bindFramebuffer(f Framebuffer) {
c.bindFramebufferImpl(f)
c.lastFramebuffer = f
}
func (c *Context) ScreenFramebuffer() Framebuffer {
return c.screenFramebuffer
}

View File

@ -37,6 +37,8 @@ type attribLocation int32
type programID uint32
const invalidFramebuffer = (1 << 32) - 1
func (p Program) id() programID {
return programID(p)
}
@ -102,17 +104,23 @@ func (c *Context) Init() error {
return err
}
c.BlendFunc(CompositeModeSourceOver)
f := int32(0)
gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &f)
c.screenFramebuffer = Framebuffer(f)
return nil
}
func (c *Context) Resume() {
c.locationCache = newLocationCache()
c.lastFramebuffer = ZeroFramebuffer
c.lastFramebuffer = invalidFramebuffer
c.lastViewportWidth = 0
c.lastViewportHeight = 0
c.lastCompositeMode = CompositeModeUnknown
gl.Enable(gl.BLEND)
c.BlendFunc(CompositeModeSourceOver)
f := int32(0)
gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &f)
c.screenFramebuffer = Framebuffer(f)
}
func (c *Context) BlendFunc(mode CompositeMode) {
@ -212,9 +220,9 @@ func (c *Context) TexSubImage2D(p []uint8, width, height int) {
})
}
func (c *Context) BindZeroFramebuffer() {
func (c *Context) BindScreenFramebuffer() {
c.RunOnContextThread(func() error {
c.bindFramebuffer(ZeroFramebuffer)
c.bindFramebuffer(c.screenFramebuffer)
return nil
})
}
@ -275,11 +283,8 @@ func (c *Context) DeleteFramebuffer(f Framebuffer) {
if !gl.IsFramebuffer(ff) {
return nil
}
// If a framebuffer to be delted is bound, a newly bound framebuffer
// will be a default framebuffer.
// https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteFramebuffers.xml
if c.lastFramebuffer == f {
c.lastFramebuffer = ZeroFramebuffer
c.lastFramebuffer = invalidFramebuffer
c.lastViewportWidth = 0
c.lastViewportHeight = 0
}

View File

@ -52,6 +52,8 @@ type attribLocation int
type programID int
var invalidFramebuffer = Framebuffer{nil}
func (p Program) id() programID {
return programID(p.Get("__ebiten_programId").Int())
}
@ -115,19 +117,22 @@ func (c *Context) init() {
gl := c.gl
// Textures' pixel formats are alpha premultiplied.
gl.Enable(gl.BLEND)
//gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
c.BlendFunc(CompositeModeSourceOver)
f := gl.GetParameter(gl.FRAMEBUFFER_BINDING)
c.screenFramebuffer = Framebuffer{f}
}
func (c *Context) Resume() {
c.locationCache = newLocationCache()
c.lastFramebuffer = ZeroFramebuffer
c.lastFramebuffer = invalidFramebuffer
c.lastViewportWidth = 0
c.lastViewportHeight = 0
c.lastCompositeMode = CompositeModeUnknown
gl := c.gl
gl.Enable(gl.BLEND)
c.BlendFunc(CompositeModeSourceOver)
f := gl.GetParameter(gl.FRAMEBUFFER_BINDING)
c.screenFramebuffer = Framebuffer{f}
}
func (c *Context) BlendFunc(mode CompositeMode) {
@ -252,7 +257,7 @@ func (c *Context) DeleteFramebuffer(f Framebuffer) {
// will be a default framebuffer.
// https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteFramebuffers.xml
if c.lastFramebuffer == f {
c.lastFramebuffer = ZeroFramebuffer
c.lastFramebuffer = invalidFramebuffer
c.lastViewportWidth = 0
c.lastViewportHeight = 0
}

View File

@ -34,6 +34,8 @@ type attribLocation mgl.Attrib
type programID uint32
var invalidFramebuffer = Framebuffer(mgl.Framebuffer{(1 << 32) - 1})
func (p Program) id() programID {
return programID(p.Value)
}
@ -75,6 +77,8 @@ func NewContext() (*Context, error) {
// Textures' pixel formats are alpha premultiplied.
c.gl.Enable(mgl.BLEND)
c.BlendFunc(CompositeModeSourceOver)
f := c.gl.GetInteger(mgl.FRAMEBUFFER_BINDING)
c.screenFramebuffer = Framebuffer(mgl.Framebuffer{uint32(f)})
close(c.initialized)
}()
return c, nil
@ -82,12 +86,14 @@ func NewContext() (*Context, error) {
func (c *Context) Resume() {
c.locationCache = newLocationCache()
c.lastFramebuffer = ZeroFramebuffer
c.lastFramebuffer = invalidFramebuffer
c.lastViewportWidth = 0
c.lastViewportHeight = 0
c.lastCompositeMode = CompositeModeUnknown
c.gl.Enable(mgl.BLEND)
c.BlendFunc(CompositeModeSourceOver)
f := c.gl.GetInteger(mgl.FRAMEBUFFER_BINDING)
c.screenFramebuffer = Framebuffer(mgl.Framebuffer{uint32(f)})
}
func (c *Context) WaitUntilInitializingDone() {
@ -172,8 +178,8 @@ func (c *Context) TexSubImage2D(p []uint8, width, height int) {
gl.TexSubImage2D(mgl.TEXTURE_2D, 0, 0, 0, width, height, mgl.RGBA, mgl.UNSIGNED_BYTE, p)
}
func (c *Context) BindZeroFramebuffer() {
c.bindFramebuffer(ZeroFramebuffer)
func (c *Context) BindScreenFramebuffer() {
c.bindFramebuffer(c.screenFramebuffer)
}
func (c *Context) NewFramebuffer(texture Texture) (Framebuffer, error) {
@ -226,7 +232,7 @@ func (c *Context) DeleteFramebuffer(f Framebuffer) {
// will be a default framebuffer.
// https://www.khronos.org/opengles/sdk/docs/man/xhtml/glDeleteFramebuffers.xml
if c.lastFramebuffer == f {
c.lastFramebuffer = ZeroFramebuffer
c.lastFramebuffer = invalidFramebuffer
c.lastViewportWidth = 0
c.lastViewportHeight = 0
}

View File

@ -255,7 +255,7 @@ func (u *userInterface) SwapBuffers() error {
func (u *userInterface) swapBuffers() {
// The bound framebuffer must be the default one (0) before swapping buffers.
u.context.BindZeroFramebuffer()
u.context.BindScreenFramebuffer()
u.context.RunOnContextThread(func() error {
u.window.SwapBuffers()
return nil