Permalink
Browse files

[WIP] Add Metal implementation

  • Loading branch information...
hajimehoshi committed Nov 12, 2018
1 parent 62210c8 commit 7cbfbdb64626fed7dc5db52b55781bf9df0e75a8
@@ -2,6 +2,7 @@
Andrew Gerrand <nf@wh3rd.net>
Ben Echols <lologarithm@gmail.com>
Brett Chalupa <brett@brettchalupa.com>
Dmitri Shuralyov <dmitri@shuralyov.com>
Evan Leis <explodes@users.noreply.github.com>
Floppy <voidcrystal200@gmail.com>
gonutz <gonutz@users.noreply.github.com>
@@ -16,6 +16,7 @@ package ebiten
import (
"math"
"runtime"
"github.com/hajimehoshi/ebiten/internal/clock"
"github.com/hajimehoshi/ebiten/internal/hooks"
@@ -86,6 +87,11 @@ func (c *graphicsContext) initializeIfNeeded() error {
return nil
}
// TODO: Merge this and ui.useGL
func useGL() bool {
return runtime.GOOS != "darwin"
}
func (c *graphicsContext) Update(afterFrameUpdate func()) error {
tps := int(MaxTPS())
updateCount := clock.Update(tps)
@@ -122,11 +128,18 @@ func (c *graphicsContext) Update(afterFrameUpdate func()) error {
}
op := &DrawImageOptions{}
// c.screen is special: its Y axis is down to up,
// and the origin point is lower left.
op.GeoM.Scale(c.screenScale, -c.screenScale)
// Make the screen height an even number to fit the upper side of the screen (#662).
op.GeoM.Translate(0, float64((c.screenHeight+1)/2*2))
// Texel (uv) directions are different among GL or others.
if useGL() {
// c.screen is special: its Y axis is down to up,
// and the origin point is lower left.
op.GeoM.Scale(c.screenScale, -c.screenScale)
// Make the screen height an even number to fit the upper side of the screen (#662).
op.GeoM.Translate(0, float64((c.screenHeight+1)/2*2))
} else {
op.GeoM.Scale(c.screenScale, c.screenScale)
}
op.GeoM.Translate(c.offsetX, c.offsetY)
op.CompositeMode = CompositeModeCopy
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !darwin ios
package graphicscommand
import (
@@ -0,0 +1,26 @@
// Copyright 2018 The Ebiten 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.
// +build darwin,!ios
package graphicscommand
import (
"github.com/hajimehoshi/ebiten/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal"
)
func driver() graphicsdriver.GraphicsDriver {
return metal.Get()
}
@@ -0,0 +1,5 @@
These packages are copied from Dmitri Shuralyov's mtl packages and edited with Dmitri's permission:
* `github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/ca` (copied from `dmitri.shuralyov.com/gpu/mtl/example/movingtriangle/internal/ca`)
* `github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl` (copied from `dmitri.shuralyov.com/gpu/mtl`)
* `github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/ns` (copied from `dmitri.shuralyov.com/gpu/mtl/example/movingtriangle/internal/ns`)
@@ -0,0 +1,150 @@
// Copyright 2018 The Ebiten 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.
// +build darwin
// Package ca provides access to Apple's Core Animation API (https://developer.apple.com/documentation/quartzcore).
//
// This package is in very early stages of development.
// It's a minimal implementation with scope limited to
// supporting the movingtriangle example.
package ca
import (
"errors"
"unsafe"
"github.com/hajimehoshi/ebiten/internal/graphicsdriver/metal/mtl"
)
// #cgo LDFLAGS: -framework QuartzCore -framework Foundation
//
// #include "ca.h"
import "C"
// Layer is an object that manages image-based content and
// allows you to perform animations on that content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/calayer.
type Layer interface {
// Layer returns the underlying CALayer * pointer.
Layer() unsafe.Pointer
}
// MetalLayer is a Core Animation Metal layer, a layer that manages a pool of Metal drawables.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
type MetalLayer struct {
metalLayer unsafe.Pointer
}
// MakeMetalLayer creates a new Core Animation Metal layer.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer.
func MakeMetalLayer() MetalLayer {
return MetalLayer{C.MakeMetalLayer()}
}
// Layer implements the Layer interface.
func (ml MetalLayer) Layer() unsafe.Pointer { return ml.metalLayer }
// PixelFormat returns the pixel format of textures for rendering layer content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
func (ml MetalLayer) PixelFormat() mtl.PixelFormat {
return mtl.PixelFormat(C.MetalLayer_PixelFormat(ml.metalLayer))
}
// SetDevice sets the Metal device responsible for the layer's drawable resources.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478163-device.
func (ml MetalLayer) SetDevice(device mtl.Device) {
C.MetalLayer_SetDevice(ml.metalLayer, device.Device())
}
// SetPixelFormat controls the pixel format of textures for rendering layer content.
//
// The pixel format for a Metal layer must be PixelFormatBGRA8UNorm, PixelFormatBGRA8UNormSRGB,
// PixelFormatRGBA16Float, PixelFormatBGRA10XR, or PixelFormatBGRA10XRSRGB.
// SetPixelFormat panics for other values.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478155-pixelformat.
func (ml MetalLayer) SetPixelFormat(pf mtl.PixelFormat) {
e := C.MetalLayer_SetPixelFormat(ml.metalLayer, C.uint16_t(pf))
if e != nil {
panic(errors.New(C.GoString(e)))
}
}
// SetMaximumDrawableCount controls the number of Metal drawables in the resource pool
// managed by Core Animation.
//
// It can set to 2 or 3 only. SetMaximumDrawableCount panics for other values.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2938720-maximumdrawablecount.
func (ml MetalLayer) SetMaximumDrawableCount(count int) {
e := C.MetalLayer_SetMaximumDrawableCount(ml.metalLayer, C.uint_t(count))
if e != nil {
panic(errors.New(C.GoString(e)))
}
}
// SetDisplaySyncEnabled controls whether the Metal layer and its drawables
// are synchronized with the display's refresh rate.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/2887087-displaysyncenabled.
func (ml MetalLayer) SetDisplaySyncEnabled(enabled bool) {
switch enabled {
case true:
C.MetalLayer_SetDisplaySyncEnabled(ml.metalLayer, 1)
case false:
C.MetalLayer_SetDisplaySyncEnabled(ml.metalLayer, 0)
}
}
// SetDrawableSize sets the size, in pixels, of textures for rendering layer content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478174-drawablesize.
func (ml MetalLayer) SetDrawableSize(width, height int) {
C.MetalLayer_SetDrawableSize(ml.metalLayer, C.double(width), C.double(height))
}
// NextDrawable returns a Metal drawable.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametallayer/1478172-nextdrawable.
func (ml MetalLayer) NextDrawable() (MetalDrawable, error) {
md := C.MetalLayer_NextDrawable(ml.metalLayer)
if md == nil {
return MetalDrawable{}, errors.New("nextDrawable returned nil")
}
return MetalDrawable{md}, nil
}
// MetalDrawable is a displayable resource that can be rendered or written to by Metal.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable.
type MetalDrawable struct {
metalDrawable unsafe.Pointer
}
// Drawable implements the mtl.Drawable interface.
func (md MetalDrawable) Drawable() unsafe.Pointer { return md.metalDrawable }
// Texture returns a Metal texture object representing the drawable object's content.
//
// Reference: https://developer.apple.com/documentation/quartzcore/cametaldrawable/1478159-texture.
func (md MetalDrawable) Texture() mtl.Texture {
return mtl.NewTexture(C.MetalDrawable_Texture(md.metalDrawable))
}
@@ -0,0 +1,33 @@
// Copyright 2018 The Ebiten 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.
// +build darwin
typedef signed char BOOL;
typedef unsigned long uint_t;
typedef unsigned short uint16_t;
void *MakeMetalLayer();
uint16_t MetalLayer_PixelFormat(void *metalLayer);
void MetalLayer_SetDevice(void *metalLayer, void *device);
const char *MetalLayer_SetPixelFormat(void *metalLayer, uint16_t pixelFormat);
const char *MetalLayer_SetMaximumDrawableCount(void *metalLayer,
uint_t maximumDrawableCount);
void MetalLayer_SetDisplaySyncEnabled(void *metalLayer,
BOOL displaySyncEnabled);
void MetalLayer_SetDrawableSize(void *metalLayer, double width, double height);
void *MetalLayer_NextDrawable(void *metalLayer);
void *MetalDrawable_Texture(void *drawable);
@@ -0,0 +1,67 @@
// Copyright 2018 The Ebiten 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.
// +build darwin
#include "ca.h"
#import <QuartzCore/QuartzCore.h>
void *MakeMetalLayer() { return [[CAMetalLayer alloc] init]; }
uint16_t MetalLayer_PixelFormat(void *metalLayer) {
return ((CAMetalLayer *)metalLayer).pixelFormat;
}
void MetalLayer_SetDevice(void *metalLayer, void *device) {
((CAMetalLayer *)metalLayer).device = (id<MTLDevice>)device;
}
const char *MetalLayer_SetPixelFormat(void *metalLayer, uint16_t pixelFormat) {
@try {
((CAMetalLayer *)metalLayer).pixelFormat = (MTLPixelFormat)pixelFormat;
} @catch (NSException *exception) {
return exception.reason.UTF8String;
}
return NULL;
}
const char *MetalLayer_SetMaximumDrawableCount(void *metalLayer,
uint_t maximumDrawableCount) {
if (@available(macOS 10.13.2, *)) {
@try {
((CAMetalLayer *)metalLayer).maximumDrawableCount =
(NSUInteger)maximumDrawableCount;
} @catch (NSException *exception) {
return exception.reason.UTF8String;
}
}
return NULL;
}
void MetalLayer_SetDisplaySyncEnabled(void *metalLayer,
BOOL displaySyncEnabled) {
((CAMetalLayer *)metalLayer).displaySyncEnabled = displaySyncEnabled;
}
void MetalLayer_SetDrawableSize(void *metalLayer, double width, double height) {
((CAMetalLayer *)metalLayer).drawableSize = (CGSize){width, height};
}
void *MetalLayer_NextDrawable(void *metalLayer) {
return [(CAMetalLayer *)metalLayer nextDrawable];
}
void *MetalDrawable_Texture(void *metalDrawable) {
return ((id<CAMetalDrawable>)metalDrawable).texture;
}
Oops, something went wrong.

0 comments on commit 7cbfbdb

Please sign in to comment.