26
26
#include <iprt/mem.h>
27
27
#include <iprt/time.h>
31
* In general it is not so easy like on the other platforms, cause Cocoa
32
* doesn't support any clipping of already painted stuff. In Mac OS X there is
33
* the concept of translucent canvas's e.g. windows and there it is just
34
* painted what should be visible to the user. Unfortunately this isn't the
35
* concept of chromium. Therefor I reroute all OpenGL operation from the guest
36
* to a frame buffer object (FBO). This is a OpenGL extension, which is
37
* supported by all OS X versions we support (AFAIC tell). Of course the guest
38
* doesn't know that and we have to make sure that the OpenGL state always is
39
* in the right state to paint into the FBO and not to the front/back buffer.
40
* Several functions below (like cocoaBindFramebufferEXT, cocoaGetIntegerv,
41
* ...) doing this. When a swap or finish is triggered by the guest, the
42
* content (which is already bound to an texture) is painted on the screen
43
* within a separate OpenGL context. This allows the usage of the same
44
* resources (texture ids, buffers ...) but at the same time having an
45
* different internal OpenGL state. Another advantage is that we can paint a
46
* thumbnail of the current output in a much more smaller (GPU accelerated
47
* scale) version on a third context and use glReadPixels to get the actual
48
* data. glReadPixels is a very slow operation, but as we just use a much more
49
* smaller image, we can handle it (anyway this is only done 5 times per
52
* Other things to know:
53
* - If the guest request double buffering, we have to make sure there are two
54
* buffers. We use the same FBO with 2 color attachments. Also glDrawBuffer
55
* and glReadBuffer is intercepted to make sure it is painted/read to/from
56
* the correct buffers. On swap our buffers are swapped and not the
58
* - If the guest request a depth/stencil buffer, a combined render buffer for
60
* - If the size of the guest OpenGL window changes, all FBO's, textures, ...
61
* need to be recreated.
62
* - We need to track any changes to the parent window
63
* (create/destroy/move/resize). The various classes like OverlayHelperView,
64
* OverlayWindow, ... are there for.
65
* - The HGCM service runs on a other thread than the Main GUI. Keeps this
66
* always in mind (see e.g. performSelectorOnMainThread in renderFBOToView)
67
* - We make heavy use of late binding. We can not be sure that the GUI (or any
68
* other third party GUI), overwrite our NSOpenGLContext. So we always ask if
69
* this is our own one, before use. Really neat concept of Objective-C/Cocoa
30
74
#define FBO 1 /* Disable this to see how the output is without the FBO in the middle of the processing chain. */
31
//#define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
32
//#define DEBUG_VERBOSE /* Define this could get some debug info about the messages flow. */
76
#define SHOW_WINDOW_BACKGROUND 1 /* Define this to see the window background even if the window is clipped */
77
#define DEBUG_VERBOSE /* Define this to get some debug info about the messages flow. */
34
80
#ifdef DEBUG_poetzsch
35
81
#define DEBUG_MSG(text) \
679
768
- (void)updateViewport
681
DEBUG_MSG(("updateViewport %p\n", self));
772
DEBUG_MSG(("OVIW(%p): updateViewport\n", (void*)self));
682
775
if (m_pSharedGLCtx)
684
777
/* Update the viewport for our OpenGL view */
685
DEBUG_MSG(("MakeCurrent (shared) %X\n", m_pSharedGLCtx));
778
DEBUG_MSG(("OVIW(%p): makeCurrent (shared) %p\n", (void*)self, (void*)m_pSharedGLCtx));
686
779
[m_pSharedGLCtx makeCurrentContext];
687
780
[m_pSharedGLCtx update];
689
NSRect r = [self frame];
690
783
/* Setup all matrices */
691
784
glMatrixMode(GL_PROJECTION);
692
785
glLoadIdentity();
693
786
glViewport(0, 0, r.size.width, r.size.height);
694
787
glOrtho(0, r.size.width, 0, r.size.height, -1, 1);
695
DEBUG_MSG_1(("frame[%i, %i, %i, %i]\n", (int)r.origin.x, (int)r.origin.x, (int)r.size.width, (int)r.size.height));
696
DEBUG_MSG_1(("m_Pos(%i,%i) m_Size(%i,%i)\n", (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height));
697
DEBUG_MSG_1(("m_RootShift(%i, %i)\n", (int)m_RootShift.x, (int)m_RootShift.y));
788
DEBUG_MSG_1(("OVIW(%p): frame[%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.x, (int)r.size.width, (int)r.size.height));
789
DEBUG_MSG_1(("OVIW(%p): m_Pos(%i,%i) m_Size(%i,%i)\n", (void*)self, (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height));
790
DEBUG_MSG_1(("OVIW(%p): m_RootShift(%i, %i)\n", (void*)self, (int)m_RootShift.x, (int)m_RootShift.y));
698
791
glMatrixMode(GL_TEXTURE);
699
792
glLoadIdentity();
700
glTranslatef(0.0f, m_RootShift.y, 0.0f);
701
793
glMatrixMode(GL_MODELVIEW);
702
794
glLoadIdentity();
703
glTranslatef(-m_RootShift.x, 0.0f, 0.0f);
705
796
/* Clear background to transparent */
706
797
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
708
glEnable(GL_TEXTURE_RECTANGLE_ARB);
709
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
711
DEBUG_MSG(("MakeCurrent %X\n", m_pGLCtx));
799
DEBUG_MSG(("OVIW(%p): makeCurrent (non shared) %p\n", (void*)self, (void*)m_pGLCtx));
712
800
[m_pGLCtx makeCurrentContext];
718
DEBUG_MSG(("(%p)reshape %p\n", RTThreadSelf(), self));
807
NSRect parentFrame = NSZeroRect;
808
NSPoint parentPos = NSZeroPoint;
809
NSPoint childPos = NSZeroPoint;
810
NSRect childFrame = NSZeroRect;
811
NSRect newFrame = NSZeroRect;
813
DEBUG_MSG(("OVIW(%p): reshape\n", (void*)self));
719
815
/* Getting the right screen coordinates of the parents frame is a little bit
720
816
* complicated. */
721
NSRect parentFrame = [m_pParentView frame];
722
NSPoint parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]];
817
parentFrame = [m_pParentView frame];
818
parentPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:NSMakePoint(parentFrame.origin.x, parentFrame.origin.y + parentFrame.size.height)]];
723
819
parentFrame.origin.x = parentPos.x;
724
820
parentFrame.origin.y = parentPos.y;
726
822
/* Calculate the new screen coordinates of the overlay window. */
727
NSPoint childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
823
childPos = NSMakePoint(m_Pos.x, m_Pos.y + m_Size.height);
728
824
childPos = [[m_pParentView window] convertBaseToScreen:[[m_pParentView superview] convertPointToBase:childPos]];
730
826
/* Make a frame out of it. */
731
NSRect childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
827
childFrame = NSMakeRect(childPos.x, childPos.y, m_Size.width, m_Size.height);
733
829
/* We have to make sure that the overlay window will not be displayed out
734
830
* of the parent window. So intersect both frames & use the result as the new
735
831
* frame for the window. */
736
NSRect newFrame = NSIntersectionRect(parentFrame, childFrame);
832
newFrame = NSIntersectionRect(parentFrame, childFrame);
738
834
/* Later we have to correct the texture position in the case the window is
739
835
* out of the parents window frame. So save the shift values for later use. */
815
917
/* Bind to FBO */
816
918
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
818
/*glEnable(GL_TEXTURE_RECTANGLE_ARB);*/
820
GLfloat imageAspectRatio = m_FBOTexSize.width / m_FBOTexSize.height;
921
glEnable(GL_TEXTURE_RECTANGLE_ARB);
924
imageAspectRatio = m_FBOTexSize.width / m_FBOTexSize.height;
822
926
/* Sanity check against maximum OpenGL texture size. If bigger adjust to
823
927
* maximum possible size while maintain the aspect ratio. */
825
928
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
827
GLint filter = GL_NEAREST;
828
if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize)
929
if (m_FBOTexSize.width > maxTexSize || m_FBOTexSize.height > maxTexSize)
830
931
filter = GL_LINEAR;
831
932
if (imageAspectRatio > 1)
833
m_FBOTexSize.width = maxTexSize;
934
m_FBOTexSize.width = maxTexSize;
834
935
m_FBOTexSize.height = maxTexSize / imageAspectRatio;
838
939
m_FBOTexSize.width = maxTexSize * imageAspectRatio;
839
m_FBOTexSize.height = maxTexSize;
940
m_FBOTexSize.height = maxTexSize;
843
/* Initialize FBO Texture */
844
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
845
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, filter);
846
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, filter);
847
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
848
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
944
DEBUG_MSG(("OVIW(%p): tex size is: %dx%d\n", (void*)self, (int)m_FBOTexSize.width, (int)m_FBOTexSize.height));
946
/* Initialize FBO Textures */
850
947
/* The GPUs like the GL_BGRA / GL_UNSIGNED_INT_8_8_8_8_REV combination
851
948
* others are also valid, but might incur a costly software translation. */
852
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
853
DEBUG_MSG(("m_FBOTexSize(%i,%i)\n", (int)m_FBOTexSize.width, (int)m_FBOTexSize.height));
855
/* Now attach texture to the FBO as its color destination */
856
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId, 0);
949
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexBackId);
950
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
951
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexFrontId);
952
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, m_FBOTexSize.width, m_FBOTexSize.height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
954
/* Now attach the textures to the FBO as its color destinations */
955
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, m_FBOAttBackId, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexBackId, 0);
956
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, m_FBOAttFrontId, GL_TEXTURE_RECTANGLE_ARB, m_FBOTexFrontId, 0);
858
958
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
859
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, m_FBOTexSize.width, m_FBOTexSize.height);
860
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
861
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
959
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_FBOTexSize.width, m_FBOTexSize.height);
960
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_FBODepthStencilPackedId);
962
/* Bind the FBOs for reading and drawing. */
963
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
964
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId);
966
/* Explicitly clear the textures otherwise they would contain old memory stuff. */
967
glDrawBuffer(m_FBOAttBackId);
968
glClear(GL_COLOR_BUFFER_BIT);
969
glDrawBuffer(m_FBOAttFrontId);
970
glClear(GL_COLOR_BUFFER_BIT);
972
/* Now initially reading/drawing to the back buffer. */
973
glReadBuffer(m_FBOAttBackId);
974
glDrawBuffer(m_FBOAttBackId);
863
976
/* Make sure the FBO was created successfully. */
864
977
if (GL_FRAMEBUFFER_COMPLETE_EXT != glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT))
865
DEBUG_MSG(("Framebuffer Object creation or update failed!\n"));
978
DEBUG_MSG(("OVIW(%p): Framebuffer Object creation or update failed!\n", (void*)self));
980
// glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
867
981
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, oldTexId);
868
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, oldFBId ? oldFBId:m_FBOId);
982
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, (GLuint)oldFBId ? (GLuint)oldFBId : m_FBOId);
870
984
/* Is there a dock tile preview enabled in the GUI? If so setup a
871
985
* additional thumbnail view for the dock tile. */
872
NSView *dockScreen = [self dockTileScreen];
986
pDockScreen = [self dockTileScreen];
875
989
if (!m_FBOThumbId)
1139
- (bool)isCurrentFBO
1144
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &curFBOId);
1145
DEBUG_MSG_1(("OVIW(%p): isCurrentFBO: curFBOId=%d FBOId=%d\n", (void*)self, curFBOId, m_FBOId));
1146
return (GLuint)curFBOId == m_FBOId;
1154
if ([self lockFocusIfCanDraw])
1156
[self renderFBOToView];
1018
1161
- (void)swapFBO
1020
DEBUG_MSG_1(("SwapCurrent called %X\n", self));
1164
GLint readFBOId = 0;
1165
GLint drawFBOId = 0;
1169
DEBUG_MSG(("OVIW(%p): swapFBO\n", (void*)self));
1024
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB);
1025
DEBUG_MSG_1(("Swap GetINT %d\n", tmpFB));
1026
/* Don't use flush buffers cause we are using FBOs here */
1027
// [m_pGLCtx flushBuffer];
1172
/* Don't use flush buffers cause we are using FBOs here! */
1174
/* Before we swap make sure everything is done (This is really
1175
* important. Don't remove.) */
1029
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1030
DEBUG_MSG_1(("swapFBO bound:%i, self:%i\n", tmpFB, m_FBOId));
1031
if (tmpFB == m_FBOId)
1033
if ([self lockFocusIfCanDraw])
1035
[self renderFBOToView];
1039
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1178
/* Fetch the current used read and draw buffers. */
1179
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &readFBOId);
1180
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &drawFBOId);
1181
glGetIntegerv(GL_READ_BUFFER, &readId);
1182
glGetIntegerv(GL_DRAW_BUFFER, &drawId);
1184
/* Do the swapping of our internal ids */
1185
sw = m_FBOTexFrontId;
1186
m_FBOTexFrontId = m_FBOTexBackId;
1187
m_FBOTexBackId = sw;
1188
sw = m_FBOAttFrontId;
1189
m_FBOAttFrontId = m_FBOAttBackId;
1190
m_FBOAttBackId = sw;
1192
DEBUG_MSG_1(("read FBO: %d draw FBO: %d readId: %d drawId: %d\n", readFBOId, drawFBOId, readId, drawId));
1193
/* We also have to swap the real ids on the current context. */
1194
if ((GLuint)readFBOId == m_FBOId)
1196
if ((GLuint)readId == m_FBOAttFrontId)
1197
glReadBuffer(m_FBOAttBackId);
1198
if ((GLuint)readId == m_FBOAttBackId)
1199
glReadBuffer(m_FBOAttFrontId);
1201
if ((GLuint)drawFBOId == m_FBOId)
1203
if ((GLuint)drawId == m_FBOAttFrontId)
1204
glDrawBuffer(m_FBOAttBackId);
1205
if ((GLuint)drawId == m_FBOAttBackId)
1206
glDrawBuffer(m_FBOAttFrontId);
1041
1211
[m_pGLCtx flushBuffer];
1045
1215
- (void)flushFBO
1048
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB);
1220
DEBUG_MSG(("OVIW(%p): flushFBO\n", (void*)self));
1050
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1051
DEBUG_MSG_1 (("Flush GetINT %d\n", tmpFB));
1052
if (tmpFB == m_FBOId)
1224
/* If at any time OpenGl operations where done in the front buffer, we need
1225
* to reflect this in the FBO as well. This is something which on real
1226
* hardware happens and unfortunately some applications rely on it (grrr ... Compiz). */
1227
if ( m_fFrontDrawing
1228
&& [self isCurrentFBO])
1054
if ([self lockFocusIfCanDraw])
1056
[self renderFBOToView];
1230
/* Only reset if we aren't currently front. */
1231
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &FBOId);
1232
glGetIntegerv(GL_DRAW_BUFFER, &drawId);
1233
if (!( (GLuint)FBOId == m_FBOId
1234
&& (GLuint)drawId == m_FBOAttFrontId))
1235
m_fFrontDrawing = false;
1060
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1063
1241
- (void)finishFBO
1066
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &tmpFB);
1243
DEBUG_MSG(("OVIW(%p): finishFBO\n", (void*)self));
1068
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1069
DEBUG_MSG_1 (("Finish GetINT %d\n", tmpFB));
1070
if (tmpFB == m_FBOId)
1072
if ([self lockFocusIfCanDraw])
1074
[self renderFBOToView];
1078
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1083
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOId);
1247
if ([self isCurrentFBO])
1252
- (void)stateInfo:(GLenum)pname withParams:(GLint*)params
1255
// DEBUG_MSG_1(("StateInfo requested: %d\n", pname));
1257
glGetIntegerv(pname, params);
1261
case GL_FRAMEBUFFER_BINDING_EXT:
1262
case GL_READ_FRAMEBUFFER_BINDING:
1263
case GL_READ_FRAMEBUFFER_EXT:
1264
case GL_DRAW_FRAMEBUFFER_EXT:
1266
if ((GLuint)*params == m_FBOId)
1270
case GL_READ_BUFFER:
1272
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &test);
1273
if ((GLuint)test == m_FBOId)
1275
if ((GLuint)*params == m_FBOAttFrontId)
1278
if ((GLuint)*params == m_FBOAttBackId)
1283
case GL_DRAW_BUFFER:
1285
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &test);
1286
if ((GLuint)test == m_FBOId)
1288
if ((GLuint)*params == m_FBOAttFrontId)
1291
if ((GLuint)*params == m_FBOAttBackId)
1300
- (void)readBuffer:(GLenum)mode
1304
if ([self isCurrentFBO])
1307
if (mode == GL_FRONT)
1309
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1310
glReadBuffer(m_FBOAttFrontId);
1312
else if (mode == GL_BACK)
1314
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1315
glReadBuffer(m_FBOAttBackId);
1325
- (void)drawBuffer:(GLenum)mode
1329
if ([self isCurrentFBO])
1332
if (mode == GL_FRONT)
1334
DEBUG_MSG(("OVIW(%p): front\n", (void*)self));
1335
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId);
1336
glDrawBuffer(m_FBOAttFrontId);
1337
m_fFrontDrawing = true;
1339
else if (mode == GL_BACK)
1341
DEBUG_MSG(("OVIW(%p): back\n", (void*)self));
1342
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_FBOId);
1343
glDrawBuffer(m_FBOAttBackId);
1347
DEBUG_MSG(("OVIW(%p): other: %d\n", (void*)self, mode));
1356
- (void)bindFBO:(GLenum)target withFrameBuffer:(GLuint)framebuffer
1359
if (framebuffer != 0)
1360
glBindFramebufferEXT(target, framebuffer);
1362
glBindFramebufferEXT(target, m_FBOId);
1364
glBindFramebufferEXT(target, framebuffer);
1086
1368
- (void)renderFBOToView
1372
GLint oldReadFBOId = 0;
1373
GLint oldDrawFBOId = 0;
1374
GLint oldReadId = 0;
1375
GLint oldDrawId = 0;
1377
DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void*)self));
1381
/* Fetch the current used read and draw buffers. */
1382
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &oldReadFBOId);
1383
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &oldDrawFBOId);
1384
glGetIntegerv(GL_READ_BUFFER, &oldReadId);
1385
glGetIntegerv(GL_DRAW_BUFFER, &oldDrawId);
1088
1387
if (!m_pSharedGLCtx)
1090
1389
/* Create a shared context out of the main context. Use the same pixel format. */
1091
1390
m_pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:[(OverlayOpenGLContext*)m_pGLCtx openGLPixelFormat] shareContext:m_pGLCtx];
1093
1392
/* Set the new context as non opaque */
1095
[m_pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
1096
/* Only swap on screen refresh */
1098
// [m_pSharedGLCtx setValues:&swap forParameter:NSOpenGLCPSwapInterval];
1393
[m_pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
1099
1394
/* Set this view as the drawable for the new context */
1100
1395
[m_pSharedGLCtx setView: self];
1101
1396
[self updateViewport];
1104
1399
if (m_pSharedGLCtx)
1106
1401
NSRect r = [self frame];
1107
DEBUG_MSG_1(("rF2V frame[%i, %i, %i, %i]\n", (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
1402
DEBUG_MSG(("OVIW(%p): rF2V frame: [%i, %i, %i, %i]\n", (void*)self, (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
1404
if (m_FBOTexFrontId > 0)
1111
1406
if ([m_pSharedGLCtx view] != self)
1113
DEBUG_MSG(("renderFBOToView: not current view of shared ctx!"));
1408
DEBUG_MSG(("OVIW(%p): not current view of shared ctx! Switching ...\n", (void*)self));
1114
1409
[m_pSharedGLCtx setView: self];
1115
1410
[self updateViewport];
1118
//DEBUG_MSG(("MakeCurrent (shared) %X\n", m_pSharedGLCtx));
1119
1413
[m_pSharedGLCtx makeCurrentContext];
1121
if (m_FBOThumbTexId > 0 &&
1122
[m_DockTileView thumbBitmap] != nil)
1124
/* Only update after at least 200 ms, cause glReadPixels is
1125
* heavy performance wise. */
1126
uint64_t uiNewTime = RTTimeMilliTS();
1127
if (uiNewTime - m_uiDockUpdateTime > 200)
1129
m_uiDockUpdateTime = uiNewTime;
1131
/* todo: check this for optimization */
1132
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
1133
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
1134
GL_STORAGE_SHARED_APPLE);
1135
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1136
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
1137
sizex, sizey, 0, GL_BGRA,
1138
GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
1139
glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
1140
0, 0, 0, 0, 0, image_width, image_height);
1142
// Do other work processing here, using a double or triple buffer
1143
glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
1144
GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
1148
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_FBOThumbId);
1150
/* We like to read from the primary color buffer */
1151
glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
1153
NSRect rr = [m_DockTileView frame];
1155
/* Setup all matrices */
1156
glMatrixMode(GL_PROJECTION);
1158
glViewport(0, 0, rr.size.width, rr.size.height);
1159
glOrtho(0, rr.size.width, 0, rr.size.height, -1, 1);
1160
glScalef(m_FBOThumbScaleX, m_FBOThumbScaleY, 1.0f);
1161
glMatrixMode(GL_TEXTURE);
1163
glTranslatef(0.0f, m_RootShift.y, 0.0f);
1164
glMatrixMode(GL_MODELVIEW);
1167
/* Clear background to transparent */
1168
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1169
glClear(GL_COLOR_BUFFER_BIT);
1171
glEnable(GL_TEXTURE_RECTANGLE_ARB);
1172
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
1174
for (i = 0; i < m_cClipRects; ++i)
1176
GLint x1 = m_paClipRects[4*i];
1177
GLint y1 = (r.size.height - m_paClipRects[4*i+1]);
1178
GLint x2 = m_paClipRects[4*i+2];
1179
GLint y2 = (r.size.height - m_paClipRects[4*i+3]);
1182
glTexCoord2i(x1, y1); glVertex2i(x1, y1);
1183
glTexCoord2i(x1, y2); glVertex2i(x1, y2);
1184
glTexCoord2i(x2, y2); glVertex2i(x2, y2);
1185
glTexCoord2i(x2, y1); glVertex2i(x2, y1);
1191
/* Here the magic of reading the FBO content in our own buffer
1192
* happens. We have to lock this access, in the case the dock
1193
* is updated currently. */
1194
[m_DockTileView lock];
1195
glReadPixels(0, 0, rr.size.width, rr.size.height,
1198
[[m_DockTileView thumbBitmap] bitmapData]);
1199
[m_DockTileView unlock];
1201
NSDockTile *pDT = [[NSApplication sharedApplication] dockTile];
1203
/* Send a display message to the dock tile in the main thread */
1204
[[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO];
1206
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1415
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1416
glReadBuffer(m_FBOAttFrontId);
1417
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
1418
glDrawBuffer(GL_BACK);
1420
/* Render FBO content to the dock tile when necessary. */
1421
[self renderFBOToDockTile];
1423
#if 1 /* Set to 0 to see the docktile instead of the real output */
1211
1424
/* Clear background to transparent */
1212
1425
glClear(GL_COLOR_BUFFER_BIT);
1214
glEnable(GL_TEXTURE_RECTANGLE_ARB);
1215
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_FBOTexId);
1217
/* Blit the content of the FBO to the screen. todo: check for
1218
* optimization with display lists. */
1427
/* Blit the content of the FBO to the screen. */
1220
1428
for (i = 0; i < m_cClipRects; ++i)
1222
1430
GLint x1 = m_paClipRects[4*i];
1223
1431
GLint y1 = r.size.height - m_paClipRects[4*i+1];
1224
1432
GLint x2 = m_paClipRects[4*i+2];
1225
1433
GLint y2 = r.size.height - m_paClipRects[4*i+3];
1228
glTexCoord2i(x1, y1); glVertex2i(x1, y1);
1229
glTexCoord2i(x1, y2); glVertex2i(x1, y2);
1230
glTexCoord2i(x2, y2); glVertex2i(x2, y2);
1231
glTexCoord2i(x2, y1); glVertex2i(x2, y1);
1434
glBlitFramebufferEXT(x1, y1 + m_RootShift.y, x2, y2 + m_RootShift.y,
1435
x1 - m_RootShift.x, y1, x2 - m_RootShift.x, y2,
1436
GL_COLOR_BUFFER_BIT, GL_NEAREST);
1442
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
1236
1443
[m_pSharedGLCtx flushBuffer];
1237
//DEBUG_MSG(("MakeCurrent %X\n", m_pGLCtx));
1238
1445
[m_pGLCtx makeCurrentContext];
1446
/* Reset to previous buffer bindings. */
1447
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, oldReadFBOId);
1448
glReadBuffer(oldReadId);
1449
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, oldDrawFBOId);
1450
glDrawBuffer(oldDrawId);
1454
[m_pGLCtx flushBuffer];
1458
- (void)renderFBOToDockTile
1460
NSRect r = [self frame];
1461
NSRect rr = NSZeroRect;
1463
NSDockTile *pDT = nil;
1468
&& [m_DockTileView thumbBitmap] != nil)
1470
/* Only update after at least 200 ms, cause glReadPixels is
1471
* heavy performance wise. */
1472
uint64_t uiNewTime = RTTimeMilliTS();
1473
if (uiNewTime - m_uiDockUpdateTime > 200)
1475
m_uiDockUpdateTime = uiNewTime;
1477
/* todo: check this for optimization */
1478
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
1479
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
1480
GL_STORAGE_SHARED_APPLE);
1481
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1482
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
1483
sizex, sizey, 0, GL_BGRA,
1484
GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
1485
glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
1486
0, 0, 0, 0, 0, image_width, image_height);
1488
/* Do other work processing here, using a double or triple buffer */
1489
glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
1490
GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
1492
/* Clear background to transparent */
1493
glClear(GL_COLOR_BUFFER_BIT);
1495
rr = [m_DockTileView frame];
1497
for (i = 0; i < m_cClipRects; ++i)
1499
GLint x1 = m_paClipRects[4*i];
1500
GLint y1 = r.size.height - m_paClipRects[4*i+1];
1501
GLint x2 = m_paClipRects[4*i+2];
1502
GLint y2 = r.size.height - m_paClipRects[4*i+3];
1504
glBlitFramebufferEXT(x1, y1 + m_RootShift.y, x2, y2 + m_RootShift.y,
1505
x1 * m_FBOThumbScaleX, y1 * m_FBOThumbScaleY, x2 * m_FBOThumbScaleX, y2 * m_FBOThumbScaleY,
1506
GL_COLOR_BUFFER_BIT, GL_LINEAR);
1510
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
1511
glReadBuffer(GL_BACK);
1512
/* Here the magic of reading the FBO content in our own buffer
1513
* happens. We have to lock this access, in the case the dock
1514
* is updated currently. */
1515
[m_DockTileView lock];
1516
glReadPixels(0, 0, rr.size.width, rr.size.height,
1518
GL_UNSIGNED_INT_8_8_8_8,
1519
[[m_DockTileView thumbBitmap] bitmapData]);
1520
[m_DockTileView unlock];
1522
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_FBOId);
1523
glReadBuffer(m_FBOAttFrontId);
1525
pDT = [[NSApplication sharedApplication] dockTile];
1527
/* Send a display message to the dock tile in the main thread */
1528
[[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:NO];
1243
1535
- (void)clearVisibleRegions
1605
1938
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1607
DEBUG_MSG(("glRenderspuBindFramebufferEXT called %d\n", framebuffer));
1940
DEBUG_MSG_1(("glBindFramebufferEXT called target: %d fb: %d\n", target, framebuffer));
1942
performSelectorOnViewTwoArgs(@selector(bindFBO:withFrameBuffer:), (id)target, (id)framebuffer);
1947
void cocoaCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)
1949
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1950
GLbitfield mask = GL_COLOR_BUFFER_BIT;
1952
DEBUG_MSG_1(("glCopyPixels called: %d,%d-%dx%d type: %d\n", x, y, width, height, type));
1610
if (framebuffer != 0)
1611
glBindFramebufferEXT(target, framebuffer);
1614
NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
1617
NSView *pView = [pCtx view];
1620
if ([pView respondsToSelector:@selector(bindFBO)])
1621
[pView performSelector:@selector(bindFBO)];
1955
if (type == GL_DEPTH)
1956
mask = GL_DEPTH_BUFFER_BIT;
1957
else if (type == GL_STENCIL)
1958
mask = GL_STENCIL_BUFFER_BIT;
1959
glBlitFramebufferEXT(x, y, x + width, y + height, x, y, x + width, y + height, mask, GL_NEAREST);
1626
glBindFramebufferEXT(target, framebuffer);
1961
glCopyPixels(x, y, width, height, type);
1629
1964
[pPool release];
1967
void cocoaGetIntegerv(GLenum pname, GLint *params)
1969
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1971
// DEBUG_MSG_1(("getIntergerv called: %d\n", pname));
1973
performSelectorOnViewTwoArgs(@selector(stateInfo:withParams:), (id)pname, (id)params);
1978
void cocoaReadBuffer(GLenum mode)
1980
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1982
DEBUG_MSG_1(("glReadBuffer called: %d\n", mode));
1984
performSelectorOnViewOneArg(@selector(readBuffer:), (id)mode);
1989
void cocoaDrawBuffer(GLenum mode)
1991
NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
1993
DEBUG_MSG_1(("glDrawBuffer called: %d\n", mode));
1995
performSelectorOnViewOneArg(@selector(drawBuffer:), (id)mode);