Skip to content

Commit

Permalink
internal/ui: use -overlay to provide the implementation for Nintendo …
Browse files Browse the repository at this point in the history
…Switch

Closes hajimehoshi#2372
  • Loading branch information
hajimehoshi committed Jan 3, 2023
1 parent edf35b0 commit 0e0205b
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 25 deletions.
2 changes: 2 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,6 @@
// `microsoftgdk` is for Microsoft GDK (e.g. Xbox).
//
// `nintendosdk` is for NintendoSDK (e.g. Nintendo Switch).
//
// `nintendosdkprofile` enables a profiler for NintendoSDK.
package ebiten
93 changes: 93 additions & 0 deletions internal/ui/egl_nintendosdk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2023 The Ebitengine 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.

//go:build nintendosdk

package ui

// #include <EGL/egl.h>
// #include <EGL/eglext.h>
import "C"

import (
"fmt"
)

type egl struct {
display C.EGLDisplay
surface C.EGLSurface
context C.EGLContext
}

func (e *egl) init(nativeWindowHandle C.NativeWindowType) error {
// Initialize EGL
e.display = C.eglGetDisplay(C.EGL_DEFAULT_DISPLAY)
if e.display == 0 {
return fmt.Errorf("ui: eglGetDisplay failed")
}

if r := C.eglInitialize(e.display, nil, nil); r == 0 {
return fmt.Errorf("ui: eglInitialize failed")
}

configAttribs := []C.EGLint{
C.EGL_RENDERABLE_TYPE, C.EGL_OPENGL_BIT,
C.EGL_SURFACE_TYPE, C.EGL_WINDOW_BIT,
C.EGL_RED_SIZE, 8,
C.EGL_GREEN_SIZE, 8,
C.EGL_BLUE_SIZE, 8,
C.EGL_ALPHA_SIZE, 8,
C.EGL_NONE}
var numConfigs C.EGLint
var config C.EGLConfig
if r := C.eglChooseConfig(e.display, &configAttribs[0], &config, 1, &numConfigs); r == 0 {
return fmt.Errorf("ui: eglChooseConfig failed")
}
if numConfigs != 1 {
return fmt.Errorf("ui: eglChooseConfig failed: numConfigs must be 1 but %d", numConfigs)
}

e.surface = C.eglCreateWindowSurface(e.display, config, nativeWindowHandle, nil)
if e.surface == C.EGL_NO_SURFACE {
return fmt.Errorf("ui: eglCreateWindowSurface failed")
}

// Set the current rendering API.
if r := C.eglBindAPI(C.EGL_OPENGL_API); r == 0 {
return fmt.Errorf("ui: eglBindAPI failed")
}

// Create new context and set it as current.
contextAttribs := []C.EGLint{
// Set target garaphics api version.
C.EGL_CONTEXT_MAJOR_VERSION, 2,
C.EGL_CONTEXT_MINOR_VERSION, 1,
// For debug callback
C.EGL_CONTEXT_FLAGS_KHR, C.EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR,
C.EGL_NONE}
e.context = C.eglCreateContext(e.display, config, C.EGL_NO_CONTEXT, &contextAttribs[0])
if e.context == C.EGL_NO_CONTEXT {
return fmt.Errorf("ui: eglCreateContext failed: error: %d", C.eglGetError())
}

if r := C.eglMakeCurrent(e.display, e.surface, e.surface, e.context); r == 0 {
return fmt.Errorf("ui: eglMakeCurrent failed")
}

return nil
}

func (e *egl) swapBuffers() {
C.eglSwapBuffers(e.display, e.surface)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 The Ebiten Authors
// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -14,27 +14,12 @@

//go:build nintendosdk

package nintendosdk
// The actual implementaiton will be provided by -overlay.

// #cgo !darwin LDFLAGS: -Wl,-unresolved-symbols=ignore-all
// #cgo darwin LDFLAGS: -Wl,-undefined,dynamic_lookup
//
// #include <stdint.h>
//
// // UI
// void EbitenInitializeGame();
// void EbitenBeginFrame();
// void EbitenEndFrame();
import "C"
#include "init_nintendosdk.h"

func InitializeGame() {
C.EbitenInitializeGame()
}
extern "C" NativeWindowType ebitengine_Init() {}

func BeginFrame() {
C.EbitenBeginFrame()
}
extern "C" void ebitengine_InitializeProfiler() {}

func EndFrame() {
C.EbitenEndFrame()
}
extern "C" void ebitengine_RecordProfilerHeartbeat() {}
29 changes: 29 additions & 0 deletions internal/ui/init_nintendosdk.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2023 The Ebitengine 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.

//go:build nintendosdk

#include <EGL/egl.h>

#ifdef __cplusplus
extern "C" {
#endif

NativeWindowType ebitengine_Init();
void ebitengine_InitializeProfiler();
void ebitengine_RecordProfilerHeartbeat();

#ifdef __cplusplus
} // extern "C"
#endif
23 changes: 23 additions & 0 deletions internal/ui/notprofile_nintendosdk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2023 The Ebitengine 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.

//go:build nintendosdk && !nintendosdkprofile

package ui

func initializeProfiler() {
}

func recordProfilerHeartbeat() {
}
28 changes: 28 additions & 0 deletions internal/ui/profile_nintendosdk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2023 The Ebitengine 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.

//go:build nintendosdk && nintendosdkprofile

package ui

// #include "init_nintendosdk.h"
import "C"

func initializeProfiler() {
C.ebitengine_InitializeProfiler()
}

func recordProfilerHeartbeat() {
C.ebitengine_RecordProfilerHeartbeat()
}
18 changes: 14 additions & 4 deletions internal/ui/ui_nintendosdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package ui

// #include "init_nintendosdk.h"
// #include "input_nintendosdk.h"
import "C"

Expand All @@ -25,7 +26,6 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/gamepad"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl"
"github.com/hajimehoshi/ebiten/v2/internal/nintendosdk"
)

type graphicsDriverCreatorImpl struct{}
Expand Down Expand Up @@ -59,6 +59,8 @@ type userInterfaceImpl struct {
context *context
inputState InputState
nativeTouches []C.struct_Touch

egl egl
}

func (u *userInterfaceImpl) Run(game Game, options *RunOptions) error {
Expand All @@ -68,18 +70,26 @@ func (u *userInterfaceImpl) Run(game Game, options *RunOptions) error {
return err
}
u.graphicsDriver = g
nintendosdk.InitializeGame()

n := C.ebitengine_Init()
if err := u.egl.init(n); err != nil {
return err
}

initializeProfiler()

for {
recordProfilerHeartbeat()

// TODO: Make a separate thread for rendering (#2512).
nintendosdk.BeginFrame()
gamepad.Update()
u.updateInputState()

if err := u.context.updateFrame(u.graphicsDriver, float64(C.kScreenWidth), float64(C.kScreenHeight), deviceScaleFactor, u); err != nil {
return err
}

nintendosdk.EndFrame()
u.egl.swapBuffers()
}
}

Expand Down

0 comments on commit 0e0205b

Please sign in to comment.