LearnWithTouch/App/LearnWithTouch_ios/Classes/Unity/GlesHelper.mm

373 lines
14 KiB
Plaintext

#include <QuartzCore/QuartzCore.h>
#include <stdio.h>
#include "GlesHelper.h"
#include "UnityAppController.h"
#include "DisplayManager.h"
#include "EAGLContextHelper.h"
#include "CVTextureCache.h"
#include "InternalProfiler.h"
// here goes some gles magic
// we include gles3 header so we will use gles3 constants.
// sure all the actual gles3 is guarded (and constants are staying same)
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
// here are the prototypes for gles2 ext functions that moved to core in gles3
extern "C" void glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum* attachments);
extern "C" void glRenderbufferStorageMultisampleAPPLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
extern "C" void glResolveMultisampleFramebufferAPPLE(void);
#define SAFE_GL_DELETE(func, obj) do { if(obj) { func(1,&obj); obj = 0; } } while(0)
#define DISCARD_FBO(ctx, fbo, cnt, att) \
do{ \
if(surface->context.API >= 3) glInvalidateFramebuffer(fbo, cnt, att);\
else if(_supportsDiscard) glDiscardFramebufferEXT(fbo, cnt, att);\
} while(0)
#define CREATE_RB_AA(ctx, aa, fmt, w, h) \
do{ \
if(surface->context.API >= 3) glRenderbufferStorageMultisample(GL_RENDERBUFFER, aa, fmt, w, h); \
else if(_supportsDiscard) glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, aa, fmt, w, h);\
} while(0)
static bool _supportsDiscard = false;
static bool _supportsPackedStencil = false;
extern "C" void InitRenderingGLES()
{
int api = UnitySelectedRenderingAPI();
assert(api == apiOpenGLES2 || api == apiOpenGLES3);
_supportsDiscard = api == apiOpenGLES2 ? UnityHasRenderingAPIExtension("GL_EXT_discard_framebuffer") : true;
_supportsMSAA = api == apiOpenGLES2 ? UnityHasRenderingAPIExtension("GL_APPLE_framebuffer_multisample") : true;
_supportsPackedStencil = api == apiOpenGLES2 ? UnityHasRenderingAPIExtension("GL_OES_packed_depth_stencil") : true;
}
extern "C" void CreateSystemRenderingSurfaceGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
DestroySystemRenderingSurfaceGLES(surface);
surface->layer.opaque = YES;
surface->layer.drawableProperties = @{ kEAGLDrawablePropertyRetainedBacking: @(FALSE), kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8 };
surface->colorFormat = GL_RGBA8;
glGenRenderbuffers(1, &surface->systemColorRB);
glBindRenderbuffer(GL_RENDERBUFFER, surface->systemColorRB);
AllocateRenderBufferStorageFromEAGLLayer((__bridge void*)surface->context, (__bridge void*)surface->layer);
glGenFramebuffers(1, &surface->systemFB);
UnityBindFramebuffer(kDrawFramebuffer, surface->systemFB);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->systemColorRB);
}
extern "C" void CreateRenderingSurfaceGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
DestroyRenderingSurfaceGLES(surface);
bool needRenderingSurface = surface->targetW != surface->systemW || surface->targetH != surface->systemH || surface->useCVTextureCache;
if (needRenderingSurface)
{
GLint oldTexBinding = 0;
if (surface->useCVTextureCache)
surface->cvTextureCache = CreateCVTextureCache();
if (surface->cvTextureCache)
{
surface->cvTextureCacheTexture = CreateReadableRTFromCVTextureCache(surface->cvTextureCache, surface->targetW, surface->targetH, &surface->cvPixelBuffer);
surface->targetColorRT = GetGLTextureFromCVTextureCache(surface->cvTextureCacheTexture);
}
else
{
glGenTextures(1, &surface->targetColorRT);
}
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTexBinding);
glBindTexture(GL_TEXTURE_2D, surface->targetColorRT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GLES_UPSCALE_FILTER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GLES_UPSCALE_FILTER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (!surface->cvTextureCache)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->targetW, surface->targetH, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glGenFramebuffers(1, &surface->targetFB);
UnityBindFramebuffer(kDrawFramebuffer, surface->targetFB);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->targetColorRT, 0);
glBindTexture(GL_TEXTURE_2D, oldTexBinding);
}
if (_supportsMSAA && surface->msaaSamples > 1)
{
glGenRenderbuffers(1, &surface->msaaColorRB);
glBindRenderbuffer(GL_RENDERBUFFER, surface->msaaColorRB);
glGenFramebuffers(1, &surface->msaaFB);
UnityBindFramebuffer(kDrawFramebuffer, surface->msaaFB);
CREATE_RB_AA(surface->context, surface->msaaSamples, surface->colorFormat, surface->targetW, surface->targetH);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, surface->msaaColorRB);
}
}
extern "C" void CreateSharedDepthbufferGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
DestroySharedDepthbufferGLES(surface);
if (surface->disableDepthAndStencil)
return;
surface->depthFormat = GL_DEPTH_COMPONENT24;
if (_supportsPackedStencil)
surface->depthFormat = GL_DEPTH24_STENCIL8;
glGenRenderbuffers(1, &surface->depthRB);
glBindRenderbuffer(GL_RENDERBUFFER, surface->depthRB);
bool needMSAA = _supportsMSAA && surface->msaaSamples > 1;
if (needMSAA)
CREATE_RB_AA(surface->context, surface->msaaSamples, surface->depthFormat, surface->targetW, surface->targetH);
if (!needMSAA)
glRenderbufferStorage(GL_RENDERBUFFER, surface->depthFormat, surface->targetW, surface->targetH);
if (surface->msaaFB)
UnityBindFramebuffer(kDrawFramebuffer, surface->msaaFB);
else if (surface->targetFB)
UnityBindFramebuffer(kDrawFramebuffer, surface->targetFB);
else
UnityBindFramebuffer(kDrawFramebuffer, surface->systemFB);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, surface->depthRB);
if (_supportsPackedStencil)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, surface->depthRB);
}
extern "C" void CreateUnityRenderBuffersGLES(UnityDisplaySurfaceGLES* surface)
{
UnityRenderBufferDesc target_desc = {surface->targetW, surface->targetH, 1, (unsigned int)surface->msaaSamples, 1};
UnityRenderBufferDesc system_desc = {surface->systemW, surface->systemH, 1, 1, 1};
{
unsigned texid = 0, rbid = 0, fbo = 0;
if (surface->msaaFB)
{
rbid = surface->msaaColorRB;
fbo = surface->msaaFB;
}
else if (surface->targetFB)
{
texid = surface->targetColorRT;
fbo = surface->targetFB;
}
else
{
rbid = surface->systemColorRB;
fbo = surface->systemFB;
}
surface->unityColorBuffer = UnityCreateExternalSurfaceGLES(surface->unityColorBuffer, true, texid, rbid, surface->colorFormat, &target_desc);
if (surface->depthRB)
surface->unityDepthBuffer = UnityCreateExternalSurfaceGLES(surface->unityDepthBuffer, false, 0, surface->depthRB, surface->depthFormat, &target_desc);
else
surface->unityDepthBuffer = UnityCreateDummySurface(surface->unityDepthBuffer, false, &target_desc);
UnityRegisterFBO(surface->unityColorBuffer, surface->unityDepthBuffer, fbo);
}
surface->systemColorBuffer = surface->systemDepthBuffer = 0;
if (surface->msaaFB || surface->targetFB)
{
unsigned rbid = surface->systemColorRB;
surface->systemColorBuffer = UnityCreateExternalSurfaceGLES(surface->systemColorBuffer, true, 0, rbid, surface->colorFormat, &system_desc);
surface->systemDepthBuffer = UnityCreateDummySurface(surface->systemDepthBuffer, false, &system_desc);
UnityRegisterFBO(surface->systemColorBuffer, surface->systemDepthBuffer, surface->systemFB);
}
surface->resolvedColorBuffer = 0;
if (surface->msaaFB && surface->targetFB)
surface->resolvedColorBuffer = UnityCreateExternalSurfaceGLES(surface->resolvedColorBuffer, true, surface->targetColorRT, 0, surface->colorFormat, &target_desc);
}
extern "C" void DestroySystemRenderingSurfaceGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
UnityBindFramebuffer(kDrawFramebuffer, 0);
if (surface->systemColorRB)
{
glBindRenderbuffer(GL_RENDERBUFFER, surface->systemColorRB);
DeallocateRenderBufferStorageFromEAGLLayer((__bridge void*)surface->context);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glDeleteRenderbuffers(1, &surface->systemColorRB);
surface->systemColorRB = 0;
}
if (surface->targetFB == 0 && surface->msaaFB == 0)
SAFE_GL_DELETE(glDeleteRenderbuffers, surface->depthRB);
SAFE_GL_DELETE(glDeleteFramebuffers, surface->systemFB);
}
extern "C" void DestroyRenderingSurfaceGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
if (surface->targetColorRT && !surface->cvTextureCache)
{
glDeleteTextures(1, &surface->targetColorRT); UnityOnDeleteGLTexture(surface->targetColorRT);
surface->targetColorRT = 0;
}
UnityBindFramebuffer(kDrawFramebuffer, 0);
UnityBindFramebuffer(kReadFramebuffer, 0);
if (surface->cvTextureCacheTexture)
CFRelease(surface->cvTextureCacheTexture);
if (surface->cvPixelBuffer)
CFRelease(surface->cvPixelBuffer);
if (surface->cvTextureCache)
CFRelease(surface->cvTextureCache);
surface->cvTextureCache = 0;
SAFE_GL_DELETE(glDeleteFramebuffers, surface->targetFB);
SAFE_GL_DELETE(glDeleteRenderbuffers, surface->msaaColorRB);
SAFE_GL_DELETE(glDeleteFramebuffers, surface->msaaFB);
}
extern "C" void DestroySharedDepthbufferGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
SAFE_GL_DELETE(glDeleteRenderbuffers, surface->depthRB);
}
extern "C" void DestroyUnityRenderBuffersGLES(UnityDisplaySurfaceGLES* surface)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
if (surface->unityColorBuffer)
UnityDestroyExternalSurface(surface->unityColorBuffer);
if (surface->systemColorBuffer)
UnityDestroyExternalSurface(surface->systemColorBuffer);
surface->unityColorBuffer = surface->systemColorBuffer = 0;
if (surface->unityDepthBuffer)
UnityDestroyExternalSurface(surface->unityDepthBuffer);
if (surface->systemDepthBuffer)
UnityDestroyExternalSurface(surface->systemDepthBuffer);
surface->unityDepthBuffer = surface->systemDepthBuffer = 0;
if (surface->resolvedColorBuffer)
UnityDestroyExternalSurface(surface->resolvedColorBuffer);
surface->resolvedColorBuffer = 0;
}
extern "C" void PreparePresentGLES(UnityDisplaySurfaceGLES* surface)
{
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
if (_supportsMSAA && surface->msaaSamples > 1)
{
Profiler_StartMSAAResolve();
GLuint targetFB = surface->targetFB ? surface->targetFB : surface->systemFB;
UnityBindFramebuffer(kReadFramebuffer, surface->msaaFB);
UnityBindFramebuffer(kDrawFramebuffer, targetFB);
GLenum discardAttach[] = {GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
DISCARD_FBO(surface->context, GL_READ_FRAMEBUFFER, 2, discardAttach);
if (surface->context.API < 3)
{
glResolveMultisampleFramebufferAPPLE();
}
else
{
const GLint w = surface->targetW, h = surface->targetH;
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
Profiler_EndMSAAResolve();
}
if (surface->allowScreenshot && UnityIsCaptureScreenshotRequested())
{
GLint targetFB = surface->targetFB ? surface->targetFB : surface->systemFB;
UnityBindFramebuffer(kReadFramebuffer, targetFB);
UnityCaptureScreenshot();
}
}
APP_CONTROLLER_RENDER_PLUGIN_METHOD(onFrameResolved);
if (surface->targetColorRT)
{
// shaders are bound to context
EAGLContextSetCurrentAutoRestore autorestore(UnityGetMainScreenContextGLES());
assert(surface->systemColorBuffer != 0 && surface->systemDepthBuffer != 0);
UnityRenderBufferHandle src = surface->resolvedColorBuffer ? surface->resolvedColorBuffer : surface->unityColorBuffer;
UnityBlitToBackbuffer(src, surface->systemColorBuffer, surface->systemDepthBuffer);
}
if (_supportsDiscard)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
GLenum discardAttach[] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT};
if (surface->msaaFB)
DISCARD_FBO(surface->context, GL_READ_FRAMEBUFFER, 3, discardAttach);
if (surface->targetFB)
{
UnityBindFramebuffer(kDrawFramebuffer, surface->targetFB);
DISCARD_FBO(surface->context, GL_FRAMEBUFFER, 3, discardAttach);
}
UnityBindFramebuffer(kDrawFramebuffer, surface->systemFB);
DISCARD_FBO(surface->context, GL_FRAMEBUFFER, 2, &discardAttach[1]);
}
}
extern "C" void PresentGLES(UnityDisplaySurfaceGLES* surface)
{
if (surface->context && surface->systemColorRB)
{
EAGLContextSetCurrentAutoRestore autorestore(surface->context);
glBindRenderbuffer(GL_RENDERBUFFER, surface->systemColorRB);
[surface->context presentRenderbuffer: GL_RENDERBUFFER];
}
}
extern "C" void StartFrameRenderingGLES(UnityDisplaySurfaceGLES* /*surface*/)
{
}
extern "C" void EndFrameRenderingGLES(UnityDisplaySurfaceGLES* /*surface*/)
{
}
extern "C" void CheckGLESError(const char* file, int line)
{
GLenum e = glGetError();
if (e)
::printf("OpenGLES error 0x%04X in %s:%i\n", e, file, line);
}