Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorThomas Dinges <dingto>2022-09-22 18:27:51 +0300
committerClément Foucault <foucault.clem@gmail.com>2022-09-22 18:32:43 +0300
commit697b447c2069bbbbaa9929aab0ea1f66ef8bf4d0 (patch)
treef5c78b102b5c1478fb1dbd262b23508f5f072e33 /intern
parentbb63b98d1ff5acfd24dff9b5e72175f82f5bca26 (diff)
Metal: MTLContext implementation and immediate mode rendering support.
MTLContext provides functionality for command encoding, binding management and graphics device management. MTLImmediate provides simple draw enablement with dynamically encoded data. These draws utilise temporary scratch buffer memory to provide minimal bandwidth overhead during workload submission. This patch also contains empty placeholders for MTLBatch and MTLDrawList to enable testing of first pixels on-screen without failure. The Metal API also requires access to the GHOST_Context to ensure the same pre-initialized Metal GPU device is used by the viewport. Given the explicit nature of Metal, explicit control is also needed over presentation, to ensure correct work scheduling and rendering pipeline state. Authored by Apple: Michael Parkin-White Ref T96261 (The diff is based on 043f59cb3b5835ba1a0bbf6f1cbad080b527f7f6) Reviewed By: fclem Differential Revision: https://developer.blender.org/D15953
Diffstat (limited to 'intern')
-rw-r--r--intern/ghost/intern/GHOST_Context.h8
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.h79
-rw-r--r--intern/ghost/intern/GHOST_ContextCGL.mm805
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp5
-rw-r--r--intern/ghost/intern/GHOST_Window.h74
-rw-r--r--intern/ghost/test/multitest/MultiTest.c6
6 files changed, 673 insertions, 304 deletions
diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h
index 3546fb6bbc7..04d445e7f85 100644
--- a/intern/ghost/intern/GHOST_Context.h
+++ b/intern/ghost/intern/GHOST_Context.h
@@ -36,19 +36,19 @@ class GHOST_Context : public GHOST_IContext {
* Swaps front and back buffers of a window.
* \return A boolean success indicator.
*/
- virtual GHOST_TSuccess swapBuffers() = 0;
+ virtual GHOST_TSuccess swapBuffers() override = 0;
/**
* Activates the drawing context of this window.
* \return A boolean success indicator.
*/
- virtual GHOST_TSuccess activateDrawingContext() = 0;
+ virtual GHOST_TSuccess activateDrawingContext() override = 0;
/**
* Release the drawing context of the calling thread.
* \return A boolean success indicator.
*/
- virtual GHOST_TSuccess releaseDrawingContext() = 0;
+ virtual GHOST_TSuccess releaseDrawingContext() override = 0;
/**
* Call immediately after new to initialize. If this fails then immediately delete the object.
@@ -130,7 +130,7 @@ class GHOST_Context : public GHOST_IContext {
* Gets the OpenGL frame-buffer associated with the OpenGL context
* \return The ID of an OpenGL frame-buffer object.
*/
- virtual unsigned int getDefaultFramebuffer()
+ virtual unsigned int getDefaultFramebuffer() override
{
return 0;
}
diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h
index fa6d6fc6fa0..5caabb8ce00 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.h
+++ b/intern/ghost/intern/GHOST_ContextCGL.h
@@ -9,8 +9,13 @@
#include "GHOST_Context.h"
+#include <Cocoa/Cocoa.h>
+#include <Metal/Metal.h>
+#include <QuartzCore/QuartzCore.h>
+
@class CAMetalLayer;
@class MTLCommandQueue;
+@class MTLDevice;
@class MTLRenderPipelineState;
@class MTLTexture;
@class NSOpenGLContext;
@@ -36,62 +41,89 @@ class GHOST_ContextCGL : public GHOST_Context {
* Swaps front and back buffers of a window.
* \return A boolean success indicator.
*/
- GHOST_TSuccess swapBuffers();
+ GHOST_TSuccess swapBuffers() override;
/**
* Activates the drawing context of this window.
* \return A boolean success indicator.
*/
- GHOST_TSuccess activateDrawingContext();
+ GHOST_TSuccess activateDrawingContext() override;
/**
* Release the drawing context of the calling thread.
* \return A boolean success indicator.
*/
- GHOST_TSuccess releaseDrawingContext();
+ GHOST_TSuccess releaseDrawingContext() override;
- unsigned int getDefaultFramebuffer();
+ unsigned int getDefaultFramebuffer() override;
/**
* Call immediately after new to initialize. If this fails then immediately delete the object.
* \return Indication as to whether initialization has succeeded.
*/
- GHOST_TSuccess initializeDrawingContext();
+ GHOST_TSuccess initializeDrawingContext() override;
/**
* Removes references to native handles from this context and then returns
* \return GHOST_kSuccess if it is OK for the parent to release the handles and
* GHOST_kFailure if releasing the handles will interfere with sharing
*/
- GHOST_TSuccess releaseNativeHandles();
+ GHOST_TSuccess releaseNativeHandles() override;
/**
* Sets the swap interval for #swapBuffers.
* \param interval: The swap interval to use.
* \return A boolean success indicator.
*/
- GHOST_TSuccess setSwapInterval(int interval);
+ GHOST_TSuccess setSwapInterval(int interval) override;
/**
* Gets the current swap interval for #swapBuffers.
* \param intervalOut: Variable to store the swap interval if it can be read.
* \return Whether the swap interval can be read.
*/
- GHOST_TSuccess getSwapInterval(int &);
+ GHOST_TSuccess getSwapInterval(int &) override;
/**
* Updates the drawing context of this window.
* Needed whenever the window is changed.
* \return Indication of success.
*/
- GHOST_TSuccess updateDrawingContext();
+ GHOST_TSuccess updateDrawingContext() override;
+
+ /**
+ * Returns a texture that Metal code can use as a render target. The current
+ * contents of this texture will be composited on top of the framebuffer
+ * each time `swapBuffers` is called.
+ */
+ id<MTLTexture> metalOverlayTexture();
+
+ /**
+ * Return a pointer to the Metal command queue used by this context.
+ */
+ MTLCommandQueue *metalCommandQueue();
+
+ /**
+ * Return a pointer to the Metal device associated with this context.
+ */
+ MTLDevice *metalDevice();
+
+ /**
+ * Register present callback
+ */
+ void metalRegisterPresentCallback(void (*callback)(
+ MTLRenderPassDescriptor *, id<MTLRenderPipelineState>, id<MTLTexture>, id<CAMetalDrawable>));
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;
MTLCommandQueue *m_metalCmdQueue;
MTLRenderPipelineState *m_metalRenderPipeline;
+ bool m_ownsMetalDevice;
/** OpenGL state, for GPUs that don't support Metal */
NSOpenGLView *m_openGLView;
@@ -102,9 +134,31 @@ class GHOST_ContextCGL : public GHOST_Context {
/** The virtualized default frame-buffer. */
unsigned int m_defaultFramebuffer;
- /** The virtualized default frame-buffer's texture. */
- MTLTexture *m_defaultFramebufferMetalTexture;
-
+ /** The virtualized default framebuffer's texture */
+ /**
+ * Texture that you can render into with Metal. The texture will be
+ * composited on top of `m_defaultFramebufferMetalTexture` whenever
+ * `swapBuffers` is called.
+ */
+ static const int METAL_SWAPCHAIN_SIZE = 3;
+ struct MTLSwapchainTexture {
+ id<MTLTexture> texture;
+ unsigned int index;
+ };
+ MTLSwapchainTexture m_defaultFramebufferMetalTexture[METAL_SWAPCHAIN_SIZE];
+ unsigned int current_swapchain_index = 0;
+
+ /* Present callback.
+ * We use this such that presentation can be controlled from within the Metal
+ * Context. This is required for optimal performance and clean control flow.
+ * Also helps ensure flickering does not occur by present being dependent
+ * on existing submissions. */
+ void (*contextPresentCallback)(MTLRenderPassDescriptor *,
+ id<MTLRenderPipelineState>,
+ id<MTLTexture>,
+ id<CAMetalDrawable>);
+
+ int mtl_SwapInterval;
const bool m_debug;
/** The first created OpenGL context (for sharing display lists) */
@@ -117,4 +171,5 @@ class GHOST_ContextCGL : public GHOST_Context {
void metalInitFramebuffer();
void metalUpdateFramebuffer();
void metalSwapBuffers();
+ void initClear();
};
diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm
index 488aa58aa59..6a0fed79fb0 100644
--- a/intern/ghost/intern/GHOST_ContextCGL.mm
+++ b/intern/ghost/intern/GHOST_ContextCGL.mm
@@ -55,139 +55,277 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
m_openGLView(openGLView),
m_openGLContext(nil),
m_defaultFramebuffer(0),
- m_defaultFramebufferMetalTexture(nil),
m_debug(false)
{
+ /* Init Metal Swapchain. */
+ current_swapchain_index = 0;
+ for (int i = 0; i < METAL_SWAPCHAIN_SIZE; i++) {
+ m_defaultFramebufferMetalTexture[i].texture = nil;
+ m_defaultFramebufferMetalTexture[i].index = i;
+ }
if (m_metalView) {
+ m_ownsMetalDevice = false;
metalInit();
}
+ else {
+ /* Prepare offscreen GHOST Context Metal device. */
+ id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
+
+ if (m_debug) {
+ printf("Selected Metal Device: %s\n", [metalDevice.name UTF8String]);
+ }
+
+ m_ownsMetalDevice = true;
+ if (metalDevice) {
+ m_metalLayer = [[CAMetalLayer alloc] init];
+ [m_metalLayer setEdgeAntialiasingMask:0];
+ [m_metalLayer setMasksToBounds:NO];
+ [m_metalLayer setOpaque:YES];
+ [m_metalLayer setFramebufferOnly:YES];
+ [m_metalLayer setPresentsWithTransaction:NO];
+ [m_metalLayer removeAllAnimations];
+ [m_metalLayer setDevice:metalDevice];
+ m_metalLayer.allowsNextDrawableTimeout = NO;
+ metalInit();
+ }
+ else {
+ ghost_fatal_error_dialog(
+ "[ERROR] Failed to create Metal device for offscreen GHOST Context.\n");
+ }
+ }
+
+ /* Initialise swapinterval. */
+ mtl_SwapInterval = 60;
}
GHOST_ContextCGL::~GHOST_ContextCGL()
{
metalFree();
- if (m_openGLContext != nil) {
- if (m_openGLContext == [NSOpenGLContext currentContext]) {
- [NSOpenGLContext clearCurrentContext];
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ if (m_openGLContext != nil) {
+ if (m_openGLContext == [NSOpenGLContext currentContext]) {
+ [NSOpenGLContext clearCurrentContext];
- if (m_openGLView) {
- [m_openGLView clearGLContext];
+ if (m_openGLView) {
+ [m_openGLView clearGLContext];
+ }
}
- }
- if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
- assert(s_sharedCount > 0);
+ if (m_openGLContext != s_sharedOpenGLContext || s_sharedCount == 1) {
+ assert(s_sharedCount > 0);
- s_sharedCount--;
+ s_sharedCount--;
- if (s_sharedCount == 0)
- s_sharedOpenGLContext = nil;
+ if (s_sharedCount == 0)
+ s_sharedOpenGLContext = nil;
- [m_openGLContext release];
+ [m_openGLContext release];
+ }
+ }
+#endif
+ }
+
+ if (m_ownsMetalDevice) {
+ if (m_metalLayer) {
+ [m_metalLayer release];
+ m_metalLayer = nil;
}
}
}
GHOST_TSuccess GHOST_ContextCGL::swapBuffers()
{
- if (m_openGLContext != nil) {
- if (m_metalView) {
- metalSwapBuffers();
+ GHOST_TSuccess return_value = GHOST_kFailure;
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ 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 if (m_openGLView) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLContext flushBuffer];
- [pool drain];
+ else {
+ return_value = GHOST_kFailure;
}
- return GHOST_kSuccess;
+#endif
}
else {
- return GHOST_kFailure;
+ if (m_metalView) {
+ metalSwapBuffers();
+ }
+ return_value = GHOST_kSuccess;
}
+ return return_value;
}
GHOST_TSuccess GHOST_ContextCGL::setSwapInterval(int interval)
{
- if (m_openGLContext != nil) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLContext setValues:&interval forParameter:NSOpenGLCPSwapInterval];
- [pool drain];
- return GHOST_kSuccess;
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ 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 {
- return GHOST_kFailure;
+ mtl_SwapInterval = interval;
+ return GHOST_kSuccess;
}
}
GHOST_TSuccess GHOST_ContextCGL::getSwapInterval(int &intervalOut)
{
- if (m_openGLContext != nil) {
- GLint interval;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ if (m_openGLContext != nil) {
+ GLint interval;
- [m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval];
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [pool drain];
+ [m_openGLContext getValues:&interval forParameter:NSOpenGLCPSwapInterval];
- intervalOut = static_cast<int>(interval);
+ [pool drain];
- return GHOST_kSuccess;
+ intervalOut = static_cast<int>(interval);
+
+ return GHOST_kSuccess;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+#endif
}
else {
- return GHOST_kFailure;
+ intervalOut = mtl_SwapInterval;
+ return GHOST_kSuccess;
}
}
GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext()
{
- if (m_openGLContext != nil) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLContext makeCurrentContext];
- [pool drain];
- return GHOST_kSuccess;
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ 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_kFailure;
+ return GHOST_kSuccess;
}
}
GHOST_TSuccess GHOST_ContextCGL::releaseDrawingContext()
{
- if (m_openGLContext != nil) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [NSOpenGLContext clearCurrentContext];
- [pool drain];
- return GHOST_kSuccess;
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ if (m_openGLContext != nil) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [NSOpenGLContext clearCurrentContext];
+ [pool drain];
+ return GHOST_kSuccess;
+ }
+ else {
+ return GHOST_kFailure;
+ }
+#endif
}
else {
- return GHOST_kFailure;
+ return GHOST_kSuccess;
}
}
unsigned int GHOST_ContextCGL::getDefaultFramebuffer()
{
- return m_defaultFramebuffer;
+
+ if (!m_useMetalForRendering) {
+ return m_defaultFramebuffer;
+ }
+ /* NOTE(Metal): This is not valid. */
+ return 0;
}
GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext()
{
- if (m_openGLContext != nil) {
- if (m_metalView) {
- metalUpdateFramebuffer();
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ if (m_openGLContext != nil) {
+ if (m_metalView) {
+ metalUpdateFramebuffer();
+ }
+ else if (m_openGLView) {
+ @autoreleasepool {
+ [m_openGLContext update];
+ }
+ }
+
+ return GHOST_kSuccess;
}
- else if (m_openGLView) {
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- [m_openGLContext update];
- [pool drain];
+ else {
+ return GHOST_kFailure;
}
-
- return GHOST_kSuccess;
+#endif
}
else {
- return GHOST_kFailure;
+ if (m_metalView) {
+ metalUpdateFramebuffer();
+ return GHOST_kSuccess;
+ }
}
+ return GHOST_kFailure;
+}
+
+id<MTLTexture> GHOST_ContextCGL::metalOverlayTexture()
+{
+ /* Increment Swapchain - Only needed if context is requesting a new texture */
+ current_swapchain_index = (current_swapchain_index + 1) % METAL_SWAPCHAIN_SIZE;
+
+ /* Ensure backing texture is ready for current swapchain index */
+ updateDrawingContext();
+
+ /* Return texture. */
+ return m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
+}
+
+MTLCommandQueue *GHOST_ContextCGL::metalCommandQueue()
+{
+ return m_metalCmdQueue;
+}
+MTLDevice *GHOST_ContextCGL::metalDevice()
+{
+ id<MTLDevice> device = m_metalLayer.device;
+ return (MTLDevice *)device;
+}
+
+void GHOST_ContextCGL::metalRegisterPresentCallback(void (*callback)(
+ MTLRenderPassDescriptor *, id<MTLRenderPipelineState>, id<MTLTexture>, id<CAMetalDrawable>))
+{
+ this->contextPresentCallback = callback;
}
static void makeAttribList(std::vector<NSOpenGLPixelFormatAttribute> &attribs,
@@ -241,120 +379,134 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext()
#endif
/* 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;
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ /* 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);
+ 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 intialisation again with feature disabled, otherwise, fail. */
+ if (increasedSamplerLimit) {
+ increasedSamplerLimit = false;
+ continue;
+ }
+ return GHOST_kFailure;
+ }
- 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;
+ /* 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;
}
- return GHOST_kFailure;
- }
- /* Attempt to create context. */
- m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
- shareContext:s_sharedOpenGLContext];
- [pixelFormat release];
+ /* Created GL context successfully, activate. */
+ [m_openGLContext makeCurrentContext];
- if (m_openGLContext == nil) {
- /* If context creation fails when testing increased sampler limit,
- * attempt re-creation with feature disabled. Otherwise, error. */
+ /* When increasing sampler limit, verify created context is a supported configuration. */
if (increasedSamplerLimit) {
- increasedSamplerLimit = false;
- continue;
+ 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;
+ }
}
-
- /* Default context creation attempt failed. */
- return GHOST_kFailure;
}
- /* Created GL context successfully, activate. */
- [m_openGLContext makeCurrentContext];
+ 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));
+ }
- /* 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;
+# 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();
+ }
- 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));
- }
+ [m_openGLContext flushBuffer];
-#ifdef GHOST_WAIT_FOR_VSYNC
- {
- GLint swapInt = 1;
- /* Wait for vertical-sync, to avoid tearing artifacts. */
- [m_openGLContext setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
- }
-#endif
+ if (s_sharedCount == 0)
+ s_sharedOpenGLContext = m_openGLContext;
- if (m_metalView) {
- if (m_defaultFramebuffer == 0) {
- /* Create a virtual frame-buffer. */
- [m_openGLContext makeCurrentContext];
+ s_sharedCount++;
+#endif
+ }
+ else {
+ /* NOTE(Metal): Metal-only path. */
+ if (m_metalView) {
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++;
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextCGL::releaseNativeHandles()
{
+#if WITH_OPENGL
m_openGLContext = nil;
m_openGLView = nil;
+#endif
m_metalView = nil;
return GHOST_kSuccess;
@@ -404,10 +556,14 @@ void GHOST_ContextCGL::metalInit()
fragment float4 fragment_shader(Vertex v [[stage_in]],
texture2d<float> t [[texture(0)]]) {
- return t.sample(s, v.texCoord);
- }
- )msl";
+ /* Final blit should ensure alpha is 1.0. This resolves
+ * rendering artifacts for blitting of final backbuffer. */
+ float4 out_tex = t.sample(s, v.texCoord);
+ out_tex.a = 1.0;
+ return out_tex;
+ }
+ )msl";
MTLCompileOptions *options = [[[MTLCompileOptions alloc] init] autorelease];
options.languageVersion = MTLLanguageVersion1_1;
@@ -424,6 +580,8 @@ void GHOST_ContextCGL::metalInit()
desc.fragmentFunction = [library newFunctionWithName:@"fragment_shader"];
desc.vertexFunction = [library newFunctionWithName:@"vertex_shader"];
+ /* Ensure library is released. */
+ [library autorelease];
[desc.colorAttachments objectAtIndexedSubscript:0].pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT;
@@ -434,6 +592,20 @@ void GHOST_ContextCGL::metalInit()
ghost_fatal_error_dialog(
"GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed!");
}
+
+ /* Create a render pipeline to composite things rendered with Metal on top
+ * of the framebuffer contents. Uses the same vertex and fragment shader
+ * as the blit above, but with alpha blending enabled. */
+ desc.label = @"Metal Overlay";
+ desc.colorAttachments[0].blendingEnabled = YES;
+ desc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorSourceAlpha;
+ desc.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactorOneMinusSourceAlpha;
+
+ if (error) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalInit: newRenderPipelineStateWithDescriptor:error: failed (when "
+ "creating the Metal overlay pipeline)!");
+ }
}
}
@@ -445,123 +617,206 @@ void GHOST_ContextCGL::metalFree()
if (m_metalRenderPipeline) {
[m_metalRenderPipeline release];
}
- if (m_defaultFramebufferMetalTexture) {
- [m_defaultFramebufferMetalTexture release];
+
+ for (int i = 0; i < METAL_SWAPCHAIN_SIZE; i++) {
+ if (m_defaultFramebufferMetalTexture[i].texture) {
+ [m_defaultFramebufferMetalTexture[i].texture release];
+ }
}
}
void GHOST_ContextCGL::metalInitFramebuffer()
{
- glGenFramebuffers(1, &m_defaultFramebuffer);
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ glGenFramebuffers(1, &m_defaultFramebuffer);
+#endif
+ }
updateDrawingContext();
- glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
+#endif
+ }
}
void GHOST_ContextCGL::metalUpdateFramebuffer()
{
- assert(m_defaultFramebuffer != 0);
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ 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;
- {
- /* Test if there is anything to update */
- id<MTLTexture> tex = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
- if (tex && tex.width == width && tex.height == height) {
- return;
+#if WITH_OPENGL
+ unsigned int glTex;
+ CVPixelBufferRef cvPixelBuffer = nil;
+ CVOpenGLTextureCacheRef cvGLTexCache = nil;
+ CVOpenGLTextureRef cvGLTex = nil;
+ CVMetalTextureCacheRef cvMetalTexCache = nil;
+ CVMetalTextureRef cvMetalTex = nil;
+#endif
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ /* 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();
+ 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!");
+ }
- NSDictionary *cvPixelBufferProps = @{
- (__bridge NSString *)kCVPixelBufferOpenGLCompatibilityKey : @YES,
- (__bridge NSString *)kCVPixelBufferMetalCompatibilityKey : @YES,
- };
- CVPixelBufferRef cvPixelBuffer = nil;
- 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. */
- CVOpenGLTextureCacheRef cvGLTexCache = nil;
- 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!");
- }
+ /* 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!");
+ }
- CVOpenGLTextureRef cvGLTex = nil;
- cvret = CVOpenGLTextureCacheCreateTextureFromImage(
- kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
- if (cvret != kCVReturnSuccess) {
- ghost_fatal_error_dialog(
- "GHOST_ContextCGL::metalUpdateFramebuffer: "
- "CVOpenGLTextureCacheCreateTextureFromImage failed!");
- }
+ cvret = CVOpenGLTextureCacheCreateTextureFromImage(
+ kCFAllocatorDefault, cvGLTexCache, cvPixelBuffer, nil, &cvGLTex);
+ if (cvret != kCVReturnSuccess) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: "
+ "CVOpenGLTextureCacheCreateTextureFromImage failed!");
+ }
- unsigned int glTex;
- glTex = CVOpenGLTextureGetName(cvGLTex);
+ glTex = CVOpenGLTextureGetName(cvGLTex);
- /* Create a Metal texture. */
- CVMetalTextureCacheRef cvMetalTexCache = nil;
- cvret = CVMetalTextureCacheCreate(
- kCFAllocatorDefault, nil, m_metalLayer.device, nil, &cvMetalTexCache);
- if (cvret != kCVReturnSuccess) {
- ghost_fatal_error_dialog(
- "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureCacheCreate failed!");
- }
+ /* 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!");
+ }
- CVMetalTextureRef cvMetalTex = nil;
- 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!");
- }
+ 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!");
+ }
- MTLTexture *tex = (MTLTexture *)CVMetalTextureGetTexture(cvMetalTex);
+ id<MTLTexture> tex = CVMetalTextureGetTexture(cvMetalTex);
- if (!tex) {
- ghost_fatal_error_dialog(
- "GHOST_ContextCGL::metalUpdateFramebuffer: CVMetalTextureGetTexture failed!");
+ 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) {
+ return;
+ }
- [m_defaultFramebufferMetalTexture release];
- m_defaultFramebufferMetalTexture = [tex retain];
+ /* Free old texture */
+ [m_defaultFramebufferMetalTexture[current_swapchain_index].texture release];
- glBindFramebuffer(GL_FRAMEBUFFER, m_defaultFramebuffer);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE, glTex, 0);
+ id<MTLDevice> device = m_metalLayer.device;
+ MTLTextureDescriptor *overlayDesc = [MTLTextureDescriptor
+ texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA16Float
+ width:width
+ height:height
+ mipmapped:NO];
+ overlayDesc.storageMode = MTLStorageModePrivate;
+ overlayDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
+
+ id<MTLTexture> overlayTex = [device newTextureWithDescriptor:overlayDesc];
+ if (!overlayTex) {
+ ghost_fatal_error_dialog(
+ "GHOST_ContextCGL::metalUpdateFramebuffer: failed to create Metal overlay texture!");
+ }
+ else {
+ overlayTex.label = [NSString
+ stringWithFormat:@"Metal Overlay for GHOST Context %p", this]; //@"";
- [m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)];
+ // NSLog(@"Created new Metal Overlay (backbuffer) for context %p\n", this);
+ }
+
+ m_defaultFramebufferMetalTexture[current_swapchain_index].texture =
+ overlayTex; //[(MTLTexture *)overlayTex retain];
+
+ /* Clear texture on create */
+ id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
+ MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
+ {
+ auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
+ attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
+ attachment.loadAction = MTLLoadActionClear;
+ attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000);
+ attachment.storeAction = MTLStoreActionStore;
+ }
+ {
+ id<MTLRenderCommandEncoder> enc = [cmdBuffer
+ renderCommandEncoderWithDescriptor:passDescriptor];
+ [enc endEncoding];
+ }
+ [cmdBuffer commit];
+ }
- CVPixelBufferRelease(cvPixelBuffer);
- CVOpenGLTextureCacheRelease(cvGLTexCache);
- CVOpenGLTextureRelease(cvGLTex);
- CFRelease(cvMetalTexCache);
- CFRelease(cvMetalTex);
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ 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) {
+#if WITH_OPENGL
+ CVPixelBufferRelease(cvPixelBuffer);
+ CVOpenGLTextureCacheRelease(cvGLTexCache);
+ CVOpenGLTextureRelease(cvGLTex);
+ CFRelease(cvMetalTexCache);
+ CFRelease(cvMetalTex);
+#endif
+ }
}
void GHOST_ContextCGL::metalSwapBuffers()
@@ -570,40 +825,88 @@ void GHOST_ContextCGL::metalSwapBuffers()
@autoreleasepool {
/* clang-format on */
updateDrawingContext();
- glFlush();
- assert(m_defaultFramebufferMetalTexture != 0);
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ glFlush();
+ assert(m_defaultFramebufferMetalTexture[current_swapchain_index].texture != nil);
+#endif
+ }
id<CAMetalDrawable> drawable = [m_metalLayer nextDrawable];
if (!drawable) {
return;
}
- id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
-
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
{
auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
attachment.texture = drawable.texture;
- attachment.loadAction = MTLLoadActionDontCare;
+ attachment.loadAction = MTLLoadActionClear;
+ attachment.clearColor = MTLClearColorMake(1.0, 0.294, 0.294, 1.000);
attachment.storeAction = MTLStoreActionStore;
}
- id<MTLTexture> srcTexture = (id<MTLTexture>)m_defaultFramebufferMetalTexture;
+ if (!m_useMetalForRendering) {
+ id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue 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,
+ (id<MTLRenderPipelineState>)m_metalRenderPipeline,
+ m_defaultFramebufferMetalTexture[current_swapchain_index].texture,
+ drawable);
+ }
+ }
+}
+
+void GHOST_ContextCGL::initClear()
+{
+
+ if (!m_useMetalForRendering) {
+#if WITH_OPENGL
+ glClearColor(0.294, 0.294, 0.294, 0.000);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0.000, 0.000, 0.000, 0.000);
+#endif
+ }
+ else {
+#if WITH_METAL
+ // TODO (mg_gpusw_apple) this path is never taken, this is legacy left from inital integration
+ // of metal and gl, the whole file should be cleaned up and stripped of the legacy path
+ id<MTLCommandBuffer> cmdBuffer = [m_metalCmdQueue commandBuffer];
+ MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
+ {
+ auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
+ attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
+ attachment.loadAction = MTLLoadActionClear;
+ attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000);
+ attachment.storeAction = MTLStoreActionStore;
+ }
+
+ // encoding
{
id<MTLRenderCommandEncoder> enc = [cmdBuffer
renderCommandEncoderWithDescriptor:passDescriptor];
-
- [enc setRenderPipelineState:(id<MTLRenderPipelineState>)m_metalRenderPipeline];
- [enc setFragmentTexture:srcTexture atIndex:0];
- [enc drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
-
[enc endEncoding];
}
-
- [cmdBuffer presentDrawable:drawable];
-
[cmdBuffer commit];
+#endif
}
}
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index db4d6c3bb71..da292a90869 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -92,6 +92,11 @@ GHOST_TSuccess GHOST_Window::getSwapInterval(int &intervalOut)
return m_context->getSwapInterval(intervalOut);
}
+GHOST_Context *GHOST_Window::getContext()
+{
+ return m_context;
+}
+
unsigned int GHOST_Window::getDefaultFramebuffer()
{
return (m_context) ? m_context->getDefaultFramebuffer() : 0;
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 2c2b75a6bd5..8e1f73d3430 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -72,7 +72,7 @@ class GHOST_Window : public GHOST_IWindow {
* Returns indication as to whether the window is valid.
* \return The validity of the window.
*/
- virtual bool getValid() const
+ virtual bool getValid() const override
{
return m_context != NULL;
}
@@ -81,15 +81,15 @@ class GHOST_Window : public GHOST_IWindow {
* Returns the associated OS object/handle
* \return The associated OS object/handle
*/
- virtual void *getOSWindow() const;
+ virtual void *getOSWindow() const override;
/**
* Returns the current cursor shape.
* \return The current cursor shape.
*/
- inline GHOST_TStandardCursor getCursorShape() const;
+ inline GHOST_TStandardCursor getCursorShape() const override;
- inline bool isDialog() const
+ inline bool isDialog() const override
{
return false;
}
@@ -99,7 +99,7 @@ class GHOST_Window : public GHOST_IWindow {
* \param cursorShape: The new cursor shape type id.
* \return Indication of success.
*/
- GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape);
+ GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) override;
/**
* Set the shape of the cursor to a custom cursor.
@@ -115,15 +115,15 @@ class GHOST_Window : public GHOST_IWindow {
int sizey,
int hotX,
int hotY,
- bool canInvertColor);
+ bool canInvertColor) override;
- GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap);
+ GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override;
/**
* Returns the visibility state of the cursor.
* \return The visibility state of the cursor.
*/
- inline bool getCursorVisibility() const;
+ inline bool getCursorVisibility() const override;
inline GHOST_TGrabCursorMode getCursorGrabMode() const;
inline bool getCursorGrabModeIsWarp() const;
inline GHOST_TAxisFlag getCursorGrabAxis() const;
@@ -136,7 +136,7 @@ class GHOST_Window : public GHOST_IWindow {
* \param visible: The new visibility state of the cursor.
* \return Indication of success.
*/
- GHOST_TSuccess setCursorVisibility(bool visible);
+ GHOST_TSuccess setCursorVisibility(bool visible) override;
/**
* Sets the cursor grab.
@@ -146,28 +146,28 @@ class GHOST_Window : public GHOST_IWindow {
GHOST_TSuccess setCursorGrab(GHOST_TGrabCursorMode mode,
GHOST_TAxisFlag wrap_axis,
GHOST_Rect *bounds,
- int32_t mouse_ungrab_xy[2]);
+ int32_t mouse_ungrab_xy[2]) override;
/**
* Gets the cursor grab region, if unset the window is used.
* reset when grab is disabled.
*/
- GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds);
+ GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) override;
void getCursorGrabState(GHOST_TGrabCursorMode &mode,
GHOST_TAxisFlag &axis_flag,
GHOST_Rect &bounds,
- bool &use_software_cursor);
+ bool &use_software_cursor) override;
/**
* Return true when a software cursor should be used.
*/
- bool getCursorGrabUseSoftwareDisplay();
+ bool getCursorGrabUseSoftwareDisplay() override;
/**
* Sets the progress bar value displayed in the window/application icon
* \param progress: The progress percentage (0.0 to 1.0).
*/
- virtual GHOST_TSuccess setProgressBar(float /*progress*/)
+ virtual GHOST_TSuccess setProgressBar(float /*progress*/) override
{
return GHOST_kFailure;
}
@@ -175,7 +175,7 @@ class GHOST_Window : public GHOST_IWindow {
/**
* Hides the progress bar in the icon
*/
- virtual GHOST_TSuccess endProgressBar()
+ virtual GHOST_TSuccess endProgressBar() override
{
return GHOST_kFailure;
}
@@ -185,43 +185,43 @@ class GHOST_Window : public GHOST_IWindow {
* \param interval: The swap interval to use.
* \return A boolean success indicator.
*/
- GHOST_TSuccess setSwapInterval(int interval);
+ GHOST_TSuccess setSwapInterval(int interval) override;
/**
* Gets the current swap interval for #swapBuffers.
* \return An integer.
*/
- GHOST_TSuccess getSwapInterval(int &intervalOut);
+ GHOST_TSuccess getSwapInterval(int &intervalOut) override;
/**
* Tells if the ongoing drag'n'drop object can be accepted upon mouse drop
*/
- void setAcceptDragOperation(bool canAccept);
+ void setAcceptDragOperation(bool canAccept) override;
/**
* Returns acceptance of the dropped object
* Usually called by the "object dropped" event handling function
*/
- bool canAcceptDragOperation() const;
+ bool canAcceptDragOperation() const override;
/**
* Sets the window "modified" status, indicating unsaved changes
* \param isUnsavedChanges: Unsaved changes or not.
* \return Indication of success.
*/
- virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges);
+ virtual GHOST_TSuccess setModifiedState(bool isUnsavedChanges) override;
/**
* Gets the window "modified" status, indicating unsaved changes
* \return True if there are unsaved changes
*/
- virtual bool getModifiedState();
+ virtual bool getModifiedState() override;
/**
* Returns the type of drawing context used in this window.
* \return The current type of drawing context.
*/
- inline GHOST_TDrawingContextType getDrawingContextType();
+ inline GHOST_TDrawingContextType getDrawingContextType() override;
/**
* Tries to install a rendering context in this window.
@@ -230,19 +230,19 @@ class GHOST_Window : public GHOST_IWindow {
* \param type: The type of rendering context installed.
* \return Indication as to whether installation has succeeded.
*/
- GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type);
+ GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override;
/**
* Swaps front and back buffers of a window.
* \return A boolean success indicator.
*/
- virtual GHOST_TSuccess swapBuffers();
+ virtual GHOST_TSuccess swapBuffers() override;
/**
* Activates the drawing context of this window.
* \return A boolean success indicator.
*/
- virtual GHOST_TSuccess activateDrawingContext();
+ virtual GHOST_TSuccess activateDrawingContext() override;
/**
* Updates the drawing context of this window. Needed
@@ -252,16 +252,22 @@ class GHOST_Window : public GHOST_IWindow {
GHOST_TSuccess updateDrawingContext();
/**
- * Gets the OpenGL frame-buffer associated with the window's contents.
- * \return The ID of an OpenGL frame-buffer object.
+ * Get the drawing context associated with this window.
+ *\return Pointer to the context object.
*/
- virtual unsigned int getDefaultFramebuffer();
+ GHOST_Context *getContext();
+
+ /**
+ * Gets the OpenGL framebuffer associated with the window's contents.
+ * \return The ID of an OpenGL framebuffer object.
+ */
+ virtual unsigned int getDefaultFramebuffer() override;
/**
* Returns the window user data.
* \return The window user data.
*/
- inline GHOST_TUserDataPtr getUserData() const
+ inline GHOST_TUserDataPtr getUserData() const override
{
return m_userData;
}
@@ -270,12 +276,12 @@ class GHOST_Window : public GHOST_IWindow {
* Changes the window user data.
* \param userData: The window user data.
*/
- void setUserData(const GHOST_TUserDataPtr userData)
+ void setUserData(const GHOST_TUserDataPtr userData) override
{
m_userData = userData;
}
- float getNativePixelSize(void)
+ float getNativePixelSize(void) override
{
if (m_nativePixelSize > 0.0f)
return m_nativePixelSize;
@@ -286,18 +292,18 @@ class GHOST_Window : public GHOST_IWindow {
* Returns the recommended DPI for this window.
* \return The recommended DPI for this window.
*/
- virtual inline uint16_t getDPIHint()
+ virtual inline uint16_t getDPIHint() override
{
return 96;
}
#ifdef WITH_INPUT_IME
- virtual void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed)
+ virtual void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) override
{
/* do nothing temporarily if not in windows */
}
- virtual void endIME()
+ virtual void endIME() override
{
/* do nothing temporarily if not in windows */
}
diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c
index 99b88dfb525..6a6a042f4ac 100644
--- a/intern/ghost/test/multitest/MultiTest.c
+++ b/intern/ghost/test/multitest/MultiTest.c
@@ -323,7 +323,7 @@ MainWindow *mainwindow_new(MultiTestApp *app)
if (win) {
MainWindow *mw = MEM_callocN(sizeof(*mw), "mainwindow_new");
- mw->gpu_context = GPU_context_create(win);
+ mw->gpu_context = GPU_context_create(win, NULL);
GPU_init();
mw->app = app;
@@ -578,7 +578,7 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app)
if (win) {
LoggerWindow *lw = MEM_callocN(sizeof(*lw), "loggerwindow_new");
- lw->gpu_context = GPU_context_create(win);
+ lw->gpu_context = GPU_context_create(win, NULL);
GPU_init();
int bbox[2][2];
@@ -780,7 +780,7 @@ ExtraWindow *extrawindow_new(MultiTestApp *app)
if (win) {
ExtraWindow *ew = MEM_callocN(sizeof(*ew), "mainwindow_new");
- ew->gpu_context = GPU_context_create(win);
+ ew->gpu_context = GPU_context_create(win, NULL);
GPU_init();
ew->app = app;