forked from bartvdbraak/blender
GHOST: Delete Mac OpenGL support
The maximum OpenGL versions supported on mac doesn't meet the minimum required version (>=4.3) anymore. This removes all the OpenGL paths in GHOST Cocoa backend and from the drop down menu in the user preferences. Pull Request: https://projects.blender.org/blender/blender/pulls/110185
This commit is contained in:
parent
940558f9ac
commit
cdb8a8929c
@ -650,8 +650,12 @@ mark_as_advanced(
|
||||
)
|
||||
|
||||
# OpenGL
|
||||
if(NOT APPLE)
|
||||
option(WITH_OPENGL_BACKEND "Enable OpenGL support as graphic backend" ON)
|
||||
mark_as_advanced(WITH_OPENGL_BACKEND)
|
||||
else()
|
||||
set(WITH_OPENGL_BACKEND OFF)
|
||||
endif()
|
||||
|
||||
# Vulkan
|
||||
option(WITH_VULKAN_BACKEND "Enable Vulkan as graphics backend (only for development)" OFF)
|
||||
|
@ -44,11 +44,7 @@ class GHOST_ContextCGL : public GHOST_Context {
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
GHOST_ContextCGL(bool stereoVisual,
|
||||
NSView *metalView,
|
||||
CAMetalLayer *metalLayer,
|
||||
NSOpenGLView *openglView,
|
||||
GHOST_TDrawingContextType type);
|
||||
GHOST_ContextCGL(bool stereoVisual, NSView *metalView, CAMetalLayer *metalLayer, int debug);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
@ -134,23 +130,11 @@ class GHOST_ContextCGL : public GHOST_Context {
|
||||
|
||||
private:
|
||||
/** Metal state */
|
||||
/* Set this flag to `true` when rendering with Metal API for Viewport.
|
||||
* TODO(Metal): This should be assigned to externally. */
|
||||
bool m_useMetalForRendering = false;
|
||||
NSView *m_metalView;
|
||||
CAMetalLayer *m_metalLayer;
|
||||
MTLRenderPipelineState *m_metalRenderPipeline;
|
||||
bool m_ownsMetalDevice;
|
||||
|
||||
/** OpenGL state, for GPUs that don't support Metal */
|
||||
NSOpenGLView *m_openGLView;
|
||||
|
||||
/** The OpenGL drawing context */
|
||||
NSOpenGLContext *m_openGLContext;
|
||||
|
||||
/** The virtualized default frame-buffer. */
|
||||
unsigned int m_defaultFramebuffer;
|
||||
|
||||
/** The virtualized default frame-buffer's texture. */
|
||||
/**
|
||||
* Texture that you can render into with Metal. The texture will be
|
||||
@ -191,5 +175,5 @@ class GHOST_ContextCGL : public GHOST_Context {
|
||||
void metalInitFramebuffer();
|
||||
void metalUpdateFramebuffer();
|
||||
void metalSwapBuffers();
|
||||
void initClear();
|
||||
void initClear(){};
|
||||
};
|
||||
|
@ -27,9 +27,7 @@
|
||||
|
||||
static void ghost_fatal_error_dialog(const char *msg)
|
||||
{
|
||||
/* clang-format off */
|
||||
@autoreleasepool {
|
||||
/* clang-format on */
|
||||
NSString *message = [NSString stringWithFormat:@"Error opening window:\n%s", msg];
|
||||
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
@ -50,17 +48,12 @@ int GHOST_ContextCGL::s_sharedCount = 0;
|
||||
GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
|
||||
NSView *metalView,
|
||||
CAMetalLayer *metalLayer,
|
||||
NSOpenGLView *openGLView,
|
||||
GHOST_TDrawingContextType type)
|
||||
int debug)
|
||||
: GHOST_Context(stereoVisual),
|
||||
m_useMetalForRendering(type == GHOST_kDrawingContextTypeMetal),
|
||||
m_metalView(metalView),
|
||||
m_metalLayer(metalLayer),
|
||||
m_metalRenderPipeline(nil),
|
||||
m_openGLView(openGLView),
|
||||
m_openGLContext(nil),
|
||||
m_defaultFramebuffer(0),
|
||||
m_debug(false)
|
||||
m_debug(debug)
|
||||
{
|
||||
/* Initialize Metal Swap-chain. */
|
||||
current_swapchain_index = 0;
|
||||
@ -68,6 +61,7 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
|
||||
m_defaultFramebufferMetalTexture[i].texture = nil;
|
||||
m_defaultFramebufferMetalTexture[i].index = i;
|
||||
}
|
||||
|
||||
if (m_metalView) {
|
||||
m_ownsMetalDevice = false;
|
||||
metalInit();
|
||||
@ -107,31 +101,6 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
|
||||
{
|
||||
metalFree();
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
if (m_openGLContext == [NSOpenGLContext currentContext]) {
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
if (m_openGLView) {
|
||||
[m_openGLView clearGLContext];
|
||||
}
|
||||
}
|
||||
|
||||
if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
|
||||
assert(s_sharedCount > 0);
|
||||
|
||||
s_sharedCount--;
|
||||
|
||||
if (s_sharedCount == 0)
|
||||
s_sharedOpenGLContext = nil;
|
||||
|
||||
[m_openGLContext release];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_ownsMetalDevice) {
|
||||
if (m_metalLayer) {
|
||||
[m_metalLayer release];
|
||||
@ -142,166 +111,46 @@ GHOST_ContextCGL::~GHOST_ContextCGL()
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::swapBuffers()
|
||||
{
|
||||
GHOST_TSuccess return_value = GHOST_kFailure;
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
if (m_metalView) {
|
||||
metalSwapBuffers();
|
||||
}
|
||||
else if (m_openGLView) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
[m_openGLContext flushBuffer];
|
||||
[pool drain];
|
||||
}
|
||||
return_value = GHOST_kSuccess;
|
||||
}
|
||||
else {
|
||||
return_value = GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (m_metalView) {
|
||||
metalSwapBuffers();
|
||||
}
|
||||
return_value = GHOST_kSuccess;
|
||||
}
|
||||
return return_value;
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::setSwapInterval(int interval)
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
[m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval];
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
else {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
mtl_SwapInterval = interval;
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::getSwapInterval(int &intervalOut)
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
GLint interval;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
[m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
[pool drain];
|
||||
|
||||
intervalOut = static_cast<int>(interval);
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
else {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
intervalOut = mtl_SwapInterval;
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext()
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
[m_openGLContext makeCurrentContext];
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
else {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext()
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
else {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int GHOST_ContextCGL::getDefaultFramebuffer()
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
return m_defaultFramebuffer;
|
||||
}
|
||||
/* NOTE(Metal): This is not valid. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (m_openGLContext != nil) {
|
||||
if (m_metalView) {
|
||||
metalUpdateFramebuffer();
|
||||
}
|
||||
else if (m_openGLView) {
|
||||
@autoreleasepool {
|
||||
[m_openGLContext update];
|
||||
}
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
else {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
if (m_metalView) {
|
||||
metalUpdateFramebuffer();
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
}
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
@ -333,202 +182,28 @@ void GHOST_ContextCGL::metalRegisterPresentCallback(void (*callback)(
|
||||
this->contextPresentCallback = callback;
|
||||
}
|
||||
|
||||
static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
|
||||
bool stereoVisual,
|
||||
bool needAlpha,
|
||||
bool softwareGL,
|
||||
bool increasedSamplerLimit)
|
||||
{
|
||||
attribs.clear();
|
||||
|
||||
attribs.push_back(NSOpenGLPFAOpenGLProfile);
|
||||
attribs.push_back(NSOpenGLProfileVersion3_2Core);
|
||||
|
||||
/* Pixel Format Attributes for the windowed #NSOpenGLContext. */
|
||||
attribs.push_back(NSOpenGLPFADoubleBuffer);
|
||||
|
||||
if (softwareGL) {
|
||||
attribs.push_back(NSOpenGLPFARendererID);
|
||||
attribs.push_back(kCGLRendererGenericFloatID);
|
||||
}
|
||||
else {
|
||||
attribs.push_back(NSOpenGLPFAAccelerated);
|
||||
attribs.push_back(NSOpenGLPFANoRecovery);
|
||||
|
||||
/* Attempt to initialize device with extended sampler limit.
|
||||
* Resolves EEVEE purple rendering artifacts on macOS. */
|
||||
if (increasedSamplerLimit) {
|
||||
attribs.push_back((NSOpenGLPixelFormatAttribute)400);
|
||||
}
|
||||
}
|
||||
|
||||
if (stereoVisual)
|
||||
attribs.push_back(NSOpenGLPFAStereo);
|
||||
|
||||
if (needAlpha) {
|
||||
attribs.push_back(NSOpenGLPFAAlphaSize);
|
||||
attribs.push_back((NSOpenGLPixelFormatAttribute)8);
|
||||
}
|
||||
|
||||
attribs.push_back((NSOpenGLPixelFormatAttribute)0);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
#ifdef GHOST_OPENGL_ALPHA
|
||||
static const bool needAlpha = true;
|
||||
#else
|
||||
static const bool needAlpha = false;
|
||||
#endif
|
||||
|
||||
/* Command-line argument would be better. */
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
/* Command-line argument would be better. */
|
||||
static bool softwareGL = getenv("BLENDER_SOFTWAREGL");
|
||||
|
||||
NSOpenGLPixelFormat *pixelFormat = nil;
|
||||
std::vector<NSOpenGLPixelFormatAttribute> attribs;
|
||||
bool increasedSamplerLimit = false;
|
||||
|
||||
/* Attempt to initialize device with increased sampler limit.
|
||||
* If this is unsupported and initialization fails, initialize GL Context as normal.
|
||||
*
|
||||
* NOTE: This is not available when using the SoftwareGL path, or for Intel-based
|
||||
* platforms. */
|
||||
if (!softwareGL) {
|
||||
if (@available(macos 11.0, *)) {
|
||||
increasedSamplerLimit = true;
|
||||
}
|
||||
}
|
||||
const int max_ctx_attempts = increasedSamplerLimit ? 2 : 1;
|
||||
for (int ctx_create_attempt = 0; ctx_create_attempt < max_ctx_attempts; ctx_create_attempt++)
|
||||
{
|
||||
|
||||
attribs.clear();
|
||||
attribs.reserve(40);
|
||||
makeAttribList(attribs, m_stereoVisual, needAlpha, softwareGL, increasedSamplerLimit);
|
||||
|
||||
pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
|
||||
if (pixelFormat == nil) {
|
||||
/* If pixel format creation fails when testing increased sampler limit,
|
||||
* attempt initialization again with feature disabled, otherwise, fail. */
|
||||
if (increasedSamplerLimit) {
|
||||
increasedSamplerLimit = false;
|
||||
continue;
|
||||
}
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/* Attempt to create context. */
|
||||
m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
|
||||
shareContext:s_sharedOpenGLContext];
|
||||
[pixelFormat release];
|
||||
|
||||
if (m_openGLContext == nil) {
|
||||
/* If context creation fails when testing increased sampler limit,
|
||||
* attempt re-creation with feature disabled. Otherwise, error. */
|
||||
if (increasedSamplerLimit) {
|
||||
increasedSamplerLimit = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Default context creation attempt failed. */
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
/* Created GL context successfully, activate. */
|
||||
[m_openGLContext makeCurrentContext];
|
||||
|
||||
/* When increasing sampler limit, verify created context is a supported configuration. */
|
||||
if (increasedSamplerLimit) {
|
||||
const char *vendor = (const char *)glGetString(GL_VENDOR);
|
||||
const char *renderer = (const char *)glGetString(GL_RENDERER);
|
||||
|
||||
/* If generated context type is unsupported, release existing context and
|
||||
* fallback to creating a normal context below. */
|
||||
if (strstr(vendor, "Intel") || strstr(renderer, "Software")) {
|
||||
[m_openGLContext release];
|
||||
m_openGLContext = nil;
|
||||
increasedSamplerLimit = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_debug) {
|
||||
GLint major = 0, minor = 0;
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
fprintf(stderr, "OpenGL version %d.%d%s\n", major, minor, softwareGL ? " (software)" : "");
|
||||
fprintf(stderr, "Renderer: %s\n", glGetString(GL_RENDERER));
|
||||
}
|
||||
|
||||
# ifdef GHOST_WAIT_FOR_VSYNC
|
||||
{
|
||||
GLint swapInt = 1;
|
||||
/* Wait for vertical-sync, to avoid tearing artifacts. */
|
||||
[m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
|
||||
}
|
||||
# endif
|
||||
|
||||
if (m_metalView) {
|
||||
if (m_defaultFramebuffer == 0) {
|
||||
/* Create a virtual frame-buffer. */
|
||||
[m_openGLContext makeCurrentContext];
|
||||
metalInitFramebuffer();
|
||||
initClearGL();
|
||||
}
|
||||
}
|
||||
else if (m_openGLView) {
|
||||
[m_openGLView setOpenGLContext:m_openGLContext];
|
||||
[m_openGLContext setView:m_openGLView];
|
||||
initClearGL();
|
||||
}
|
||||
|
||||
[m_openGLContext flushBuffer];
|
||||
|
||||
if (s_sharedCount == 0)
|
||||
s_sharedOpenGLContext = m_openGLContext;
|
||||
|
||||
s_sharedCount++;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* NOTE(Metal): Metal-only path. */
|
||||
if (m_metalView) {
|
||||
metalInitFramebuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
|
||||
{
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
m_openGLContext = nil;
|
||||
m_openGLView = nil;
|
||||
#endif
|
||||
m_metalView = nil;
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
/* OpenGL on Metal
|
||||
*
|
||||
* Use Metal layer to avoid Viewport lagging on macOS, see #60043. */
|
||||
|
||||
static const MTLPixelFormat METAL_FRAMEBUFFERPIXEL_FORMAT = MTLPixelFormatBGRA8Unorm;
|
||||
static const OSType METAL_CORE_VIDEO_PIXEL_FORMAT = kCVPixelFormatType_32BGRA;
|
||||
|
||||
void GHOST_ContextCGL::metalInit()
|
||||
{
|
||||
/* clang-format off */
|
||||
@autoreleasepool {
|
||||
/* clang-format on */
|
||||
id<MTLDevice> device = m_metalLayer.device;
|
||||
|
||||
/* Create a command queue for blit/present operation. Note: All context should share a single
|
||||
@ -634,128 +309,16 @@ void GHOST_ContextCGL::metalFree()
|
||||
|
||||
void GHOST_ContextCGL::metalInitFramebuffer()
|
||||
{
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
glGenFramebuffers(1, &m_defaultFramebuffer);
|
||||
#endif
|
||||
}
|
||||
updateDrawingContext();
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_ContextCGL::metalUpdateFramebuffer()
|
||||
{
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
assert(m_defaultFramebuffer != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
NSRect bounds = [m_metalView bounds];
|
||||
NSSize backingSize = [m_metalView convertSizeToBacking:bounds.size];
|
||||
size_t width = (size_t)backingSize.width;
|
||||
size_t height = (size_t)backingSize.height;
|
||||
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
unsigned int glTex;
|
||||
CVPixelBufferRef cvPixelBuffer = nil;
|
||||
CVOpenGLTextureCacheRef cvGLTexCache = nil;
|
||||
CVOpenGLTextureRef cvGLTex = nil;
|
||||
CVMetalTextureCacheRef cvMetalTexCache = nil;
|
||||
CVMetalTextureRef cvMetalTex = nil;
|
||||
#endif
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
/* OPENGL path */
|
||||
{
|
||||
/* Test if there is anything to update */
|
||||
id<MTLTexture> tex = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
|
||||
if (tex && tex.width == width && tex.height == height) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
activateDrawingContext();
|
||||
|
||||
NSDictionary *cvPixelBufferProps = @{
|
||||
(__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES,
|
||||
(__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
|
||||
};
|
||||
CVReturn cvret = CVPixelBufferCreate(kCFAllocatorDefault,
|
||||
width,
|
||||
height,
|
||||
METAL_CORE_VIDEO_PIXEL_FORMAT,
|
||||
(__bridge CFDictionaryRef)cvPixelBufferProps,
|
||||
&cvPixelBuffer);
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: CVPixelBufferCreate failed!");
|
||||
}
|
||||
|
||||
/* Create an OpenGL texture. */
|
||||
cvret = CVOpenGLTextureCacheCreate(kCFAllocatorDefault,
|
||||
nil,
|
||||
m_openGLContext.CGLContextObj,
|
||||
m_openGLContext.pixelFormat.CGLPixelFormatObj,
|
||||
nil,
|
||||
&cvGLTexCache);
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: CVOpenGLTextureCacheCreate failed!");
|
||||
}
|
||||
|
||||
cvret = CVOpenGLTextureCacheCreateTextureFromImage(
|
||||
kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: "
|
||||
"CVOpenGLTextureCacheCreateTextureFromImage failed!");
|
||||
}
|
||||
|
||||
glTex = CVOpenGLTextureGetName(cvGLTex);
|
||||
|
||||
/* Create a Metal texture. */
|
||||
cvret = CVMetalTextureCacheCreate(
|
||||
kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!");
|
||||
}
|
||||
|
||||
cvret = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
|
||||
cvMetalTexCache,
|
||||
cvPixelBuffer,
|
||||
nil,
|
||||
METAL_FRAMEBUFFERPIXEL_FORMAT,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
&cvMetalTex);
|
||||
if (cvret != kCVReturnSuccess) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: "
|
||||
"CVMetalTextureCacheCreateTextureFromImage failed!");
|
||||
}
|
||||
|
||||
id<MTLTexture> tex = CVMetalTextureGetTexture(cvMetalTex);
|
||||
|
||||
if (!tex) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!");
|
||||
}
|
||||
|
||||
[m_defaultFramebufferMetalTexture[current_swapchain_index].texture release];
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture = [tex retain];
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* NOTE(Metal): Metal API Path. */
|
||||
if (m_defaultFramebufferMetalTexture[current_swapchain_index].texture &&
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.width == width &&
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.height == height)
|
||||
@ -806,41 +369,15 @@ void GHOST_ContextCGL::metalUpdateFramebuffer()
|
||||
[enc endEncoding];
|
||||
}
|
||||
[cmdBuffer commit];
|
||||
}
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
[m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)];
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
CVPixelBufferRelease(cvPixelBuffer);
|
||||
CVOpenGLTextureCacheRelease(cvGLTexCache);
|
||||
CVOpenGLTextureRelease(cvGLTex);
|
||||
CFRelease(cvMetalTexCache);
|
||||
CFRelease(cvMetalTex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_ContextCGL::metalSwapBuffers()
|
||||
{
|
||||
/* clang-format off */
|
||||
@autoreleasepool {
|
||||
/* clang-format on */
|
||||
updateDrawingContext();
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
glFlush();
|
||||
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
|
||||
#endif
|
||||
}
|
||||
|
||||
id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
|
||||
if (!drawable) {
|
||||
return;
|
||||
@ -855,25 +392,6 @@ void GHOST_ContextCGL::metalSwapBuffers()
|
||||
attachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
|
||||
{
|
||||
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
|
||||
id<MTLRenderCommandEncoder> enc = [cmdBuffer
|
||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
||||
[enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline];
|
||||
[enc setFragmentTexture:m_defaultFramebufferMetalTexture[current_swapchain_index].texture
|
||||
atIndex:0];
|
||||
[enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
|
||||
[enc endEncoding];
|
||||
}
|
||||
|
||||
[cmdBuffer presentDrawable:drawable];
|
||||
|
||||
/* Submit command buffer */
|
||||
[cmdBuffer commit];
|
||||
}
|
||||
else {
|
||||
assert(contextPresentCallback);
|
||||
assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
|
||||
(*contextPresentCallback)(passDescriptor,
|
||||
@ -882,16 +400,3 @@ void GHOST_ContextCGL::metalSwapBuffers()
|
||||
drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_ContextCGL::initClear()
|
||||
{
|
||||
|
||||
if (!m_useMetalForRendering) {
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
glClearColor(0.294, 0.294, 0.294, 0.000);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glClearColor(0.000, 0.000, 0.000, 0.000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#if defined(WITH_OPENGL_BACKEND) || defined(WITH_METAL_BACKEND)
|
||||
#ifdef WITH_METAL_BACKEND
|
||||
# include "GHOST_ContextCGL.hh"
|
||||
#endif
|
||||
|
||||
@ -763,10 +763,11 @@ GHOST_IWindow *GHOST_SystemCocoa::createWindow(const char *title,
|
||||
*/
|
||||
GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GPUSettings gpuSettings)
|
||||
{
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
|
||||
switch (gpuSettings.context_type) {
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
case GHOST_kDrawingContextTypeVulkan: {
|
||||
const bool debug_context = (gpuSettings.flags & GHOST_gpuDebugContext) != 0;
|
||||
GHOST_Context *context = new GHOST_ContextVK(false, NULL, 1, 2, debug_context);
|
||||
if (context->initializeDrawingContext()) {
|
||||
return context;
|
||||
@ -775,17 +776,11 @@ GHOST_IContext *GHOST_SystemCocoa::createOffscreenContext(GHOST_GPUSettings gpuS
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
case GHOST_kDrawingContextTypeOpenGL:
|
||||
#endif
|
||||
|
||||
#ifdef WITH_METAL_BACKEND
|
||||
case GHOST_kDrawingContextTypeMetal:
|
||||
#endif
|
||||
#if defined(WITH_OPENGL_BACKEND) || defined(WITH_METAL_BACKEND)
|
||||
{
|
||||
case GHOST_kDrawingContextTypeMetal: {
|
||||
/* TODO(fclem): Remove OpenGL support and rename context to ContextMTL */
|
||||
GHOST_Context *context = new GHOST_ContextCGL(
|
||||
false, NULL, NULL, NULL, gpuSettings.context_type);
|
||||
GHOST_Context *context = new GHOST_ContextCGL(false, NULL, NULL, debug_context);
|
||||
if (context->initializeDrawingContext()) {
|
||||
return context;
|
||||
}
|
||||
|
@ -13,7 +13,9 @@
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_METAL_BACKEND
|
||||
# include "GHOST_ContextCGL.hh"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
# include "GHOST_ContextVK.hh"
|
||||
@ -816,37 +818,34 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
|
||||
|
||||
GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type)
|
||||
{
|
||||
switch (type) {
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
if (type == GHOST_kDrawingContextTypeVulkan) {
|
||||
case GHOST_kDrawingContextTypeVulkan: {
|
||||
GHOST_Context *context = new GHOST_ContextVK(m_wantStereoVisual, m_metalLayer, 1, 2, true);
|
||||
|
||||
if (!context->initializeDrawingContext()) {
|
||||
delete context;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (context->initializeDrawingContext()) {
|
||||
return context;
|
||||
}
|
||||
delete context;
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (true
|
||||
#if defined(WITH_OPENGL_BACKEND)
|
||||
|| type == GHOST_kDrawingContextTypeOpenGL
|
||||
#elif defined(WITH_METAL_BACKEND)
|
||||
|| type == GHOST_kDrawingContextTypeMetal
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#ifdef WITH_METAL_BACKEND
|
||||
case GHOST_kDrawingContextTypeMetal: {
|
||||
GHOST_Context *context = new GHOST_ContextCGL(
|
||||
m_wantStereoVisual, m_metalView, m_metalLayer, m_openGLView, type);
|
||||
|
||||
if (context->initializeDrawingContext())
|
||||
m_wantStereoVisual, m_metalView, m_metalLayer, false);
|
||||
if (context->initializeDrawingContext()) {
|
||||
return context;
|
||||
else
|
||||
delete context;
|
||||
}
|
||||
delete context;
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
default:
|
||||
/* Unsupported backend. */
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark invalidate
|
||||
|
@ -611,27 +611,6 @@ class USERPREF_PT_system_cycles_devices(SystemPanel, CenterAlignMixIn, Panel):
|
||||
del addon
|
||||
|
||||
|
||||
class USERPREF_PT_system_gpu_backend(SystemPanel, CenterAlignMixIn, Panel):
|
||||
bl_label = "GPU Backend"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, _context):
|
||||
# Only for Apple so far
|
||||
import sys
|
||||
return sys.platform == "darwin"
|
||||
|
||||
def draw_centered(self, context, layout):
|
||||
import gpu
|
||||
prefs = context.preferences
|
||||
system = prefs.system
|
||||
|
||||
col = layout.column()
|
||||
col.prop(system, "gpu_backend")
|
||||
|
||||
if system.gpu_backend != gpu.platform.backend_type_get():
|
||||
layout.label(text="Requires a restart of Blender to take effect", icon='INFO')
|
||||
|
||||
|
||||
class USERPREF_PT_system_os_settings(SystemPanel, CenterAlignMixIn, Panel):
|
||||
bl_label = "Operating System Settings"
|
||||
|
||||
@ -2525,7 +2504,6 @@ classes = (
|
||||
USERPREF_PT_animation_fcurves,
|
||||
|
||||
USERPREF_PT_system_cycles_devices,
|
||||
USERPREF_PT_system_gpu_backend,
|
||||
USERPREF_PT_system_os_settings,
|
||||
USERPREF_PT_system_memory,
|
||||
USERPREF_PT_system_video_sequencer,
|
||||
|
@ -845,6 +845,13 @@ void blo_do_versions_userdef(UserDef *userdef)
|
||||
*/
|
||||
{
|
||||
/* Keep this block, even when empty. */
|
||||
|
||||
#ifdef __APPLE__
|
||||
/* Drop OpenGL support on MAC devices as they don't support OpenGL 4.3. */
|
||||
if (userdef->gpu_backend == GPU_BACKEND_OPENGL) {
|
||||
userdef->gpu_backend = GPU_BACKEND_METAL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LISTBASE_FOREACH (bTheme *, btheme, &userdef->themes) {
|
||||
|
@ -219,9 +219,6 @@ void GPU_render_step()
|
||||
/** \name Backend selection
|
||||
* \{ */
|
||||
|
||||
/* NOTE: To enable Metal API, we need to temporarily change this to `GPU_BACKEND_METAL`.
|
||||
* Until a global switch is added, Metal also needs to be enabled in GHOST_ContextCGL:
|
||||
* `m_useMetalForRendering = true`. */
|
||||
static eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
|
||||
static std::optional<eGPUBackendType> g_backend_type_override = std::nullopt;
|
||||
static std::optional<bool> g_backend_type_supported = std::nullopt;
|
||||
@ -255,13 +252,11 @@ bool GPU_backend_type_selection_detect()
|
||||
backends_to_check.append(*g_backend_type_override);
|
||||
}
|
||||
else {
|
||||
#if defined(WITH_OPENGL_BACKEND)
|
||||
backends_to_check.append(GPU_BACKEND_OPENGL);
|
||||
}
|
||||
|
||||
/* Add fallback to OpenGL when Metal backend is requested on a platform that doesn't support
|
||||
* metal. */
|
||||
if (backends_to_check[0] == GPU_BACKEND_METAL) {
|
||||
backends_to_check.append(GPU_BACKEND_OPENGL);
|
||||
#elif defined(WITH_METAL_BACKEND)
|
||||
backends_to_check.append(GPU_BACKEND_METAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
for (const eGPUBackendType backend_type : backends_to_check) {
|
||||
|
Loading…
Reference in New Issue
Block a user