mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
ebiten: add ColorSpace and RunGameOptions.ColorSpace
This works only for macOS Metal and WebGL so far. Closes #2871
This commit is contained in:
parent
42209606b1
commit
f98003bcd5
@ -50,6 +50,7 @@ var (
|
||||
flagMaxWindowSize = flag.String("maxwindowsize", "", "maximum window size (e.g., 1920x1080)")
|
||||
flagGraphicsLibrary = flag.String("graphicslibrary", "", "graphics library (e.g. opengl)")
|
||||
flagRunnableOnUnfocused = flag.Bool("runnableonunfocused", true, "whether the app is runnable even on unfocused")
|
||||
flagColorSpace = flag.String("colorspace", "", "color space ('', 'srgb', or 'display-p3')")
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -473,6 +474,14 @@ func main() {
|
||||
default:
|
||||
log.Fatalf("unexpected graphics library: %s", *flagGraphicsLibrary)
|
||||
}
|
||||
switch *flagColorSpace {
|
||||
case "":
|
||||
op.ColorSpace = ebiten.ColorSpaceDefault
|
||||
case "srgb":
|
||||
op.ColorSpace = ebiten.ColorSpaceSRGB
|
||||
case "display-p3":
|
||||
op.ColorSpace = ebiten.ColorSpaceDisplayP3
|
||||
}
|
||||
op.InitUnfocused = !*flagInitFocused
|
||||
op.ScreenTransparent = *flagTransparent
|
||||
op.X11ClassName = "Window-Size"
|
||||
|
14
graphics.go
14
graphics.go
@ -72,3 +72,17 @@ type DebugInfo struct {
|
||||
func ReadDebugInfo(d *DebugInfo) {
|
||||
d.GraphicsLibrary = GraphicsLibrary(ui.Get().GraphicsLibrary())
|
||||
}
|
||||
|
||||
// ColorSpace represents the color space of the screen.
|
||||
type ColorSpace int
|
||||
|
||||
const (
|
||||
// ColorSpaceDefault represents the default color space.
|
||||
ColorSpaceDefault ColorSpace = iota
|
||||
|
||||
// ColorSpaceSRGB represents the sRGB color space (https://en.wikipedia.org/wiki/SRGB).
|
||||
ColorSpaceSRGB
|
||||
|
||||
// ColorSpaceDisplayP3 represents the Display P3 color space (https://en.wikipedia.org/wiki/DCI-P3).
|
||||
ColorSpaceDisplayP3
|
||||
)
|
||||
|
@ -95,3 +95,11 @@ type Shader interface {
|
||||
}
|
||||
|
||||
type ShaderID int
|
||||
|
||||
type ColorSpace int
|
||||
|
||||
const (
|
||||
ColorSpaceDefault ColorSpace = iota
|
||||
ColorSpaceSRGB
|
||||
ColorSpaceDisplayP3
|
||||
)
|
||||
|
@ -29,6 +29,7 @@ import (
|
||||
"github.com/ebitengine/purego/objc"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/cocoa"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
|
||||
@ -51,7 +52,7 @@ type MetalLayer struct {
|
||||
// NewMetalLayer creates a new Core Animation Metal layer.
|
||||
//
|
||||
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer?language=objc.
|
||||
func NewMetalLayer() (MetalLayer, error) {
|
||||
func NewMetalLayer(colorSpace graphicsdriver.ColorSpace) (MetalLayer, error) {
|
||||
coreGraphics, err := purego.Dlopen("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics", purego.RTLD_LAZY|purego.RTLD_GLOBAL)
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
@ -67,14 +68,31 @@ func NewMetalLayer() (MetalLayer, error) {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
|
||||
var colorSpaceSym uintptr
|
||||
switch colorSpace {
|
||||
case graphicsdriver.ColorSpaceSRGB:
|
||||
kCGColorSpaceSRGB, err := purego.Dlsym(coreGraphics, "kCGColorSpaceSRGB")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
colorSpaceSym = kCGColorSpaceSRGB
|
||||
default:
|
||||
fallthrough
|
||||
case graphicsdriver.ColorSpaceDisplayP3:
|
||||
kCGColorSpaceDisplayP3, err := purego.Dlsym(coreGraphics, "kCGColorSpaceDisplayP3")
|
||||
if err != nil {
|
||||
return MetalLayer{}, err
|
||||
}
|
||||
colorSpaceSym = kCGColorSpaceDisplayP3
|
||||
}
|
||||
|
||||
layer := objc.ID(objc.GetClass("CAMetalLayer")).Send(objc.RegisterName("new"))
|
||||
// setColorspace: is available from iOS 13.0?
|
||||
// https://github.com/hajimehoshi/ebiten/commit/3af351a2aa31e30affd433429c42130015b302f3
|
||||
// TODO: Enable this on iOS as well.
|
||||
if runtime.GOOS != "ios" {
|
||||
colorspace, _, _ := purego.SyscallN(cgColorSpaceCreateWithName, **(**uintptr)(unsafe.Pointer(&kCGColorSpaceDisplayP3))) // Dlsym returns pointer to symbol so dereference it
|
||||
// Dlsym returns pointer to symbol so dereference it.
|
||||
colorspace, _, _ := purego.SyscallN(cgColorSpaceCreateWithName, **(**uintptr)(unsafe.Pointer(&colorSpaceSym)))
|
||||
layer.Send(objc.RegisterName("setColorspace:"), colorspace)
|
||||
purego.SyscallN(cgColorSpaceRelease, colorspace)
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ import (
|
||||
type Graphics struct {
|
||||
view view
|
||||
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
|
||||
cq mtl.CommandQueue
|
||||
cb mtl.CommandBuffer
|
||||
rce mtl.RenderCommandEncoder
|
||||
@ -90,7 +92,7 @@ func init() {
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for Metal.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
func NewGraphics(colorSpace graphicsdriver.ColorSpace) (graphicsdriver.Graphics, error) {
|
||||
// On old mac devices like iMac 2011, Metal is not supported (#779).
|
||||
// TODO: Is there a better way to check whether Metal is available or not?
|
||||
// It seems OK to call MTLCreateSystemDefaultDevice multiple times, so this should be fine.
|
||||
@ -98,12 +100,14 @@ func NewGraphics() (graphicsdriver.Graphics, error) {
|
||||
return nil, fmt.Errorf("metal: mtl.CreateSystemDefaultDevice failed: %w", systemDefaultDeviceErr)
|
||||
}
|
||||
|
||||
g := &Graphics{}
|
||||
g := &Graphics{
|
||||
colorSpace: colorSpace,
|
||||
}
|
||||
|
||||
if runtime.GOOS != "ios" {
|
||||
// Initializing a Metal device and a layer must be done in the main thread on macOS.
|
||||
// Note that this assumes NewGraphics is called on the main thread on desktops.
|
||||
if err := g.view.initialize(systemDefaultDevice); err != nil {
|
||||
if err := g.view.initialize(systemDefaultDevice, colorSpace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -388,7 +392,7 @@ func (g *Graphics) Initialize() error {
|
||||
|
||||
if runtime.GOOS == "ios" {
|
||||
// Initializing a Metal device and a layer must be done in the render thread on iOS.
|
||||
if err := g.view.initialize(systemDefaultDevice); err != nil {
|
||||
if err := g.view.initialize(systemDefaultDevice, g.colorSpace); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package metal
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/ca"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/metal/mtl"
|
||||
)
|
||||
@ -58,10 +59,10 @@ func (v *view) colorPixelFormat() mtl.PixelFormat {
|
||||
return v.ml.PixelFormat()
|
||||
}
|
||||
|
||||
func (v *view) initialize(device mtl.Device) error {
|
||||
func (v *view) initialize(device mtl.Device, colorSpace graphicsdriver.ColorSpace) error {
|
||||
v.device = device
|
||||
|
||||
ml, err := ca.NewMetalLayer()
|
||||
ml, err := ca.NewMetalLayer(colorSpace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ type graphicsPlatform struct {
|
||||
|
||||
// NewGraphics creates an implementation of graphicsdriver.Graphics for OpenGL.
|
||||
// The returned graphics value is nil iff the error is not nil.
|
||||
func NewGraphics(canvas js.Value) (graphicsdriver.Graphics, error) {
|
||||
func NewGraphics(canvas js.Value, colorSpace graphicsdriver.ColorSpace) (graphicsdriver.Graphics, error) {
|
||||
var glContext js.Value
|
||||
|
||||
attr := js.Global().Get("Object").New()
|
||||
@ -41,6 +41,13 @@ func NewGraphics(canvas js.Value) (graphicsdriver.Graphics, error) {
|
||||
return nil, fmt.Errorf("opengl: getContext for webgl2 failed")
|
||||
}
|
||||
|
||||
switch colorSpace {
|
||||
case graphicsdriver.ColorSpaceSRGB:
|
||||
glContext.Set("drawingBufferColorSpace", "srgb")
|
||||
case graphicsdriver.ColorSpaceDisplayP3:
|
||||
glContext.Set("drawingBufferColorSpace", "display-p3")
|
||||
}
|
||||
|
||||
ctx, err := gl.NewDefaultContext(glContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
_ "github.com/ebitengine/hideconsole"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/atlas"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/mipmap"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/thread"
|
||||
)
|
||||
@ -177,6 +178,7 @@ type RunOptions struct {
|
||||
SkipTaskbar bool
|
||||
SingleThread bool
|
||||
DisableHiDPI bool
|
||||
ColorSpace graphicsdriver.ColorSpace
|
||||
X11ClassName string
|
||||
X11InstanceName string
|
||||
}
|
||||
|
@ -95,6 +95,7 @@ import (
|
||||
)
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, GraphicsLibrary, error) {
|
||||
|
@ -167,6 +167,7 @@ func (u *UserInterface) initializePlatform() error {
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
transparent bool
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, GraphicsLibrary, error) {
|
||||
@ -189,8 +190,8 @@ func (*graphicsDriverCreatorImpl) newDirectX() (graphicsdriver.Graphics, error)
|
||||
return nil, errors.New("ui: DirectX is not supported in this environment")
|
||||
}
|
||||
|
||||
func (*graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
|
||||
return metal.NewGraphics()
|
||||
func (g *graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
|
||||
return metal.NewGraphics(g.colorSpace)
|
||||
}
|
||||
|
||||
func (*graphicsDriverCreatorImpl) newPlayStation5() (graphicsdriver.Graphics, error) {
|
||||
|
@ -1089,6 +1089,7 @@ func (u *UserInterface) initOnMainThread(options *RunOptions) error {
|
||||
|
||||
g, lib, err := newGraphicsDriver(&graphicsDriverCreatorImpl{
|
||||
transparent: options.ScreenTransparent,
|
||||
colorSpace: options.ColorSpace,
|
||||
}, options.GraphicsLibrary)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
)
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, GraphicsLibrary, error) {
|
||||
@ -57,7 +58,7 @@ func (*graphicsDriverCreatorImpl) newDirectX() (graphicsdriver.Graphics, error)
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newMetal() (graphicsdriver.Graphics, error) {
|
||||
return metal.NewGraphics()
|
||||
return metal.NewGraphics(g.colorSpace)
|
||||
}
|
||||
|
||||
func (*graphicsDriverCreatorImpl) newPlayStation5() (graphicsdriver.Graphics, error) {
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
canvas js.Value
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, GraphicsLibrary, error) {
|
||||
@ -38,7 +39,7 @@ func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, Graphics
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newOpenGL() (graphicsdriver.Graphics, error) {
|
||||
return opengl.NewGraphics(g.canvas)
|
||||
return opengl.NewGraphics(g.canvas, g.colorSpace)
|
||||
}
|
||||
|
||||
func (*graphicsDriverCreatorImpl) newDirectX() (graphicsdriver.Graphics, error) {
|
||||
@ -772,6 +773,7 @@ func (u *UserInterface) initOnMainThread(options *RunOptions) error {
|
||||
|
||||
g, lib, err := newGraphicsDriver(&graphicsDriverCreatorImpl{
|
||||
canvas: canvas,
|
||||
colorSpace: options.ColorSpace,
|
||||
}, options.GraphicsLibrary)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -36,6 +36,7 @@ func (u *UserInterface) initializePlatform() error {
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
transparent bool
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, GraphicsLibrary, error) {
|
||||
|
@ -143,7 +143,9 @@ func (u *UserInterface) runMobile(game Game, options *RunOptions) (err error) {
|
||||
|
||||
u.context = newContext(game)
|
||||
|
||||
g, lib, err := newGraphicsDriver(&graphicsDriverCreatorImpl{}, options.GraphicsLibrary)
|
||||
g, lib, err := newGraphicsDriver(&graphicsDriverCreatorImpl{
|
||||
colorSpace: options.ColorSpace,
|
||||
}, options.GraphicsLibrary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ func (u *UserInterface) initializePlatform() error {
|
||||
|
||||
type graphicsDriverCreatorImpl struct {
|
||||
transparent bool
|
||||
colorSpace graphicsdriver.ColorSpace
|
||||
}
|
||||
|
||||
func (g *graphicsDriverCreatorImpl) newAuto() (graphicsdriver.Graphics, GraphicsLibrary, error) {
|
||||
|
10
run.go
10
run.go
@ -22,6 +22,7 @@ import (
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/clock"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
|
||||
"github.com/hajimehoshi/ebiten/v2/internal/ui"
|
||||
)
|
||||
|
||||
@ -283,6 +284,14 @@ type RunGameOptions struct {
|
||||
// The default (zero) value is false, which means that HiDPI is enabled.
|
||||
DisableHiDPI bool
|
||||
|
||||
// ColorSpace indicates the color space of the screen.
|
||||
//
|
||||
// ColorSpace is available only with some graphics libraries (macOS Metal and WebGL so far).
|
||||
// Otherwise, ColorSpace is ignored.
|
||||
//
|
||||
// The default (zero) value is ColorSpaceDefault, which means that color space depends on the environment.
|
||||
ColorSpace ColorSpace
|
||||
|
||||
// X11DisplayName is a class name in the ICCCM WM_CLASS window property.
|
||||
X11ClassName string
|
||||
|
||||
@ -713,6 +722,7 @@ func toUIRunOptions(options *RunGameOptions) *ui.RunOptions {
|
||||
SkipTaskbar: options.SkipTaskbar,
|
||||
SingleThread: options.SingleThread,
|
||||
DisableHiDPI: options.DisableHiDPI,
|
||||
ColorSpace: graphicsdriver.ColorSpace(options.ColorSpace),
|
||||
X11ClassName: options.X11ClassName,
|
||||
X11InstanceName: options.X11InstanceName,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user