#pragma once #include #ifdef __OBJC__ @class CAEAGLLayer; @class EAGLContext; #else typedef struct objc_object CAEAGLLayer; typedef struct objc_object EAGLContext; #endif #ifdef __OBJC__ @class CAMetalLayer; @protocol CAMetalDrawable; @protocol MTLDrawable; @protocol MTLDevice; @protocol MTLTexture; @protocol MTLCommandBuffer; @protocol MTLCommandQueue; @protocol MTLCommandEncoder; typedef id CAMetalDrawableRef; typedef id MTLDeviceRef; typedef id MTLTextureRef; typedef id MTLCommandBufferRef; typedef id MTLCommandQueueRef; typedef id MTLCommandEncoderRef; #else typedef struct objc_object CAMetalLayer; typedef struct objc_object* CAMetalDrawableRef; typedef struct objc_object* MTLDeviceRef; typedef struct objc_object* MTLTextureRef; typedef struct objc_object* MTLCommandBufferRef; typedef struct objc_object* MTLCommandQueueRef; typedef struct objc_object* MTLCommandEncoderRef; #endif // unity internal native render buffer struct (the one you acquire in C# with RenderBuffer.GetNativeRenderBufferPtr()) struct RenderSurfaceBase; typedef struct RenderSurfaceBase* UnityRenderBufferHandle; // be aware that this struct is shared with unity implementation so you should absolutely not change it typedef struct UnityRenderBufferDesc { unsigned width, height, depth; unsigned samples; int backbuffer; } UnityRenderBufferDesc; // trick to make structure inheritance work transparently between c/cpp // for c we use "anonymous struct" #ifdef __cplusplus #define START_STRUCT(T, Base) struct T : Base { #define END_STRUCT(T) }; #else #define START_STRUCT(T, Base) typedef struct T { struct Base; #define END_STRUCT(T) } T; #endif // we will keep objc objects in struct, so we need to explicitely mark references as strong to not confuse ARC // please note that actual object lifetime is managed in objc++ code, so __unsafe_unretained is good enough for objc code // DO NOT assign objects to UnityDisplaySurface* members in objc code. // DO NOT store objects from UnityDisplaySurface* members in objc code, as this wont be caught by ARC #ifdef __OBJC__ #ifdef __cplusplus #define OBJC_OBJECT_PTR __strong #else #define OBJC_OBJECT_PTR __unsafe_unretained #endif #else #define OBJC_OBJECT_PTR #endif // unity common rendering (display) surface typedef struct UnityDisplaySurfaceBase { UnityRenderBufferHandle unityColorBuffer; UnityRenderBufferHandle unityDepthBuffer; UnityRenderBufferHandle systemColorBuffer; UnityRenderBufferHandle systemDepthBuffer; void* cvTextureCache; // CVMetalTextureCacheRef void* cvTextureCacheTexture; // CVMetalTextureRef void* cvPixelBuffer; // CVPixelBufferRef unsigned targetW, targetH; unsigned systemW, systemH; int msaaSamples; int useCVTextureCache; // [bool] int srgb; // [bool] int wideColor; // [bool] int hdr; // [bool] int disableDepthAndStencil; // [bool] int allowScreenshot; // [bool] currently we allow screenshots (from script) only on main display int memorylessDepth; // [bool] int api; // [UnityRenderingAPI] } UnityDisplaySurfaceBase; // START_STRUCT confuse clang c compiler (though it is idiomatic c code that works) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-declarations" // on iOS/tvOS: we render to the drawable directly // and we need proxy only to delay acquiring drawable until we actually want to render to the "backbuffer" // thus just one proxy and it will be marked as "empty" (we only need it to query texture params, like extents) // on macOS: we render to the offscreen RT and blit to the drawable, thus we need several proxy RT // and all of them will be full blown textures (with GPU backing) #if PLATFORM_OSX #define kUnityNumOffscreenSurfaces 2 #else #define kUnityNumOffscreenSurfaces 1 #endif // Metal display surface START_STRUCT(UnityDisplaySurfaceMTL, UnityDisplaySurfaceBase) OBJC_OBJECT_PTR CAMetalLayer * layer; OBJC_OBJECT_PTR MTLDeviceRef device; OBJC_OBJECT_PTR MTLCommandQueueRef commandQueue; OBJC_OBJECT_PTR MTLCommandQueueRef drawableCommandQueue; OBJC_OBJECT_PTR MTLCommandBufferRef presentCB; OBJC_OBJECT_PTR CAMetalDrawableRef drawable; OBJC_OBJECT_PTR MTLTextureRef drawableProxyRT[kUnityNumOffscreenSurfaces]; int drawableProxyNeedsClear[kUnityNumOffscreenSurfaces]; // [bool] Tracks whether the drawableProxy requires a clear after initial creation // This is used on a Mac with drawableProxyRT when off-screen rendering is used int proxySwaps; // Counts times proxy RTs have swapped since surface recreated int proxyReady; // [bool] Proxy RT has swapped since last present; frame ended OBJC_OBJECT_PTR MTLTextureRef systemColorRB; OBJC_OBJECT_PTR MTLTextureRef targetColorRT; OBJC_OBJECT_PTR MTLTextureRef targetAAColorRT; OBJC_OBJECT_PTR MTLTextureRef depthRB; OBJC_OBJECT_PTR MTLTextureRef stencilRB; unsigned colorFormat; // [MTLPixelFormat] unsigned depthFormat; // [MTLPixelFormat] int framebufferOnly; END_STRUCT(UnityDisplaySurfaceMTL) // START_STRUCT confuse clang c compiler (though it is idiomatic c code that works) #pragma clang diagnostic pop // be aware that this enum is shared with unity implementation so you should absolutely not change it typedef enum UnityRenderingAPI { apiMetal = 4, // command line argument: -nographics // does not initialize real graphics device and bypass all the rendering // currently supported only on simulators apiNoGraphics = -1, } UnityRenderingAPI; typedef struct RenderingSurfaceParams { // rendering setup int msaaSampleCount; int renderW; int renderH; int srgb; int wideColor; int hdr; int metalFramebufferOnly; int metalMemorylessDepth; // unity setup int disableDepthAndStencil; int useCVTextureCache; } RenderingSurfaceParams; #ifdef __cplusplus extern "C" { #endif int UnitySelectedRenderingAPI(void); #ifdef __cplusplus } // extern "C" #endif // metal #ifdef __cplusplus extern "C" { #endif void InitRenderingMTL(void); void CreateSystemRenderingSurfaceMTL(UnityDisplaySurfaceMTL* surface); void DestroySystemRenderingSurfaceMTL(UnityDisplaySurfaceMTL* surface); void CreateRenderingSurfaceMTL(UnityDisplaySurfaceMTL* surface); void DestroyRenderingSurfaceMTL(UnityDisplaySurfaceMTL* surface); void CreateSharedDepthbufferMTL(UnityDisplaySurfaceMTL* surface); void DestroySharedDepthbufferMTL(UnityDisplaySurfaceMTL* surface); void CreateUnityRenderBuffersMTL(UnityDisplaySurfaceMTL* surface); void DestroyUnityRenderBuffersMTL(UnityDisplaySurfaceMTL* surface); void StartFrameRenderingMTL(UnityDisplaySurfaceMTL* surface); void EndFrameRenderingMTL(UnityDisplaySurfaceMTL* surface); void PreparePresentMTL(UnityDisplaySurfaceMTL* surface); void PresentMTL(UnityDisplaySurfaceMTL* surface); // Acquires CAMetalDrawable resource for the surface and returns the drawable texture MTLTextureRef AcquireDrawableMTL(UnityDisplaySurfaceMTL* surface); unsigned UnityHDRSurfaceDepth(void); // starting with ios11 apple insists on having just one presentDrawable per command buffer // hence we keep normal processing for main screen, but when airplay is used we will create extra command buffers void PreparePresentNonMainScreenMTL(UnityDisplaySurfaceMTL* surface); void SetDrawableSizeMTL(UnityDisplaySurfaceMTL* surface, int width, int height); #ifdef __cplusplus } // extern "C" #endif // no graphics #ifdef __cplusplus extern "C" { #endif void InitRenderingNULL(void); void CreateSystemRenderingSurfaceNULL(UnityDisplaySurfaceBase* surface); void CreateRenderingSurfaceNULL(UnityDisplaySurfaceBase* surface); void DestroyRenderingSurfaceNULL(UnityDisplaySurfaceBase* surface); void CreateSharedDepthbufferNULL(UnityDisplaySurfaceBase* surface); void DestroySharedDepthbufferNULL(UnityDisplaySurfaceBase* surface); void CreateUnityRenderBuffersNULL(UnityDisplaySurfaceBase* surface); void DestroySystemRenderingSurfaceNULL(UnityDisplaySurfaceBase* surface); void DestroyUnityRenderBuffersNULL(UnityDisplaySurfaceBase* surface); void StartFrameRenderingNULL(UnityDisplaySurfaceBase* surface); void EndFrameRenderingNULL(UnityDisplaySurfaceBase* surface); void PreparePresentNULL(UnityDisplaySurfaceBase* surface); void PresentNULL(UnityDisplaySurfaceBase* surface); #ifdef __cplusplus } // extern "C" #endif #ifdef __cplusplus extern "C" { #endif // for Create* functions if surf is null we will actuially create new one, otherwise we update the one provided // metal: resolveTex should be non-nil only if tex have AA UnityRenderBufferHandle UnityCreateExternalSurfaceMTL(UnityRenderBufferHandle surf, int isColor, MTLTextureRef tex, const UnityRenderBufferDesc* desc); // Passing non-nil displaySurface will mark render surface as proxy and will do a delayed drawable acquisition when setting up framebuffer UnityRenderBufferHandle UnityCreateExternalColorSurfaceMTL(UnityRenderBufferHandle surf, MTLTextureRef tex, MTLTextureRef resolveTex, const UnityRenderBufferDesc* desc, UnityDisplaySurfaceMTL* displaySurface); UnityRenderBufferHandle UnityCreateExternalDepthSurfaceMTL(UnityRenderBufferHandle surf, MTLTextureRef tex, MTLTextureRef stencilTex, const UnityRenderBufferDesc* desc); // creates "dummy" surface - will indicate "missing" buffer (e.g. depth-only RT will have color as dummy) UnityRenderBufferHandle UnityCreateDummySurface(UnityRenderBufferHandle surf, int isColor, const UnityRenderBufferDesc* desc); // disable rendering to render buffers (all Cameras that were rendering to one of buffers would be reset to use backbuffer) void UnityDisableRenderBuffers(UnityRenderBufferHandle color, UnityRenderBufferHandle depth); // destroys render buffer void UnityDestroyExternalSurface(UnityRenderBufferHandle surf); // sets current render target void UnitySetRenderTarget(UnityRenderBufferHandle color, UnityRenderBufferHandle depth); // final blit to backbuffer void UnityBlitToBackbuffer(UnityRenderBufferHandle srcColor, UnityRenderBufferHandle dstColor, UnityRenderBufferHandle dstDepth); // get native renderbuffer from handle // sets vSync on OSX 10.13 and up #if PLATFORM_OSX void MetalUpdateDisplaySync(void); #endif UnityRenderBufferHandle UnityNativeRenderBufferFromHandle(void *rb); MTLCommandBufferRef UnityCurrentMTLCommandBuffer(void); void UnityUpdateDrawableSize(UnityDisplaySurfaceMTL* surface); #ifdef __cplusplus } // extern "C" #endif // metal/gles unification #define GLES_METAL_COMMON_IMPL_SURF(f) \ inline void f(UnityDisplaySurfaceBase* surface) \ { \ switch(surface->api) { \ case apiMetal: f ## MTL((UnityDisplaySurfaceMTL*)surface); break; \ case apiNoGraphics: f ## NULL(surface); break; \ } \ } \ #define GLES_METAL_COMMON_IMPL(f) \ inline void f() \ { \ switch(UnitySelectedRenderingAPI()) { \ case apiMetal: f ## MTL(); break; \ case apiNoGraphics: f ## NULL(); break; \ } \ } \ GLES_METAL_COMMON_IMPL(InitRendering); GLES_METAL_COMMON_IMPL_SURF(CreateSystemRenderingSurface); GLES_METAL_COMMON_IMPL_SURF(DestroySystemRenderingSurface); GLES_METAL_COMMON_IMPL_SURF(CreateRenderingSurface); GLES_METAL_COMMON_IMPL_SURF(DestroyRenderingSurface); GLES_METAL_COMMON_IMPL_SURF(CreateSharedDepthbuffer); GLES_METAL_COMMON_IMPL_SURF(DestroySharedDepthbuffer); GLES_METAL_COMMON_IMPL_SURF(CreateUnityRenderBuffers); GLES_METAL_COMMON_IMPL_SURF(DestroyUnityRenderBuffers); GLES_METAL_COMMON_IMPL_SURF(StartFrameRendering); GLES_METAL_COMMON_IMPL_SURF(EndFrameRendering); GLES_METAL_COMMON_IMPL_SURF(PreparePresent); GLES_METAL_COMMON_IMPL_SURF(Present); #undef GLES_METAL_COMMON_IMPL_SURF #undef GLES_METAL_COMMON_IMPL