d4a03329b56a493ad587d4de063bc4b383df81f7
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / cocoa / gstglcaopengllayer.m
1 /*
2  * GStreamer
3  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <Cocoa/Cocoa.h>
26
27 #include "gstglcaopengllayer.h"
28 #include "gstgl_cocoa_private.h"
29
30 @implementation GstGLCAOpenGLLayer
31 - (void)dealloc {
32   if (self->draw_notify)
33     self->draw_notify (self->draw_data);
34
35   GST_TRACE ("dealloc GstGLCAOpenGLLayer %p context %p", self, self->gst_gl_context);
36
37   [super dealloc];
38 }
39
40 - (id)initWithGstGLContext:(GstGLContextCocoa *)parent_gl_context {
41   [super init];
42
43   GST_LOG ("init CAOpenGLLayer");
44
45   self->gst_gl_context = parent_gl_context;
46   self.asynchronous = YES;
47   self.opaque = YES;
48   self.needsDisplayOnBoundsChange = YES;
49
50   return self;
51 }
52
53 - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
54   CGLPixelFormatObj fmt = NULL;
55
56   if (self->gst_gl_context)
57     fmt = gst_gl_context_cocoa_get_pixel_format (self->gst_gl_context);
58
59   if (!fmt) {
60     CGLPixelFormatAttribute attribs[] = {
61       kCGLPFADoubleBuffer,
62       kCGLPFAAccumSize, 32,
63       0
64     };
65     CGLError ret;
66     gint npix = 0;
67
68     GST_DEBUG ("creating new pixel format for CAOpenGLLayer %p", self);
69
70     ret = CGLChoosePixelFormat (attribs, &fmt, &npix);
71     if (ret != kCGLNoError) {
72       GST_ERROR ("CAOpenGLLayer cannot choose a pixel format: %s", CGLErrorString (ret));
73     }
74   }
75
76   return fmt;
77 }
78
79 - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
80   CGLContextObj external_context = NULL;
81   CGLError ret;
82
83   if (self->gst_gl_context)
84     external_context = (CGLContextObj) gst_gl_context_get_gl_context (GST_GL_CONTEXT (self->gst_gl_context));
85
86   GST_INFO ("attempting to create CGLContext for CAOpenGLLayer with "
87       "share context %p", external_context);
88
89   ret = CGLCreateContext (pixelFormat, external_context, &self->gl_context);
90   if (ret != kCGLNoError) {
91     GST_ERROR ("failed to create CGL context in CAOpenGLLayer with share context %p: %s", external_context, CGLErrorString(ret));
92   }
93
94   return self->gl_context;
95 }
96
97 - (void)releaseCGLContext:(CGLContextObj)glContext {
98   CGLReleaseContext (glContext);
99 }
100
101 - (void)setDrawCallback:(GstGLWindowCB)cb data:(gpointer)data
102       notify:(GDestroyNotify)notify {
103   g_return_if_fail (cb);
104
105   if (self->draw_notify)
106     self->draw_notify (self->draw_data);
107
108   self->draw_cb = cb;
109   self->draw_data = data;
110   self->draw_notify = notify;
111 }
112
113 - (void)setResizeCallback:(GstGLWindowResizeCB)cb data:(gpointer)data
114       notify:(GDestroyNotify)notify {
115   if (self->resize_notify)
116     self->resize_notify (self->resize_notify);
117
118   self->resize_cb = cb;
119   self->resize_data = data;
120   self->resize_notify = notify;
121 }
122
123 - (void)drawInCGLContext:(CGLContextObj)glContext
124                pixelFormat:(CGLPixelFormatObj)pixelFormat
125             forLayerTime:(CFTimeInterval)interval
126              displayTime:(const CVTimeStamp *)timeStamp {
127   const GstGLFuncs *gl = ((GstGLContext *)self->gst_gl_context)->gl_vtable;
128   GstVideoRectangle src, dst, result;
129   gint ca_viewport[4];
130
131   GST_LOG ("CAOpenGLLayer drawing with cgl context %p", glContext);
132
133   /* attempt to get the correct viewport back due to CA being too smart
134    * and messing around with it so center the expected viewport into
135    * the CA viewport set up on entry to this function */
136   gl->GetIntegerv (GL_VIEWPORT, ca_viewport);
137
138   if (self->last_bounds.size.width != self.bounds.size.width
139       || self->last_bounds.size.height != self.bounds.size.height) {
140     if (self->resize_cb) {
141       self->resize_cb (self->resize_data, self.bounds.size.width,
142           self.bounds.size.height);
143
144       gl->GetIntegerv (GL_VIEWPORT, self->expected_dims);
145     } else {
146       /* default to whatever ca gives us */
147       self->expected_dims[0] = ca_viewport[0];
148       self->expected_dims[1] = ca_viewport[1];
149       self->expected_dims[2] = ca_viewport[2];
150       self->expected_dims[3] = ca_viewport[3];
151     }
152
153     self->last_bounds = self.bounds;
154   }
155
156   src.x = self->expected_dims[0];
157   src.y = self->expected_dims[1];
158   src.w = self->expected_dims[2];
159   src.h = self->expected_dims[3];
160
161   dst.x = ca_viewport[0];
162   dst.y = ca_viewport[1];
163   dst.w = ca_viewport[2];
164   dst.h = ca_viewport[3];
165
166   gst_video_sink_center_rect (src, dst, &result, TRUE);
167
168   gl->Viewport (result.x, result.y, result.w, result.h);
169
170   if (self->draw_cb)
171     self->draw_cb (self->draw_data);
172
173   /* flushes the buffer */
174   [super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:interval displayTime:timeStamp];
175 }
176
177 @end