Skip to content

Commit

Permalink
chore: Updates based on new OpenEmuShaders
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartcarnie committed Aug 3, 2022
1 parent e217cec commit 382ebf7
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 96 deletions.
12 changes: 8 additions & 4 deletions OpenEmuKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
0572A42C287BEA3800AC32F8 /* NSXPCConnection+HelperApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0572A42B287BEA3800AC32F8 /* NSXPCConnection+HelperApp.swift */; };
0572A42E287CD66A00AC32F8 /* NSXPCListener+HelperApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0572A42D287CD66A00AC32F8 /* NSXPCListener+HelperApp.swift */; };
0578484B25C1392400A842E7 /* ShaderCompilerOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0578484A25C1392300A842E7 /* ShaderCompilerOptions.swift */; };
05796B2528723C750007E415 /* MTLGameRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05796B2428723C750007E415 /* MTLGameRenderer.swift */; };
05796B2728727F790007E415 /* MTLGameRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05796B2628727F790007E415 /* MTLGameRenderer.swift */; };
05796B2B28738FFE0007E415 /* CoreVideoTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05796B2A28738FFE0007E415 /* CoreVideoTexture.swift */; };
057E7FED28755CB100BC1C04 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057E7FEC28755CB100BC1C04 /* Logging.swift */; };
057E7FEF28762D4700BC1C04 /* OpenGL2GameRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 057E7FEE28762D4700BC1C04 /* OpenGL2GameRenderer.swift */; };
Expand All @@ -59,6 +59,7 @@
05C40F8826F69B6F0072B722 /* ShaderParamValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C40F8726F69B6F0072B722 /* ShaderParamValue.swift */; };
05C40F8A26F6A72F0072B722 /* ApproximatelyEqual.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05C40F8926F6A72F0072B722 /* ApproximatelyEqual.swift */; };
05D53292289330FF004DC253 /* OpenGLGameRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05D53291289330FF004DC253 /* OpenGLGameRenderer.swift */; };
05D532942895F73C004DC253 /* ScreenShot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05D532932895F73C004DC253 /* ScreenShot.swift */; };
05D828D524E9881E00BB975E /* OEXPCMatchMaking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05D828D424E9881E00BB975E /* OEXPCMatchMaking.swift */; };
05D828DB24E98A8E00BB975E /* OEXPCMatchMaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05D828DA24E98A8E00BB975E /* OEXPCMatchMaker.swift */; };
05E6958424CA5D4200ACFB35 /* OpenEmuKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 05E6958224CA5D4200ACFB35 /* OpenEmuKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -152,7 +153,7 @@
0572A42B287BEA3800AC32F8 /* NSXPCConnection+HelperApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSXPCConnection+HelperApp.swift"; sourceTree = "<group>"; };
0572A42D287CD66A00AC32F8 /* NSXPCListener+HelperApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSXPCListener+HelperApp.swift"; sourceTree = "<group>"; };
0578484A25C1392300A842E7 /* ShaderCompilerOptions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShaderCompilerOptions.swift; sourceTree = "<group>"; };
05796B2428723C750007E415 /* MTLGameRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MTLGameRenderer.swift; sourceTree = "<group>"; };
05796B2628727F790007E415 /* MTLGameRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTLGameRenderer.swift; sourceTree = "<group>"; };
05796B2A28738FFE0007E415 /* CoreVideoTexture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreVideoTexture.swift; sourceTree = "<group>"; };
057E7FEA28755C5600BC1C04 /* OpenEmuHelperApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenEmuHelperApp.swift; sourceTree = "<group>"; };
057E7FEC28755CB100BC1C04 /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
Expand All @@ -165,6 +166,7 @@
05C40F8726F69B6F0072B722 /* ShaderParamValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShaderParamValue.swift; sourceTree = "<group>"; };
05C40F8926F6A72F0072B722 /* ApproximatelyEqual.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApproximatelyEqual.swift; sourceTree = "<group>"; };
05D53291289330FF004DC253 /* OpenGLGameRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGLGameRenderer.swift; sourceTree = "<group>"; };
05D532932895F73C004DC253 /* ScreenShot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenShot.swift; sourceTree = "<group>"; };
05D828D424E9881E00BB975E /* OEXPCMatchMaking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OEXPCMatchMaking.swift; sourceTree = "<group>"; };
05D828DA24E98A8E00BB975E /* OEXPCMatchMaker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OEXPCMatchMaker.swift; sourceTree = "<group>"; };
05E6957F24CA5D4200ACFB35 /* OpenEmuKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenEmuKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -336,6 +338,7 @@
05E6B9FF24CCD47400ACFB35 /* Video */,
057E7FEA28755C5600BC1C04 /* OpenEmuHelperApp.swift */,
0572A4002877883100AC32F8 /* OpenEmuXPCHelperApp.swift */,
05D532932895F73C004DC253 /* ScreenShot.swift */,
);
name = "Helper App (Remote Layer)";
sourceTree = "<group>";
Expand All @@ -344,7 +347,7 @@
isa = PBXGroup;
children = (
0572A4122878D76C00AC32F8 /* GameRenderer.swift */,
05796B2428723C750007E415 /* MTLGameRenderer.swift */,
05796B2628727F790007E415 /* MTLGameRenderer.swift */,
05796B2A28738FFE0007E415 /* CoreVideoTexture.swift */,
05D53291289330FF004DC253 /* OpenGLGameRenderer.swift */,
057E7FEE28762D4700BC1C04 /* OpenGL2GameRenderer.swift */,
Expand Down Expand Up @@ -633,6 +636,7 @@
buildActionMask = 2147483647;
files = (
05EEF0F22707C875008A03DC /* ShaderPresetData.swift in Sources */,
05796B2728727F790007E415 /* MTLGameRenderer.swift in Sources */,
057E7FF2287630C000BC1C04 /* OpenEmuHelperApp.swift in Sources */,
05D828D524E9881E00BB975E /* OEXPCMatchMaking.swift in Sources */,
057E7FEF28762D4700BC1C04 /* OpenGL2GameRenderer.swift in Sources */,
Expand All @@ -650,9 +654,9 @@
05E6BA3E24CCD79600ACFB35 /* OEThreadProxy.m in Sources */,
05E6BA3D24CCD79600ACFB35 /* OELogging.m in Sources */,
05201D672777EA910028CBE0 /* OESystemShaderStore.swift in Sources */,
05796B2528723C750007E415 /* MTLGameRenderer.swift in Sources */,
05AAD98726758240004466E3 /* XPCDebugSupport.swift in Sources */,
05ED1CFC259D43E800A2D400 /* LaunchControl.swift in Sources */,
05D532942895F73C004DC253 /* ScreenShot.swift in Sources */,
8F3A1837285C9F88008A7AC9 /* NSBundle+CacheFlushing.m in Sources */,
0547FD9824E7717E005C1FFC /* OEShaderStore.swift in Sources */,
05201D73277D82920028CBE0 /* ShaderPresetStorage.swift in Sources */,
Expand Down
39 changes: 15 additions & 24 deletions Source/CoreVideoTexture.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,22 @@ import CoreVideo

// source: https://developer.apple.com/documentation/metal/mixing_metal_and_opengl_rendering_in_a_view

@objc public class CoreVideoTexture: NSObject {
final class CoreVideoTexture {
let mtlPixelFormat: MTLPixelFormat
let cvPixelFormat: OSType
let metalDevice: MTLDevice

@objc public init(metalPixelFormat mtlPixelFormat: MTLPixelFormat) {
public init(device: MTLDevice, metalPixelFormat mtlPixelFormat: MTLPixelFormat) {
guard let cv = Self.metalToCVMap[mtlPixelFormat]
else { fatalError("Unsupported Metal pixel format") }
self.metalDevice = device
self.mtlPixelFormat = mtlPixelFormat
self.cvPixelFormat = cv
super.init()
}

var cvPixelBuffer: CVPixelBuffer?

@objc public var size: CGSize = .zero {
var size: CGSize = .zero {
didSet {
let cvBufferProperties = [
kCVPixelBufferOpenGLCompatibilityKey: true,
Expand All @@ -61,34 +62,24 @@ import CoreVideo
createGLTexture(context: openGLContext)
}

if let metalDevice = metalDevice {
createMetalTexture(device: metalDevice)
}
createMetalTexture(device: metalDevice)
}
}

// MARK: - Metal resources

@objc public var metalDevice: MTLDevice? {
didSet {
if let metalDevice = metalDevice {
createMetalTexture(device: metalDevice)
}
}
}

@objc public var metalTexture: MTLTexture?
var metalTexture: MTLTexture?

var cvMTLTextureCache: CVMetalTextureCache?
var cvMTLTexture: CVMetalTexture?

func releaseMetalTexture() {
private func releaseMetalTexture() {
metalTexture = nil
cvMTLTexture = nil
cvMTLTextureCache = nil
}

func createMetalTexture(device: MTLDevice) {
private func createMetalTexture(device: MTLDevice) {
releaseMetalTexture()
guard size != .zero else { return }

Expand Down Expand Up @@ -125,7 +116,7 @@ import CoreVideo
}
}

@objc public var metalTextureIsFlipped: Bool {
var metalTextureIsFlippedVertically: Bool {
if let cvMTLTexture = cvMTLTexture {
return CVMetalTextureIsFlipped(cvMTLTexture)
}
Expand All @@ -134,27 +125,27 @@ import CoreVideo

// MARK: - OpenGL resources

@objc public var openGLContext: CGLContextObj? {
var openGLContext: CGLContextObj? {
didSet {
if let openGLContext = openGLContext {
cglPixelFormat = CGLGetPixelFormat(openGLContext)
createGLTexture(context: openGLContext)
}
}
}
@objc public var openGLTexture: GLuint = 0
var openGLTexture: GLuint = 0

var cvGLTextureCache: CVOpenGLTextureCache?
var cvGLTexture: CVOpenGLTexture?
var cglPixelFormat: CGLPixelFormatObj?

func releaseGLTexture() {
private func releaseGLTexture() {
openGLTexture = 0
cvGLTexture = nil
cvGLTextureCache = nil
}

func createGLTexture(context: CGLContextObj) {
private func createGLTexture(context: CGLContextObj) {
releaseGLTexture()

guard size != .zero else { return }
Expand Down Expand Up @@ -190,7 +181,7 @@ import CoreVideo

// source: https://developer.apple.com/documentation/metal/mixing_metal_and_opengl_rendering_in_a_view

static let metalToCVMap: [MTLPixelFormat: OSType] = [
private static let metalToCVMap: [MTLPixelFormat: OSType] = [
.bgra8Unorm: kCVPixelFormatType_32BGRA,
.bgr10a2Unorm: kCVPixelFormatType_ARGB2101010LEPacked,
.bgra8Unorm_srgb: kCVPixelFormatType_32BGRA,
Expand Down
8 changes: 5 additions & 3 deletions Source/GameRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@

import Foundation
import OpenEmuBase
import Metal

protocol GameRenderer {
var gameCore: OEGameCore { get }
var surfaceSize: OEIntSize { get }

/// The current rendered texture that may be displayed or filtered
// var renderedTexture: MTLTexture { get }

var canChangeBufferSize: Bool { get }

/// Called when the gameCore or image render dimensions have changed.
Expand All @@ -42,6 +40,10 @@ protocol GameRenderer {
func willExecuteFrame()
func didExecuteFrame()

/// Called after the core has executed the next frame and prior filters being applied to the ``renderTexture``.
/// - Returns: A texture containing the core's output in ``Metal.MTLPixelFormat.bgra8Unorm`` format.
func prepareFrameForRender(commandBuffer: MTLCommandBuffer) -> MTLTexture?

func suspendFPSLimiting()
func resumeFPSLimiting()
}
Expand Down
86 changes: 56 additions & 30 deletions Source/MTLGameRenderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,51 +30,68 @@ import OpenGL
final class MTLGameRenderer: GameRenderer {
var surfaceSize: OEIntSize { gameCore.bufferSize }
let gameCore: OEGameCore
private(set) var renderTexture: MTLTexture?

var buffer: PixelBuffer!
private let device: MTLDevice
private let converter: MTLPixelConverter
private var buffer: PixelBuffer!
private var texture: MTLTexture!

private let filterChain: FilterChain

init(withFilterChain filterChain: FilterChain, gameCore: OEGameCore) {
self.filterChain = filterChain
init(withDevice device: MTLDevice, gameCore: OEGameCore) throws {
self.device = device
self.converter = try .init(device: device)
self.gameCore = gameCore
}

func update() {
precondition(gameCore.gameCoreRendering == .rendering2DVideo, "Metal only supports 2D rendering")
setup2D()
}

private func setup2D() {

let pixelFormat = gameCore.pixelFormat
let pixelType = gameCore.pixelType
guard let pf = glToRPixelFormat(pixelFormat: pixelFormat, pixelType: pixelType) else {
fatalError("Invalid pixel format")
}

let rect = gameCore.screenRect
let sourceRect = CGRect(x: CGFloat(rect.origin.x), y: CGFloat(rect.origin.y),
width: CGFloat(rect.size.width), height: CGFloat(rect.size.height))
let aspectSize = CGSize(width: CGFloat(gameCore.aspectSize.width),
height: CGFloat(gameCore.aspectSize.height))
filterChain.setSourceRect(sourceRect, aspect: aspectSize)


// bufferSize is fixed for 2D, so doesn't need to be reallocated.
if buffer != nil { return }

let bufferSize = gameCore.bufferSize
let bytesPerRow = gameCore.bytesPerRow

buffer = filterChain.newBuffer(withFormat: pf, height: UInt(bufferSize.height), bytesPerRow: UInt(bytesPerRow))
let buf = UnsafeMutableRawPointer(mutating: gameCore.getVideoBuffer(withHint: buffer.contents))
if buf != buffer.contents {
buffer = filterChain.newBuffer(withFormat: pf,
height: UInt(bufferSize.height),
bytesPerRow: UInt(bytesPerRow),
bytes: buf)
if buffer == nil {
let bufferSize = gameCore.bufferSize
let bytesPerRow = gameCore.bytesPerRow

buffer = PixelBuffer.makeBuffer(withDevice: device,
converter: converter,
format: pf,
height: Int(bufferSize.height),
bytesPerRow: bytesPerRow)

let buf = UnsafeMutableRawPointer(mutating: gameCore.getVideoBuffer(withHint: buffer.contents))
if buf != buffer.contents {
buffer = PixelBuffer.makeBuffer(withDevice: device,
converter: converter,
format: pf,
height: Int(bufferSize.height),
bytesPerRow: bytesPerRow,
bytes: buf)
}
}

guard let buffer = buffer else {
fatalError("buffer == nil")
}

let rect = gameCore.screenRect
let sourceRect = CGRect(x: CGFloat(rect.origin.x), y: CGFloat(rect.origin.y),
width: CGFloat(rect.size.width), height: CGFloat(rect.size.height))
buffer.outputRect = sourceRect

let td = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: .bgra8Unorm,
width: Int(sourceRect.width),
height: Int(sourceRect.height),
mipmapped: false)
td.storageMode = .private
td.usage = [.shaderRead, .shaderWrite]
renderTexture = device.makeTexture(descriptor: td)
}

var canChangeBufferSize: Bool { true }

func willExecuteFrame() {
Expand All @@ -83,6 +100,15 @@ final class MTLGameRenderer: GameRenderer {
}

func didExecuteFrame() { }

func prepareFrameForRender(commandBuffer: MTLCommandBuffer) -> MTLTexture? {
guard let renderTexture = renderTexture else {
return nil
}
buffer.prepare(withCommandBuffer: commandBuffer, texture: renderTexture)
return renderTexture
}

func suspendFPSLimiting() { }
func resumeFPSLimiting() { }

Expand Down
32 changes: 12 additions & 20 deletions Source/OEGameCoreHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,16 @@ import AudioToolbox
case displayAlways
}

/**
* A protocol that defines the behaviour required to control an emulator core.
*
* A host application obtains an instance of @c OEGameCoreHelper in order
* to communicate with the core, which may be running in another thread or
* a remote process.
*/
/// A protocol that defines the behaviour required to control an emulator core.
///
/// A host application obtains an instance of @c OEGameCoreHelper in order
/// to communicate with the core, which may be running in another thread or
/// a remote process.
@objc(OEGameCoreHelper) public protocol OEGameCoreHelper: NSObjectProtocol {

/**
* Adjust the output volume of the core.
* @param value The new volume level, from @c [0,1.0]
*/

/// Adjust the output volume of the core.
///
/// - Parameter value: The new volume level, from @c [0,1.0]
func setVolume(_ value: Float)

/**
Expand All @@ -66,8 +63,7 @@ import AudioToolbox
func setOutputBounds(_ rect: NSRect)
func setBackingScaleFactor(_ newBackingScaleFactor: CGFloat)

/** Controls whether the renderer should use a variable refresh rate.
*/
/// Controls whether the renderer should use a variable refresh rate.
func setAdaptiveSyncEnabled(_ enabled: Bool)
func setShaderURL(_ url: URL, parameters: [String: NSNumber]?, completionHandler block: @escaping (Error?) -> Void)
func setShaderParameterValue(_ value: CGFloat, forKey key: String)
Expand All @@ -88,13 +84,9 @@ import AudioToolbox
func systemBindingsDidSetEvent(_ event: OEHIDEvent, forBinding bindingDescription: OEBindingDescription, playerNumber: UInt)
func systemBindingsDidUnsetEvent(_ event: OEHIDEvent, forBinding bindingDescription: OEBindingDescription, playerNumber: UInt)

/**
* Capture an image of the core's video display buffer, which includes all shader effects.
*/
/// Capture an image of the core's video display buffer, which includes all shader effects.
func captureOutputImage(completionHandler block: @escaping (NSBitmapImageRep) -> Void)

/**
* Capture an image of the core's raw video display buffer with no effects.
*/
/// Capture an image of the core's raw video display buffer with no effects.
func captureSourceImage(completionHandler block: @escaping (NSBitmapImageRep) -> Void)
}
Loading

0 comments on commit 382ebf7

Please sign in to comment.