• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2* Copyright (C) 2011 The Android Open Source Project
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16#include <Cocoa/Cocoa.h>
17#include <OpenGL/OpenGL.h>
18#include <OpenGL/gl3.h>
19#include <stdio.h>
20#include "MacPixelFormatsAttribs.h"
21
22//
23// EmuGLContext inherit from NSOpenGLContext
24// and adds binding state for the context to know
25// if it was last bounded to a pbuffer or a window.
26// This is because after the context was bounded to
27// a Pbuffer, before we bind it to a window we must
28// release it form the pbuffer by calling the
29// clearDrawable method. We do not want to call clearDrawable
30// more than really needed since when it is called at a time
31// that a window is bounded to the context it will clear the
32// window content causing flickering effect.
33// Thererfore we call clearDrawable only when we bind the context
34// to a window and it was previously bound to a Pbuffer.
35//
36@interface EmuGLContext : NSOpenGLContext {
37    @private
38        int boundToPbuffer;
39        int boundToWin;
40    @public
41        GLuint ytexForDecoder;
42        GLuint uvtexForDecoder;
43}
44
45- (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share;
46- (void) preBind:(int)forPbuffer;
47@end
48
49@implementation EmuGLContext
50- (id) initWithFormat:(NSOpenGLPixelFormat *)pixelFormat shareContext:(NSOpenGLContext *)share
51{
52    self = [super initWithFormat:pixelFormat shareContext:share];
53    if (self != nil) {
54        boundToPbuffer = 0;
55        boundToWin = 0;
56        ytexForDecoder = 0;
57        uvtexForDecoder = 0;
58    }
59    return self;
60}
61
62- (void) preBind:(int)forPbuffer
63{
64    if ((!forPbuffer && boundToPbuffer)) {
65        [self clearDrawable];
66    }
67    boundToPbuffer = forPbuffer;
68    boundToWin = !boundToPbuffer;
69}
70@end
71
72int getAttrListLength(const NSOpenGLPixelFormatAttribute* list) {
73    int count = 0;
74    while (list[count++] != 0);
75    return count ? (count - 1) : 0;
76}
77
78static const NSOpenGLPixelFormatAttribute core32TestProfile[] = {
79    NSOpenGLPFAAccelerated,
80    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
81    NSOpenGLPFADoubleBuffer,
82    NSOpenGLPFAColorSize   ,32,
83    NSOpenGLPFADepthSize   ,24,
84    NSOpenGLPFAStencilSize ,8,
85    0
86};
87
88static const NSOpenGLPixelFormatAttribute core41TestProfile[] = {
89    NSOpenGLPFAAccelerated,
90    NSOpenGLPFANoRecovery,
91    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,
92    NSOpenGLPFADoubleBuffer,
93    NSOpenGLPFAColorSize   ,32,
94    NSOpenGLPFADepthSize   ,24,
95    NSOpenGLPFAStencilSize ,8,
96    0
97};
98
99int setupCoreProfileNativeFormats() {
100
101    NSOpenGLPixelFormat* core41Supported =
102        [[NSOpenGLPixelFormat alloc] initWithAttributes: core41TestProfile];
103
104    if (core41Supported) {
105        setCoreProfileLevel(NSOpenGLProfileVersion4_1Core);
106        [core41Supported release];
107        return (int)NSOpenGLProfileVersion4_1Core;
108    }
109
110    NSOpenGLPixelFormat* core32Supported =
111        [[NSOpenGLPixelFormat alloc] initWithAttributes: core32TestProfile];
112
113    if (core32Supported) {
114        setCoreProfileLevel(NSOpenGLProfileVersion3_2Core);
115        [core32Supported release];
116        return (int)NSOpenGLProfileVersion3_2Core;
117    }
118
119    return (int)NSOpenGLProfileVersionLegacy;
120}
121
122int getNumPixelFormats(){
123    int size;
124    const NSOpenGLPixelFormatAttribute* const* attrib_lists =
125        getPixelFormatsAttributes(&size);
126    return size;
127}
128
129void* finalizePixelFormat(bool coreProfile,
130                          int attribsId) {
131    int size;
132    const NSOpenGLPixelFormatAttribute* const* attrib_lists =
133        getPixelFormatsAttributes(&size);
134
135    assert(attribsId < size);
136
137    const NSOpenGLPixelFormatAttribute*  attrs =
138        attrib_lists[attribsId];
139
140    const NSOpenGLPixelFormatAttribute* selected_variant =
141        coreProfile ?
142        getCoreProfileAttributes() :
143        getLegacyProfileAttributes();
144
145    // Format it as |variant| |attribs|
146    int variant_size =
147        getAttrListLength(selected_variant);
148    int attrib_size = getAttrListLength(attrs);
149    int numAttribsTotal = attrib_size + variant_size + 1; // for trailing 0
150
151    NSOpenGLPixelFormatAttribute* newAttrs =
152        malloc(sizeof(NSOpenGLPixelFormatAttribute) * numAttribsTotal);
153
154    int variant_part_bytes =
155        sizeof(NSOpenGLPixelFormatAttribute) * variant_size;
156    int attribs_part_bytes =
157        sizeof(NSOpenGLPixelFormatAttribute) * attrib_size;
158
159    memcpy(newAttrs, selected_variant, variant_part_bytes);
160    memcpy((char*)newAttrs + variant_part_bytes,
161           attrs, attribs_part_bytes);
162    newAttrs[numAttribsTotal - 1] = 0;
163
164    void* finalizedFormat =
165        [[NSOpenGLPixelFormat alloc] initWithAttributes: newAttrs];
166
167    free(newAttrs);
168
169    return finalizedFormat;
170}
171
172static bool sIsKeyValueAttrib(NSOpenGLPixelFormatAttribute attrib) {
173    switch (attrib) {
174        // These are the ones that take a value, according to the current
175        // NSOpenGLPixelFormat docs
176        case NSOpenGLPFAOpenGLProfile:
177        case NSOpenGLPFAAuxBuffers:
178        case NSOpenGLPFAColorSize:
179        case NSOpenGLPFAAlphaSize:
180        case NSOpenGLPFADepthSize:
181        case NSOpenGLPFAStencilSize:
182        case NSOpenGLPFAAccumSize:
183        case NSOpenGLPFARendererID:
184        case NSOpenGLPFAScreenMask:
185            return true;
186        default:
187            return false;
188    }
189}
190
191int getPixelFormatAttrib(int i, int _query) {
192    NSOpenGLPixelFormatAttribute query =
193        (NSOpenGLPixelFormatAttribute)_query;
194    int size;
195    const NSOpenGLPixelFormatAttribute* const* attrib_lists = getPixelFormatsAttributes(&size);
196    int attributes_num = i % size;
197    const NSOpenGLPixelFormatAttribute* attribs = attrib_lists[attributes_num];
198    int res = 0;
199    while (*attribs) {
200        if (sIsKeyValueAttrib(*attribs)) {
201            if (query == *attribs) {
202                return attribs[1];
203            }
204            attribs += 2;
205        } else {
206            // these are boolean attribs.
207            // their mere presence signals
208            // that the query should return true.
209            if (query == *attribs) {
210                return 1;
211            }
212            attribs++;
213        }
214    }
215    // return 0 if key not found---takes care of all boolean attribs,
216    // and we depend on returning alpha=0 to make the default
217    // config for GLSurfaceView happy.
218    return 0;
219}
220
221void* nsCreateContext(void* format,void* share){
222    NSOpenGLPixelFormat* frmt = (NSOpenGLPixelFormat*)format;
223    return [[EmuGLContext alloc] initWithFormat:frmt shareContext:share];
224}
225
226void* nsGetLowLevelContext(void* context) {
227    EmuGLContext* ctx = (EmuGLContext*)context;
228    return ctx;
229}
230
231void nsCopyTexture(void* context, int from, int to, int width, int height) {
232    EmuGLContext* ctx = (EmuGLContext*)context;
233
234    if (glGetError() != GL_NO_ERROR) {
235        // ignore
236    }
237    int tex1 = from;
238    int tex2 = to;
239    GLuint g_fb = 0;
240    glGenFramebuffers(1, &g_fb);
241    glBindFramebuffer(GL_FRAMEBUFFER, g_fb);
242    glBindTexture(GL_TEXTURE_RECTANGLE, tex1);
243    glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
244                           GL_TEXTURE_RECTANGLE, tex1, 0);
245    if (glGetError() != GL_NO_ERROR) {
246        return;
247    }
248    glBindTexture(GL_TEXTURE_2D, tex2);
249    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
250                           GL_TEXTURE_2D, tex2, 0);
251    if (glGetError() != GL_NO_ERROR) {
252        return;
253    }
254    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
255
256    glBindTexture(GL_TEXTURE_RECTANGLE, 0);
257    glBindTexture(GL_TEXTURE_2D, 0);
258
259    if (glGetError() != GL_NO_ERROR) {
260        return;
261    }
262
263    glBindFramebuffer(GL_FRAMEBUFFER, 0);
264    glDeleteFramebuffers(1, &g_fb);
265}
266
267void nsConvertVideoFrameToNV12Textures(void* context,
268                                       void* iosurface,
269                                       int Ytexd,
270                                       int UVtexd) {
271    EmuGLContext* ctx = (EmuGLContext*)context;
272
273    CGLContextObj cgl_ctx = ctx.CGLContextObj;
274
275    glEnable(GL_TEXTURE_RECTANGLE);
276
277    IOSurfaceRef* surface = (IOSurfaceRef*)iosurface;
278
279    GLsizei surface_w = (GLsizei)IOSurfaceGetWidth(surface);
280    GLsizei surface_h = (GLsizei)IOSurfaceGetHeight(surface);
281
282    if (!ctx->ytexForDecoder) {
283        glGenTextures(1, &ctx->ytexForDecoder);
284    }
285    if (!ctx->uvtexForDecoder) {
286        glGenTextures(1, &ctx->uvtexForDecoder);
287    }
288    GLuint Ytex = ctx->ytexForDecoder;
289    GLuint UVtex = ctx->uvtexForDecoder;
290
291    glBindTexture(GL_TEXTURE_RECTANGLE, Ytex);
292    CGLError cglError = CGLTexImageIOSurface2D(
293            cgl_ctx, GL_TEXTURE_RECTANGLE, GL_R8, surface_w, surface_h, GL_RED,
294            GL_UNSIGNED_BYTE, surface, 0);
295
296    if (cglError != kCGLNoError) {
297        return;
298    }
299
300    glBindTexture(GL_TEXTURE_RECTANGLE, UVtex);
301    cglError = CGLTexImageIOSurface2D(cgl_ctx, GL_TEXTURE_RECTANGLE, GL_RG8,
302                                      surface_w / 2, surface_h / 2, GL_RG,
303                                      GL_UNSIGNED_BYTE, surface, 1);
304
305    if (cglError != kCGLNoError) {
306        return;
307    }
308    glBindTexture(GL_TEXTURE_RECTANGLE, 0);
309
310    nsCopyTexture(context, (int)Ytex, Ytexd, surface_w, surface_h);
311    nsCopyTexture(context, (int)UVtex, UVtexd, surface_w/2, surface_h/2);
312}
313
314void  nsPBufferMakeCurrent(void* context,void* nativePBuffer,int level){
315    EmuGLContext* ctx = (EmuGLContext *)context;
316    NSOpenGLPixelBuffer* pbuff = (NSOpenGLPixelBuffer *)nativePBuffer;
317    if(ctx == nil){
318        [NSOpenGLContext clearCurrentContext];
319    } else {
320        if(pbuff != nil){
321            [ctx preBind:1];
322            [ctx setPixelBuffer:pbuff cubeMapFace:0 mipMapLevel:level currentVirtualScreen:0];
323            [ctx makeCurrentContext];
324        } else {
325            // in this case, pbuffers deprecated and disabled.
326            [ctx preBind:0];
327            [ctx makeCurrentContext];
328        }
329    }
330}
331
332void nsWindowMakeCurrent(void* context,void* nativeWin){
333    EmuGLContext* ctx = (EmuGLContext *)context;
334    NSView* win = (NSView *)nativeWin;
335    if(ctx == nil){
336        [NSOpenGLContext clearCurrentContext];
337    } else if (win != nil) {
338        [ctx preBind:0];
339        [ctx setView: win];
340        [ctx makeCurrentContext];
341    }
342}
343
344void nsSwapBuffers(){
345    NSOpenGLContext* ctx = [NSOpenGLContext currentContext];
346    if(ctx != nil){
347        [ctx flushBuffer];
348    }
349}
350
351void nsSwapInterval(int *interval){
352    NSOpenGLContext* ctx = [NSOpenGLContext currentContext];
353    if( ctx != nil){
354        [ctx setValues:interval forParameter:NSOpenGLCPSwapInterval];
355    }
356}
357
358
359void nsDestroyContext(void* context){
360    EmuGLContext *ctx = (EmuGLContext*)context;
361    if(ctx != nil){
362        if (ctx->ytexForDecoder != 0) {
363            glDeleteTextures(1, &ctx->ytexForDecoder);
364            ctx->ytexForDecoder = 0;
365        }
366        if (ctx->uvtexForDecoder != 0) {
367            glDeleteTextures(1, &ctx->uvtexForDecoder);
368            ctx->uvtexForDecoder = 0;
369        }
370        [ctx release];
371    }
372}
373
374
375void* nsCreatePBuffer(GLenum target,GLenum format,int maxMip,int width,int height){
376    return [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:target
377                                        textureInternalFormat:format
378                                        textureMaxMipMapLevel:maxMip
379                                        pixelsWide:width pixelsHigh:height];
380
381}
382
383void nsDestroyPBuffer(void* pbuffer){
384    NSOpenGLPixelBuffer *pbuf = (NSOpenGLPixelBuffer*)pbuffer;
385    if(pbuf != nil){
386        [pbuf release];
387    }
388}
389
390bool nsGetWinDims(void* win,unsigned int* width,unsigned int* height){
391    NSView* view = (NSView*)win;
392    if(view != nil){
393        NSRect rect = [view bounds];
394        *width  = rect.size.width;
395        *height = rect.size.height;
396        return true;
397    }
398    return false;
399}
400
401bool  nsCheckColor(void* win,int colorSize){
402    NSView* view = (NSView*)win;
403   if(view != nil){
404       NSWindow* wnd = [view window];
405       if(wnd != nil){
406           NSWindowDepth limit = [wnd depthLimit];
407           NSWindowDepth defaultLimit = [NSWindow defaultDepthLimit];
408
409           int depth = (limit != 0) ? NSBitsPerPixelFromDepth(limit):
410                                      NSBitsPerPixelFromDepth(defaultLimit);
411           return depth >= colorSize;
412
413       }
414   }
415   return false;
416
417}
418
419void* nsGetLayer(void* win) {
420    NSView* view = (NSView*)win;
421    return view.layer;
422}
423