summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/HostServices/SharedOpenGL
parentInitial commit. (diff)
downloadvirtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.tar.xz
virtualbox-f8fe689a81f906d1b91bb3220acde2a4ecb14c5b.zip
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/.scm-settings42
-rw-r--r--src/VBox/HostServices/SharedOpenGL/LICENSE32
-rw-r--r--src/VBox/HostServices/SharedOpenGL/Makefile.kmk459
-rw-r--r--src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTest.cpp103
-rw-r--r--src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestApp.cpp363
-rw-r--r--src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestDarwin.cpp176
-rw-r--r--src/VBox/HostServices/SharedOpenGL/OpenGLTest/VBoxTestOGL.rc51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserver/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserver/VBoxSharedCrOpenGL.rc51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp1603
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserver/main.c23
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/crserverlib.def14
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py468
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp390
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp341
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp381
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp574
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp347
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp4063
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h440
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp480
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server.h718
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_boundsinfo.c329
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c111
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c492
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_clip.c588
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c404
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c481
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py137
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c237
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_gentextures.c142
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py145
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getmap.c247
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpixelmap.c142
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpointer.c32
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c395
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getstring.c38
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getteximage.c156
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c262
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c284
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c4039
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c2016
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp840
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_occlude.c37
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_papi.c272
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_projmatrix.c402
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_readpixels.c91
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py83
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp755
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py152
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_special268
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c934
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c323
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_viewport.c288
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c484
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_winpos.c95
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_writeback.c28
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm.c575
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm.h31
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_arrays.c387
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_checklist.c51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_error.c56
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/dlm/dlm_generated.py355
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_header.py274
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_lists.c452
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.c1125
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.h81
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_special21
-rw-r--r--src/VBox/HostServices/SharedOpenGL/dlm/dlm_state.c280
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expando.py91
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expando_special18
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expandospu.c182
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expandospu.def6
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expandospu.h69
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c48
-rw-r--r--src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c289
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/render.def7
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu.c1960
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu.h506
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c907
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c479
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h65
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m3283
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c392
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c2042
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c623
-rw-r--r--src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c1741
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack.def11
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/unpacker/unpack.py394
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_arrays.c312
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bounds.c27
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bufferobject.c54
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_calllists.c17
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_clipplane.c19
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_context.c46
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_drawpixels.c94
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/unpacker/unpack_extend.py35
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fence.c10
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fog.c25
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_framebuffer.c37
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/unpacker/unpack_header.py30
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_lights.c45
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_map.c138
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_materials.c27
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_matrices.c72
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_misc.c87
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_pixelmap.c65
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_point.c24
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_program.c386
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_readpixels.c46
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_regcombiner.c35
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_shaders.c386
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_stipple.c27
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_texture.c507
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_visibleregion.c37
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpack_writeback.c35
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpacker.h19
-rw-r--r--src/VBox/HostServices/SharedOpenGL/unpacker/unpacker_special184
126 files changed, 46577 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/.scm-settings b/src/VBox/HostServices/SharedOpenGL/.scm-settings
new file mode 100644
index 00000000..b16af1ce
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/.scm-settings
@@ -0,0 +1,42 @@
+# $Id: .scm-settings $
+## @file
+# Source code massager settings for the SharedOpenGL host service.
+#
+
+#
+# Copyright (C) 2017-2019 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+
+# The basic config here is external copyright, however there are lots of exceptions
+/*.h: --external-copyright --no-convert-tabs --no-strip-trailing-blanks --no-fix-header-guards
+/crserverlib/presenter/server_presenter.h: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/render/renderspu_cocoa_helper.h: --no-external-copyright --convert-tabs --strip-trailing-blanks
+
+/*.c: --external-copyright --no-convert-tabs --no-strip-trailing-blanks
+/crserverlib/server_framebuffer.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/crserverlib/server_getshaders.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/crserverlib/server_glsl.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/crserverlib/server_texture.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/dlm/dlm_lists.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/dlm/dlm_state.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/expando/expandospu.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/render/renderspu_cocoa.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/unpacker/unpack_framebuffer.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/unpacker/unpack_shaders.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+/unpacker/unpack_visibleregion.c: --no-external-copyright --convert-tabs --strip-trailing-blanks
+
+/*.def: --external-copyright
+/*.py: --external-copyright --no-convert-tabs --no-strip-trailing-blanks
+
+--filter-out-files *_special
+--filter-out-files /LICENSE
+
diff --git a/src/VBox/HostServices/SharedOpenGL/LICENSE b/src/VBox/HostServices/SharedOpenGL/LICENSE
new file mode 100644
index 00000000..d609a358
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/LICENSE
@@ -0,0 +1,32 @@
+Copyright (c) 2002, Stanford University
+All rights reserved.
+
+Some portions of Chromium are copyrighted by individual organizations.
+Please see the files COPYRIGHT.LLNL and COPYRIGHT.REDHAT for more
+information.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of Stanford University nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/VBox/HostServices/SharedOpenGL/Makefile.kmk b/src/VBox/HostServices/SharedOpenGL/Makefile.kmk
new file mode 100644
index 00000000..e0faf5d6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/Makefile.kmk
@@ -0,0 +1,459 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the Shared OpenGL Host Service.
+#
+
+#
+# Copyright (C) 2008-2019 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+
+#
+# Target lists.
+#
+ifdef VBOX_WITH_MAIN
+DLLS += VBoxSharedCrOpenGL VBoxOGLrenderspu
+LIBRARIES += VBoxOGLcrserverlib VBoxOGLcrunpacker
+BLDDIRS += \
+ $(VBOX_PATH_CROGL_GENFILES)/
+endif
+
+ifdef VBOX_WITH_CR_DISPLAY_LISTS
+ LIBRARIES += VBoxOGLcrdlm
+ DLLS += VBoxOGLexpandospu
+endif # VBOX_WITH_CR_DISPLAY_LISTS
+
+ifeq ($(KBUILD_TARGET),darwin)
+ #
+ # We have to symlink the system headers of OpenGl cause they have some
+ # different directory hierarchy on Mac OS X (no /GL sub directory).
+ #
+ # See Config.kmk for the global variables.
+ #
+ INSTALLS += DarwinOpenGLHdrs
+ DarwinOpenGLHdrs_INST = $(VBOX_DARWIN_OPENGL_INST)
+ DarwinOpenGLHdrs_SYMLINKS = \
+ $(foreach hdr, $(VBOX_DARWIN_OPENGL_HEADERS),\
+ $(hdr)=>$(VBOX_PATH_MACOSX_SDK)/System/Library/Frameworks/OpenGL.framework/Versions/Current/Headers/$(hdr))
+endif # darwin
+
+#
+# VBoxSharedCrOpenGL
+#
+VBoxSharedCrOpenGL_TEMPLATE = VBOXCROGLR3HOSTDLL
+ifdef VBOX_WITH_XPCOM
+ VBoxSharedCrOpenGL_DEFS = VBOX_WITH_XPCOM
+ VBoxSharedCrOpenGL_CXXFLAGS = -Wno-non-virtual-dtor -fshort-wchar $(VBOX_GCC_std)
+endif
+VBoxSharedCrOpenGL_INTERMEDIATES = \
+ $(TEMPLATE_VBOXMAINEXE_INTERMEDIATES)
+VBoxSharedCrOpenGL_INCS = $(VBOX_GRAPHICS_INCS)
+VBoxSharedCrOpenGL_INCS.win = \
+ $(VBOX_PATH_SDK)/bindings/mscom/include
+ifdef VBOX_WITH_XPCOM
+VBoxSharedCrOpenGL_INCS += \
+ $(VBOX_XPCOM_INCS)
+endif
+VBoxSharedCrOpenGL_SOURCES = \
+ crserver/crservice.cpp
+VBoxSharedCrOpenGL_SOURCES.win = \
+ crserver/VBoxSharedCrOpenGL.rc
+VBoxSharedCrOpenGL_LDFLAGS.darwin = -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxSharedCrOpenGL.dylib
+VBoxSharedCrOpenGL_LIBS = \
+ $(PATH_STAGE_LIB)/VBoxOGLcrserverlib$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBoxOGLhostcrstate$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBoxOGLcrunpacker$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBoxOGLhostcrpacker$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBoxOGLhostspuload$(VBOX_SUFF_LIB) \
+ $(VBOX_LIB_OGL_HOSTCRUTIL) \
+ $(PATH_STAGE_LIB)/VBoxCOM$(VBOX_SUFF_LIB) \
+ $(LIB_RUNTIME) \
+ $(LIB_VMM)
+VBoxSharedCrOpenGL_LIBS.darwin = \
+ $(LIB_REM)
+ifeq ($(KBUILD_TARGET),win)
+ VBoxSharedCrOpenGL_LIBS += \
+ $(PATH_OBJ)/VBoxOGLrenderspu/VBoxOGLrenderspu$(VBOX_SUFF_LIB)
+else
+ VBoxSharedCrOpenGL_LIBS += \
+ $(PATH_STAGE_BIN)/VBoxOGLrenderspu$(VBOX_SUFF_DLL)
+endif
+ifdef VBOX_WITH_XPCOM
+ VBoxSharedCrOpenGL_LIBS += \
+ $(LIB_XPCOM)
+endif
+ifdef VBOX_WITH_CRHGSMI
+VBoxSharedCrOpenGL_DEFS += VBOX_WITH_CRHGSMI
+endif
+ifdef VBOX_WITH_CR_DISPLAY_LISTS
+VBoxSharedCrOpenGL_LIBS += $(PATH_STAGE_LIB)/VBoxOGLcrdlm$(VBOX_SUFF_LIB)
+endif
+
+#
+# VBoxOGLcrserverlib
+#
+VBoxOGLcrserverlib_TEMPLATE = VBOXCROGLR3HOSTLIB
+VBoxOGLcrserverlib_INCS = \
+ . \
+ crserverlib \
+ $(VBOX_GRAPHICS_INCS)
+VBoxOGLcrserverlib_INTERMEDIATES = \
+ $(VBOX_PATH_CROGL_GENFILES)/spu_dispatch_table.h \
+ $(VBOX_PATH_CROGL_GENFILES)/server_dispatch.h \
+ $(VBOX_PATH_CROGL_GENFILES)/cr_opcodes.h \
+ $(VBOX_PATH_CROGL_GENFILES)/state/cr_currentpointers.h \
+ $(VBOX_PATH_CROGL_GENFILES)/state/cr_statefuncs.h
+
+ifdef VBOX_WITH_CR_DISPLAY_LISTS
+VBoxOGLcrserverlib_INTERMEDIATES += $(VBOX_PATH_CROGL_GENFILES)/cr_dlm.h
+endif
+
+VBoxOGLcrserverlib_SOURCES := \
+ crserverlib/server_main.c \
+ crserverlib/server_boundsinfo.c \
+ crserverlib/server_bufferobject.c \
+ crserverlib/server_clear.c \
+ crserverlib/server_clip.c \
+ crserverlib/server_config.c \
+ crserverlib/server_context.c \
+ crserverlib/server_gentextures.c \
+ crserverlib/server_getmap.c \
+ crserverlib/server_getstring.c \
+ crserverlib/server_getpointer.c \
+ crserverlib/server_getpixelmap.c \
+ crserverlib/server_getteximage.c \
+ crserverlib/server_lists.c \
+ crserverlib/server_misc.c \
+ crserverlib/server_occlude.c \
+ crserverlib/server_papi.c \
+ crserverlib/server_projmatrix.c \
+ crserverlib/server_readpixels.c \
+ crserverlib/server_stream.c \
+ crserverlib/server_viewport.c \
+ crserverlib/server_window.c \
+ crserverlib/server_winpos.c \
+ crserverlib/server_writeback.c \
+ crserverlib/server_getshaders.c \
+ crserverlib/server_framebuffer.c \
+ crserverlib/server_glsl.c \
+ crserverlib/server_muralfbo.cpp \
+ crserverlib/server_texture.c \
+ crserverlib/presenter/server_presenter.cpp \
+ crserverlib/presenter/display_base.cpp \
+ crserverlib/presenter/display_composite.cpp \
+ crserverlib/presenter/window.cpp \
+ crserverlib/presenter/display_window.cpp \
+ crserverlib/presenter/display_window_rootvr.cpp \
+ crserverlib/presenter/display_vrdp.cpp \
+ crserverlib/server_rpw.cpp \
+ $(VBOX_PATH_CROGL_GENFILES)/server_dispatch.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_retval.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_get.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_simpleget.c
+VBoxOGLcrserverlib_CLEAN = \
+ $(VBOX_PATH_CROGL_GENFILES)/server_dispatch.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_retval.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_get.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_simpleget.c \
+ $(VBOX_PATH_CROGL_GENFILES)/server_dispatch.h
+ifdef VBOX_WITH_CR_DISPLAY_LISTS
+VBoxOGLcrserverlib_DEFS += VBOX_WITH_CR_DISPLAY_LISTS
+endif
+ifdef VBOXCR_LOGFPS
+VBoxOGLcrserverlib_DEFS += VBOXCR_LOGFPS
+endif
+ifdef VBOX_WITH_CRHGSMI
+VBoxOGLcrserverlib_DEFS += ifdef VBOX_WITH_CRHGSMI
+endif
+ifdef VBOX_WITH_CRDUMPER
+VBoxOGLcrserverlib_DEFS += VBOX_WITH_CRDUMPER
+endif
+ifdef VBOX_WITH_CRSERVER_DUMPER
+VBoxOGLcrserverlib_DEFS += VBOX_WITH_CRSERVER_DUMPER
+endif
+
+
+#
+# Generate files for VBoxOGLcrserverlib
+#
+$(VBOX_PATH_CROGL_GENFILES)/server_dispatch.h: $(addprefix $(PATH_SUB_CURRENT)/crserverlib/, server_dispatch_header.py server_special) $(VBOX_CROGL_API_FILES) $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/state_tracker/state_special | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+$(VBOX_PATH_CROGL_GENFILES)/server_dispatch.c: $(addprefix $(PATH_SUB_CURRENT)/crserverlib/, server_dispatch.py server_special) $(VBOX_CROGL_API_FILES) $(PATH_ROOT)/src/VBox/GuestHost/OpenGL/state_tracker/state_special | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+$(VBOX_PATH_CROGL_GENFILES)/server_retval.c: $(addprefix $(PATH_SUB_CURRENT)/crserverlib/, server_retval.py server_special) $(VBOX_CROGL_API_FILES) | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+$(VBOX_PATH_CROGL_GENFILES)/server_get.c: $(addprefix $(PATH_SUB_CURRENT)/crserverlib/, server_get.py server_special) $(VBOX_CROGL_API_FILES) | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+$(VBOX_PATH_CROGL_GENFILES)/server_simpleget.c: $(addprefix $(PATH_SUB_CURRENT)/crserverlib/, server_simpleget.py get_sizes.py) $(VBOX_CROGL_API_FILES) | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+
+#
+# VBoxOGLcrunpacker
+#
+VBoxOGLcrunpacker_TEMPLATE = VBOXCROGLR3HOSTLIB
+VBoxOGLcrunpacker_INCS = \
+ unpacker \
+ $(VBOX_GRAPHICS_INCS)
+VBoxOGLcrunpacker_INTERMEDIATES = \
+ $(VBOX_PATH_CROGL_GENFILES)/spu_dispatch_table.h \
+ $(VBOX_PATH_CROGL_GENFILES)/cr_opcodes.h \
+ $(VBOX_PATH_CROGL_GENFILES)/unpack_extend.h \
+ $(VBOX_PATH_CROGL_GENFILES)/state/cr_currentpointers.h \
+ $(VBOX_PATH_CROGL_GENFILES)/state/cr_statefuncs.h
+VBoxOGLcrunpacker_SOURCES = \
+ unpacker/unpack_arrays.c \
+ unpacker/unpack_bounds.c \
+ unpacker/unpack_bufferobject.c \
+ unpacker/unpack_calllists.c \
+ unpacker/unpack_clipplane.c \
+ unpacker/unpack_context.c \
+ unpacker/unpack_drawpixels.c \
+ unpacker/unpack_fence.c \
+ unpacker/unpack_fog.c \
+ unpacker/unpack_lights.c \
+ unpacker/unpack_map.c \
+ unpacker/unpack_materials.c \
+ unpacker/unpack_matrices.c \
+ unpacker/unpack_misc.c \
+ unpacker/unpack_pixelmap.c \
+ unpacker/unpack_point.c \
+ unpacker/unpack_program.c \
+ unpacker/unpack_readpixels.c \
+ unpacker/unpack_regcombiner.c \
+ unpacker/unpack_stipple.c \
+ unpacker/unpack_texture.c \
+ unpacker/unpack_writeback.c \
+ unpacker/unpack_visibleregion.c \
+ unpacker/unpack_shaders.c \
+ unpacker/unpack_framebuffer.c \
+ $(VBOX_PATH_CROGL_GENFILES)/unpack.c
+VBoxOGLcrunpacker_CLEAN = \
+ $(VBOX_PATH_CROGL_GENFILES)/unpack.c \
+ $(VBOX_PATH_CROGL_GENFILES)/unpack_extend.h
+
+#
+# Generate files for VBoxOGLcrunpacker.
+#
+$(VBOX_PATH_CROGL_GENFILES)/unpack.c: \
+ $(addprefix $(PATH_SUB_CURRENT)/unpacker/, unpack.py unpacker_special) \
+ $(VBOX_PATH_CROGL_GENFILES)/unpack_extend.h \
+ $(VBOX_CROGL_API_FILES) \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+$(VBOX_PATH_CROGL_GENFILES)/unpack_extend.h: \
+ $(addprefix $(PATH_SUB_CURRENT)/unpacker/, unpack_extend.py unpacker_special) \
+ $(VBOX_CROGL_API_FILES) \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D)
+
+
+ifdef VBOX_WITH_CR_DISPLAY_LISTS
+#
+# VBoxOGLcrdlm
+#
+
+VBoxOGLcrdlm_TEMPLATE = VBOXCROGLR3HOSTLIB
+VBoxOGLcrdlm_INCS = \
+ dlm
+VBoxOGLcrdlm_INTERMEDIATES = \
+ $(VBOX_PATH_CROGL_GENFILES)/cr_dlm.h \
+ $(VBOX_PATH_CROGL_GENFILES)/dlm_generated.h
+
+VBoxOGLcrdlm_SOURCES = \
+ dlm/dlm.c \
+ dlm/dlm_arrays.c \
+ dlm/dlm_state.c \
+ dlm/dlm_checklist.c \
+ dlm/dlm_error.c \
+ dlm/dlm_lists.c \
+ dlm/dlm_pointers.c \
+ $(VBOX_PATH_CROGL_GENFILES)/dlm_generated.c
+
+VBoxOGLcrdlm_CLEAN = \
+ $(VBOX_PATH_CROGL_GENFILES)/dlm_generated.c \
+ $(VBOX_PATH_CROGL_GENFILES)/cr_dlm.h \
+ $(VBOX_PATH_CROGL_GENFILES)/dlm_generated.h
+#
+# Generate files for VBoxOGLcrdlm.
+#
+$(VBOX_PATH_CROGL_GENFILES)/cr_dlm.h: \
+ $(addprefix $(PATH_SUB_CURRENT)/dlm/, dlm_header.py) \
+ $(VBOX_CROGL_API_FILES) \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< header $(<D) $(VBOX_PATH_CROGL_GLAPI) > $@
+
+$(VBOX_PATH_CROGL_GENFILES)/dlm_generated.h: \
+ $(addprefix $(PATH_SUB_CURRENT)/dlm/, dlm_generated.py dlm_special) \
+ $(VBOX_PATH_CROGL_GENFILES)/cr_dlm.h \
+ $(VBOX_CROGL_API_FILES) \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< headers $(<D) $(VBOX_PATH_CROGL_GLAPI) > $@
+
+$(VBOX_PATH_CROGL_GENFILES)/dlm_generated.c: \
+ $(addprefix $(PATH_SUB_CURRENT)/dlm/, dlm_generated.py dlm_special) \
+ $(VBOX_PATH_CROGL_GENFILES)/dlm_generated.h \
+ $(VBOX_CROGL_API_FILES) \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< source $(<D) $(VBOX_PATH_CROGL_GLAPI) > $@
+
+
+#
+# VBoxOGLexpandospu
+#
+VBoxOGLexpandospu_TEMPLATE = VBOXCROGLR3HOSTDLL
+VBoxOGLexpandospu_INCS = \
+ expando
+VBoxOGLexpandospu_SOURCES = \
+ expando/expandospu.c \
+ expando/expandospu_config.c \
+ expando/expandospu_init.c \
+ $(VBOX_PATH_CROGL_GENFILES)/expando.c
+VBoxOGLexpandospu_CLEAN = \
+ $(VBOX_PATH_CROGL_GENFILES)/expando.c
+VBoxOGLexpandospu_CLEAN = \
+ $(VBOX_PATH_CROGL_GENFILES)/expando.c
+VBoxOGLexpandospu_LDFLAGS.darwin += -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxOGLexpandospu.dylib
+VBoxOGLexpandospu_LIBS = \
+ $(PATH_STAGE_LIB)/VBoxOGLcrdlm$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBoxOGLhostcrstate$(VBOX_SUFF_LIB) \
+ $(PATH_STAGE_LIB)/VBoxOGLhostspuload$(VBOX_SUFF_LIB) \
+ $(VBOX_LIB_OGL_HOSTCRUTIL) \
+ $(LIB_RUNTIME) \
+ $(LIB_VMM)
+#
+# Generate files for VBoxOGLexpandospu.
+#
+$(VBOX_PATH_CROGL_GENFILES)/expando.c: \
+ $(addprefix $(PATH_SUB_CURRENT)/expando/, expando.py expando_special) \
+ $(VBOX_CROGL_API_FILES) \
+ | $$(dir $$@)
+ $(call MSG_GENERATE,python,$@,$<)
+ $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D) > $@
+endif
+
+
+#
+# VBoxOGLrenderspu
+#
+VBoxOGLrenderspu_TEMPLATE = VBOXCROGLR3HOSTDLL
+VBoxOGLrenderspu_INTERMEDIATES = \
+ $(VBOX_PATH_CROGL_GENFILES)/state/cr_currentpointers.h \
+ $(VBOX_PATH_CROGL_GENFILES)/state/cr_statefuncs.h
+VBoxOGLrenderspu_INCS = $(VBOX_GRAPHICS_INCS)
+VBoxOGLrenderspu_SOURCES = \
+ render/renderspu.c \
+ render/renderspu_config.c \
+ render/renderspu_init.c
+VBoxOGLrenderspu_SOURCES.win = \
+ render/renderspu_wgl.c \
+ render/render.def \
+ render/VBoxOGLrenderspu.rc
+VBoxOGLrenderspu_SOURCES.linux = render/renderspu_glx.c
+VBoxOGLrenderspu_SOURCES.solaris = render/renderspu_glx.c
+VBoxOGLrenderspu_SOURCES.freebsd = render/renderspu_glx.c
+VBoxOGLrenderspu_OBJCFLAGS.darwin = -Wno-shadow
+VBoxOGLrenderspu_SOURCES.darwin = \
+ OpenGLTest/OpenGLTestDarwin.cpp \
+ render/renderspu_cocoa.c \
+ render/renderspu_cocoa_helper.m
+ifdef VBOX_WITH_CRHGSMI
+VBoxOGLrenderspu_DEFS += VBOX_WITH_CRHGSMI
+endif
+ifdef VBOX_WITH_VDMA
+VBoxOGLrenderspu_DEFS += VBOX_WITH_VDMA
+endif
+VBoxOGLrenderspu_LDFLAGS.darwin += -install_name $(VBOX_DYLD_EXECUTABLE_PATH)/VBoxOGLrenderspu.dylib -framework IOKit
+VBoxOGLrenderspu_LIBS = \
+ $(PATH_STAGE_LIB)/VBoxOGLhostspuload$(VBOX_SUFF_LIB) \
+ $(VBOX_LIB_OGL_HOSTCRUTIL) \
+ $(LIB_RUNTIME)
+if1of ($(KBUILD_TARGET), freebsd linux netbsd openbsd solaris) # the X11 gang
+ VBoxOGLrenderspu_LIBS += \
+ Xmu \
+ X11 \
+ Xext
+ VBoxOGLrenderspu_LIBPATH = \
+ $(VBOX_LIBPATH_X11)
+endif
+
+LIBRARIES += VBoxOGLTest
+VBoxOGLTest_TEMPLATE = VBOXR3
+ifneq ($(KBUILD_TARGET),darwin)
+ VBoxOGLTest_SOURCES = OpenGLTest/OpenGLTest.cpp
+endif
+VBoxOGLTest_SOURCES.darwin = OpenGLTest/OpenGLTestDarwin.cpp
+
+#
+# VBoxTestOGL - OpenGL support test app.
+# Note! Doesn't link with VBOX_WITH_DEBUG_VCC_CRT defined because it uses Qt.
+#
+if ( defined(VBOX_WITH_QTGUI) \
+ && (defined(VBOX_WITH_CROGL) || defined(VBOX_WITH_VIDEOHWACCEL)) \
+ && !defined(VBOX_WITH_DEBUG_VCC_CRT))
+ ifneq ($(KBUILD_TARGET),darwin)
+ ifdef VBOX_WITH_VIDEOHWACCEL
+ USES += qt5
+ endif
+ PROGRAMS += VBoxTestOGL
+ VBoxTestOGL_TEMPLATE = $(if $(VBOX_WITH_VIDEOHWACCEL),$(if $(VBOX_WITH_HARDENING),VBOXQTGUI,VBOXQTGUIEXE),VBOXMAINEXE)
+ VBoxTestOGL_SOURCES = OpenGLTest/OpenGLTestApp.cpp
+ VBoxTestOGL_SOURCES.win = OpenGLTest/VBoxTestOGL.rc
+ VBoxTestOGL_LIBS = \
+ $(if $(VBOX_WITH_CROGL), \
+ $(PATH_STAGE_LIB)/VBoxOGLhostspuload$(VBOX_SUFF_LIB) \
+ $(VBOX_LIB_OGL_HOSTCRUTIL),) \
+ $(if $(VBOX_WITH_VIDEOHWACCEL), $(PATH_STAGE_LIB)/VBoxOGL2D$(VBOX_SUFF_LIB),) \
+ $(LIB_RUNTIME)
+ VBoxTestOGL_DEFS += \
+ VBOX_BUILD_TARGET=\"$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)\" \
+ $(if $(VBOX_WITH_CROGL), VBOX_WITH_CROGL,) \
+ $(if $(VBOX_WITH_VIDEOHWACCEL), VBOX_WITH_VIDEOHWACCEL,)
+ ifdef VBOX_WITH_VIDEOHWACCEL
+ VBoxTestOGL_QT_MODULES += Core Gui OpenGL Widgets
+ VBoxTestOGL_LIBS.linux += xcb
+ VBoxTestOGL_LIBS.solaris += xcb
+ VBoxTestOGL_LIBS.freebsd += xcb
+ VBoxTestOGL_LDFLAGS.darwin += -framework OpenGL
+ VBoxTestOGL_LIBS.win += $(PATH_SDK_$(VBOX_WINPSDK)_LIB)/Opengl32.lib
+ if1of ($(KBUILD_TARGET), solaris linux freebsd)
+ # must come after VBoxOGL2D, therefore don't set the arch-specific LIBS variable here!
+ VBoxTestOGL_LIBS += GL
+ endif
+ endif
+ # Don't let ld strip out explicitly linked libraries even when they are not needed.
+ # This was causing some dynamic library loading problems in case of indirect dependencies
+ # in systems where RUNPATH instead of RPATH is utilized.
+ VBoxTestOGL_LDFLAGS.linux = -Wl,--no-as-needed
+ VBoxTestOGL_LDFLAGS.win = /SUBSYSTEM:windows
+ endif
+endif
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTest.cpp b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTest.cpp
new file mode 100644
index 00000000..379fbcdd
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTest.cpp
@@ -0,0 +1,103 @@
+/* $Id: OpenGLTest.cpp $ */
+/** @file
+ * VBox host opengl support test - generic implementation.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <VBox/err.h>
+#include <iprt/assert.h>
+#include <iprt/env.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/process.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+#include <iprt/env.h>
+#include <iprt/log.h>
+
+#include <VBox/VBoxOGL.h>
+
+bool RTCALL VBoxOglIs3DAccelerationSupported(void)
+{
+ if (RTEnvExist("VBOX_CROGL_FORCE_SUPPORTED"))
+ {
+ LogRel(("VBOX_CROGL_FORCE_SUPPORTED is specified, skipping 3D test, and treating as supported\n"));
+ return true;
+ }
+
+ static char pszVBoxPath[RTPATH_MAX];
+ const char *papszArgs[4] = { NULL, "-test", "3D", NULL};
+ int rc;
+ RTPROCESS Process;
+ RTPROCSTATUS ProcStatus;
+ uint64_t StartTS;
+
+#ifdef __SANITIZE_ADDRESS__
+ /* The OpenGL test tool contains a number of memory leaks which cause it to
+ * return failure when run with ASAN unless we disable the leak detector. */
+ RTENV env;
+ if (RT_FAILURE(RTEnvClone(&env, RTENV_DEFAULT)))
+ return false;
+ RTEnvPutEx(env, "ASAN_OPTIONS=detect_leaks=0"); /* If this fails we will notice later */
+#endif
+ rc = RTPathExecDir(pszVBoxPath, RTPATH_MAX); AssertRCReturn(rc, false);
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ rc = RTPathAppend(pszVBoxPath, RTPATH_MAX, "VBoxTestOGL.exe");
+#else
+ rc = RTPathAppend(pszVBoxPath, RTPATH_MAX, "VBoxTestOGL");
+#endif
+ papszArgs[0] = pszVBoxPath; /* argv[0] */
+ AssertRCReturn(rc, false);
+
+#ifndef __SANITIZE_ADDRESS__
+ rc = RTProcCreate(pszVBoxPath, papszArgs, RTENV_DEFAULT, 0, &Process);
+#else
+ rc = RTProcCreate(pszVBoxPath, papszArgs, env, 0, &Process);
+ RTEnvDestroy(env);
+#endif
+ if (RT_FAILURE(rc))
+ return false;
+
+ StartTS = RTTimeMilliTS();
+
+ while (1)
+ {
+ rc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
+ if (rc != VERR_PROCESS_RUNNING)
+ break;
+
+#ifndef DEBUG_misha
+ if (RTTimeMilliTS() - StartTS > 30*1000 /* 30 sec */)
+ {
+ RTProcTerminate(Process);
+ RTThreadSleep(100);
+ RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ProcStatus);
+ return false;
+ }
+#endif
+ RTThreadSleep(100);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ if ((ProcStatus.enmReason==RTPROCEXITREASON_NORMAL) && (ProcStatus.iStatus==0))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestApp.cpp b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestApp.cpp
new file mode 100644
index 00000000..dca5daf6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestApp.cpp
@@ -0,0 +1,363 @@
+/* $Id: OpenGLTestApp.cpp $ */
+/** @file
+ * VBox host opengl support test application.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <iprt/assert.h>
+#include <iprt/buildconfig.h>
+#include <iprt/errcore.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/stream.h>
+#ifdef RT_OS_WINDOWS
+# include <iprt/win/windows.h>
+#endif
+#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+# include <sys/resource.h>
+# include <fcntl.h>
+# include <unistd.h>
+#endif
+
+#include <string.h>
+
+#define VBOXGLTEST_WITH_LOGGING
+
+#ifdef VBOXGLTEST_WITH_LOGGING
+#include "package-generated.h"
+
+#include <iprt/log.h>
+#include <iprt/param.h>
+#include <iprt/time.h>
+#include <iprt/system.h>
+#include <iprt/process.h>
+#include <iprt/env.h>
+
+#include <VBox/log.h>
+#include <VBox/version.h>
+#endif
+
+#ifdef VBOX_WITH_CROGL
+
+extern "C"
+{
+ extern void * crSPULoad(void *, int, char *, char *, void *);
+ extern void crSPUUnloadChain(void *);
+}
+
+
+static int vboxCheck3DAccelerationSupported()
+{
+ LogRel(("Testing 3D Support:\n"));
+ void *spu = crSPULoad(NULL, 0, (char*)"render", NULL, NULL);
+ if (spu)
+ {
+ crSPUUnloadChain(spu);
+ LogRel(("Testing 3D Succeeded!\n"));
+ return 0;
+ }
+ LogRel(("Testing 3D Failed\n"));
+ return 1;
+}
+#endif
+
+#ifdef VBOX_WITH_VIDEOHWACCEL
+#include <QGLWidget>
+#include <QApplication>
+#include <VBox/VBoxGL2D.h>
+
+static int vboxCheck2DVideoAccelerationSupported()
+{
+ LogRel(("Testing 2D Support:\n"));
+ static int dummyArgc = 1;
+ static char * dummyArgv = (char*)"GlTest";
+ QApplication app (dummyArgc, &dummyArgv);
+
+ VBoxGLTmpContext ctx;
+ const QGLContext *pContext = ctx.makeCurrent();
+ if(pContext)
+ {
+ VBoxVHWAInfo supportInfo;
+ supportInfo.init(pContext);
+ if(supportInfo.isVHWASupported())
+ {
+ LogRel(("Testing 2D Succeeded!\n"));
+ return 0;
+ }
+ }
+ else
+ {
+ LogRel(("Failed to create gl context\n"));
+ }
+ LogRel(("Testing 2D Failed\n"));
+ return 1;
+}
+#endif
+
+#ifdef VBOXGLTEST_WITH_LOGGING
+static int vboxInitLogging(const char *pszFilename, bool bGenNameSuffix)
+{
+ PRTLOGGER loggerRelease;
+ static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
+ RTUINT fFlags = RTLOGFLAGS_PREFIX_TIME_PROG;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ fFlags |= RTLOGFLAGS_USECRLF;
+#endif
+ const char * pszFilenameFmt;
+ RTLOGDEST enmLogDest;
+ if(pszFilename)
+ {
+ if(bGenNameSuffix)
+ pszFilenameFmt = "%s.%ld.log";
+ else
+ pszFilenameFmt = "%s";
+ enmLogDest = RTLOGDEST_FILE;
+ }
+ else
+ {
+ pszFilenameFmt = NULL;
+ enmLogDest = RTLOGDEST_STDOUT;
+ }
+
+ int vrc = RTLogCreateEx(&loggerRelease, fFlags, "all",
+ "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, enmLogDest,
+ NULL /* pfnBeginEnd */, 0 /* cHistory */, 0 /* cbHistoryFileMax */, 0 /* uHistoryTimeMax */,
+ NULL /* pErrInfo */, pszFilenameFmt, pszFilename, RTTimeMilliTS());
+ if (RT_SUCCESS(vrc))
+ {
+ /* some introductory information */
+ RTTIMESPEC timeSpec;
+ char szTmp[256];
+ RTTimeSpecToString(RTTimeNow(&timeSpec), szTmp, sizeof(szTmp));
+ RTLogRelLogger(loggerRelease, 0, ~0U,
+ "VBoxTestGL %s r%u %s (%s %s) release log\n"
+#ifdef VBOX_BLEEDING_EDGE
+ "EXPERIMENTAL build " VBOX_BLEEDING_EDGE "\n"
+#endif
+ "Log opened %s\n",
+ VBOX_VERSION_STRING, RTBldCfgRevision(), VBOX_BUILD_TARGET,
+ __DATE__, __TIME__, szTmp);
+
+ vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
+ if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
+ RTLogRelLogger(loggerRelease, 0, ~0U, "OS Product: %s\n", szTmp);
+ vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
+ if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
+ RTLogRelLogger(loggerRelease, 0, ~0U, "OS Release: %s\n", szTmp);
+ vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
+ if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
+ RTLogRelLogger(loggerRelease, 0, ~0U, "OS Version: %s\n", szTmp);
+ vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
+ if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
+ RTLogRelLogger(loggerRelease, 0, ~0U, "OS Service Pack: %s\n", szTmp);
+// RTLogRelLogger(loggerRelease, 0, ~0U, "Host RAM: %uMB RAM, available: %uMB\n",
+// uHostRamMb, uHostRamAvailMb);
+ /* the package type is interesting for Linux distributions */
+ char szExecName[RTPATH_MAX];
+ char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
+ RTLogRelLogger(loggerRelease, 0, ~0U,
+ "Executable: %s\n"
+ "Process ID: %u\n"
+ "Package type: %s"
+#ifdef VBOX_OSE
+ " (OSE)"
+#endif
+ "\n",
+ pszExecName ? pszExecName : "unknown",
+ RTProcSelf(),
+ VBOX_PACKAGE_STRING);
+
+ /* register this logger as the release logger */
+ RTLogRelSetDefaultInstance(loggerRelease);
+
+ return VINF_SUCCESS;
+ }
+
+ return vrc;
+}
+#endif
+
+static int vboxInitQuietMode()
+{
+#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
+ /* This small test application might crash on some hosts. Do never
+ * generate a core dump as most likely some OpenGL library is
+ * responsible. */
+ struct rlimit lim = { 0, 0 };
+ setrlimit(RLIMIT_CORE, &lim);
+
+ /* Redirect stderr to /dev/null */
+ int fd = open("/dev/null", O_WRONLY);
+ if (fd != -1)
+ dup2(fd, STDERR_FILENO);
+#endif
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int rc = 0;
+
+ RTR3InitExe(argc, &argv, 0);
+
+ if(argc < 2)
+ {
+#ifdef VBOX_WITH_CROGL
+ /* backwards compatibility: check 3D */
+ rc = vboxCheck3DAccelerationSupported();
+#endif
+ }
+ else
+ {
+ static const RTGETOPTDEF s_aOptionDefs[] =
+ {
+ { "--test", 't', RTGETOPT_REQ_STRING },
+ { "-test", 't', RTGETOPT_REQ_STRING },
+#ifdef VBOXGLTEST_WITH_LOGGING
+ { "--log", 'l', RTGETOPT_REQ_STRING },
+#endif
+ };
+
+ RTGETOPTSTATE State;
+ rc = RTGetOptInit(&State, argc-1, argv+1, &s_aOptionDefs[0], RT_ELEMENTS(s_aOptionDefs), 0, 0);
+ AssertRCReturn(rc, 49);
+
+#ifdef VBOX_WITH_VIDEOHWACCEL
+ bool bTest2D = false;
+#endif
+#ifdef VBOX_WITH_CROGL
+ bool bTest3D = false;
+#endif
+#ifdef VBOXGLTEST_WITH_LOGGING
+ bool bLog = false;
+ bool bLogSuffix = false;
+ const char * pLog = NULL;
+#endif
+
+ for (;;)
+ {
+ RTGETOPTUNION Val;
+ rc = RTGetOpt(&State, &Val);
+ if (!rc)
+ break;
+ switch (rc)
+ {
+ case 't':
+#ifdef VBOX_WITH_CROGL
+ if (!strcmp(Val.psz, "3D") || !strcmp(Val.psz, "3d"))
+ {
+ bTest3D = true;
+ rc = 0;
+ break;
+ }
+#endif
+#ifdef VBOX_WITH_VIDEOHWACCEL
+ if (!strcmp(Val.psz, "2D") || !strcmp(Val.psz, "2d"))
+ {
+ bTest2D = true;
+ rc = 0;
+ break;
+ }
+#endif
+ rc = 1;
+ break;
+#ifdef VBOXGLTEST_WITH_LOGGING
+ case 'l':
+ bLog = true;
+ pLog = Val.psz;
+ rc = 0;
+ break;
+#endif
+ case 'h':
+ RTPrintf(VBOX_PRODUCT " Helper for testing 2D/3D OpenGL capabilities %u.%u.%u\n"
+ "(C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
+ "All rights reserved.\n"
+ "\n"
+ "Parameters:\n"
+#ifdef VBOX_WITH_VIDEOHWACCEL
+ " --test 2D test for 2D (video) OpenGL capabilities\n"
+#endif
+#ifdef VBOX_WITH_CROGL
+ " --test 3D test for 3D OpenGL capabilities\n"
+#endif
+#ifdef VBOXGLTEST_WITH_LOGGING
+ " --log <log_file_name> log the GL test result to the given file\n"
+ "\n"
+ "Logging can alternatively be enabled by specifying the VBOXGLTEST_LOG=<log_file_name> env variable\n"
+
+#endif
+ "\n",
+ RTBldCfgVersionMajor(), RTBldCfgVersionMinor(), RTBldCfgVersionBuild());
+ break;
+
+ case 'V':
+ RTPrintf("$Revision: 127855 $\n");
+ return 0;
+
+ case VERR_GETOPT_UNKNOWN_OPTION:
+ case VINF_GETOPT_NOT_OPTION:
+ rc = 1;
+
+ default:
+ /* complain? RTGetOptPrintError(rc, &Val); */
+ break;
+ }
+
+ if (rc)
+ break;
+ }
+
+ if(!rc)
+ {
+#ifdef VBOXGLTEST_WITH_LOGGING
+ if(!bLog)
+ {
+ /* check the VBOXGLTEST_LOG env var */
+ pLog = RTEnvGet("VBOXGLTEST_LOG");
+ if(pLog)
+ bLog = true;
+ bLogSuffix = true;
+ }
+ if(bLog)
+ rc = vboxInitLogging(pLog, bLogSuffix);
+ else
+#endif
+ rc = vboxInitQuietMode();
+
+#ifdef VBOX_WITH_CROGL
+ if(!rc && bTest3D)
+ rc = vboxCheck3DAccelerationSupported();
+#endif
+
+#ifdef VBOX_WITH_VIDEOHWACCEL
+ if(!rc && bTest2D)
+ rc = vboxCheck2DVideoAccelerationSupported();
+#endif
+
+ }
+ }
+
+ /*RTR3Term();*/
+ return rc;
+
+}
+
+#ifdef RT_OS_WINDOWS
+extern "C" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
+{
+ RT_NOREF(hInstance, hPrevInstance, lpCmdLine, nShowCmd);
+ return main(__argc, __argv);
+}
+#endif
+
diff --git a/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestDarwin.cpp b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestDarwin.cpp
new file mode 100644
index 00000000..35b573c2
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/OpenGLTestDarwin.cpp
@@ -0,0 +1,176 @@
+/* $Id: OpenGLTestDarwin.cpp $ */
+/** @file
+ * VBox host opengl support test
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <VBox/VBoxOGL.h>
+
+#include <IOKit/IOKitLib.h>
+#include <OpenGL/OpenGL.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <OpenGL/gl.h>
+#ifdef VBOX_WITH_COCOA_QT
+# include <OpenGL/glu.h>
+#endif
+
+#include <iprt/env.h>
+#include <iprt/log.h>
+#include <iprt/once.h>
+
+
+
+/**
+ * @callback_method_impl{FNRTONCE,
+ * For determining the cached VBoxOglIsOfflineRenderingAppropriate result.}
+ */
+static DECLCALLBACK(int32_t) vboxOglIsOfflineRenderingAppropriateOnce(void *pvUser)
+{
+ bool *pfAppropriate = (bool *)pvUser;
+
+ /* It is assumed that it is makes sense to enable offline rendering
+ only in case if host has more than one GPU installed. This routine
+ counts all the PCI devices in IORegistry which have IOName property
+ set to "display". If the number of such devices is greater than one,
+ it sets pfAppropriate to TRUE, otherwise to FALSE. */
+
+ CFStringRef apKeyStrings[] = { CFSTR(kIOProviderClassKey), CFSTR(kIONameMatchKey) };
+ CFStringRef apValueStrings[] = { CFSTR("IOPCIDevice"), CFSTR("display") };
+ Assert(RT_ELEMENTS(apKeyStrings) == RT_ELEMENTS(apValueStrings));
+
+ CFDictionaryRef pMatchingDictionary = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **)apKeyStrings,
+ (const void **)apValueStrings,
+ RT_ELEMENTS(apKeyStrings),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ if (pMatchingDictionary)
+ {
+ /* The reference to pMatchingDictionary is consumed by the function below => no IORelease(pMatchingDictionary)! */
+ io_iterator_t matchingServices;
+ kern_return_t krc = IOServiceGetMatchingServices(kIOMasterPortDefault, pMatchingDictionary, &matchingServices);
+ if (krc == kIOReturnSuccess)
+ {
+ io_object_t matchingService;
+ int cMatchingServices = 0;
+
+ while ((matchingService = IOIteratorNext(matchingServices)) != 0)
+ {
+ cMatchingServices++;
+ IOObjectRelease(matchingService);
+ }
+
+ *pfAppropriate = cMatchingServices > 1;
+
+ IOObjectRelease(matchingServices);
+ }
+ }
+
+ LogRel(("OpenGL: Offline rendering support is %s (pid=%d)\n", *pfAppropriate ? "ON" : "OFF", (int)getpid()));
+ return VINF_SUCCESS;
+}
+
+
+bool RTCALL VBoxOglIsOfflineRenderingAppropriate(void)
+{
+ /* In order to do not slowdown 3D engine which can ask about offline rendering several times,
+ let's cache the result and assume that renderers amount value is constant. Use the IPRT
+ execute once construct to make sure there aren't any threading issues. */
+ static RTONCE s_Once = RTONCE_INITIALIZER;
+ static bool s_fCached = false;
+ int rc = RTOnce(&s_Once, vboxOglIsOfflineRenderingAppropriateOnce, &s_fCached);
+ AssertRC(rc);
+ return s_fCached;
+}
+
+
+bool RTCALL VBoxOglIs3DAccelerationSupported(void)
+{
+ if (RTEnvExist("VBOX_CROGL_FORCE_SUPPORTED"))
+ {
+ LogRel(("VBOX_CROGL_FORCE_SUPPORTED is specified, skipping 3D test, and treating as supported\n"));
+ return true;
+ }
+
+ CGOpenGLDisplayMask cglDisplayMask = CGDisplayIDToOpenGLDisplayMask(CGMainDisplayID());
+ CGLPixelFormatAttribute aAttribs[] =
+ {
+ kCGLPFADisplayMask,
+ (CGLPixelFormatAttribute)cglDisplayMask,
+ kCGLPFAAccelerated,
+ kCGLPFADoubleBuffer,
+ VBoxOglIsOfflineRenderingAppropriate() ? kCGLPFAAllowOfflineRenderers : (CGLPixelFormatAttribute)NULL,
+ (CGLPixelFormatAttribute)NULL
+ };
+ CGLPixelFormatObj pPixelFormat = NULL;
+ GLint cPixelFormatsIgnored = 0;
+ CGLError rcCgl = CGLChoosePixelFormat(aAttribs, &pPixelFormat, &cPixelFormatsIgnored);
+ if (rcCgl != kCGLNoError)
+ {
+ LogRel(("OpenGL Info: 3D test unable to choose pixel format (rcCgl=0x%X)\n", rcCgl));
+ return false;
+ }
+
+ if (pPixelFormat)
+ {
+ CGLContextObj pCglContext = 0;
+ rcCgl = CGLCreateContext(pPixelFormat, NULL, &pCglContext);
+ CGLDestroyPixelFormat(pPixelFormat);
+
+ if (rcCgl != kCGLNoError)
+ {
+ LogRel(("OpenGL Info: 3D test unable to create context (rcCgl=0x%X)\n", rcCgl));
+ return false;
+ }
+
+ if (pCglContext)
+ {
+ GLboolean isSupported = GL_TRUE;
+
+#ifdef VBOX_WITH_COCOA_QT
+ /*
+ * In the Cocoa port we depend on the GL_EXT_framebuffer_object &
+ * the GL_EXT_texture_rectangle extension. If they are not
+ * available, disable 3D support.
+ */
+ CGLSetCurrentContext(pCglContext);
+ const GLubyte *pszExts = glGetString(GL_EXTENSIONS);
+ isSupported = gluCheckExtension((const GLubyte *)"GL_EXT_framebuffer_object", pszExts);
+ if (isSupported)
+ {
+ isSupported = gluCheckExtension((const GLubyte *)"GL_EXT_texture_rectangle", pszExts);
+ if (!isSupported)
+ LogRel(("OpenGL Info: 3D test found that GL_EXT_texture_rectangle extension not supported.\n"));
+ }
+ else
+ LogRel(("OpenGL Info: 3D test found that GL_EXT_framebuffer_object extension not supported.\n"));
+#endif /* VBOX_WITH_COCOA_QT */
+
+ CGLDestroyContext(pCglContext);
+ LogRel(("OpenGL Info: 3D test %spassed\n", isSupported == GL_TRUE ? "" : "not "));
+ return isSupported == GL_TRUE;
+ }
+
+ LogRel(("OpenGL Info: 3D test unable to create context (internal error).\n"));
+ }
+ else
+ LogRel(("OpenGL Info: 3D test unable to choose pixel format (internal error).\n"));
+
+ return false;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/OpenGLTest/VBoxTestOGL.rc b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/VBoxTestOGL.rc
new file mode 100644
index 00000000..a6504424
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/OpenGLTest/VBoxTestOGL.rc
@@ -0,0 +1,51 @@
+/* $Id: VBoxTestOGL.rc $ */
+/** @file
+ * VBoxTestOGL - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_APP
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox OpenGL Test Tool\0"
+ VALUE "InternalName", "VBoxTestOGL\0"
+ VALUE "OriginalFilename", "VBoxTestOGL.exe\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostServices/SharedOpenGL/crserver/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/crserver/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserver/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/crserver/VBoxSharedCrOpenGL.rc b/src/VBox/HostServices/SharedOpenGL/crserver/VBoxSharedCrOpenGL.rc
new file mode 100644
index 00000000..bf24ea32
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserver/VBoxSharedCrOpenGL.rc
@@ -0,0 +1,51 @@
+/* $Id: VBoxSharedCrOpenGL.rc $ */
+/** @file
+ * VBoxSharedCrOpenGL - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox crOpenGL Host Service\0"
+ VALUE "InternalName", "VBoxSharedCrOpenGL\0"
+ VALUE "OriginalFilename", "VBoxSharedCrOpenGL.dll\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp b/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
new file mode 100644
index 00000000..770b5847
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserver/crservice.cpp
@@ -0,0 +1,1603 @@
+/* $Id: crservice.cpp $ */
+/** @file
+ * VBox crOpenGL - Host service entry points.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_SHARED_CROPENGL
+
+#define __STDC_CONSTANT_MACROS /* needed for a definition in iprt/string.h */
+
+#include <iprt/assert.h>
+#include <iprt/asm.h>
+#include <iprt/critsect.h>
+#include <iprt/mem.h>
+#include <iprt/semaphore.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/thread.h>
+
+#include <VBox/err.h>
+#include <VBox/hgcmsvc.h>
+#include <VBox/log.h>
+#include <VBox/com/array.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/VirtualBox.h>
+#include <VBox/com/errorprint.h>
+#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
+#include <VBox/vmm/ssm.h>
+#include <VBox/VBoxOGL.h>
+
+#include "cr_mem.h"
+#include "cr_server.h"
+
+#ifndef RT_OS_WINDOWS
+# define DWORD int
+# define WINAPI
+#endif
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+PVBOXHGCMSVCHELPERS g_pHelpers;
+static IConsole* g_pConsole = NULL;
+static uint32_t g_u32ScreenCount = 0;
+static PVM g_pVM = NULL;
+static uint32_t g_u32fCrHgcmDisabled = 0;
+
+static const char *gszVBoxOGLSSMMagic = "***OpenGL state data***";
+
+/* Used to process guest calls exceeding maximum allowed HGCM call size in a sequence of smaller calls */
+typedef struct _CRVBOXSVCBUFFER_t {
+ uint32_t uiId;
+ uint32_t uiSize;
+ void* pData;
+ _CRVBOXSVCBUFFER_t *pNext, *pPrev;
+} CRVBOXSVCBUFFER_t;
+
+static CRVBOXSVCBUFFER_t *g_pCRVBoxSVCBuffers = NULL;
+static uint32_t g_CRVBoxSVCBufferID = 0;
+
+/* svcPresentFBO related data */
+typedef struct _CRVBOXSVCPRESENTFBOCMD_t {
+ void *pData;
+ int32_t screenId, x, y, w, h;
+ _CRVBOXSVCPRESENTFBOCMD_t *pNext;
+} CRVBOXSVCPRESENTFBOCMD_t, *PCRVBOXSVCPRESENTFBOCMD_t;
+
+
+static DECLCALLBACK(void) svcNotifyEventCB(int32_t screenId, uint32_t uEvent, void* pvData, uint32_t cbData)
+{
+ ComPtr<IDisplay> pDisplay;
+ ComPtr<IFramebuffer> pFramebuffer;
+
+ if (!g_pConsole)
+ {
+ crWarning("Console not defined!");
+ return;
+ }
+
+ CHECK_ERROR2I_STMT(g_pConsole, COMGETTER(Display)(pDisplay.asOutParam()), return);
+
+ CHECK_ERROR2I_STMT(pDisplay, QueryFramebuffer(screenId, pFramebuffer.asOutParam()), return);
+
+ if (!pFramebuffer)
+ return;
+
+ com::SafeArray<BYTE> data(cbData);
+ if (cbData)
+ memcpy(data.raw(), pvData, cbData);
+
+ pFramebuffer->Notify3DEvent(uEvent, ComSafeArrayAsInParam(data));
+}
+
+
+static DECLCALLBACK(int) svcUnload (void *)
+{
+ int rc = VINF_SUCCESS;
+
+ Log(("SHARED_CROPENGL svcUnload\n"));
+
+ crVBoxServerTearDown();
+
+ return rc;
+}
+
+static DECLCALLBACK(int) svcConnect (void *, uint32_t u32ClientID, void *pvClient, uint32_t fRequestor, bool fRestoring)
+{
+ RT_NOREF(pvClient, fRequestor, fRestoring);
+
+ if (g_u32fCrHgcmDisabled)
+ {
+ WARN(("connect not expected"));
+ return VERR_INVALID_STATE;
+ }
+
+ Log(("SHARED_CROPENGL svcConnect: u32ClientID = %d\n", u32ClientID));
+
+ int rc = crVBoxServerAddClient(u32ClientID);
+
+ return rc;
+}
+
+static DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient)
+{
+ int rc = VINF_SUCCESS;
+
+ NOREF(pvClient);
+
+ if (g_u32fCrHgcmDisabled)
+ {
+ WARN(("disconnect not expected"));
+ return VINF_SUCCESS;
+ }
+
+ Log(("SHARED_CROPENGL svcDisconnect: u32ClientID = %d\n", u32ClientID));
+
+ crVBoxServerRemoveClient(u32ClientID);
+
+ return rc;
+}
+
+static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
+{
+ int rc = VINF_SUCCESS;
+
+ NOREF(pvClient);
+
+ Log(("SHARED_CROPENGL svcSaveState: u32ClientID = %d\n", u32ClientID));
+
+ /* Start*/
+ rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
+ AssertRCReturn(rc, rc);
+
+ /* Version */
+ rc = SSMR3PutU32(pSSM, (uint32_t) SHCROGL_SSM_VERSION);
+ AssertRCReturn(rc, rc);
+
+ /* The state itself */
+ rc = crVBoxServerSaveState(pSSM);
+ AssertRCReturn(rc, rc);
+
+ /* Save svc buffers info */
+ {
+ CRVBOXSVCBUFFER_t *pBuffer = g_pCRVBoxSVCBuffers;
+
+ rc = SSMR3PutU32(pSSM, g_CRVBoxSVCBufferID);
+ AssertRCReturn(rc, rc);
+
+ while (pBuffer)
+ {
+ rc = SSMR3PutU32(pSSM, pBuffer->uiId);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, pBuffer->uiSize);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutMem(pSSM, pBuffer->pData, pBuffer->uiSize);
+ AssertRCReturn(rc, rc);
+
+ pBuffer = pBuffer->pNext;
+ }
+
+ rc = SSMR3PutU32(pSSM, 0);
+ AssertRCReturn(rc, rc);
+ }
+
+ /* End */
+ rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
+ AssertRCReturn(rc, rc);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM, uint32_t uVersion)
+{
+ RT_NOREF(pvClient, uVersion);
+ int rc = VINF_SUCCESS;
+
+ Log(("SHARED_CROPENGL svcLoadState: u32ClientID = %d\n", u32ClientID));
+
+ char psz[2000];
+ uint32_t ui32;
+
+ /* Start of data */
+ rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
+ AssertRCReturn(rc, rc);
+ if (strcmp(gszVBoxOGLSSMMagic, psz))
+ return VERR_SSM_UNEXPECTED_DATA;
+
+ /* Version */
+ rc = SSMR3GetU32(pSSM, &ui32);
+ AssertRCReturn(rc, rc);
+
+ /* The state itself */
+ rc = crVBoxServerLoadState(pSSM, ui32);
+
+ if (rc==VERR_SSM_DATA_UNIT_FORMAT_CHANGED && ui32!=SHCROGL_SSM_VERSION)
+ {
+ LogRel(("OpenGL: svcLoadState: Unsupported save state version %d\n", ui32));
+
+ /** @todo ugly hack, as we don't know size of stored opengl data try to read untill end of opengl data marker*/
+ /*VBoxSharedCrOpenGL isn't last hgcm service now, so can't use SSMR3SkipToEndOfUnit*/
+ {
+ const char *pMatch = &gszVBoxOGLSSMMagic[0];
+ char current;
+
+ while (*pMatch)
+ {
+ rc = SSMR3GetS8(pSSM, (int8_t*)&current);
+ AssertRCReturn(rc, rc);
+
+ if (current==*pMatch)
+ {
+ pMatch++;
+ }
+ else
+ {
+ pMatch = &gszVBoxOGLSSMMagic[0];
+ }
+ }
+ }
+
+ return VINF_SUCCESS;
+ }
+ AssertRCReturn(rc, rc);
+
+ /* Load svc buffers info */
+ if (ui32>=24)
+ {
+ uint32_t uiId;
+
+ rc = SSMR3GetU32(pSSM, &g_CRVBoxSVCBufferID);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &uiId);
+ AssertRCReturn(rc, rc);
+
+ while (uiId)
+ {
+ CRVBOXSVCBUFFER_t *pBuffer = (CRVBOXSVCBUFFER_t *) RTMemAlloc(sizeof(CRVBOXSVCBUFFER_t));
+ if (!pBuffer)
+ {
+ return VERR_NO_MEMORY;
+ }
+ pBuffer->uiId = uiId;
+
+ rc = SSMR3GetU32(pSSM, &pBuffer->uiSize);
+ AssertRCReturn(rc, rc);
+
+ pBuffer->pData = RTMemAlloc(pBuffer->uiSize);
+ if (!pBuffer->pData)
+ {
+ RTMemFree(pBuffer);
+ return VERR_NO_MEMORY;
+ }
+
+ rc = SSMR3GetMem(pSSM, pBuffer->pData, pBuffer->uiSize);
+ AssertRCReturn(rc, rc);
+
+ pBuffer->pNext = g_pCRVBoxSVCBuffers;
+ pBuffer->pPrev = NULL;
+ if (g_pCRVBoxSVCBuffers)
+ {
+ g_pCRVBoxSVCBuffers->pPrev = pBuffer;
+ }
+ g_pCRVBoxSVCBuffers = pBuffer;
+
+ rc = SSMR3GetU32(pSSM, &uiId);
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ /* End of data */
+ rc = SSMR3GetStrZEx(pSSM, psz, 2000, NULL);
+ AssertRCReturn(rc, rc);
+ if (strcmp(gszVBoxOGLSSMMagic, psz))
+ return VERR_SSM_UNEXPECTED_DATA;
+
+ return VINF_SUCCESS;
+}
+
+static void svcClientVersionUnsupported(uint32_t minor, uint32_t major)
+{
+ LogRel(("OpenGL: Unsupported client version %d.%d\n", minor, major));
+
+ /*MS's opengl32 tries to load our ICD around 30 times on failure...this is to prevent unnecessary spam*/
+ static int shown = 0;
+
+ if (g_pVM && !shown)
+ {
+ VMSetRuntimeError(g_pVM, VMSETRTERR_FLAGS_NO_WAIT, "3DSupportIncompatibleAdditions",
+ "An attempt by the virtual machine to use hardware 3D acceleration failed. "
+ "The version of the Guest Additions installed in the virtual machine does not match the "
+ "version of VirtualBox on the host. Please install appropriate Guest Additions to fix this issue");
+ shown = 1;
+ }
+}
+
+static CRVBOXSVCBUFFER_t* svcGetBuffer(uint32_t iBuffer, uint32_t cbBufferSize)
+{
+ CRVBOXSVCBUFFER_t* pBuffer;
+
+ if (iBuffer)
+ {
+ pBuffer = g_pCRVBoxSVCBuffers;
+ while (pBuffer)
+ {
+ if (pBuffer->uiId == iBuffer)
+ {
+ if (cbBufferSize && pBuffer->uiSize!=cbBufferSize)
+ {
+ static int shown=0;
+
+ if (shown<20)
+ {
+ shown++;
+ LogRel(("OpenGL: svcGetBuffer: Invalid buffer(%i) size %i instead of %i\n",
+ iBuffer, pBuffer->uiSize, cbBufferSize));
+ }
+ return NULL;
+ }
+ return pBuffer;
+ }
+ pBuffer = pBuffer->pNext;
+ }
+ return NULL;
+ }
+ else /*allocate new buffer*/
+ {
+ pBuffer = (CRVBOXSVCBUFFER_t*) RTMemAlloc(sizeof(CRVBOXSVCBUFFER_t));
+ if (pBuffer)
+ {
+ /* Filling host buffer with zeroes to prevent possible host->guest memory disclosure */
+ pBuffer->pData = RTMemAllocZ(cbBufferSize);
+ if (!pBuffer->pData)
+ {
+ LogRel(("OpenGL: svcGetBuffer: Not enough memory (%d)\n", cbBufferSize));
+ RTMemFree(pBuffer);
+ return NULL;
+ }
+ pBuffer->uiId = ++g_CRVBoxSVCBufferID;
+ if (!pBuffer->uiId)
+ {
+ pBuffer->uiId = ++g_CRVBoxSVCBufferID;
+ }
+ Assert(pBuffer->uiId);
+ pBuffer->uiSize = cbBufferSize;
+ pBuffer->pPrev = NULL;
+ pBuffer->pNext = g_pCRVBoxSVCBuffers;
+ if (g_pCRVBoxSVCBuffers)
+ {
+ g_pCRVBoxSVCBuffers->pPrev = pBuffer;
+ }
+ g_pCRVBoxSVCBuffers = pBuffer;
+ }
+ else
+ {
+ LogRel(("OpenGL: svcGetBuffer: Not enough memory (%d)\n", sizeof(CRVBOXSVCBUFFER_t)));
+ }
+ return pBuffer;
+ }
+}
+
+static void svcFreeBuffer(CRVBOXSVCBUFFER_t* pBuffer)
+{
+ Assert(pBuffer);
+
+ if (pBuffer->pPrev)
+ {
+ pBuffer->pPrev->pNext = pBuffer->pNext;
+ }
+ else
+ {
+ Assert(pBuffer==g_pCRVBoxSVCBuffers);
+ g_pCRVBoxSVCBuffers = pBuffer->pNext;
+ }
+
+ if (pBuffer->pNext)
+ {
+ pBuffer->pNext->pPrev = pBuffer->pPrev;
+ }
+
+ RTMemFree(pBuffer->pData);
+ RTMemFree(pBuffer);
+}
+
+static DECLCALLBACK(void) svcCall (void *, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient,
+ uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)
+{
+ RT_NOREF(pvClient, tsArrival);
+ int rc = VINF_SUCCESS;
+
+ if (g_u32fCrHgcmDisabled)
+ {
+ WARN(("cr hgcm disabled!"));
+ return;
+ }
+
+ Log(("SHARED_CROPENGL svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n", u32ClientID, u32Function, cParms, paParms));
+
+#ifdef DEBUG
+ uint32_t i;
+
+ for (i = 0; i < cParms; i++)
+ {
+ /** @todo parameters other than 32 bit */
+ Log((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
+ }
+#endif
+
+ switch (u32Function)
+ {
+ case SHCRGL_GUEST_FN_WRITE:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_WRITE)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint8_t *pBuffer = (uint8_t *)paParms[0].u.pointer.addr;
+ uint32_t cbBuffer = paParms[0].u.pointer.size;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientWrite(u32ClientID, pBuffer, cbBuffer);
+ if (!RT_SUCCESS(rc))
+ {
+ Assert(VERR_NOT_SUPPORTED==rc);
+ svcClientVersionUnsupported(0, 0);
+ }
+
+ }
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_INJECT:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_INJECT)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* u32ClientID */
+ || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint32_t u32InjectClientID = paParms[0].u.uint32;
+ uint8_t *pBuffer = (uint8_t *)paParms[1].u.pointer.addr;
+ uint32_t cbBuffer = paParms[1].u.pointer.size;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientWrite(u32InjectClientID, pBuffer, cbBuffer);
+ if (!RT_SUCCESS(rc))
+ {
+ if (VERR_NOT_SUPPORTED==rc)
+ {
+ svcClientVersionUnsupported(0, 0);
+ }
+ else
+ {
+ crWarning("SHCRGL_GUEST_FN_INJECT failed to inject for %i from %i", u32InjectClientID, u32ClientID);
+ }
+ }
+ }
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_READ)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */
+ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* cbBuffer */
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ /* Fetch parameters. */
+ uint8_t *pBuffer = (uint8_t *)paParms[0].u.pointer.addr;
+ uint32_t cbBuffer = paParms[0].u.pointer.size;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientRead(u32ClientID, pBuffer, &cbBuffer);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Update parameters.*/
+ paParms[0].u.pointer.size = cbBuffer; /// @todo guest doesn't see this change somehow?
+ } else if (VERR_NOT_SUPPORTED==rc)
+ {
+ svcClientVersionUnsupported(0, 0);
+ }
+
+ /* Return the required buffer size always */
+ paParms[1].u.uint32 = cbBuffer;
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_WRITE_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_WRITE_READ)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pBuffer */
+ || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* pWriteback */
+ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* cbWriteback */
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint8_t *pBuffer = (uint8_t *)paParms[0].u.pointer.addr;
+ uint32_t cbBuffer = paParms[0].u.pointer.size;
+
+ uint8_t *pWriteback = (uint8_t *)paParms[1].u.pointer.addr;
+ uint32_t cbWriteback = paParms[1].u.pointer.size;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientWrite(u32ClientID, pBuffer, cbBuffer);
+ if (!RT_SUCCESS(rc))
+ {
+ Assert(VERR_NOT_SUPPORTED==rc);
+ svcClientVersionUnsupported(0, 0);
+ }
+
+ rc = crVBoxServerClientRead(u32ClientID, pWriteback, &cbWriteback);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Update parameters.*/
+ paParms[1].u.pointer.size = cbWriteback;
+ }
+ /* Return the required buffer size always */
+ paParms[2].u.uint32 = cbWriteback;
+ }
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_VERSION:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_SET_VERSION\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_SET_VERSION)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* vMajor */
+ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* vMinor */
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint32_t vMajor = paParms[0].u.uint32;
+ uint32_t vMinor = paParms[1].u.uint32;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientSetVersion(u32ClientID, vMajor, vMinor);
+
+ if (!RT_SUCCESS(rc))
+ {
+ svcClientVersionUnsupported(vMajor, vMinor);
+ }
+ }
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_PID:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_SET_PID\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_SET_PID)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_64BIT)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint64_t pid = paParms[0].u.uint64;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientSetPID(u32ClientID, pid);
+ }
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_WRITE_BUFFER:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_BUFFER\n"));
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_WRITE_BUFFER)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /*iBufferID*/
+ || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /*cbBufferSize*/
+ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /*ui32Offset*/
+ || paParms[3].type != VBOX_HGCM_SVC_PARM_PTR /*pBuffer*/
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint32_t iBuffer = paParms[0].u.uint32;
+ uint32_t cbBufferSize = paParms[1].u.uint32;
+ uint32_t ui32Offset = paParms[2].u.uint32;
+ uint8_t *pBuffer = (uint8_t *)paParms[3].u.pointer.addr;
+ uint32_t cbBuffer = paParms[3].u.pointer.size;
+
+ /* Execute the function. */
+ CRVBOXSVCBUFFER_t *pSvcBuffer = svcGetBuffer(iBuffer, cbBufferSize);
+ if (!pSvcBuffer || ((uint64_t)ui32Offset+cbBuffer)>cbBufferSize)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ memcpy((void*)((uintptr_t)pSvcBuffer->pData+ui32Offset), pBuffer, cbBuffer);
+
+ /* Return the buffer id */
+ paParms[0].u.uint32 = pSvcBuffer->uiId;
+ }
+ }
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_WRITE_READ_BUFFERED:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ_BUFFERED\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_WRITE_READ_BUFFERED)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* iBufferID */
+ || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* pWriteback */
+ || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* cbWriteback */
+ || !paParms[0].u.uint32 /*iBufferID can't be 0 here*/
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint32_t iBuffer = paParms[0].u.uint32;
+ uint8_t *pWriteback = (uint8_t *)paParms[1].u.pointer.addr;
+ uint32_t cbWriteback = paParms[1].u.pointer.size;
+
+ CRVBOXSVCBUFFER_t *pSvcBuffer = svcGetBuffer(iBuffer, 0);
+ if (!pSvcBuffer)
+ {
+ LogRel(("OpenGL: svcCall(WRITE_READ_BUFFERED): Invalid buffer (%d)\n", iBuffer));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ uint8_t *pBuffer = (uint8_t *)pSvcBuffer->pData;
+ uint32_t cbBuffer = pSvcBuffer->uiSize;
+
+ /* Execute the function. */
+ rc = crVBoxServerClientWrite(u32ClientID, pBuffer, cbBuffer);
+ if (!RT_SUCCESS(rc))
+ {
+ Assert(VERR_NOT_SUPPORTED==rc);
+ svcClientVersionUnsupported(0, 0);
+ }
+
+ rc = crVBoxServerClientRead(u32ClientID, pWriteback, &cbWriteback);
+
+ if (RT_SUCCESS(rc))
+ {
+ /* Update parameters.*/
+ paParms[1].u.pointer.size = cbWriteback;
+ }
+ /* Return the required buffer size always */
+ paParms[2].u.uint32 = cbWriteback;
+
+ svcFreeBuffer(pSvcBuffer);
+ }
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_GET_CAPS_NEW:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_GET_CAPS_NEW\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_GET_CAPS_NEW)
+ {
+ WARN(("invalid parameter count"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms[0].u.pointer.size < sizeof (CR_CAPS_INFO))
+ {
+ WARN(("invalid buffer size"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CR_CAPS_INFO *pInfo = (CR_CAPS_INFO*)paParms[0].u.pointer.addr;
+ rc = crVBoxServerClientGetCapsNew(u32ClientID, pInfo);
+ AssertRC(rc);
+
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_GET_CAPS_LEGACY:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_GET_CAPS_LEGACY\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_GET_CAPS_LEGACY)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Execute the function. */
+ rc = crVBoxServerClientGetCapsLegacy(u32ClientID, &paParms[0].u.uint32);
+ AssertRC(rc);
+ }
+
+ break;
+ }
+
+ default:
+ {
+ WARN(("svcCall: unexpected u32Function %d", u32Function));
+ rc = VERR_NOT_IMPLEMENTED;
+ }
+ }
+
+
+ LogFlow(("svcCall: rc = %Rrc\n", rc));
+
+ g_pHelpers->pfnCallComplete (callHandle, rc);
+}
+
+static void crScreenshotHandle(CRVBOXHGCMTAKESCREENSHOT *pScreenshot, uint32_t idScreen, uint64_t u64Now)
+{
+ if (!pScreenshot->pfnScreenshotBegin || pScreenshot->pfnScreenshotBegin(pScreenshot->pvContext, idScreen, u64Now))
+ {
+ CR_SCREENSHOT Screenshot;
+
+ int rc = crServerVBoxScreenshotGet(idScreen, pScreenshot->u32Width, pScreenshot->u32Height, pScreenshot->u32Pitch, pScreenshot->pvBuffer, &Screenshot);
+ if (RT_SUCCESS(rc))
+ {
+ if (pScreenshot->pfnScreenshotPerform)
+ pScreenshot->pfnScreenshotPerform(pScreenshot->pvContext, idScreen,
+ 0, 0, 32,
+ Screenshot.Img.pitch, Screenshot.Img.width, Screenshot.Img.height,
+ (uint8_t*)Screenshot.Img.pvData, u64Now);
+ crServerVBoxScreenshotRelease(&Screenshot);
+ }
+ else
+ {
+ Assert(rc == VERR_INVALID_STATE);
+ }
+
+ if (pScreenshot->pfnScreenshotEnd)
+ pScreenshot->pfnScreenshotEnd(pScreenshot->pvContext, idScreen, u64Now);
+ }
+}
+
+/*
+ * We differentiate between a function handler for the guest and one for the host.
+ */
+static int svcHostCallPerform(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+ int rc = VINF_SUCCESS;
+
+ Log(("SHARED_CROPENGL svcHostCall: fn = %d, cParms = %d, pparms = %d\n", u32Function, cParms, paParms));
+
+#ifdef DEBUG
+ uint32_t i;
+
+ for (i = 0; i < cParms; i++)
+ {
+ /** @todo parameters other than 32 bit */
+ Log((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
+ }
+#endif
+
+ switch (u32Function)
+ {
+#ifdef VBOX_WITH_CRHGSMI
+ case SHCRGL_HOST_FN_CRHGSMI_CMD:
+ {
+ Assert(cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR);
+ if (cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR)
+ {
+ rc = crVBoxServerCrHgsmiCmd((PVBOXVDMACMD_CHROMIUM_CMD)paParms[0].u.pointer.addr, paParms[0].u.pointer.size);
+ if (VERR_NOT_SUPPORTED == rc)
+ {
+ svcClientVersionUnsupported(0, 0);
+ }
+ }
+ else
+ rc = VERR_INVALID_PARAMETER;
+ } break;
+ case SHCRGL_HOST_FN_CRHGSMI_CTL:
+ {
+ Assert(cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR);
+ if (cParms == 1 && paParms[0].type == VBOX_HGCM_SVC_PARM_PTR)
+ rc = crVBoxServerCrHgsmiCtl((PVBOXVDMACMD_CHROMIUM_CTL)paParms[0].u.pointer.addr, paParms[0].u.pointer.size);
+ else
+ rc = VERR_INVALID_PARAMETER;
+ } break;
+#endif
+ case SHCRGL_HOST_FN_SET_CONSOLE:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_SET_DISPLAY\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_SET_CONSOLE)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ IConsole* pConsole = (IConsole*)paParms[0].u.pointer.addr;
+ uint32_t cbData = paParms[0].u.pointer.size;
+
+ /* Verify parameters values. */
+ if (cbData != sizeof (IConsole*))
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else if (!pConsole)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else /* Execute the function. */
+ {
+ ComPtr<IMachine> pMachine;
+ ComPtr<IDisplay> pDisplay;
+ ComPtr<IFramebuffer> pFramebuffer;
+ LONG xo, yo;
+ LONG64 winId = 0;
+ ULONG monitorCount, i, w, h;
+
+ CHECK_ERROR_BREAK(pConsole, COMGETTER(Machine)(pMachine.asOutParam()));
+ CHECK_ERROR_BREAK(pMachine, COMGETTER(MonitorCount)(&monitorCount));
+ CHECK_ERROR_BREAK(pConsole, COMGETTER(Display)(pDisplay.asOutParam()));
+
+ g_pConsole = pConsole;
+ g_u32ScreenCount = monitorCount;
+
+ rc = crVBoxServerSetScreenCount(monitorCount);
+ AssertRCReturn(rc, rc);
+
+#if 1
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
+ for (i=0; i<monitorCount; ++i)
+ {
+ CHECK_ERROR_RET(pDisplay, QueryFramebuffer(i, pFramebuffer.asOutParam()), rc);
+
+ if (!pFramebuffer)
+ {
+ rc = crVBoxServerUnmapScreen(i);
+ AssertRCReturn(rc, rc);
+ }
+ else
+ {
+ CHECK_ERROR_RET(pFramebuffer, COMGETTER(WinId)(&winId), rc);
+ CHECK_ERROR_RET(pFramebuffer, COMGETTER(Width)(&w), rc);
+ CHECK_ERROR_RET(pFramebuffer, COMGETTER(Height)(&h), rc);
+ ULONG dummy;
+ GuestMonitorStatus_T monitorStatus;
+ CHECK_ERROR_RET(pDisplay, GetScreenResolution(i, &dummy, &dummy, &dummy, &xo, &yo, &monitorStatus), rc);
+
+ rc = crVBoxServerMapScreen(i, xo, yo, w, h, winId);
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+#endif
+
+ rc = VINF_SUCCESS;
+ }
+ }
+ break;
+ }
+ case SHCRGL_HOST_FN_SET_VM:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_SET_VM\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_SET_VM)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ PVM pVM = (PVM)paParms[0].u.pointer.addr;
+ uint32_t cbData = paParms[0].u.pointer.size;
+
+ /* Verify parameters values. */
+ if (cbData != sizeof (PVM))
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Execute the function. */
+ g_pVM = pVM;
+ rc = VINF_SUCCESS;
+ }
+ }
+ break;
+ }
+ case SHCRGL_HOST_FN_SET_VISIBLE_REGION:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_SET_VISIBLE_REGION\n"));
+
+ if (cParms != SHCRGL_CPARMS_SET_VISIBLE_REGION)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if ( paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* pRects */
+ )
+ {
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ Assert(sizeof (RTRECT) == 4 * sizeof (GLint));
+
+ rc = crVBoxServerSetRootVisibleRegion(paParms[0].u.pointer.size / sizeof (RTRECT), (const RTRECT*)paParms[0].u.pointer.addr);
+ break;
+ }
+ case SHCRGL_HOST_FN_SCREEN_CHANGED:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_SCREEN_CHANGED\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_SCREEN_CHANGED)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ uint32_t screenId = paParms[0].u.uint32;
+
+ /* Execute the function. */
+ ComPtr<IDisplay> pDisplay;
+ ComPtr<IFramebuffer> pFramebuffer;
+ LONG xo, yo;
+ LONG64 winId = 0;
+ ULONG w, h;
+
+ Assert(g_pConsole);
+ CHECK_ERROR_RET(g_pConsole, COMGETTER(Display)(pDisplay.asOutParam()), rc);
+ CHECK_ERROR_RET(pDisplay, QueryFramebuffer(screenId, pFramebuffer.asOutParam()), rc);
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
+ if (!pFramebuffer)
+ {
+ rc = crVBoxServerUnmapScreen(screenId);
+ AssertRCReturn(rc, rc);
+ }
+ else
+ {
+ do {
+ /* determine if the framebuffer is functional */
+ com::SafeArray<BYTE> data;
+ rc = pFramebuffer->Notify3DEvent(VBOX3D_NOTIFY_EVENT_TYPE_TEST_FUNCTIONAL, ComSafeArrayAsInParam(data));
+
+ if (rc == S_OK)
+ CHECK_ERROR_BREAK(pFramebuffer, COMGETTER(WinId)(&winId));
+
+ if (!winId)
+ {
+ /* View associated with framebuffer is destroyed, happens with 2d accel enabled */
+ rc = crVBoxServerUnmapScreen(screenId);
+ AssertRCReturn(rc, rc);
+ }
+ else
+ {
+ CHECK_ERROR_BREAK(pFramebuffer, COMGETTER(Width)(&w));
+ CHECK_ERROR_BREAK(pFramebuffer, COMGETTER(Height)(&h));
+ ULONG dummy;
+ GuestMonitorStatus_T monitorStatus;
+ CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(screenId, &dummy, &dummy, &dummy, &xo, &yo, &monitorStatus));
+
+ rc = crVBoxServerMapScreen(screenId, xo, yo, w, h, winId);
+ AssertRCReturn(rc, rc);
+ }
+ } while (0);
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+
+ rc = VINF_SUCCESS;
+ }
+ break;
+ }
+ case SHCRGL_HOST_FN_TAKE_SCREENSHOT:
+ {
+ if (cParms != 1)
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_TAKE_SCREENSHOT: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!paParms->u.pointer.addr)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms->u.pointer.size != sizeof (CRVBOXHGCMTAKESCREENSHOT))
+ {
+ AssertMsgFailed(("invalid param\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)paParms->u.pointer.addr;
+ uint64_t u64Now = RTTimeProgramMilliTS();
+
+ if (pScreenshot->u32Screen == CRSCREEN_ALL)
+ {
+ for (uint32_t i = 0; i < g_u32ScreenCount; ++i)
+ {
+ crScreenshotHandle(pScreenshot, i, u64Now);
+ }
+ }
+ else if (pScreenshot->u32Screen < g_u32ScreenCount)
+ {
+ crScreenshotHandle(pScreenshot, pScreenshot->u32Screen, u64Now);
+ }
+ else
+ {
+ AssertMsgFailed(("invalid screen id\n"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ break;
+ }
+ case SHCRGL_HOST_FN_DEV_RESIZE:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_DEV_RESIZE\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_DEV_RESIZE)
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_DEV_RESIZE: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (!paParms->u.pointer.addr)
+ {
+ AssertMsgFailed(("invalid param\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (paParms->u.pointer.size != sizeof (CRVBOXHGCMDEVRESIZE))
+ {
+ AssertMsgFailed(("invalid param\n"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ CRVBOXHGCMDEVRESIZE *pResize = (CRVBOXHGCMDEVRESIZE*)paParms->u.pointer.addr;
+
+ rc = crVBoxServerNotifyResize(&pResize->Screen, pResize->pvVRAM);
+ break;
+ }
+ case SHCRGL_HOST_FN_VIEWPORT_CHANGED:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_VIEWPORT_CHANGED\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_VIEWPORT_CHANGED)
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ for (int i = 0; i < SHCRGL_CPARMS_VIEWPORT_CHANGED; ++i)
+ {
+ if (paParms[i].type != VBOX_HGCM_SVC_PARM_32BIT)
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: param[%d] type invalid - %d", i, paParms[i].type));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ if (!RT_SUCCESS(rc))
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: param validation failed, returning.."));
+ break;
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
+ rc = crVBoxServerSetScreenViewport((int)paParms[0].u.uint32,
+ paParms[1].u.uint32, /* x */
+ paParms[2].u.uint32, /* y */
+ paParms[3].u.uint32, /* w */
+ paParms[4].u.uint32 /* h */);
+ if (!RT_SUCCESS(rc))
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: crVBoxServerSetScreenViewport failed, rc %d", rc));
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+
+ break;
+ }
+ case SHCRGL_HOST_FN_VIEWPORT_CHANGED2:
+ {
+ Log(("svcCall: SHCRGL_HOST_FN_VIEWPORT_CHANGED\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_VIEWPORT_CHANGED)
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: cParms invalid - %d", cParms));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR
+ || !paParms[0].u.pointer.addr
+ || paParms[0].u.pointer.size != sizeof (CRVBOXHGCMVIEWPORT))
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: param invalid - %d, %#x, %d",
+ paParms[0].type,
+ paParms[0].u.pointer.addr,
+ paParms[0].u.pointer.size));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_FALSE);
+
+ CRVBOXHGCMVIEWPORT *pViewportInfo = (CRVBOXHGCMVIEWPORT*)paParms[0].u.pointer.addr;
+
+ rc = crVBoxServerSetScreenViewport(pViewportInfo->u32Screen,
+ pViewportInfo->x, /* x */
+ pViewportInfo->y, /* y */
+ pViewportInfo->width, /* w */
+ pViewportInfo->height /* h */);
+ if (!RT_SUCCESS(rc))
+ {
+ LogRel(("OpenGL: SHCRGL_HOST_FN_VIEWPORT_CHANGED: crVBoxServerSetScreenViewport failed, rc %d", rc));
+ }
+
+ crServerVBoxCompositionSetEnableStateGlobal(GL_TRUE);
+
+ break;
+ }
+ case SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT:
+ {
+ /*
+ * OutputRedirect.
+ * Note: the service calls OutputRedirect callbacks directly
+ * and they must not block. If asynchronous processing is needed,
+ * the callback provider must organize this.
+ */
+ Log(("svcCall: SHCRGL_HOST_FN_SET_OUTPUT_REDIRECT\n"));
+
+ /* Verify parameter count and types. */
+ if (cParms != SHCRGL_CPARMS_SET_OUTPUT_REDIRECT)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else if (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Fetch parameters. */
+ H3DOUTPUTREDIRECT *pOutputRedirect = (H3DOUTPUTREDIRECT *)paParms[0].u.pointer.addr;
+ uint32_t cbData = paParms[0].u.pointer.size;
+
+ /* Verify parameters values. */
+ if (cbData != sizeof (H3DOUTPUTREDIRECT))
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else /* Execute the function. */
+ {
+ if (pOutputRedirect->H3DORBegin != NULL)
+ {
+ CROutputRedirect outputRedirect;
+ outputRedirect.pvContext = pOutputRedirect->pvContext;
+ outputRedirect.CRORBegin = pOutputRedirect->H3DORBegin;
+ outputRedirect.CRORGeometry = pOutputRedirect->H3DORGeometry;
+ outputRedirect.CRORVisibleRegion = pOutputRedirect->H3DORVisibleRegion;
+ outputRedirect.CRORFrame = pOutputRedirect->H3DORFrame;
+ outputRedirect.CROREnd = pOutputRedirect->H3DOREnd;
+ outputRedirect.CRORContextProperty = pOutputRedirect->H3DORContextProperty;
+ rc = crVBoxServerOutputRedirectSet(&outputRedirect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = crVBoxServerSetOffscreenRendering(GL_TRUE);
+ }
+ }
+ else
+ {
+ /* Redirection is disabled. */
+ crVBoxServerSetOffscreenRendering(GL_FALSE);
+ crVBoxServerOutputRedirectSet(NULL);
+ }
+ }
+ }
+ break;
+ }
+ case SHCRGL_HOST_FN_WINDOWS_SHOW:
+ {
+ /* Verify parameter count and types. */
+ if (cParms != 1)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crServerVBoxWindowsShow(!!paParms[0].u.uint32);
+ if (!RT_SUCCESS(rc))
+ WARN(("crServerVBoxWindowsShow failed rc %d", rc));
+
+ break;
+ }
+ case SHCRGL_HOST_FN_SET_SCALE_FACTOR:
+ {
+ /* Verify parameter count and types. */
+ if (cParms != 1
+ || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR
+ || paParms[0].u.pointer.size != sizeof(CRVBOXHGCMSETSCALEFACTOR)
+ || !paParms[0].u.pointer.addr)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRVBOXHGCMSETSCALEFACTOR *pData = (CRVBOXHGCMSETSCALEFACTOR *)paParms[0].u.pointer.addr;
+ double dScaleFactorW = (double)(pData->u32ScaleFactorWMultiplied) / VBOX_OGL_SCALE_FACTOR_MULTIPLIER;
+ double dScaleFactorH = (double)(pData->u32ScaleFactorHMultiplied) / VBOX_OGL_SCALE_FACTOR_MULTIPLIER;
+
+ rc = VBoxOglSetScaleFactor(pData->u32Screen, dScaleFactorW, dScaleFactorH);
+
+ /* Log scaling factor rounded to nearest 'int' value (not so precise). */
+ LogRel(("OpenGL: Set 3D content scale factor to (%u, %u), multiplier %d (rc=%Rrc)\n",
+ pData->u32ScaleFactorWMultiplied,
+ pData->u32ScaleFactorHMultiplied,
+ (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER,
+ rc));
+
+ break;
+ }
+
+ case SHCRGL_HOST_FN_SET_UNSCALED_HIDPI:
+ {
+ /* Verify parameter count and types. */
+ if (cParms != 1
+ || paParms[0].type != VBOX_HGCM_SVC_PARM_PTR
+ || paParms[0].u.pointer.size != sizeof(CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT)
+ || !paParms[0].u.pointer.addr)
+ {
+ WARN(("invalid parameter"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *pData = (CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *)paParms[0].u.pointer.addr;
+ crServerSetUnscaledHiDPI(pData->fUnscaledHiDPI);
+ LogRel(("OpenGL: Set OpenGL scale policy on HiDPI displays (fUnscaledHiDPI=%d)\n", pData->fUnscaledHiDPI));
+ break;
+ }
+
+ default:
+ WARN(("svcHostCallPerform: unexpected u32Function %d", u32Function));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ LogFlow(("svcHostCall: rc = %Rrc\n", rc));
+ return rc;
+}
+
+int crVBoxServerHostCtl(VBOXCRCMDCTL *pCtl, uint32_t cbCtl)
+{
+ if ((cbCtl - sizeof (VBOXCRCMDCTL)) % sizeof(VBOXHGCMSVCPARM))
+ {
+ WARN(("invalid param size"));
+ return VERR_INVALID_PARAMETER;
+ }
+ uint32_t cParams = (cbCtl - sizeof (VBOXCRCMDCTL)) / sizeof (VBOXHGCMSVCPARM);
+ bool fHasCallout = VBOXCRCMDCTL_IS_CALLOUT_AVAILABLE(pCtl);
+ if (fHasCallout)
+ crVBoxServerCalloutEnable(pCtl);
+
+ int rc = svcHostCallPerform(pCtl->u32Function, cParams, (VBOXHGCMSVCPARM*)(pCtl + 1));
+
+ if (fHasCallout)
+ crVBoxServerCalloutDisable();
+
+ return rc;
+}
+
+static DECLCALLBACK(int) svcHostCall(void *, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
+{
+ switch (u32Function)
+ {
+ case SHCRGL_HOST_FN_CTL:
+ {
+ if (cParms != 1)
+ {
+ WARN(("cParams != 1"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (paParms->type != VBOX_HGCM_SVC_PARM_PTR)
+ {
+ WARN(("invalid param type"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (paParms->u.pointer.size < sizeof (VBOXCRCMDCTL))
+ {
+ WARN(("invalid param size"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ VBOXCRCMDCTL *pCtl = (VBOXCRCMDCTL*)paParms->u.pointer.addr;
+ switch (pCtl->enmType)
+ {
+ case VBOXCRCMDCTL_TYPE_HGCM:
+ {
+ return crVBoxServerHostCtl(pCtl, paParms->u.pointer.size);
+ }
+ case VBOXCRCMDCTL_TYPE_DISABLE:
+ {
+ if (paParms->u.pointer.size != sizeof (VBOXCRCMDCTL_DISABLE))
+ WARN(("invalid param size"));
+ VBOXCRCMDCTL_DISABLE *pDisable = (VBOXCRCMDCTL_DISABLE*)pCtl;
+ int rc = crVBoxServerHgcmDisable(&pDisable->Data);
+ if (RT_SUCCESS(rc))
+ g_u32fCrHgcmDisabled = 1;
+ else
+ WARN(("crVBoxServerHgcmDisable failed %d", rc));
+ return rc;
+ }
+ case VBOXCRCMDCTL_TYPE_ENABLE:
+ {
+ if (paParms->u.pointer.size != sizeof (VBOXCRCMDCTL_ENABLE))
+ WARN(("invalid param size"));
+ VBOXCRCMDCTL_ENABLE *pEnable = (VBOXCRCMDCTL_ENABLE*)pCtl;
+ int rc = crVBoxServerHgcmEnable(&pEnable->Data);
+ if (RT_SUCCESS(rc))
+ g_u32fCrHgcmDisabled = 0;
+ else
+ WARN(("crVBoxServerHgcmEnable failed %d", rc));
+ return rc;
+ }
+ default:
+ WARN(("svcHostCall: invalid function %d", pCtl->enmType));
+ return VERR_INVALID_PARAMETER;
+ }
+ /* not reached. */
+ }
+
+ default:
+ if (g_u32fCrHgcmDisabled)
+ {
+ WARN(("cr hgcm disabled!"));
+ return VERR_INVALID_STATE;
+ }
+ return svcHostCallPerform(u32Function, cParms, paParms);
+ }
+}
+
+extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
+{
+ int rc = VINF_SUCCESS;
+
+ Log(("SHARED_CROPENGL VBoxHGCMSvcLoad: ptable = %p\n", ptable));
+
+ if (!ptable)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ Log(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
+
+ if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
+ || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
+ {
+ rc = VERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ g_pHelpers = ptable->pHelpers;
+
+ g_u32fCrHgcmDisabled = 0;
+
+ ptable->cbClient = sizeof (void*);
+
+ ptable->pfnUnload = svcUnload;
+ ptable->pfnConnect = svcConnect;
+ ptable->pfnDisconnect = svcDisconnect;
+ ptable->pfnCall = svcCall;
+ ptable->pfnHostCall = svcHostCall;
+ ptable->pfnSaveState = svcSaveState;
+ ptable->pfnLoadState = svcLoadState;
+ ptable->pfnNotify = NULL;
+ ptable->pvService = NULL;
+
+ if (!crVBoxServerInit())
+ return VERR_NOT_SUPPORTED;
+
+ crServerVBoxSetNotifyEventCB(svcNotifyEventCB);
+ }
+ }
+
+ return rc;
+}
+
+#ifdef RT_OS_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <iprt/win/windows.h>
+BOOL WINAPI DllMain(HINSTANCE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
+{
+ (void) lpvReserved;
+
+ switch (fdwReason)
+ {
+ case DLL_THREAD_ATTACH:
+ {
+ crStateVBoxAttachThread();
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ /* do exactly the same thing as for DLL_THREAD_DETACH since
+ * DLL_THREAD_DETACH is not called for the thread doing DLL_PROCESS_DETACH according to msdn docs */
+ case DLL_THREAD_DETACH:
+ {
+ crStateVBoxDetachThread();
+ break;
+ }
+
+ case DLL_PROCESS_ATTACH:
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/crserver/main.c b/src/VBox/HostServices/SharedOpenGL/crserver/main.c
new file mode 100644
index 00000000..9b525e56
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserver/main.c
@@ -0,0 +1,23 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_server.h"
+
+/**
+ * \mainpage Crserver
+ *
+ * \section CrserverIntroduction Introduction
+ *
+ * Chromium consists of all the top-level files in the cr
+ * directory. The crserver module basically takes care of API dispatch,
+ * and OpenGL state management.
+ *
+ */
+
+int main( int argc, char *argv[] )
+{
+ return CRServerMain( argc, argv );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/crserverlib/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/crserverlib.def b/src/VBox/HostServices/SharedOpenGL/crserverlib/crserverlib.def
new file mode 100644
index 00000000..a72ac3f9
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/crserverlib.def
@@ -0,0 +1,14 @@
+; Copyright (c) 2001, Stanford University
+; All rights reserved.
+;
+; See the file LICENSE.txt for information on redistributing this software.
+EXPORTS
+CRServerMain
+crVBoxServerInit
+crVBoxServerTearDown
+crVBoxServerAddClient
+crVBoxServerRemoveClient
+crVBoxServerClientWrite
+crVBoxServerClientRead
+crVBoxServerCrHgsmiCmd
+crVBoxServerCrHgsmiCtl
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py
new file mode 100755
index 00000000..cbe1061b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py
@@ -0,0 +1,468 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+
+num_get_values = {
+ 'GL_ACCUM_ALPHA_BITS' : 1,
+ 'GL_ACCUM_BLUE_BITS' : 1,
+ 'GL_ACCUM_CLEAR_VALUE': 4,
+ 'GL_ACCUM_GREEN_BITS' : 1,
+ 'GL_ACCUM_RED_BITS' : 1,
+ 'GL_ALPHA_BIAS' : 1,
+ 'GL_ALPHA_BITS' : 1,
+ 'GL_ALPHA_SCALE' : 1,
+ 'GL_ALPHA_TEST' : 1,
+ 'GL_ALPHA_TEST_FUNC' : 1,
+ 'GL_ALPHA_TEST_REF' : 1,
+ 'GL_ATTRIB_STACK_DEPTH' : 1,
+ 'GL_AUTO_NORMAL' : 1,
+ 'GL_AUX_BUFFERS' : 1,
+ 'GL_BLEND' : 1,
+ 'GL_BLEND_DST' : 1,
+ 'GL_BLEND_SRC' : 1,
+ 'GL_BLUE_BIAS' : 1,
+ 'GL_BLUE_BITS' : 1,
+ 'GL_BLUE_SCALE' : 1,
+ 'GL_CLIENT_ATTRIB_STACK_DEPTH' : 1,
+ 'GL_CLIP_PLANE0' : 1,
+ 'GL_CLIP_PLANE1' : 1,
+ 'GL_CLIP_PLANE2' : 1,
+ 'GL_CLIP_PLANE3' : 1,
+ 'GL_CLIP_PLANE4' : 1,
+ 'GL_CLIP_PLANE5' : 1,
+ 'GL_COLOR_ARRAY' : 1,
+ 'GL_COLOR_ARRAY_SIZE' : 1,
+ 'GL_COLOR_ARRAY_STRIDE' : 1,
+ 'GL_COLOR_ARRAY_TYPE' : 1,
+ 'GL_COLOR_CLEAR_VALUE': 4,
+ 'GL_COLOR_LOGIC_OP' : 1,
+ 'GL_COLOR_MATERIAL' : 1,
+ 'GL_COLOR_MATERIAL_FACE' : 1,
+ 'GL_COLOR_MATERIAL_PARAMETER' : 1,
+ 'GL_COLOR_MATRIX_STACK_DEPTH' : 1,
+ 'GL_COLOR_WRITEMASK': 4,
+ 'GL_CULL_FACE' : 1,
+ 'GL_CULL_FACE_MODE' : 1,
+ 'GL_CURRENT_COLOR': 4,
+ 'GL_CURRENT_INDEX' : 1,
+ 'GL_CURRENT_NORMAL': 3,
+ 'GL_CURRENT_RASTER_COLOR': 4,
+ 'GL_CURRENT_RASTER_DISTANCE' : 1,
+ 'GL_CURRENT_RASTER_INDEX' : 1,
+ 'GL_CURRENT_RASTER_POSITION': 4,
+ 'GL_CURRENT_RASTER_POSITION_VALID' : 1,
+ 'GL_CURRENT_RASTER_TEXTURE_COORDS': 4,
+ 'GL_CURRENT_TEXTURE_COORDS': 4,
+ 'GL_DEPTH_BIAS' : 1,
+ 'GL_DEPTH_BITS' : 1,
+ 'GL_DEPTH_CLEAR_VALUE' : 1,
+ 'GL_DEPTH_FUNC' : 1,
+ 'GL_DEPTH_RANGE': 2,
+ 'GL_DEPTH_SCALE' : 1,
+ 'GL_DEPTH_TEST' : 1,
+ 'GL_DEPTH_WRITEMASK' : 1,
+ 'GL_DITHER' : 1,
+ 'GL_DOUBLEBUFFER' : 1,
+ 'GL_DRAW_BUFFER' : 1,
+ 'GL_EDGE_FLAG' : 1,
+ 'GL_EDGE_FLAG_ARRAY' : 1,
+ 'GL_EDGE_FLAG_ARRAY_STRIDE' : 1,
+ 'GL_FEEDBACK_BUFFER_SIZE' : 1,
+ 'GL_FEEDBACK_BUFFER_TYPE' : 1,
+ 'GL_FOG' : 1,
+ 'GL_FOG_COLOR': 4,
+ 'GL_FOG_DENSITY' : 1,
+ 'GL_FOG_END' : 1,
+ 'GL_FOG_HINT' : 1,
+ 'GL_FOG_INDEX' : 1,
+ 'GL_FOG_MODE' : 1,
+ 'GL_FOG_START' : 1,
+ 'GL_FRONT_FACE' : 1,
+ 'GL_GREEN_BIAS' : 1,
+ 'GL_GREEN_BITS' : 1,
+ 'GL_GREEN_SCALE' : 1,
+ 'GL_INDEX_ARRAY' : 1,
+ 'GL_INDEX_ARRAY_STRIDE' : 1,
+ 'GL_INDEX_ARRAY_TYPE' : 1,
+ 'GL_INDEX_BITS' : 1,
+ 'GL_INDEX_CLEAR_VALUE' : 1,
+ 'GL_INDEX_LOGIC_OP' : 1,
+ 'GL_INDEX_MODE' : 1,
+ 'GL_INDEX_OFFSET' : 1,
+ 'GL_INDEX_SHIFT' : 1,
+ 'GL_INDEX_WRITEMASK' : 1,
+ 'GL_LIGHT0' : 1,
+ 'GL_LIGHT1' : 1,
+ 'GL_LIGHT2' : 1,
+ 'GL_LIGHT3' : 1,
+ 'GL_LIGHT4' : 1,
+ 'GL_LIGHT5' : 1,
+ 'GL_LIGHT6' : 1,
+ 'GL_LIGHT7' : 1,
+ 'GL_LIGHTING' : 1,
+ 'GL_LIGHT_MODEL_AMBIENT': 4,
+ 'GL_LIGHT_MODEL_LOCAL_VIEWER' : 1,
+ 'GL_LIGHT_MODEL_TWO_SIDE' : 1,
+ 'GL_LINE_SMOOTH' : 1,
+ 'GL_LINE_SMOOTH_HINT' : 1,
+ 'GL_LINE_STIPPLE' : 1,
+ 'GL_LINE_STIPPLE_PATTERN' : 1,
+ 'GL_LINE_STIPPLE_REPEAT' : 1,
+ 'GL_LINE_WIDTH' : 1,
+ 'GL_LINE_WIDTH_GRANULARITY' : 1,
+ 'GL_LINE_WIDTH_RANGE': 2,
+ 'GL_LIST_BASE' : 1,
+ 'GL_LIST_INDEX' : 1,
+ 'GL_LIST_MODE' : 1,
+ 'GL_LOGIC_OP_MODE' : 1,
+ 'GL_MAP1_COLOR_4' : 1,
+ 'GL_MAP1_GRID_DOMAIN': 2,
+ 'GL_MAP1_GRID_SEGMENTS' : 1,
+ 'GL_MAP1_INDEX' : 1,
+ 'GL_MAP1_NORMAL' : 1,
+ 'GL_MAP1_TEXTURE_COORD_1' : 1,
+ 'GL_MAP1_TEXTURE_COORD_2' : 1,
+ 'GL_MAP1_TEXTURE_COORD_3' : 1,
+ 'GL_MAP1_TEXTURE_COORD_4' : 1,
+ 'GL_MAP1_VERTEX_3' : 1,
+ 'GL_MAP1_VERTEX_4' : 1,
+ 'GL_MAP2_COLOR_4' : 1,
+ 'GL_MAP2_GRID_DOMAIN': 4,
+ 'GL_MAP2_GRID_SEGMENTS': 2,
+ 'GL_MAP2_INDEX' : 1,
+ 'GL_MAP2_NORMAL' : 1,
+ 'GL_MAP2_TEXTURE_COORD_1' : 1,
+ 'GL_MAP2_TEXTURE_COORD_2' : 1,
+ 'GL_MAP2_TEXTURE_COORD_3' : 1,
+ 'GL_MAP2_TEXTURE_COORD_4' : 1,
+ 'GL_MAP2_VERTEX_3' : 1,
+ 'GL_MAP2_VERTEX_4' : 1,
+ 'GL_MAP_COLOR' : 1,
+ 'GL_MAP_STENCIL' : 1,
+ 'GL_MATRIX_MODE' : 1,
+ 'GL_MAX_CLIENT_ATTRIB_STACK_DEPTH' : 1,
+ 'GL_MAX_ATTRIB_STACK_DEPTH' : 1,
+ 'GL_MAX_CLIP_PLANES' : 1,
+ 'GL_MAX_COLOR_MATRIX_STACK_DEPTH' : 1,
+ 'GL_MAX_EVAL_ORDER' : 1,
+ 'GL_MAX_LIGHTS' : 1,
+ 'GL_MAX_LIST_NESTING' : 1,
+ 'GL_MAX_MODELVIEW_STACK_DEPTH' : 1,
+ 'GL_MAX_NAME_STACK_DEPTH' : 1,
+ 'GL_MAX_PIXEL_MAP_TABLE' : 1,
+ 'GL_MAX_PROJECTION_STACK_DEPTH' : 1,
+ 'GL_MAX_TEXTURE_SIZE' : 1,
+ 'GL_MAX_3D_TEXTURE_SIZE' : 1,
+ 'GL_MAX_TEXTURE_STACK_DEPTH' : 1,
+ 'GL_MAX_VIEWPORT_DIMS': 2,
+ 'GL_MODELVIEW_MATRIX': 16,
+ 'GL_MODELVIEW_STACK_DEPTH' : 1,
+ 'GL_NAME_STACK_DEPTH' : 1,
+ 'GL_NORMAL_ARRAY' : 1,
+ 'GL_NORMAL_ARRAY_STRIDE' : 1,
+ 'GL_NORMAL_ARRAY_TYPE' : 1,
+ 'GL_NORMALIZE' : 1,
+ 'GL_PACK_ALIGNMENT' : 1,
+ 'GL_PACK_LSB_FIRST' : 1,
+ 'GL_PACK_ROW_LENGTH' : 1,
+ 'GL_PACK_SKIP_PIXELS' : 1,
+ 'GL_PACK_SKIP_ROWS' : 1,
+ 'GL_PACK_SWAP_BYTES' : 1,
+ 'GL_PERSPECTIVE_CORRECTION_HINT' : 1,
+ 'GL_PIXEL_MAP_A_TO_A_SIZE' : 1,
+ 'GL_PIXEL_MAP_B_TO_B_SIZE' : 1,
+ 'GL_PIXEL_MAP_G_TO_G_SIZE' : 1,
+ 'GL_PIXEL_MAP_I_TO_A_SIZE' : 1,
+ 'GL_PIXEL_MAP_I_TO_B_SIZE' : 1,
+ 'GL_PIXEL_MAP_I_TO_G_SIZE' : 1,
+ 'GL_PIXEL_MAP_I_TO_I_SIZE' : 1,
+ 'GL_PIXEL_MAP_I_TO_R_SIZE' : 1,
+ 'GL_PIXEL_MAP_R_TO_R_SIZE' : 1,
+ 'GL_PIXEL_MAP_S_TO_S_SIZE' : 1,
+ 'GL_POINT_SIZE' : 1,
+ 'GL_POINT_SIZE_GRANULARITY' : 1,
+ 'GL_POINT_SIZE_RANGE': 2,
+ 'GL_POINT_SMOOTH' : 1,
+ 'GL_POINT_SMOOTH_HINT' : 1,
+ 'GL_POLYGON_MODE': 2,
+ 'GL_POLYGON_OFFSET_FACTOR' : 1,
+ 'GL_POLYGON_OFFSET_UNITS' : 1,
+ 'GL_POLYGON_OFFSET_FILL' : 1,
+ 'GL_POLYGON_OFFSET_LINE' : 1,
+ 'GL_POLYGON_OFFSET_POINT' : 1,
+ 'GL_POLYGON_SMOOTH' : 1,
+ 'GL_POLYGON_SMOOTH_HINT' : 1,
+ 'GL_POLYGON_STIPPLE' : 1,
+ 'GL_PROJECTION_MATRIX': 16,
+ 'GL_PROJECTION_STACK_DEPTH' : 1,
+ 'GL_READ_BUFFER' : 1,
+ 'GL_RED_BIAS' : 1,
+ 'GL_RED_BITS' : 1,
+ 'GL_RED_SCALE' : 1,
+ 'GL_RENDER_MODE' : 1,
+ 'GL_RGBA_MODE' : 1,
+ 'GL_SCISSOR_BOX': 4,
+ 'GL_SCISSOR_TEST' : 1,
+ 'GL_SELECTION_BUFFER_SIZE' : 1,
+ 'GL_SHADE_MODEL' : 1,
+ 'GL_STENCIL_BITS' : 1,
+ 'GL_STENCIL_CLEAR_VALUE' : 1,
+ 'GL_STENCIL_FAIL' : 1,
+ 'GL_STENCIL_FUNC' : 1,
+ 'GL_STENCIL_PASS_DEPTH_FAIL' : 1,
+ 'GL_STENCIL_PASS_DEPTH_PASS' : 1,
+ 'GL_STENCIL_REF' : 1,
+ 'GL_STENCIL_TEST' : 1,
+ 'GL_STENCIL_VALUE_MASK' : 1,
+ 'GL_STENCIL_WRITEMASK' : 1,
+ 'GL_STEREO' : 1,
+ 'GL_SUBPIXEL_BITS' : 1,
+ 'GL_TEXTURE_1D' : 1,
+ 'GL_TEXTURE_2D' : 1,
+ 'GL_TEXTURE_BINDING_1D' : 1,
+ 'GL_TEXTURE_BINDING_2D' : 1,
+ 'GL_TEXTURE_BINDING_3D' : 1,
+ 'GL_TEXTURE_COORD_ARRAY' : 1,
+ 'GL_TEXTURE_COORD_ARRAY_SIZE' : 1,
+ 'GL_TEXTURE_COORD_ARRAY_STRIDE' : 1,
+ 'GL_TEXTURE_COORD_ARRAY_TYPE' : 1,
+ 'GL_TEXTURE_ENV_COLOR': 4,
+ 'GL_TEXTURE_ENV_MODE' : 1,
+ 'GL_TEXTURE_GEN_Q' : 1,
+ 'GL_TEXTURE_GEN_R' : 1,
+ 'GL_TEXTURE_GEN_S' : 1,
+ 'GL_TEXTURE_GEN_T' : 1,
+ 'GL_TEXTURE_MATRIX': 16,
+ 'GL_TEXTURE_STACK_DEPTH' : 1,
+ 'GL_UNPACK_ALIGNMENT' : 1,
+ 'GL_UNPACK_LSB_FIRST' : 1,
+ 'GL_UNPACK_ROW_LENGTH' : 1,
+ 'GL_UNPACK_SKIP_PIXELS' : 1,
+ 'GL_UNPACK_SKIP_ROWS' : 1,
+ 'GL_UNPACK_SWAP_BYTES' : 1,
+ 'GL_VERTEX_ARRAY' : 1,
+ 'GL_VERTEX_ARRAY_SIZE' : 1,
+ 'GL_VERTEX_ARRAY_STRIDE' : 1,
+ 'GL_VERTEX_ARRAY_TYPE' : 1,
+ 'GL_VIEWPORT': 4,
+ 'GL_ZOOM_X' : 1,
+ 'GL_ZOOM_Y' : 1,
+ #GL_ARB_IMAGING which is part of 1.2.1
+ 'GL_COLOR_MATRIX' : 16,
+ 'GL_COLOR_MATRIX_STACK_DEPTH' : 1,
+ 'GL_COLOR_TABLE' : 1,
+ 'GL_POST_CONVOLUTION_COLOR_TABLE' : 1,
+ 'GL_POST_COLOR_MATRIX_COLOR_TABLE' : 1,
+ 'GL_PROXY_COLOR_TABLE' : 1,
+ 'GL_CONVOLUTION_1D' : 1,
+ 'GL_CONVOLUTION_2D' : 1,
+ 'GL_SEPARABLE_2D' : 1,
+ 'GL_POST_CONVOLUTION_RED_SCALE' : 1,
+ 'GL_POST_CONVOLUTION_GREEN_SCALE' : 1,
+ 'GL_POST_CONVOLUTION_BLUE_SCALE' : 1,
+ 'GL_POST_CONVOLUTION_ALPHA_SCALE' : 1,
+ 'GL_POST_CONVOLUTION_RED_BIAS' : 1,
+ 'GL_POST_CONVOLUTION_GREEN_BIAS' : 1,
+ 'GL_POST_CONVOLUTION_BLUE_BIAS' : 1,
+ 'GL_POST_CONVOLUTION_ALPHA_BIAS' : 1,
+ 'GL_HISTOGRAM' : 1,
+ 'GL_MINMAX' : 1,
+ 'GL_MAX_COLOR_MATRIX_STACK_DEPTH' : 1,
+ 'GL_MAX_CONVOLUTION_WIDTH' : 1,
+ 'GL_MAX_CONVOLUTION_HEIGHT' : 1,
+}
+
+extensions_num_get_values = {
+ 'GL_BLEND_COLOR_EXT': (4, 'CR_EXT_blend_color'),
+ 'GL_BLEND_EQUATION_EXT': (1, 'CR_EXT_blend_minmax'),
+ 'GL_BLEND_SRC_RGB_EXT': (1, 'CR_EXT_blend_func_separate'),
+ 'GL_BLEND_DST_RGB_EXT': (1, 'CR_EXT_blend_func_separate'),
+ 'GL_BLEND_SRC_ALPHA_EXT': (1, 'CR_EXT_blend_func_separate'),
+ 'GL_BLEND_DST_ALPHA_EXT': (1, 'CR_EXT_blend_func_separate'),
+ 'GL_FOG_DISTANCE_MODE_NV': (1, 'CR_NV_fog_distance'),
+ 'GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB': (1, 'CR_ARB_texture_cube_map'),
+ 'GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT': (1, 'CR_EXT_texture_filter_anisotropic'),
+ 'GL_TEXTURE_BINDING_CUBE_MAP_ARB': (1, 'CR_ARB_texture_cube_map'),
+ 'GL_TEXTURE_CUBE_MAP_ARB': (1, 'CR_ARB_texture_cube_map'),
+ 'GL_ACTIVE_TEXTURE_ARB': (1, 'CR_ARB_multitexture'),
+ 'GL_CLIENT_ACTIVE_TEXTURE_ARB': (1, 'CR_ARB_multitexture'),
+ 'GL_MAX_TEXTURE_UNITS_ARB': (1, 'CR_ARB_multitexture'),
+ 'GL_NUM_GENERAL_COMBINERS_NV': (1, 'CR_NV_register_combiners'),
+ 'GL_MAX_GENERAL_COMBINERS_NV': (1, 'CR_NV_register_combiners'),
+ 'GL_COLOR_SUM_CLAMP_NV': (1, 'CR_NV_register_combiners'),
+ 'GL_CONSTANT_COLOR0_NV': (4, 'CR_NV_register_combiners'),
+ 'GL_CONSTANT_COLOR1_NV': (4, 'CR_NV_register_combiners'),
+ 'GL_PER_STAGE_CONSTANTS_NV': (1, 'CR_NV_register_combiners2'),
+ 'GL_LIGHT_MODEL_COLOR_CONTROL_EXT': (1, 'CR_EXT_separate_specular_color'),
+ 'GL_COLOR_SUM_EXT': (1, 'CR_EXT_secondary_color'),
+ 'GL_CURRENT_SECONDARY_COLOR_EXT': (4, 'CR_EXT_secondary_color'),
+ 'GL_SECONDARY_COLOR_ARRAY_SIZE_EXT': (1, 'CR_EXT_secondary_color'),
+ 'GL_SECONDARY_COLOR_ARRAY_TYPE_EXT': (1, 'CR_EXT_secondary_color'),
+ 'GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT': (1, 'CR_EXT_secondary_color'),
+ 'GL_RESCALE_NORMAL': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_NUM_COMPRESSED_TEXTURE_FORMATS': (1, 'CR_ARB_texture_compression'),
+ 'GL_TEXTURE_3D': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_LIGHT_MODEL_COLOR_CONTROL': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_UNPACK_IMAGE_HEIGHT': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_UNPACK_SKIP_IMAGES': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_PACK_IMAGE_HEIGHT': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_PACK_SKIP_IMAGES': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_ALIASED_POINT_SIZE_RANGE': (2, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_ALIASED_LINE_WIDTH_RANGE': (2, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_MAX_ELEMENTS_INDICES': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_MAX_ELEMENTS_VERTICES': (1, 'CR_OPENGL_VERSION_1_2'),
+ 'GL_MULTISAMPLE_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLE_ALPHA_TO_COVERAGE_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLE_ALPHA_TO_ONE_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLE_COVERAGE_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLE_BUFFERS_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLES_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLE_COVERAGE_VALUE_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_SAMPLE_COVERAGE_INVERT_ARB': (1, 'CR_ARB_multisample'),
+ 'GL_POINT_SPRITE_ARB': (1, 'CR_ARB_point_sprite'),
+ 'GL_MAX_TEXTURE_LOD_BIAS_EXT': (1, 'CR_EXT_texture_lod_bias'),
+ 'GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB': (1, 'CR_ARB_texture_compression'),
+ 'GL_PROGRAM_ERROR_POSITION_NV': (1, 'CR_NV_vertex_program'),
+ 'GL_VERTEX_PROGRAM_BINDING_NV': (1, 'CR_NV_vertex_program'),
+ 'GL_MAX_VERTEX_ATTRIBS_ARB': (1, 'CR_ARB_vertex_program'),
+ 'GL_MAX_TEXTURE_COORDS_ARB': (1, 'CR_ARB_vertex_program'),
+ 'GL_PROGRAM_ERROR_POSITION_NV': (1, 'CR_NV_fragment_program'),
+ 'GL_FRAGMENT_PROGRAM_BINDING_NV': (1, 'CR_NV_fragment_program'),
+ 'GL_MAX_RECTANGLE_TEXTURE_SIZE_NV': (1, 'CR_NV_texture_rectangle'),
+ 'GL_TEXTURE_RECTANGLE_NV': (1, 'CR_NV_texture_rectangle'),
+ 'GL_TEXTURE_BINDING_RECTANGLE_NV': (1, 'CR_NV_texture_rectangle'),
+ 'GL_CLIP_VOLUME_CLIPPING_HINT_EXT' : (3, 'CR_EXT_clip_volume_hint'),
+ 'GL_RASTER_POSITION_UNCLIPPED_IBM' : (1, 'CR_IBM_rasterpos_clip'),
+ 'GL_GENERATE_MIPMAP_HINT_SGIS' : (1, 'CR_SGIS_generate_mipmap'),
+ 'GL_CURRENT_FOG_COORDINATE_EXT' : (1, 'CR_EXT_fog_coord'),
+ 'GL_FOG_COORDINATE_ARRAY_TYPE_EXT' : (1, 'CR_EXT_fog_coord'),
+ 'GL_FOG_COORDINATE_ARRAY_STRIDE_EXT' : (1, 'CR_EXT_fog_coord'),
+ 'GL_TRANSPOSE_COLOR_MATRIX_ARB': (16, 'CR_ARB_transpose_matrix'),
+ 'GL_TRANSPOSE_MODELVIEW_MATRIX_ARB': (16, 'CR_ARB_transpose_matrix'),
+ 'GL_TRANSPOSE_PROJECTION_MATRIX_ARB': (16, 'CR_ARB_transpose_matrix'),
+ 'GL_TRANSPOSE_TEXTURE_MATRIX_ARB': (16, 'CR_ARB_transpose_matrix'),
+ 'GL_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_VERTEX_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_NORMAL_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_COLOR_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_INDEX_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'),
+ 'GL_MAX_TEXTURE_IMAGE_UNITS_ARB': (1, 'CR_ARB_fragment_program'),
+ 'GL_MAX_PROGRAM_MATRICES_ARB': (1, 'CR_ARB_vertex_program'),
+ 'GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB': (1, 'CR_ARB_vertex_program'),
+ # Vertex shaders (2.0) #
+ 'GL_MAX_VERTEX_UNIFORM_COMPONENTS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_MAX_VARYING_FLOATS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_MAX_VERTEX_ATTRIBS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_MAX_TEXTURE_IMAGE_UNITS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_MAX_TEXTURE_COORDS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_VERTEX_PROGRAM_POINT_SIZE': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_VERTEX_PROGRAM_TWO_SIDE': (1, 'CR_OPENGL_VERSION_2_0'),
+ # Fragment shaders (2.0) #
+ 'GL_MAX_FRAGMENT_UNIFORM_COMPONENTS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_FRAGMENT_SHADER_DERIVATIVE_HINT': (1, 'CR_OPENGL_VERSION_2_0'),
+ # Draw buffers (2.0) / GL_ARB_draw_buffers #
+ 'GL_MAX_DRAW_BUFFERS': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER0': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER1': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER2': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER3': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER4': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER5': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER6': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER7': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER8': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER9': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER10': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER11': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER12': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER13': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER14': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_DRAW_BUFFER15': (1, 'CR_OPENGL_VERSION_2_0'),
+ # Point sprite (2.0) #
+ 'GL_POINT_SPRITE': (1, 'CR_OPENGL_VERSION_2_0'),
+ # Separate stencil (2.0) #
+ 'GL_STENCIL_BACK_FUNC': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_STENCIL_BACK_REF': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_STENCIL_BACK_VALUE_MASK': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_STENCIL_BACK_FAIL': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_STENCIL_BACK_PASS_DEPTH_FAIL': (1, 'CR_OPENGL_VERSION_2_0'),
+ 'GL_STENCIL_BACK_PASS_DEPTH_PASS': (1, 'CR_OPENGL_VERSION_2_0'),
+ # Frame buffer object EXT #
+ 'GL_FRAMEBUFFER_BINDING_EXT': (1, 'CR_EXT_framebuffer_object'),
+ 'GL_RENDERBUFFER_BINDING_EXT': (1, 'CR_EXT_framebuffer_object'),
+ 'GL_MAX_COLOR_ATTACHMENTS_EXT': (1, 'CR_EXT_framebuffer_object'),
+ 'GL_MAX_RENDERBUFFER_SIZE_EXT': (1, 'CR_EXT_framebuffer_object'),
+ # ARB_shader_objects
+ 'GL_CURRENT_PROGRAM': (1, 'CR_ARB_shader_objects'),
+ # EXT_framebuffer_blit
+ 'GL_READ_FRAMEBUFFER_BINDING_EXT': (1, 'CR_EXT_framebuffer_blit'),
+ 'GL_DRAW_FRAMEBUFFER_BINDING_EXT': (1, 'CR_EXT_framebuffer_blit'),
+ # EXT_stencil_two_side
+ 'GL_ACTIVE_STENCIL_FACE_EXT': (1, 'CR_EXT_stencil_two_side'),
+}
+
+get_keys = list(num_get_values.keys()) + list(extensions_num_get_values.keys())
+get_keys.sort()
+max_keyvalues = 0
+
+print("""
+static struct nv_struct { GLenum pname; unsigned int num_values;
+#ifdef VBOX_WITH_CRDUMPER
+const char* pszName;
+#endif
+} num_values_array[] = {
+""")
+for key in get_keys:
+ try:
+ keyvalues = num_get_values[key]
+ if max_keyvalues < keyvalues:
+ max_keyvalues = keyvalues
+ print("""
+ \t{ %s, %d
+#ifdef VBOX_WITH_CRDUMPER
+ , "%s"
+#endif
+ },
+ """ % (key, keyvalues, key))
+ except KeyError:
+ (nv, ifdef) = extensions_num_get_values[key]
+ if max_keyvalues < nv:
+ max_keyvalues = nv
+ print('#ifdef %s' % ifdef)
+ print("""
+ \t{ %s, %d
+ #ifdef VBOX_WITH_CRDUMPER
+ , "%s"
+ #endif
+ },
+ """ % (key, nv, key))
+ print('#endif /* %s */' % ifdef)
+print("\t{ 0, 0 }")
+print("};")
+print("#define CR_MAX_GET_VALUES %d" % max_keyvalues)
+
+print("""
+static unsigned int __numValues( GLenum pname )
+{
+ struct nv_struct *temp;
+
+ for (temp = num_values_array; temp->num_values != 0 ; temp++)
+ {
+ if (temp->pname == pname)
+ return temp->num_values;
+ }
+ crDebug( "Invalid pname to __numValues: 0x%x\\n", (int) pname );
+ return 0;
+}
+""")
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp
new file mode 100644
index 00000000..797104f0
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp
@@ -0,0 +1,390 @@
+/* $Id: display_base.cpp $ */
+
+/** @file
+ * Presenter API: display base class implementation.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server_presenter.h"
+
+CrFbDisplayBase::CrFbDisplayBase() :
+ mpContainer(NULL),
+ mpFb(NULL),
+ mcUpdates(0),
+ mhSlot(CRHTABLE_HANDLE_INVALID)
+{
+ mFlags.u32Value = 0;
+}
+
+
+CrFbDisplayBase::~CrFbDisplayBase()
+{
+ Assert(!mcUpdates);
+
+ if (mpContainer)
+ mpContainer->remove(this);
+}
+
+
+bool CrFbDisplayBase::isComposite()
+{
+ return false;
+}
+
+
+class CrFbDisplayComposite* CrFbDisplayBase::getContainer()
+{
+ return mpContainer;
+}
+
+
+bool CrFbDisplayBase::isInList()
+{
+ return !!mpContainer;
+}
+
+
+bool CrFbDisplayBase::isUpdating()
+{
+ return !!mcUpdates;
+}
+
+
+int CrFbDisplayBase::setRegionsChanged()
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+
+ mFlags.fRegionsShanged = 1;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::setFramebuffer(struct CR_FRAMEBUFFER *pFb)
+{
+ if (mcUpdates)
+ {
+ WARN(("trying to set framebuffer while update is in progress"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (mpFb == pFb)
+ return VINF_SUCCESS;
+
+ int rc = setFramebufferBegin(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ if (mpFb)
+ {
+ rc = fbCleanup();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ setFramebufferEnd(pFb);
+ return rc;
+ }
+ }
+
+ mpFb = pFb;
+
+ if (mpFb)
+ {
+ rc = fbSync();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ setFramebufferEnd(pFb);
+ return rc;
+ }
+ }
+
+ setFramebufferEnd(pFb);
+ return VINF_SUCCESS;
+}
+
+
+struct CR_FRAMEBUFFER* CrFbDisplayBase::getFramebuffer()
+{
+ return mpFb;
+}
+
+
+int CrFbDisplayBase::UpdateBegin(struct CR_FRAMEBUFFER *pFb)
+{
+ ++mcUpdates;
+ Assert(!mFlags.fRegionsShanged || mcUpdates > 1);
+ return VINF_SUCCESS;
+}
+
+
+void CrFbDisplayBase::UpdateEnd(struct CR_FRAMEBUFFER *pFb)
+{
+ --mcUpdates;
+ Assert(mcUpdates < UINT32_MAX/2);
+ if (!mcUpdates)
+ onUpdateEnd();
+}
+
+
+int CrFbDisplayBase::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ mFlags.fRegionsShanged = 1;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry,
+ HCR_FRAMEBUFFER_ENTRY hReplacedEntry)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ mFlags.fRegionsShanged = 1;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ mFlags.fRegionsShanged = 1;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::RegionsChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ mFlags.fRegionsShanged = 1;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::FramebufferChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ if (!mcUpdates)
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+ return VINF_SUCCESS;
+}
+
+
+void CrFbDisplayBase::onUpdateEnd()
+{
+ if (mFlags.fRegionsShanged)
+ {
+ mFlags.fRegionsShanged = 0;
+ if (getFramebuffer()) /*<-dont't do anything on cleanup*/
+ ueRegions();
+ }
+}
+
+
+void CrFbDisplayBase::ueRegions()
+{
+}
+
+
+DECLCALLBACK(bool) CrFbDisplayBase::entriesCreateCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext)
+{
+ int rc = ((ICrFbDisplay*)(pvContext))->EntryCreated(hFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ }
+ return true;
+}
+
+
+DECLCALLBACK(bool) CrFbDisplayBase::entriesDestroyCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext)
+{
+ int rc = ((ICrFbDisplay*)(pvContext))->EntryDestroyed(hFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ }
+ return true;
+}
+
+
+int CrFbDisplayBase::fbSynchAddAllEntries()
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+
+ CrVrScrCompositorConstIterInit(CrFbGetCompositor(mpFb), &Iter);
+ int rc = VINF_SUCCESS;
+
+ CrFbVisitCreatedEntries(mpFb, entriesCreateCb, this);
+
+ while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
+ {
+ HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
+
+ rc = EntryAdded(mpFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ EntryDestroyed(mpFb, hEntry);
+ break;
+ }
+ }
+
+ return rc;
+}
+
+
+int CrFbDisplayBase::fbCleanupRemoveAllEntries()
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+
+ CrVrScrCompositorConstIterInit(CrFbGetCompositor(mpFb), &Iter);
+
+ int rc = VINF_SUCCESS;
+
+ while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
+ {
+ HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
+ rc = EntryRemoved(mpFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ break;
+ }
+ }
+
+ CrFbVisitCreatedEntries(mpFb, entriesDestroyCb, this);
+
+ return rc;
+}
+
+
+int CrFbDisplayBase::setFramebufferBegin(struct CR_FRAMEBUFFER *pFb)
+{
+ return UpdateBegin(pFb);
+}
+
+
+void CrFbDisplayBase::setFramebufferEnd(struct CR_FRAMEBUFFER *pFb)
+{
+ UpdateEnd(pFb);
+}
+
+
+DECLCALLBACK(void) CrFbDisplayBase::slotEntryReleaseCB(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext)
+{
+}
+
+
+void CrFbDisplayBase::slotRelease()
+{
+ Assert(mhSlot);
+ CrFbDDataReleaseSlot(mpFb, mhSlot, slotEntryReleaseCB, this);
+}
+
+
+int CrFbDisplayBase::fbCleanup()
+{
+ if (mhSlot)
+ {
+ slotRelease();
+ mhSlot = 0;
+ }
+
+ mpFb = NULL;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayBase::fbSync()
+{
+ return VINF_SUCCESS;
+}
+
+
+CRHTABLE_HANDLE CrFbDisplayBase::slotGet()
+{
+ if (!mhSlot)
+ {
+ if (mpFb)
+ mhSlot = CrFbDDataAllocSlot(mpFb);
+ }
+
+ return mhSlot;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp
new file mode 100644
index 00000000..697c2c96
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp
@@ -0,0 +1,341 @@
+/* $Id: display_composite.cpp $ */
+
+/** @file
+ * Presenter API: display composite class implementation.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server_presenter.h"
+
+CrFbDisplayComposite::CrFbDisplayComposite() :
+ mcDisplays(0)
+{
+ RTListInit(&mDisplays);
+}
+
+
+bool CrFbDisplayComposite::isComposite()
+{
+ return true;
+}
+
+
+uint32_t CrFbDisplayComposite::getDisplayCount()
+{
+ return mcDisplays;
+}
+
+
+bool CrFbDisplayComposite::add(CrFbDisplayBase *pDisplay)
+{
+ if (pDisplay->isInList())
+ {
+ WARN(("entry in list already"));
+ return false;
+ }
+
+ RTListAppend(&mDisplays, &pDisplay->mNode);
+ pDisplay->mpContainer = this;
+ pDisplay->setFramebuffer(getFramebuffer());
+ ++mcDisplays;
+ return true;
+}
+
+
+bool CrFbDisplayComposite::remove(CrFbDisplayBase *pDisplay, bool fCleanupDisplay)
+{
+ if (pDisplay->getContainer() != this)
+ {
+ WARN(("invalid entry container"));
+ return false;
+ }
+
+ RTListNodeRemove(&pDisplay->mNode);
+ pDisplay->mpContainer = NULL;
+ if (fCleanupDisplay)
+ pDisplay->setFramebuffer(NULL);
+ --mcDisplays;
+ return true;
+}
+
+
+CrFbDisplayBase* CrFbDisplayComposite::first()
+{
+ return RTListGetFirstCpp(&mDisplays, CrFbDisplayBase, mNode);
+}
+
+
+CrFbDisplayBase* CrFbDisplayComposite::next(CrFbDisplayBase* pDisplay)
+{
+ if (pDisplay->getContainer() != this)
+ {
+ WARN(("invalid entry container"));
+ return NULL;
+ }
+
+ return RTListGetNextCpp(&mDisplays, pDisplay, CrFbDisplayBase, mNode);
+}
+
+
+int CrFbDisplayComposite::setFramebuffer(struct CR_FRAMEBUFFER *pFb)
+{
+ CrFbDisplayBase::setFramebuffer(pFb);
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ pIter->setFramebuffer(pFb);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::UpdateBegin(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::UpdateBegin(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ rc = pIter->UpdateBegin(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+void CrFbDisplayComposite::UpdateEnd(struct CR_FRAMEBUFFER *pFb)
+{
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ pIter->UpdateEnd(pFb);
+ }
+
+ CrFbDisplayBase::UpdateEnd(pFb);
+}
+
+
+int CrFbDisplayComposite::EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryAdded(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->EntryAdded(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryAdded(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->EntryCreated(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry)
+{
+ int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->EntryReplaced(pFb, hNewEntry, hReplacedEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->EntryTexChanged(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryRemoved(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->EntryRemoved(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryDestroyed(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->EntryDestroyed(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::RegionsChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::RegionsChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->RegionsChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayComposite::FramebufferChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::FramebufferChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ CrFbDisplayBase *pIter;
+ RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode)
+ {
+ int rc = pIter->FramebufferChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+CrFbDisplayComposite::~CrFbDisplayComposite()
+{
+ cleanup();
+}
+
+
+void CrFbDisplayComposite::cleanup(bool fCleanupDisplays)
+{
+ CrFbDisplayBase *pIter, *pIterNext;
+ RTListForEachSafeCpp(&mDisplays, pIter, pIterNext, CrFbDisplayBase, mNode)
+ {
+ remove(pIter, fCleanupDisplays);
+ }
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp
new file mode 100644
index 00000000..908117d4
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp
@@ -0,0 +1,381 @@
+/* $Id: display_vrdp.cpp $ */
+
+/** @file
+ * Presenter API: CrFbDisplayVrdp class implementation -- display content over VRDP.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server_presenter.h"
+
+
+CrFbDisplayVrdp::CrFbDisplayVrdp()
+{
+ memset(&mPos, 0, sizeof (mPos));
+}
+
+
+int CrFbDisplayVrdp::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("EntryAdded failed rc %d", rc));
+ return rc;
+ }
+
+ Assert(!CrFbDDataEntryGet(hEntry, slotGet()));
+ rc = vrdpCreate(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("vrdpCreate failed rc %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry)
+{
+ int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pReplacedEntry = CrFbEntryGetCompositorEntry(hReplacedEntry);
+ CR_TEXDATA *pReplacedTex = CrVrScrCompositorEntryTexGet(pReplacedEntry);
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pNewEntry = CrFbEntryGetCompositorEntry(hNewEntry);
+ CR_TEXDATA *pNewTex = CrVrScrCompositorEntryTexGet(pNewEntry);
+
+ CrTdBltDataInvalidateNe(pReplacedTex);
+
+ rc = CrTdBltEnter(pNewTex);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vrdpFrame(hNewEntry);
+ CrTdBltLeave(pNewTex);
+ }
+ else
+ WARN(("CrTdBltEnter failed %d", rc));
+
+ return rc;
+}
+
+
+int CrFbDisplayVrdp::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry);
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+
+ rc = CrTdBltEnter(pTex);
+ if (RT_SUCCESS(rc))
+ {
+ rc = vrdpFrame(hEntry);
+ CrTdBltLeave(pTex);
+ }
+ else
+ WARN(("CrTdBltEnter failed %d", rc));
+
+ return rc;
+}
+
+
+int CrFbDisplayVrdp::EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryRemoved(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry);
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+ CrTdBltDataInvalidateNe(pTex);
+
+ return vrdpRegions(pFb, hEntry);
+}
+
+
+int CrFbDisplayVrdp::EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryDestroyed(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ vrdpDestroy(hEntry);
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryPosChanged(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ vrdpGeometry(hEntry);
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::RegionsChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::RegionsChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return vrdpRegionsAll(pFb);
+}
+
+
+int CrFbDisplayVrdp::FramebufferChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::FramebufferChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ syncPos();
+
+ rc = vrdpSyncEntryAll(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return vrdpRegionsAll(pFb);
+}
+
+
+void CrFbDisplayVrdp::syncPos()
+{
+ const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(getFramebuffer());
+ mPos.x = pScreenInfo->i32OriginX;
+ mPos.y = pScreenInfo->i32OriginY;
+}
+
+int CrFbDisplayVrdp::fbCleanup()
+{
+ int rc = fbCleanupRemoveAllEntries();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return CrFbDisplayBase::fbCleanup();
+}
+
+
+int CrFbDisplayVrdp::fbSync()
+{
+ syncPos();
+
+ int rc = fbSynchAddAllEntries();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return CrFbDisplayBase::fbSync();
+}
+
+
+void CrFbDisplayVrdp::vrdpDestroy(HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet());
+ cr_server.outputRedirect.CROREnd(pVrdp);
+}
+
+
+void CrFbDisplayVrdp::vrdpGeometry(HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet());
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry);
+
+ cr_server.outputRedirect.CRORGeometry(
+ pVrdp,
+ mPos.x + CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
+ mPos.y + CrVrScrCompositorEntryRectGet(pEntry)->yTop,
+ CrVrScrCompositorEntryTexGet(pEntry)->Tex.width,
+ CrVrScrCompositorEntryTexGet(pEntry)->Tex.height);
+}
+
+
+int CrFbDisplayVrdp::vrdpRegions(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet());
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb);
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry);
+ uint32_t cRects;
+ const RTRECT *pRects;
+
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, &pRects, NULL, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc));
+ return rc;
+ }
+
+ cr_server.outputRedirect.CRORVisibleRegion(pVrdp, cRects, pRects);
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::vrdpFrame(HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet());
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry);
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+ const CR_BLITTER_IMG *pImg;
+ CrTdBltDataInvalidateNe(pTex);
+
+ int rc = CrTdBltDataAcquire(pTex, GL_BGRA, !!(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS), &pImg);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltDataAcquire failed rc %d", rc));
+ return rc;
+ }
+
+ cr_server.outputRedirect.CRORFrame(pVrdp, pImg->pvData, pImg->cbData);
+ CrTdBltDataRelease(pTex);
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::vrdpRegionsAll(struct CR_FRAMEBUFFER *pFb)
+{
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb);
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ CrVrScrCompositorConstIterInit(pCompositor, &Iter);
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
+ {
+ HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
+ vrdpRegions(pFb, hEntry);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::vrdpSynchEntry(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ vrdpGeometry(hEntry);
+
+ return vrdpRegions(pFb, hEntry);;
+}
+
+
+int CrFbDisplayVrdp::vrdpSyncEntryAll(struct CR_FRAMEBUFFER *pFb)
+{
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb);
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ CrVrScrCompositorConstIterInit(pCompositor, &Iter);
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
+ {
+ HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
+ int rc = vrdpSynchEntry(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("vrdpSynchEntry failed rc %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayVrdp::vrdpCreate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ void *pVrdp;
+
+ /* Query supported formats. */
+ uint32_t cbFormats = 4096;
+ char *pachFormats = (char *)crAlloc(cbFormats);
+
+ if (!pachFormats)
+ {
+ WARN(("crAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+
+ int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext,
+ 0 /* H3DOR_PROP_FORMATS */, /// @todo from a header
+ pachFormats, cbFormats, &cbFormats);
+ if (RT_SUCCESS(rc))
+ {
+ if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN"))
+ {
+ cr_server.outputRedirect.CRORBegin(
+ cr_server.outputRedirect.pvContext,
+ &pVrdp,
+ "H3DOR_FMT_RGBA_TOPDOWN"); /// @todo from a header
+
+ if (pVrdp)
+ {
+ rc = CrFbDDataEntryPut(hEntry, slotGet(), pVrdp);
+ if (RT_SUCCESS(rc))
+ {
+ vrdpGeometry(hEntry);
+ vrdpRegions(hFb, hEntry);
+ //vrdpFrame(hEntry);
+ return VINF_SUCCESS;
+ }
+ else
+ WARN(("CrFbDDataEntryPut failed rc %d", rc));
+
+ cr_server.outputRedirect.CROREnd(pVrdp);
+ }
+ else
+ {
+ WARN(("CRORBegin failed"));
+ rc = VERR_GENERAL_FAILURE;
+ }
+ }
+ }
+ else
+ WARN(("CRORContextProperty failed rc %d", rc));
+
+ crFree(pachFormats);
+
+ return rc;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp
new file mode 100644
index 00000000..c888987c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp
@@ -0,0 +1,574 @@
+/* $Id: display_window.cpp $ */
+
+/** @file
+ * Presenter API: CrFbDisplayWindow class implementation -- display content into host GUI window.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server_presenter.h"
+
+CrFbDisplayWindow::CrFbDisplayWindow(const RTRECT *pViewportRect, uint64_t parentId) :
+ mpWindow(NULL),
+ mViewportRect(*pViewportRect),
+ mu32Screen(~0),
+ mParentId(parentId)
+{
+ mFlags.u32Value = 0;
+}
+
+
+CrFbDisplayWindow::~CrFbDisplayWindow()
+{
+ if (mpWindow)
+ delete mpWindow;
+}
+
+
+int CrFbDisplayWindow::UpdateBegin(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = mpWindow ? mpWindow->UpdateBegin() : VINF_SUCCESS;
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrFbDisplayBase::UpdateBegin(pFb);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ else
+ {
+ WARN(("err"));
+ if (mpWindow)
+ mpWindow->UpdateEnd();
+ }
+ }
+ else
+ WARN(("err"));
+
+ return rc;
+}
+
+
+void CrFbDisplayWindow::UpdateEnd(struct CR_FRAMEBUFFER *pFb)
+{
+ CrFbDisplayBase::UpdateEnd(pFb);
+
+ if (mpWindow)
+ mpWindow->UpdateEnd();
+}
+
+
+int CrFbDisplayWindow::RegionsChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::RegionsChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ if (mpWindow && mpWindow->GetParentId())
+ {
+ rc = mpWindow->Create();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindow::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ if (mpWindow && mpWindow->GetParentId())
+ {
+ rc = mpWindow->Create();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindow::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry)
+{
+ int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ if (mpWindow && mpWindow->GetParentId())
+ {
+ rc = mpWindow->Create();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindow::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ if (mpWindow && mpWindow->GetParentId())
+ {
+ rc = mpWindow->Create();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindow::FramebufferChanged(struct CR_FRAMEBUFFER *pFb)
+{
+ int rc = CrFbDisplayBase::FramebufferChanged(pFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return screenChanged();
+}
+
+
+const RTRECT* CrFbDisplayWindow::getViewportRect()
+{
+ return &mViewportRect;
+}
+
+
+int CrFbDisplayWindow::setViewportRect(const RTRECT *pViewportRect)
+{
+ if (!isUpdating())
+ {
+ WARN(("not updating!"));
+ return VERR_INVALID_STATE;
+ }
+
+ // always call SetPosition to ensure window is adjustep properly
+ // if (pViewportRect->xLeft != mViewportRect.xLeft || pViewportRect->yTop != mViewportRect.yTop)
+ if (mpWindow)
+ {
+ const RTRECT* pRect = getRect();
+ int rc = mpWindow->SetPosition(pRect->xLeft - pViewportRect->xLeft, pRect->yTop - pViewportRect->yTop);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("SetPosition failed"));
+ return rc;
+ }
+ }
+
+ mViewportRect = *pViewportRect;
+
+ return VINF_SUCCESS;
+}
+
+
+CrFbWindow * CrFbDisplayWindow::windowDetach(bool fCleanup)
+{
+ if (isUpdating())
+ {
+ WARN(("updating!"));
+ return NULL;
+ }
+
+ CrFbWindow * pWindow = mpWindow;
+ if (mpWindow)
+ {
+ if (fCleanup)
+ windowCleanup();
+ mpWindow = NULL;
+ }
+ return pWindow;
+}
+
+
+CrFbWindow * CrFbDisplayWindow::windowAttach(CrFbWindow * pNewWindow)
+{
+ if (isUpdating())
+ {
+ WARN(("updating!"));
+ return NULL;
+ }
+
+ CrFbWindow * pOld = mpWindow;
+ if (mpWindow)
+ windowDetach();
+
+ mpWindow = pNewWindow;
+ if (pNewWindow)
+ windowSync();
+
+ return mpWindow;
+}
+
+
+int CrFbDisplayWindow::reparent(uint64_t parentId)
+{
+ if (!isUpdating())
+ {
+ WARN(("not updating!"));
+ return VERR_INVALID_STATE;
+ }
+
+ crDebug("CrFbDisplayWindow: change parent from %p to %p.", mParentId, parentId);
+
+ mParentId = parentId;
+ int rc = VINF_SUCCESS;
+
+ /* Force notify Render SPU about parent window ID change in order to prevent
+ * crashes when it tries to access already deallocated parent window.
+ * Previously, we also used isActive() here, however it might become FALSE for the case
+ * when VM Window goes fullscreen mode and back. */
+ if ( /* isActive() && */ mpWindow)
+ {
+ rc = mpWindow->Reparent(parentId);
+ if (!RT_SUCCESS(rc))
+ WARN(("window reparent failed"));
+
+ mFlags.fNeForce = 1;
+ }
+
+ return rc;
+}
+
+
+bool CrFbDisplayWindow::isVisible()
+{
+ HCR_FRAMEBUFFER hFb = getFramebuffer();
+ if (!hFb)
+ return false;
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb);
+ return !CrVrScrCompositorIsEmpty(pCompositor);
+}
+
+
+int CrFbDisplayWindow::winVisibilityChanged()
+{
+ HCR_FRAMEBUFFER hFb = getFramebuffer();
+ if (!hFb || !CrFbIsEnabled(hFb))
+ {
+ Assert(!mpWindow || !mpWindow->IsVisivle());
+ return VINF_SUCCESS;
+ }
+
+ int rc = VINF_SUCCESS;
+
+ if (mpWindow)
+ {
+ rc = mpWindow->UpdateBegin();
+ if (RT_SUCCESS(rc))
+ {
+ rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden);
+ if (!RT_SUCCESS(rc))
+ WARN(("SetVisible failed, rc %d", rc));
+
+ mpWindow->UpdateEnd();
+ }
+ else
+ WARN(("UpdateBegin failed, rc %d", rc));
+ }
+
+ return rc;
+}
+
+
+CrFbWindow* CrFbDisplayWindow::getWindow()
+{
+ return mpWindow;
+}
+
+
+void CrFbDisplayWindow::onUpdateEnd()
+{
+ CrFbDisplayBase::onUpdateEnd();
+ bool fVisible = isVisible();
+ if (mFlags.fNeVisible != fVisible || mFlags.fNeForce)
+ {
+ crVBoxServerNotifyEvent(mu32Screen,
+ fVisible? VBOX3D_NOTIFY_EVENT_TYPE_3DDATA_VISIBLE:
+ VBOX3D_NOTIFY_EVENT_TYPE_3DDATA_HIDDEN,
+ NULL, 0);
+ mFlags.fNeVisible = fVisible;
+ mFlags.fNeForce = 0;
+ }
+}
+
+
+void CrFbDisplayWindow::ueRegions()
+{
+ if (mpWindow)
+ mpWindow->SetVisibleRegionsChanged();
+}
+
+
+int CrFbDisplayWindow::screenChanged()
+{
+ if (!isUpdating())
+ {
+ WARN(("not updating!"));
+ return VERR_INVALID_STATE;
+ }
+
+ int rc = windowDimensionsSync();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("windowDimensionsSync failed rc %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindow::windowSetCompositor(bool fSet)
+{
+ if (!mpWindow)
+ return VINF_SUCCESS;
+
+ if (fSet)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer());
+ return mpWindow->SetCompositor(pCompositor);
+ }
+ return mpWindow->SetCompositor(NULL);
+}
+
+
+int CrFbDisplayWindow::windowCleanup()
+{
+ if (!mpWindow)
+ return VINF_SUCCESS;
+
+ int rc = mpWindow->UpdateBegin();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ rc = windowDimensionsSync(true);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ mpWindow->UpdateEnd();
+ return rc;
+ }
+
+ rc = windowSetCompositor(false);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ mpWindow->UpdateEnd();
+ return rc;
+ }
+
+ mpWindow->UpdateEnd();
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindow::fbCleanup()
+{
+ int rc = windowCleanup();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("windowCleanup failed"));
+ return rc;
+ }
+ return CrFbDisplayBase::fbCleanup();
+}
+
+
+bool CrFbDisplayWindow::isActive()
+{
+ HCR_FRAMEBUFFER hFb = getFramebuffer();
+ return hFb && CrFbIsEnabled(hFb);
+}
+
+
+int CrFbDisplayWindow::windowDimensionsSync(bool fForceCleanup)
+{
+ int rc = VINF_SUCCESS;
+
+ if (!mpWindow)
+ return VINF_SUCCESS;
+
+ //HCR_FRAMEBUFFER hFb = getFramebuffer();
+ if (!fForceCleanup && isActive())
+ {
+ const RTRECT* pRect = getRect();
+
+ if (mpWindow->GetParentId() != mParentId)
+ {
+ rc = mpWindow->Reparent(mParentId);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+
+ rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ setRegionsChanged();
+
+ rc = mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop));
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ else
+ {
+ rc = mpWindow->SetVisible(false);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+#if 0
+ rc = mpWindow->Reparent(mDefaultParentId);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+#endif
+ }
+
+ return rc;
+}
+
+
+int CrFbDisplayWindow::windowSync()
+{
+ if (!mpWindow)
+ return VINF_SUCCESS;
+
+ int rc = mpWindow->UpdateBegin();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ rc = windowSetCompositor(true);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ mpWindow->UpdateEnd();
+ return rc;
+ }
+
+ rc = windowDimensionsSync();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ mpWindow->UpdateEnd();
+ return rc;
+ }
+
+ mpWindow->UpdateEnd();
+
+ return rc;
+}
+
+
+int CrFbDisplayWindow::fbSync()
+{
+ int rc = CrFbDisplayBase::fbSync();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ HCR_FRAMEBUFFER hFb = getFramebuffer();
+
+ mu32Screen = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+
+ rc = windowSync();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("windowSync failed %d", rc));
+ return rc;
+ }
+
+ if (CrFbHas3DData(hFb))
+ {
+ if (mpWindow && mpWindow->GetParentId())
+ {
+ rc = mpWindow->Create();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+const struct RTRECT* CrFbDisplayWindow::getRect()
+{
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer());
+ return CrVrScrCompositorRectGet(pCompositor);
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp
new file mode 100644
index 00000000..ddc76848
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp
@@ -0,0 +1,347 @@
+/* $Id: display_window_rootvr.cpp $ */
+
+/** @file
+ * Presenter API: CrFbDisplayWindowRootVr class implementation -- display seamless content (visible regions).
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server_presenter.h"
+
+
+CrFbDisplayWindowRootVr::CrFbDisplayWindowRootVr(const RTRECT *pViewportRect, uint64_t parentId) :
+ CrFbDisplayWindow(pViewportRect, parentId)
+{
+ CrVrScrCompositorInit(&mCompositor, NULL);
+}
+
+
+int CrFbDisplayWindowRootVr::EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayWindow::EntryCreated(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ Assert(!CrFbDDataEntryGet(hEntry, slotGet()));
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry);
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = entryAlloc();
+ CrVrScrCompositorEntryInit(pMyEntry, CrVrScrCompositorEntryRectGet(pSrcEntry), CrVrScrCompositorEntryTexGet(pSrcEntry), NULL);
+ CrVrScrCompositorEntryFlagsSet(pMyEntry, CrVrScrCompositorEntryFlagsGet(pSrcEntry));
+ rc = CrFbDDataEntryPut(hEntry, slotGet(), pMyEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbDDataEntryPut failed rc %d", rc));
+ entryFree(pMyEntry);
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayWindow::EntryAdded(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry);
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet());
+ Assert(pMyEntry);
+ CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcEntry));
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry)
+{
+ int rc = CrFbDisplayWindow::EntryReplaced(pFb, hNewEntry, hReplacedEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcNewEntry = CrFbEntryGetCompositorEntry(hNewEntry);
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hNewEntry, slotGet());
+ CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcNewEntry));
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayWindow::EntryTexChanged(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry);
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet());
+ CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcEntry));
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayWindow::EntryRemoved(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet());
+ rc = CrVrScrCompositorEntryRegionsSet(&mCompositor, pMyEntry, NULL, 0, NULL, false, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ int rc = CrFbDisplayWindow::EntryDestroyed(pFb, hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry);
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet());
+ CrVrScrCompositorEntryCleanup(pMyEntry);
+ entryFree(pMyEntry);
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::setViewportRect(const RTRECT *pViewportRect)
+{
+ int rc = CrFbDisplayWindow::setViewportRect(pViewportRect);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ rc = setRegionsChanged();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::windowSetCompositor(bool fSet)
+{
+ if (fSet)
+ return getWindow()->SetCompositor(&mCompositor);
+ return getWindow()->SetCompositor(NULL);
+}
+
+
+void CrFbDisplayWindowRootVr::ueRegions()
+{
+ synchCompositorRegions();
+}
+
+
+int CrFbDisplayWindowRootVr::compositorMarkUpdated()
+{
+ CrVrScrCompositorClear(&mCompositor);
+
+ int rc = CrVrScrCompositorRectSet(&mCompositor, CrVrScrCompositorRectGet(CrFbGetCompositor(getFramebuffer())), NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ rc = setRegionsChanged();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("screenChanged failed %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbDisplayWindowRootVr::screenChanged()
+{
+ int rc = compositorMarkUpdated();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ rc = CrFbDisplayWindow::screenChanged();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("screenChanged failed %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+const struct RTRECT* CrFbDisplayWindowRootVr::getRect()
+{
+ return CrVrScrCompositorRectGet(&mCompositor);
+}
+
+int CrFbDisplayWindowRootVr::fbCleanup()
+{
+ int rc = clearCompositor();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return CrFbDisplayWindow::fbCleanup();
+}
+
+
+int CrFbDisplayWindowRootVr::fbSync()
+{
+ int rc = synchCompositor();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return CrFbDisplayWindow::fbSync();
+}
+
+
+VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbDisplayWindowRootVr::entryAlloc()
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ return (VBOXVR_SCR_COMPOSITOR_ENTRY*)RTMemCacheAlloc(g_CrPresenter.CEntryLookasideList);
+#else
+ return (VBOXVR_SCR_COMPOSITOR_ENTRY*)RTMemAlloc(sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY));
+#endif
+}
+
+
+void CrFbDisplayWindowRootVr::entryFree(VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry)
+{
+ Assert(!CrVrScrCompositorEntryIsUsed(pEntry));
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ RTMemCacheFree(g_CrPresenter.CEntryLookasideList, pEntry);
+#else
+ RTMemFree(pEntry);
+#endif
+}
+
+
+int CrFbDisplayWindowRootVr::synchCompositorRegions()
+{
+ int rc;
+
+ rootVrTranslateForPos();
+
+ /* ensure the rootvr compositor does not hold any data,
+ * i.e. cleanup all rootvr entries data */
+ CrVrScrCompositorClear(&mCompositor);
+
+ rc = CrVrScrCompositorIntersectedList(CrFbGetCompositor(getFramebuffer()), &cr_server.RootVr, &mCompositor, rootVrGetCEntry, this, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorIntersectedList failed, rc %d", rc));
+ return rc;
+ }
+
+ return getWindow()->SetVisibleRegionsChanged();
+}
+
+
+int CrFbDisplayWindowRootVr::synchCompositor()
+{
+ int rc = compositorMarkUpdated();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("compositorMarkUpdated failed, rc %d", rc));
+ return rc;
+ }
+
+ rc = fbSynchAddAllEntries();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("fbSynchAddAllEntries failed, rc %d", rc));
+ return rc;
+ }
+
+ return rc;
+}
+
+
+int CrFbDisplayWindowRootVr::clearCompositor()
+{
+ return fbCleanupRemoveAllEntries();
+}
+
+
+void CrFbDisplayWindowRootVr::rootVrTranslateForPos()
+{
+ const RTRECT *pRect = getViewportRect();
+ const struct VBVAINFOSCREEN* pScreen = CrFbGetScreenInfo(getFramebuffer());
+ int32_t x = pScreen->i32OriginX;
+ int32_t y = pScreen->i32OriginY;
+ int32_t dx = cr_server.RootVrCurPoint.x - x;
+ int32_t dy = cr_server.RootVrCurPoint.y - y;
+
+ cr_server.RootVrCurPoint.x = x;
+ cr_server.RootVrCurPoint.y = y;
+
+ VBoxVrListTranslate(&cr_server.RootVr, dx, dy);
+}
+
+
+DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) CrFbDisplayWindowRootVr::rootVrGetCEntry(const VBOXVR_SCR_COMPOSITOR_ENTRY*pEntry, void *pvContext)
+{
+ CrFbDisplayWindowRootVr *pThis = (CrFbDisplayWindowRootVr*)pvContext;
+ HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, pThis->slotGet());
+ Assert(!CrVrScrCompositorEntryIsUsed(pMyEntry));
+ CrVrScrCompositorEntryRectSet(&pThis->mCompositor, pMyEntry, CrVrScrCompositorEntryRectGet(pEntry));
+ return pMyEntry;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp
new file mode 100644
index 00000000..7ced10de
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp
@@ -0,0 +1,4063 @@
+/* $Id: server_presenter.cpp $ */
+
+/** @file
+ * Presenter API
+ */
+
+/*
+ * Copyright (C) 2012-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifdef DEBUG_misha
+# define VBOXVDBG_MEMCACHE_DISABLE
+#endif
+
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+# include <iprt/memcache.h>
+#endif
+
+#include "server_presenter.h"
+
+//#define CR_SERVER_WITH_CLIENT_CALLOUTS
+
+#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_UOFFSETOF(CR_FBTEX, Tex)))
+#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_UOFFSETOF(CR_FRAMEBUFFER, Compositor)))
+#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_UOFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry)))
+
+
+static int crPMgrFbConnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeAdd);
+
+CR_PRESENTER_GLOBALS g_CrPresenter;
+
+/* FRAMEBUFFER */
+
+void CrFbInit(CR_FRAMEBUFFER *pFb, uint32_t idFb)
+{
+ RTRECT Rect;
+ Rect.xLeft = 0;
+ Rect.yTop = 0;
+ Rect.xRight = 1;
+ Rect.yBottom = 1;
+ memset(pFb, 0, sizeof (*pFb));
+ pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED;
+ pFb->ScreenInfo.u32ViewIndex = idFb;
+ CrVrScrCompositorInit(&pFb->Compositor, &Rect);
+ RTListInit(&pFb->EntriesList);
+ CrHTableCreate(&pFb->SlotTable, 0);
+}
+
+
+bool CrFbIsEnabled(CR_FRAMEBUFFER *pFb)
+{
+ return !(pFb->ScreenInfo.u16Flags & VBVA_SCREEN_F_DISABLED);
+}
+
+
+const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(CR_FRAMEBUFFER *pFb)
+{
+ return &pFb->Compositor;
+}
+
+DECLINLINE(CR_FRAMEBUFFER*) CrFbFromCompositor(const struct VBOXVR_SCR_COMPOSITOR* pCompositor)
+{
+ return RT_FROM_MEMBER(pCompositor, CR_FRAMEBUFFER, Compositor);
+}
+
+const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb)
+{
+ return &hFb->ScreenInfo;
+}
+
+void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb)
+{
+ return hFb->pvVram;
+}
+
+int CrFbUpdateBegin(CR_FRAMEBUFFER *pFb)
+{
+ ++pFb->cUpdating;
+
+ if (pFb->cUpdating == 1)
+ {
+ if (pFb->pDisplay)
+ pFb->pDisplay->UpdateBegin(pFb);
+ }
+
+ return VINF_SUCCESS;
+}
+
+void CrFbUpdateEnd(CR_FRAMEBUFFER *pFb)
+{
+ if (!pFb->cUpdating)
+ {
+ WARN(("invalid UpdateEnd call!"));
+ return;
+ }
+
+ --pFb->cUpdating;
+
+ if (!pFb->cUpdating)
+ {
+ if (pFb->pDisplay)
+ pFb->pDisplay->UpdateEnd(pFb);
+ }
+}
+
+bool CrFbIsUpdating(const CR_FRAMEBUFFER *pFb)
+{
+ return !!pFb->cUpdating;
+}
+
+bool CrFbHas3DData(HCR_FRAMEBUFFER hFb)
+{
+ return !CrVrScrCompositorIsEmpty(&hFb->Compositor);
+}
+
+static void crFbImgFromScreenVram(const VBVAINFOSCREEN *pScreen, void *pvVram, CR_BLITTER_IMG *pImg)
+{
+ pImg->pvData = pvVram;
+ pImg->cbData = pScreen->u32LineSize * pScreen->u32Height;
+ pImg->enmFormat = GL_BGRA;
+ pImg->width = pScreen->u32Width;
+ pImg->height = pScreen->u32Height;
+ pImg->bpp = pScreen->u16BitsPerPixel;
+ pImg->pitch = pScreen->u32LineSize;
+}
+
+static void crFbImgFromDimPtrBGRA(void *pvVram, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg)
+{
+ pImg->pvData = pvVram;
+ pImg->cbData = width * height * 4;
+ pImg->enmFormat = GL_BGRA;
+ pImg->width = width;
+ pImg->height = height;
+ pImg->bpp = 32;
+ pImg->pitch = width * 4;
+}
+
+static int8_t crFbImgFromDimOffVramBGRA(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, CR_BLITTER_IMG *pImg)
+{
+ uint32_t cbBuff = width * height * 4;
+ if (offVRAM >= g_cbVRam
+ || offVRAM + cbBuff >= g_cbVRam)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ uint8_t *pu8Buf = g_pvVRamBase + offVRAM;
+ crFbImgFromDimPtrBGRA(pu8Buf, width, height, pImg);
+
+ return 0;
+}
+
+static int8_t crFbImgFromDescBGRA(const VBOXCMDVBVA_ALLOCDESC *pDesc, CR_BLITTER_IMG *pImg)
+{
+ return crFbImgFromDimOffVramBGRA(pDesc->Info.u.offVRAM, pDesc->u16Width, pDesc->u16Height, pImg);
+}
+
+static void crFbImgFromFb(HCR_FRAMEBUFFER hFb, CR_BLITTER_IMG *pImg)
+{
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+ void *pvVram = CrFbGetVRAM(hFb);
+ crFbImgFromScreenVram(pScreen, pvVram, pImg);
+}
+
+static int crFbTexDataGetContents(CR_TEXDATA *pTex, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
+{
+ const CR_BLITTER_IMG *pSrcImg;
+ int rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltDataAcquire failed rc %d", rc));
+ return rc;
+ }
+
+ CrMBltImg(pSrcImg, pPos, cRects, pRects, pDst);
+
+ CrTdBltDataRelease(pTex);
+
+ return VINF_SUCCESS;
+}
+
+static int crFbBltGetContentsScaledDirect(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
+{
+ VBOXVR_LIST List;
+ uint32_t c2DRects = 0;
+ CR_TEXDATA *pEnteredTex = NULL;
+ PCR_BLITTER pEnteredBlitter = NULL;
+
+ /* Scaled texture size and rect calculated for every new "entered" texture. */
+ uint32_t width = 0, height = 0;
+ RTRECT ScaledSrcRect = {0};
+
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ int32_t srcWidth = pSrcRectSize->cx;
+ int32_t srcHeight = pSrcRectSize->cy;
+ int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
+ int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
+
+ RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
+ float strX = ((float)dstWidth) / srcWidth;
+ float strY = ((float)dstHeight) / srcHeight;
+ bool fScale = (dstWidth != srcWidth || dstHeight != srcHeight);
+ Assert(fScale);
+
+ /* 'List' contains the destination rectangles to be updated (in pDst coords). */
+ VBoxVrListInit(&List);
+ int rc = VBoxVrListRectsAdd(&List, cRects, pRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsAdd failed rc %d", rc));
+ goto end;
+ }
+
+ CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter);
+
+ for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter);
+ pEntry;
+ pEntry = CrVrScrCompositorConstIterNext(&Iter))
+ {
+ /* Where the entry would be located in pDst coords, i.e. convert pEntry hFb coord to pDst coord. */
+ RTPOINT ScaledEntryPoint;
+ ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft) + pDstRect->xLeft;
+ ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop) + pDstRect->yTop;
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+
+ /* Optimization to avoid entering/leaving the same texture and its blitter. */
+ if (pEnteredTex != pTex)
+ {
+ if (!pEnteredBlitter)
+ {
+ pEnteredBlitter = CrTdBlitterGet(pTex);
+ rc = CrBltEnter(pEnteredBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrBltEnter failed %d", rc));
+ pEnteredBlitter = NULL;
+ goto end;
+ }
+ }
+
+ if (pEnteredTex)
+ {
+ CrTdBltLeave(pEnteredTex);
+
+ pEnteredTex = NULL;
+
+ if (pEnteredBlitter != CrTdBlitterGet(pTex))
+ {
+ WARN(("blitters not equal!"));
+ CrBltLeave(pEnteredBlitter);
+
+ pEnteredBlitter = CrTdBlitterGet(pTex);
+ rc = CrBltEnter(pEnteredBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrBltEnter failed %d", rc));
+ pEnteredBlitter = NULL;
+ goto end;
+ }
+ }
+ }
+
+ rc = CrTdBltEnter(pTex);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltEnter failed %d", rc));
+ goto end;
+ }
+
+ pEnteredTex = pTex;
+
+ const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex);
+
+ width = CR_FLOAT_RCAST(uint32_t, strX * pVrTex->width);
+ height = CR_FLOAT_RCAST(uint32_t, strY * pVrTex->height);
+ ScaledSrcRect.xLeft = ScaledEntryPoint.x;
+ ScaledSrcRect.yTop = ScaledEntryPoint.y;
+ ScaledSrcRect.xRight = width + ScaledEntryPoint.x;
+ ScaledSrcRect.yBottom = height + ScaledEntryPoint.y;
+ }
+
+ bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
+
+ /* pRegions is where the pEntry was drawn in hFb coords. */
+ uint32_t cRegions;
+ const RTRECT *pRegions;
+ rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
+ goto end;
+ }
+
+ /* CrTdBltDataAcquireScaled/CrTdBltDataReleaseScaled can use cached data,
+ * so it is not necessary to optimize and Aquire only when Tex changes.
+ */
+ const CR_BLITTER_IMG *pSrcImg;
+ rc = CrTdBltDataAcquireScaled(pTex, GL_BGRA, false, width, height, &pSrcImg);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltDataAcquire failed rc %d", rc));
+ goto end;
+ }
+
+ for (uint32_t j = 0; j < cRegions; ++j)
+ {
+ /* rects are in dst coordinates,
+ * while the pReg is in source coords
+ * convert */
+ const RTRECT * pReg = &pRegions[j];
+ RTRECT ScaledReg;
+ /* scale */
+ VBoxRectScaled(pReg, strX, strY, &ScaledReg);
+ /* translate */
+ VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop);
+
+ /* Exclude the pEntry rectangle, because it will be updated now in pDst.
+ * List uses dst coords and pRegions use hFb coords, therefore use
+ * ScaledReg which is already translated to dst.
+ */
+ rc = VBoxVrListRectsSubst(&List, 1, &ScaledReg, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsSubst failed rc %d", rc));
+ goto end;
+ }
+
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ const RTRECT * pRect = &pRects[i];
+
+ RTRECT Intersection;
+ VBoxRectIntersected(pRect, &ScaledReg, &Intersection);
+ if (VBoxRectIsZero(&Intersection))
+ continue;
+
+ VBoxRectIntersect(&Intersection, &ScaledSrcRect);
+ if (VBoxRectIsZero(&Intersection))
+ continue;
+
+ CrMBltImgRect(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, pDst);
+ }
+ }
+
+ CrTdBltDataReleaseScaled(pTex, pSrcImg);
+ }
+
+ /* Blit still not updated dst rects, i.e. not covered by 3D entries. */
+ c2DRects = VBoxVrListRectsCount(&List);
+ if (c2DRects)
+ {
+ if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT))
+ {
+ if (g_CrPresenter.pvTmpBuf2)
+ RTMemFree(g_CrPresenter.pvTmpBuf2);
+
+ g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT);
+ g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2);
+ if (!g_CrPresenter.pvTmpBuf2)
+ {
+ WARN(("RTMemAlloc failed!"));
+ g_CrPresenter.cbTmpBuf2 = 0;
+ rc = VERR_NO_MEMORY;
+ goto end;
+ }
+ }
+
+ RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2;
+
+ rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsGet failed, rc %d", rc));
+ goto end;
+ }
+
+ /* p2DRects are in pDst coords and already scaled. */
+
+ CR_BLITTER_IMG FbImg;
+
+ crFbImgFromFb(hFb, &FbImg);
+
+ CrMBltImgScaled(&FbImg, pSrcRectSize, pDstRect, c2DRects, p2DRects, pDst);
+ }
+
+end:
+
+ if (pEnteredTex)
+ CrTdBltLeave(pEnteredTex);
+
+ if (pEnteredBlitter)
+ CrBltLeave(pEnteredBlitter);
+
+ VBoxVrListClear(&List);
+
+ return rc;
+}
+
+static int crFbBltGetContentsScaledCPU(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+ WARN(("not implemented!"));
+ return VERR_NOT_IMPLEMENTED;
+#if 0
+ int32_t srcWidth = pSrcRectSize->cx;
+ int32_t srcHeight = pSrcRectSize->cy;
+ int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
+ int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
+
+ RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop};
+ float strX = ((float)dstWidth) / srcWidth;
+ float strY = ((float)dstHeight) / srcHeight;
+
+ RTPOINT UnscaledPos;
+ UnscaledPos.x = CR_FLOAT_RCAST(int32_t, pDstRect->xLeft / strX);
+ UnscaledPos.y = CR_FLOAT_RCAST(int32_t, pDstRect->yTop / strY);
+
+ /* destination is bigger than the source, do 3D data stretching with CPU */
+ CR_BLITTER_IMG Img;
+ Img.cbData = srcWidth * srcHeight * 4;
+ Img.pvData = RTMemAlloc(Img.cbData);
+ if (!Img.pvData)
+ {
+ WARN(("RTMemAlloc Failed"));
+ return VERR_NO_MEMORY;
+ }
+ Img.enmFormat = pImg->enmFormat;
+ Img.width = srcWidth;
+ Img.height = srcHeight;
+ Img.bpp = pImg->bpp;
+ Img.pitch = Img.width * 4;
+
+ int rc = CrFbBltGetContents(hFb, &UnscaledPos, cRects, pRects, &Img);
+ if (RT_SUCCESS(rc))
+ {
+ CrBmpScale32((uint8_t *)pImg->pvData,
+ pImg->pitch,
+ pImg->width, pImg->height,
+ (const uint8_t *)Img.pvData,
+ Img.pitch,
+ Img.width, Img.height);
+ }
+ else
+ WARN(("CrFbBltGetContents failed %d", rc));
+
+ RTMemFree(Img.pvData);
+
+ return rc;
+#endif
+}
+
+static int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pDst)
+{
+ VBOXVR_LIST List;
+ uint32_t c2DRects = 0;
+ CR_TEXDATA *pEnteredTex = NULL;
+ PCR_BLITTER pEnteredBlitter = NULL;
+
+ /* 'List' contains the destination rectangles to be updated (in pDst coords). */
+ VBoxVrListInit(&List);
+ int rc = VBoxVrListRectsAdd(&List, cRects, pRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsAdd failed rc %d", rc));
+ goto end;
+ }
+
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter);
+
+ for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter);
+ pEntry;
+ pEntry = CrVrScrCompositorConstIterNext(&Iter))
+ {
+ /* Where the entry would be located in pDst coords (pPos = pDst_coord - hFb_coord). */
+ RTPOINT EntryPoint;
+ EntryPoint.x = CrVrScrCompositorEntryRectGet(pEntry)->xLeft + pPos->x;
+ EntryPoint.y = CrVrScrCompositorEntryRectGet(pEntry)->yTop + pPos->y;
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry);
+
+ /* Optimization to avoid entering/leaving the same texture and its blitter. */
+ if (pEnteredTex != pTex)
+ {
+ if (!pEnteredBlitter)
+ {
+ pEnteredBlitter = CrTdBlitterGet(pTex);
+ rc = CrBltEnter(pEnteredBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrBltEnter failed %d", rc));
+ pEnteredBlitter = NULL;
+ goto end;
+ }
+ }
+
+ if (pEnteredTex)
+ {
+ CrTdBltLeave(pEnteredTex);
+
+ pEnteredTex = NULL;
+
+ if (pEnteredBlitter != CrTdBlitterGet(pTex))
+ {
+ WARN(("blitters not equal!"));
+ CrBltLeave(pEnteredBlitter);
+
+ pEnteredBlitter = CrTdBlitterGet(pTex);
+ rc = CrBltEnter(pEnteredBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrBltEnter failed %d", rc));
+ pEnteredBlitter = NULL;
+ goto end;
+ }
+ }
+ }
+
+ rc = CrTdBltEnter(pTex);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltEnter failed %d", rc));
+ goto end;
+ }
+
+ pEnteredTex = pTex;
+ }
+
+ bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS);
+
+ /* pRegions is where the pEntry was drawn in hFb coords. */
+ uint32_t cRegions;
+ const RTRECT *pRegions;
+ rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
+ goto end;
+ }
+
+ /* CrTdBltDataAcquire/CrTdBltDataRelease can use cached data,
+ * so it is not necessary to optimize and Aquire only when Tex changes.
+ */
+ const CR_BLITTER_IMG *pSrcImg;
+ rc = CrTdBltDataAcquire(pTex, GL_BGRA, false, &pSrcImg);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltDataAcquire failed rc %d", rc));
+ goto end;
+ }
+
+ for (uint32_t j = 0; j < cRegions; ++j)
+ {
+ /* rects are in dst coordinates,
+ * while the pReg is in source coords
+ * convert */
+ const RTRECT * pReg = &pRegions[j];
+ RTRECT SrcReg;
+ /* translate */
+ VBoxRectTranslated(pReg, pPos->x, pPos->y, &SrcReg);
+
+ /* Exclude the pEntry rectangle, because it will be updated now in pDst.
+ * List uses dst coords and pRegions use hFb coords, therefore use
+ * SrcReg which is already translated to dst.
+ */
+ rc = VBoxVrListRectsSubst(&List, 1, &SrcReg, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsSubst failed rc %d", rc));
+ goto end;
+ }
+
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ const RTRECT * pRect = &pRects[i];
+
+ RTRECT Intersection;
+ VBoxRectIntersected(pRect, &SrcReg, &Intersection);
+ if (VBoxRectIsZero(&Intersection))
+ continue;
+
+ CrMBltImgRect(pSrcImg, &EntryPoint, fInvert, &Intersection, pDst);
+ }
+ }
+
+ CrTdBltDataRelease(pTex);
+ }
+
+ /* Blit still not updated dst rects, i.e. not covered by 3D entries. */
+ c2DRects = VBoxVrListRectsCount(&List);
+ if (c2DRects)
+ {
+ if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT))
+ {
+ if (g_CrPresenter.pvTmpBuf2)
+ RTMemFree(g_CrPresenter.pvTmpBuf2);
+
+ g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT);
+ g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2);
+ if (!g_CrPresenter.pvTmpBuf2)
+ {
+ WARN(("RTMemAlloc failed!"));
+ g_CrPresenter.cbTmpBuf2 = 0;
+ rc = VERR_NO_MEMORY;
+ goto end;
+ }
+ }
+
+ RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2;
+
+ rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("VBoxVrListRectsGet failed, rc %d", rc));
+ goto end;
+ }
+
+ CR_BLITTER_IMG FbImg;
+
+ crFbImgFromFb(hFb, &FbImg);
+
+ CrMBltImg(&FbImg, pPos, c2DRects, p2DRects, pDst);
+ }
+
+end:
+
+ if (pEnteredTex)
+ CrTdBltLeave(pEnteredTex);
+
+ if (pEnteredBlitter)
+ CrBltLeave(pEnteredBlitter);
+
+ VBoxVrListClear(&List);
+
+ return rc;
+}
+
+int CrFbBltGetContentsEx(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+ uint32_t srcWidth = pSrcRectSize->cx;
+ uint32_t srcHeight = pSrcRectSize->cy;
+ uint32_t dstWidth = pDstRect->xRight - pDstRect->xLeft;
+ uint32_t dstHeight = pDstRect->yBottom - pDstRect->yTop;
+ if (srcWidth == dstWidth
+ && srcHeight == dstHeight)
+ {
+ RTPOINT Pos = {pDstRect->xLeft, pDstRect->yTop};
+ return CrFbBltGetContents(hFb, &Pos, cRects, pRects, pImg);
+ }
+ if (!CrFbHas3DData(hFb)
+ || (srcWidth * srcHeight > dstWidth * dstHeight))
+ return crFbBltGetContentsScaledDirect(hFb, pSrcRectSize, pDstRect, cRects, pRects, pImg);
+
+ return crFbBltGetContentsScaledCPU(hFb, pSrcRectSize, pDstRect, cRects, pRects, pImg);
+}
+
+static void crFbBltPutContentsFbVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pSrc)
+{
+ const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor);
+
+ CR_BLITTER_IMG FbImg;
+
+ crFbImgFromFb(hFb, &FbImg);
+
+ CrMBltImg(pSrc, pPos, cRects, pRects, &FbImg);
+}
+
+static void crFbClrFillFbVram(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
+{
+ CR_BLITTER_IMG FbImg;
+
+ crFbImgFromFb(hFb, &FbImg);
+
+ CrMClrFillImg(&FbImg, cRects, pRects, u32Color);
+}
+
+int CrFbClrFill(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
+{
+ if (!hFb->cUpdating)
+ {
+ WARN(("framebuffer not updating"));
+ return VERR_INVALID_STATE;
+ }
+
+ crFbClrFillFbVram(hFb, cRects, pRects, u32Color);
+
+ RTPOINT DstPoint = {0, 0};
+
+ int rc = CrFbEntryRegionsAdd(hFb, NULL, &DstPoint, cRects, pRects, false);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryRegionsAdd failed %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+ crFbBltPutContentsFbVram(hFb, pPos, cRects, pRects, pImg);
+
+ int rc = CrFbEntryRegionsAdd(hFb, NULL, pPos, cRects, pRects, false);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryRegionsAdd failed %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+ if (!hFb->cUpdating)
+ {
+ WARN(("framebuffer not updating"));
+ return VERR_INVALID_STATE;
+ }
+
+ return crFbBltPutContents(hFb, pPos, cRects, pRects, pImg);
+}
+
+static int crFbRegionsIsIntersectRects(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, bool *pfRegChanged)
+{
+ uint32_t cCompRects;
+ const RTRECT *pCompRects;
+ int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cCompRects, NULL, NULL, &pCompRects);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc));
+ return rc;
+ }
+
+ bool fRegChanged = false;
+ for (uint32_t i = 0; i < cCompRects; ++i)
+ {
+ const RTRECT *pCompRect = &pCompRects[i];
+ for (uint32_t j = 0; j < cRects; ++j)
+ {
+ const RTRECT *pRect = &pRects[j];
+ if (VBoxRectIsIntersect(pCompRect, pRect))
+ {
+ *pfRegChanged = true;
+ return VINF_SUCCESS;
+ }
+ }
+ }
+
+ *pfRegChanged = false;
+ return VINF_SUCCESS;
+}
+
+int CrFbBltPutContentsNe(HCR_FRAMEBUFFER hFb, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg)
+{
+ bool fRegChanged = false;
+ int rc = crFbRegionsIsIntersectRects(hFb, cRects, pRects, &fRegChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crFbRegionsIsIntersectRects failed rc %d", rc));
+ return rc;
+ }
+
+ if (fRegChanged)
+ {
+ rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrFbBltPutContents(hFb, pPos, cRects, pRects, pImg);
+ if (!RT_SUCCESS(rc))
+ WARN(("CrFbBltPutContents failed rc %d", rc));
+ CrFbUpdateEnd(hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+
+ return rc;
+ }
+
+ crFbBltPutContentsFbVram(hFb, pPos, cRects, pRects, pImg);
+ return VINF_SUCCESS;
+}
+
+int CrFbClrFillNe(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects, uint32_t u32Color)
+{
+ bool fRegChanged = false;
+ int rc = crFbRegionsIsIntersectRects(hFb, cRects, pRects, &fRegChanged);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crFbRegionsIsIntersectRects failed rc %d", rc));
+ return rc;
+ }
+
+ if (fRegChanged)
+ {
+ rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrFbClrFill(hFb, cRects, pRects, u32Color);
+ if (!RT_SUCCESS(rc))
+ WARN(("CrFbClrFill failed rc %d", rc));
+ CrFbUpdateEnd(hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+
+ return rc;
+ }
+
+ crFbClrFillFbVram(hFb, cRects, pRects, u32Color);
+ return VINF_SUCCESS;
+}
+
+int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM)
+{
+ if (!pFb->cUpdating)
+ {
+ WARN(("no update in progress"));
+ return VERR_INVALID_STATE;
+ }
+
+ int rc = VINF_SUCCESS;
+ if (CrFbIsEnabled(pFb))
+ {
+ rc = CrFbRegionsClear(pFb);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("CrFbRegionsClear failed %d", rc));
+ return rc;
+ }
+ }
+
+ RTRECT Rect;
+ Rect.xLeft = 0;
+ Rect.yTop = 0;
+ Rect.xRight = pScreen->u32Width;
+ Rect.yBottom = pScreen->u32Height;
+ rc = CrVrScrCompositorRectSet(&pFb->Compositor, &Rect, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorRectSet failed rc %d", rc));
+ return rc;
+ }
+
+ pFb->ScreenInfo = *pScreen;
+ pFb->pvVram = pvVRAM ? pvVRAM : g_pvVRamBase + pScreen->u32StartOffset;
+
+ if (pFb->pDisplay)
+ pFb->pDisplay->FramebufferChanged(pFb);
+
+ return VINF_SUCCESS;
+}
+
+void CrFbTerm(CR_FRAMEBUFFER *pFb)
+{
+ if (pFb->cUpdating)
+ {
+ WARN(("update in progress"));
+ return;
+ }
+ uint32_t idFb = pFb->ScreenInfo.u32ViewIndex;
+
+ CrVrScrCompositorClear(&pFb->Compositor);
+ CrHTableDestroy(&pFb->SlotTable);
+
+ Assert(RTListIsEmpty(&pFb->EntriesList));
+ Assert(!pFb->cEntries);
+
+ memset(pFb, 0, sizeof (*pFb));
+
+ pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED;
+ pFb->ScreenInfo.u32ViewIndex = idFb;
+}
+
+ICrFbDisplay* CrFbDisplayGet(CR_FRAMEBUFFER *pFb)
+{
+ return pFb->pDisplay;
+}
+
+int CrFbDisplaySet(CR_FRAMEBUFFER *pFb, ICrFbDisplay *pDisplay)
+{
+ if (pFb->cUpdating)
+ {
+ WARN(("update in progress"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pFb->pDisplay == pDisplay)
+ return VINF_SUCCESS;
+
+ pFb->pDisplay = pDisplay;
+
+ return VINF_SUCCESS;
+}
+
+#define CR_PMGR_MODE_WINDOW 0x1
+/* mutually exclusive with CR_PMGR_MODE_WINDOW */
+#define CR_PMGR_MODE_ROOTVR 0x2
+#define CR_PMGR_MODE_VRDP 0x4
+#define CR_PMGR_MODE_ALL 0x7
+
+static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove);
+static void crPMgrCleanUnusedDisplays();
+
+static CR_FBTEX* crFbTexAlloc()
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ return (CR_FBTEX*)RTMemCacheAlloc(g_CrPresenter.FbTexLookasideList);
+#else
+ return (CR_FBTEX*)RTMemAlloc(sizeof (CR_FBTEX));
+#endif
+}
+
+static void crFbTexFree(CR_FBTEX *pTex)
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ RTMemCacheFree(g_CrPresenter.FbTexLookasideList, pTex);
+#else
+ RTMemFree(pTex);
+#endif
+}
+
+static CR_FRAMEBUFFER_ENTRY* crFbEntryAlloc()
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ return (CR_FRAMEBUFFER_ENTRY*)RTMemCacheAlloc(g_CrPresenter.FbEntryLookasideList);
+#else
+ return (CR_FRAMEBUFFER_ENTRY*)RTMemAlloc(sizeof (CR_FRAMEBUFFER_ENTRY));
+#endif
+}
+
+static void crFbEntryFree(CR_FRAMEBUFFER_ENTRY *pEntry)
+{
+ Assert(!CrVrScrCompositorEntryIsUsed(&pEntry->Entry));
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ RTMemCacheFree(g_CrPresenter.FbEntryLookasideList, pEntry);
+#else
+ RTMemFree(pEntry);
+#endif
+}
+
+DECLCALLBACK(void) crFbTexRelease(CR_TEXDATA *pTex)
+{
+ CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTex);
+ CRTextureObj *pTobj = pFbTex->pTobj;
+
+ CrTdBltDataCleanupNe(pTex);
+
+ if (pTobj)
+ {
+ crHashtableDelete(g_CrPresenter.pFbTexMap, pTobj->id, NULL);
+
+ crStateReleaseTexture(cr_server.MainContextInfo.pContext, pTobj);
+
+
+ crStateGlobalSharedRelease();
+ }
+
+ crFbTexFree(pFbTex);
+}
+
+void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased)
+{
+ PCR_BLITTER pBlitter = crServerVBoxBlitterGet();
+
+ CrTdInit(pFbTex, pTex, pBlitter, pfnTextureReleased);
+}
+
+static CR_FBTEX* crFbTexCreate(const VBOXVR_TEXTURE *pTex)
+{
+ CR_FBTEX *pFbTex = crFbTexAlloc();
+ if (!pFbTex)
+ {
+ WARN(("crFbTexAlloc failed!"));
+ return NULL;
+ }
+
+ CrFbTexDataInit(&pFbTex->Tex, pTex, crFbTexRelease);
+ pFbTex->pTobj = NULL;
+
+ return pFbTex;
+}
+
+CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex)
+{
+ CR_FBTEX *pFbTex = crFbTexCreate(pTex);
+ if (!pFbTex)
+ {
+ WARN(("crFbTexCreate failed!"));
+ return NULL;
+ }
+
+ return &pFbTex->Tex;
+}
+
+static CR_FBTEX* crFbTexAcquire(GLuint idTexture)
+{
+ CR_FBTEX *pFbTex = (CR_FBTEX *)crHashtableSearch(g_CrPresenter.pFbTexMap, idTexture);
+ if (pFbTex)
+ {
+ CrTdAddRef(&pFbTex->Tex);
+ return pFbTex;
+ }
+
+ CRSharedState *pShared = crStateGlobalSharedAcquire();
+ if (!pShared)
+ {
+ WARN(("pShared is null!"));
+ return NULL;
+ }
+
+ CRTextureObj *pTobj = (CRTextureObj*)crHashtableSearch(pShared->textureTable, idTexture);
+ if (!pTobj)
+ {
+ LOG(("pTobj is null!"));
+ crStateGlobalSharedRelease();
+ return NULL;
+ }
+
+ Assert(pTobj->id == idTexture);
+
+ GLuint hwid = crStateGetTextureObjHWID(pTobj);
+ if (!hwid)
+ {
+ WARN(("hwId is null!"));
+ crStateGlobalSharedRelease();
+ return NULL;
+ }
+
+ VBOXVR_TEXTURE Tex;
+ Tex.width = pTobj->level[0]->width;
+ Tex.height = pTobj->level[0]->height;
+ Tex.hwid = hwid;
+ Tex.target = pTobj->target;
+
+ pFbTex = crFbTexCreate(&Tex);
+ if (!pFbTex)
+ {
+ WARN(("crFbTexCreate failed!"));
+ crStateGlobalSharedRelease();
+ return NULL;
+ }
+
+ CR_STATE_SHAREDOBJ_USAGE_SET(pTobj, cr_server.MainContextInfo.pContext);
+
+ pFbTex->pTobj = pTobj;
+
+ crHashtableAdd(g_CrPresenter.pFbTexMap, idTexture, pFbTex);
+
+ return pFbTex;
+}
+
+static CR_TEXDATA* CrFbTexDataAcquire(GLuint idTexture)
+{
+ CR_FBTEX* pTex = crFbTexAcquire(idTexture);
+ if (!pTex)
+ {
+ WARN(("crFbTexAcquire failed for %d", idTexture));
+ return NULL;
+ }
+
+ return &pTex->Tex;
+}
+
+static void crFbEntryMarkDestroyed(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry)
+{
+ if (pEntry->Flags.fCreateNotified)
+ {
+ pEntry->Flags.fCreateNotified = 0;
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryDestroyed(pFb, pEntry);
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
+ if (pTex)
+ CrTdBltDataInvalidateNe(pTex);
+ }
+}
+
+static void crFbEntryDestroy(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry)
+{
+ crFbEntryMarkDestroyed(pFb, pEntry);
+ CrVrScrCompositorEntryCleanup(&pEntry->Entry);
+ CrHTableDestroy(&pEntry->HTable);
+ Assert(pFb->cEntries);
+ RTListNodeRemove(&pEntry->Node);
+ --pFb->cEntries;
+ crFbEntryFree(pEntry);
+}
+
+DECLINLINE(uint32_t) crFbEntryAddRef(CR_FRAMEBUFFER_ENTRY* pEntry)
+{
+ return ++pEntry->cRefs;
+}
+
+DECLINLINE(uint32_t) crFbEntryRelease(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry)
+{
+ uint32_t cRefs = --pEntry->cRefs;
+ if (!cRefs)
+ crFbEntryDestroy(pFb, pEntry);
+ return cRefs;
+}
+
+static DECLCALLBACK(void) crFbEntryReleased(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry)
+{
+ CR_FRAMEBUFFER *pFb = PCR_FRAMEBUFFER_FROM_COMPOSITOR(pCompositor);
+ CR_FRAMEBUFFER_ENTRY *pFbEntry = PCR_FBENTRY_FROM_ENTRY(pEntry);
+ CR_FRAMEBUFFER_ENTRY *pFbReplacingEntry = pReplacingEntry ? PCR_FBENTRY_FROM_ENTRY(pReplacingEntry) : NULL;
+ if (pFbReplacingEntry)
+ {
+ /*replace operation implies the replaced entry gets auto-destroyed,
+ * while all its data gets moved to the *clean* replacing entry
+ * 1. ensure the replacing entry is cleaned up */
+ crFbEntryMarkDestroyed(pFb, pFbReplacingEntry);
+
+ CrHTableMoveTo(&pFbEntry->HTable, &pFbReplacingEntry->HTable);
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
+ CR_TEXDATA *pReplacingTex = CrVrScrCompositorEntryTexGet(&pFbReplacingEntry->Entry);
+
+ CrTdBltScaleCacheMoveTo(pTex, pReplacingTex);
+
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryReplaced(pFb, pFbReplacingEntry, pFbEntry);
+
+ CrTdBltDataInvalidateNe(pTex);
+
+ /* 2. mark the replaced entry is destroyed */
+ Assert(pFbEntry->Flags.fCreateNotified);
+ Assert(pFbEntry->Flags.fInList);
+ pFbEntry->Flags.fCreateNotified = 0;
+ pFbEntry->Flags.fInList = 0;
+ pFbReplacingEntry->Flags.fCreateNotified = 1;
+ pFbReplacingEntry->Flags.fInList = 1;
+ }
+ else
+ {
+ if (pFbEntry->Flags.fInList)
+ {
+ pFbEntry->Flags.fInList = 0;
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryRemoved(pFb, pFbEntry);
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry);
+ if (pTex)
+ CrTdBltDataInvalidateNe(pTex);
+ }
+ }
+
+ crFbEntryRelease(pFb, pFbEntry);
+}
+
+static CR_FRAMEBUFFER_ENTRY* crFbEntryCreate(CR_FRAMEBUFFER *pFb, CR_TEXDATA* pTex, const RTRECT *pRect, uint32_t fFlags)
+{
+ CR_FRAMEBUFFER_ENTRY *pEntry = crFbEntryAlloc();
+ if (!pEntry)
+ {
+ WARN(("crFbEntryAlloc failed!"));
+ return NULL;
+ }
+
+ CrVrScrCompositorEntryInit(&pEntry->Entry, pRect, pTex, crFbEntryReleased);
+ CrVrScrCompositorEntryFlagsSet(&pEntry->Entry, fFlags);
+ pEntry->cRefs = 1;
+ pEntry->Flags.Value = 0;
+ CrHTableCreate(&pEntry->HTable, 0);
+
+ RTListAppend(&pFb->EntriesList, &pEntry->Node);
+ ++pFb->cEntries;
+
+ return pEntry;
+}
+
+int CrFbEntryCreateForTexData(CR_FRAMEBUFFER *pFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry)
+{
+ if (pTex == NULL)
+ {
+ WARN(("pTex is NULL"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ RTRECT Rect;
+ Rect.xLeft = 0;
+ Rect.yTop = 0;
+ Rect.xRight = pTex->Tex.width;
+ Rect.yBottom = pTex->Tex.height;
+ CR_FRAMEBUFFER_ENTRY* pEntry = crFbEntryCreate(pFb, pTex, &Rect, fFlags);
+ if (!pEntry)
+ {
+ WARN(("crFbEntryCreate failed"));
+ return VERR_NO_MEMORY;
+ }
+
+ *phEntry = pEntry;
+ return VINF_SUCCESS;
+}
+
+int CrFbEntryTexDataUpdate(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex)
+{
+ if (!pFb->cUpdating)
+ {
+ WARN(("framebuffer not updating"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pTex)
+ CrVrScrCompositorEntryTexSet(&pEntry->Entry, pTex);
+
+ if (CrVrScrCompositorEntryIsUsed(&pEntry->Entry))
+ {
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryTexChanged(pFb, pEntry);
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry);
+ if (pTex)
+ CrTdBltDataInvalidateNe(pTex);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbEntryCreateForTexId(CR_FRAMEBUFFER *pFb, GLuint idTexture, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry)
+{
+ CR_FBTEX* pFbTex = crFbTexAcquire(idTexture);
+ if (!pFbTex)
+ {
+ LOG(("crFbTexAcquire failed"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ CR_TEXDATA* pTex = &pFbTex->Tex;
+ int rc = CrFbEntryCreateForTexData(pFb, pTex, fFlags, phEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryCreateForTexData failed rc %d", rc));
+ }
+
+ /*always release the tex, the CrFbEntryCreateForTexData will do incref as necessary */
+ CrTdRelease(pTex);
+ return rc;
+}
+
+void CrFbEntryAddRef(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ ++hEntry->cRefs;
+}
+
+void CrFbEntryRelease(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ crFbEntryRelease(pFb, hEntry);
+}
+
+static int8_t crVBoxServerCrCmdBltPrimaryVramGenericProcess(uint32_t u32PrimaryID, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, bool fToPrimary);
+
+int CrFbRegionsClear(HCR_FRAMEBUFFER hFb)
+{
+ if (!hFb->cUpdating)
+ {
+ WARN(("framebuffer not updating"));
+ return VERR_INVALID_STATE;
+ }
+
+ uint32_t cRegions;
+ const RTRECT *pRegions;
+ int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cRegions, NULL, NULL, &pRegions);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc));
+ return rc;
+ }
+
+ const struct VBVAINFOSCREEN* pScreen = CrFbGetScreenInfo(hFb);
+ VBOXCMDVBVAOFFSET offVRAM = (VBOXCMDVBVAOFFSET)(((uintptr_t)CrFbGetVRAM(hFb)) - ((uintptr_t)g_pvVRamBase));
+ RTPOINT Pos = {0,0};
+ int8_t i8Result = crVBoxServerCrCmdBltPrimaryVramGenericProcess(pScreen->u32ViewIndex, offVRAM, pScreen->u32Width, pScreen->u32Height, &Pos, cRegions, pRegions, true);
+ if (i8Result)
+ {
+ WARN(("crVBoxServerCrCmdBltPrimaryVramGenericProcess failed"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+#ifdef DEBUG
+ {
+ uint32_t cTmpRegions;
+ const RTRECT *pTmpRegions;
+ int tmpRc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cTmpRegions, NULL, NULL, &pTmpRegions);
+ if (!RT_SUCCESS(tmpRc))
+ {
+ WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", tmpRc));
+ }
+ Assert(!cTmpRegions);
+ }
+#endif
+
+ /* just in case */
+ bool fChanged = false;
+ CrVrScrCompositorRegionsClear(&hFb->Compositor, &fChanged);
+ Assert(!fChanged);
+
+ if (cRegions)
+ {
+ if (hFb->pDisplay)
+ hFb->pDisplay->RegionsChanged(hFb);
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrFbEntryRegionsAdd(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated)
+{
+ if (!pFb->cUpdating)
+ {
+ WARN(("framebuffer not updating"));
+ return VERR_INVALID_STATE;
+ }
+
+ uint32_t fChangeFlags = 0;
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL;
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry;
+ bool fEntryWasInList;
+
+ if (hEntry)
+ {
+ crFbEntryAddRef(hEntry);
+ pNewEntry = &hEntry->Entry;
+ fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry);
+
+ Assert(!hEntry->Flags.fInList == !fEntryWasInList);
+ }
+ else
+ {
+ pNewEntry = NULL;
+ fEntryWasInList = false;
+ }
+
+ int rc = CrVrScrCompositorEntryRegionsAdd(&pFb->Compositor, hEntry ? &hEntry->Entry : NULL, pPos, cRegions, paRegions, fPosRelated, &pReplacedScrEntry, &fChangeFlags);
+ if (RT_SUCCESS(rc))
+ {
+ if (fChangeFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED)
+ {
+ if (!fEntryWasInList && pNewEntry)
+ {
+ Assert(CrVrScrCompositorEntryIsUsed(pNewEntry));
+ if (!hEntry->Flags.fCreateNotified)
+ {
+ hEntry->Flags.fCreateNotified = 1;
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryCreated(pFb, hEntry);
+ }
+
+#ifdef DEBUG_misha
+ /* in theory hEntry->Flags.fInList can be set if entry is replaced,
+ * but then modified to fit the compositor rects,
+ * and so we get the regions changed notification as a result
+ * this should not generally happen though, so put an assertion to debug that situation */
+ Assert(!hEntry->Flags.fInList);
+#endif
+ if (!hEntry->Flags.fInList)
+ {
+ hEntry->Flags.fInList = 1;
+
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryAdded(pFb, hEntry);
+ }
+ }
+ if (pFb->pDisplay)
+ pFb->pDisplay->RegionsChanged(pFb);
+
+ Assert(!pReplacedScrEntry);
+ }
+ else if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED)
+ {
+ Assert(pReplacedScrEntry);
+ /* we have already processed that in a "release" callback */
+ Assert(hEntry);
+ }
+ else
+ {
+ Assert(!fChangeFlags);
+ Assert(!pReplacedScrEntry);
+ }
+
+ if (hEntry)
+ {
+ if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry))
+ {
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryTexChanged(pFb, hEntry);
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
+ if (pTex)
+ CrTdBltDataInvalidateNe(pTex);
+ }
+ }
+ }
+ else
+ WARN(("CrVrScrCompositorEntryRegionsAdd failed, rc %d", rc));
+
+ return rc;
+}
+
+int CrFbEntryRegionsSet(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated)
+{
+ if (!pFb->cUpdating)
+ {
+ WARN(("framebuffer not updating"));
+ return VERR_INVALID_STATE;
+ }
+
+ bool fChanged = 0;
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL;
+ VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry;
+ bool fEntryWasInList;
+
+ if (hEntry)
+ {
+ crFbEntryAddRef(hEntry);
+ pNewEntry = &hEntry->Entry;
+ fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry);
+ Assert(!hEntry->Flags.fInList == !fEntryWasInList);
+ }
+ else
+ {
+ pNewEntry = NULL;
+ fEntryWasInList = false;
+ }
+
+ int rc = CrVrScrCompositorEntryRegionsSet(&pFb->Compositor, pNewEntry, pPos, cRegions, paRegions, fPosRelated, &fChanged);
+ if (RT_SUCCESS(rc))
+ {
+ if (fChanged)
+ {
+ if (!fEntryWasInList && pNewEntry)
+ {
+ if (CrVrScrCompositorEntryIsUsed(pNewEntry))
+ {
+ if (!hEntry->Flags.fCreateNotified)
+ {
+ hEntry->Flags.fCreateNotified = 1;
+
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryCreated(pFb, hEntry);
+ }
+
+ Assert(!hEntry->Flags.fInList);
+ hEntry->Flags.fInList = 1;
+
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryAdded(pFb, hEntry);
+ }
+ }
+
+ if (pFb->pDisplay)
+ pFb->pDisplay->RegionsChanged(pFb);
+ }
+
+ if (hEntry)
+ {
+ if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry))
+ {
+ if (pFb->pDisplay)
+ pFb->pDisplay->EntryTexChanged(pFb, hEntry);
+
+ CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry);
+ if (pTex)
+ CrTdBltDataInvalidateNe(pTex);
+ }
+ }
+ }
+ else
+ WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc));
+
+ return rc;
+}
+
+const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry)
+{
+ return &hEntry->Entry;
+}
+
+HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry)
+{
+ return RT_FROM_MEMBER(pCEntry, CR_FRAMEBUFFER_ENTRY, Entry);
+}
+
+void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext)
+{
+ HCR_FRAMEBUFFER_ENTRY hEntry, hNext;
+ RTListForEachSafe(&hFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node)
+ {
+ if (hEntry->Flags.fCreateNotified)
+ {
+ if (!pfnVisitorCb(hFb, hEntry, pvContext))
+ return;
+ }
+ }
+}
+
+
+CRHTABLE_HANDLE CrFbDDataAllocSlot(CR_FRAMEBUFFER *pFb)
+{
+ return CrHTablePut(&pFb->SlotTable, (void*)1);
+}
+
+void CrFbDDataReleaseSlot(CR_FRAMEBUFFER *pFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext)
+{
+ HCR_FRAMEBUFFER_ENTRY hEntry, hNext;
+ RTListForEachSafe(&pFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node)
+ {
+ if (CrFbDDataEntryGet(hEntry, hSlot))
+ {
+ if (pfnReleaseCb)
+ pfnReleaseCb(pFb, hEntry, pvContext);
+
+ CrFbDDataEntryClear(hEntry, hSlot);
+ }
+ }
+
+ CrHTableRemove(&pFb->SlotTable, hSlot);
+}
+
+int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData)
+{
+ return CrHTablePutToSlot(&hEntry->HTable, hSlot, pvData);
+}
+
+void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot)
+{
+ return CrHTableRemove(&hEntry->HTable, hSlot);
+}
+
+void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot)
+{
+ return CrHTableGet(&hEntry->HTable, hSlot);
+}
+
+int CrPMgrDisable()
+{
+ if (!g_CrPresenter.fEnabled)
+ return VINF_SUCCESS;
+
+ g_CrPresenter.u32DisabledDisplayMode = g_CrPresenter.u32DisplayMode;
+
+ int rc = crPMgrModeModifyGlobal(0, CR_PMGR_MODE_WINDOW);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrModeModifyGlobal failed %d", rc));
+ return rc;
+ }
+
+ crPMgrCleanUnusedDisplays();
+
+ g_CrPresenter.fEnabled = false;
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrEnable()
+{
+ if (g_CrPresenter.fEnabled)
+ return VINF_SUCCESS;
+
+ g_CrPresenter.fEnabled = true;
+
+ int rc = crPMgrModeModifyGlobal(g_CrPresenter.u32DisabledDisplayMode, 0);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrModeModifyGlobal failed %d", rc));
+ g_CrPresenter.fEnabled = false;
+ return rc;
+ }
+
+ g_CrPresenter.u32DisabledDisplayMode = 0;
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrInit()
+{
+ int rc = VINF_SUCCESS;
+ memset(&g_CrPresenter, 0, sizeof (g_CrPresenter));
+ g_CrPresenter.fEnabled = true;
+ for (int i = 0; i < RT_ELEMENTS(g_CrPresenter.aDisplayInfos); ++i)
+ {
+ g_CrPresenter.aDisplayInfos[i].u32Id = i;
+ g_CrPresenter.aDisplayInfos[i].iFb = -1;
+
+ g_CrPresenter.aFbInfos[i].u32Id = i;
+ }
+
+ g_CrPresenter.pFbTexMap = crAllocHashtable();
+ if (g_CrPresenter.pFbTexMap)
+ {
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ rc = RTMemCacheCreate(&g_CrPresenter.FbEntryLookasideList, sizeof (CR_FRAMEBUFFER_ENTRY),
+ 0, /* size_t cbAlignment */
+ UINT32_MAX, /* uint32_t cMaxObjects */
+ NULL, /* PFNMEMCACHECTOR pfnCtor*/
+ NULL, /* PFNMEMCACHEDTOR pfnDtor*/
+ NULL, /* void *pvUser*/
+ 0 /* uint32_t fFlags*/
+ );
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTMemCacheCreate(&g_CrPresenter.FbTexLookasideList, sizeof (CR_FBTEX),
+ 0, /* size_t cbAlignment */
+ UINT32_MAX, /* uint32_t cMaxObjects */
+ NULL, /* PFNMEMCACHECTOR pfnCtor*/
+ NULL, /* PFNMEMCACHEDTOR pfnDtor*/
+ NULL, /* void *pvUser*/
+ 0 /* uint32_t fFlags*/
+ );
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTMemCacheCreate(&g_CrPresenter.CEntryLookasideList, sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY),
+ 0, /* size_t cbAlignment */
+ UINT32_MAX, /* uint32_t cMaxObjects */
+ NULL, /* PFNMEMCACHECTOR pfnCtor*/
+ NULL, /* PFNMEMCACHEDTOR pfnDtor*/
+ NULL, /* void *pvUser*/
+ 0 /* uint32_t fFlags*/
+ );
+ if (RT_SUCCESS(rc))
+ {
+#endif
+ rc = crPMgrModeModifyGlobal(CR_PMGR_MODE_WINDOW, 0);
+ if (RT_SUCCESS(rc))
+ return VINF_SUCCESS;
+ else
+ WARN(("crPMgrModeModifyGlobal failed rc %d", rc));
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList);
+ }
+ else
+ WARN(("RTMemCacheCreate failed rc %d", rc));
+
+ RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList);
+ }
+ else
+ WARN(("RTMemCacheCreate failed rc %d", rc));
+
+ RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList);
+ }
+ else
+ WARN(("RTMemCacheCreate failed rc %d", rc));
+#endif
+ }
+ else
+ {
+ WARN(("crAllocHashtable failed"));
+ rc = VERR_NO_MEMORY;
+ }
+ return rc;
+}
+
+void CrPMgrTerm()
+{
+ crPMgrModeModifyGlobal(0, CR_PMGR_MODE_ALL);
+
+ HCR_FRAMEBUFFER hFb;
+
+ for (hFb = CrPMgrFbGetFirstInitialized();
+ hFb;
+ hFb = CrPMgrFbGetNextInitialized(hFb))
+ {
+ uint32_t iFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CrFbDisplaySet(hFb, NULL);
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[iFb];
+ if (pFbInfo->pDpComposite)
+ {
+ delete pFbInfo->pDpComposite;
+ pFbInfo->pDpComposite = NULL;
+ }
+
+ CrFbTerm(hFb);
+ }
+
+ crPMgrCleanUnusedDisplays();
+
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList);
+ RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList);
+ RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList);
+#endif
+ crFreeHashtable(g_CrPresenter.pFbTexMap, NULL);
+
+ if (g_CrPresenter.pvTmpBuf)
+ RTMemFree(g_CrPresenter.pvTmpBuf);
+
+ if (g_CrPresenter.pvTmpBuf2)
+ RTMemFree(g_CrPresenter.pvTmpBuf2);
+
+ memset(&g_CrPresenter, 0, sizeof (g_CrPresenter));
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idFb)
+{
+ if (idFb >= CR_MAX_GUEST_MONITORS)
+ {
+ WARN(("invalid idFb %d", idFb));
+ return NULL;
+ }
+
+ if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idFb))
+ {
+ CrFbInit(&g_CrPresenter.aFramebuffers[idFb], idFb);
+ CrFBmSetAtomic(&g_CrPresenter.FramebufferInitMap, idFb);
+ }
+ else
+ Assert(g_CrPresenter.aFramebuffers[idFb].ScreenInfo.u32ViewIndex == idFb);
+
+ return &g_CrPresenter.aFramebuffers[idFb];
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetInitialized(uint32_t idFb)
+{
+ if (idFb >= CR_MAX_GUEST_MONITORS)
+ {
+ WARN(("invalid idFb %d", idFb));
+ return NULL;
+ }
+
+ if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idFb))
+ {
+ return NULL;
+ }
+ else
+ Assert(g_CrPresenter.aFramebuffers[idFb].ScreenInfo.u32ViewIndex == idFb);
+
+ return &g_CrPresenter.aFramebuffers[idFb];
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idFb)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(idFb);
+
+ if(hFb && CrFbIsEnabled(hFb))
+ return hFb;
+
+ return NULL;
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetEnabledForScreen(uint32_t idScreen)
+{
+ if (idScreen >= (uint32_t)cr_server.screenCount)
+ {
+ WARN(("invalid target id"));
+ return NULL;
+ }
+
+ const CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
+ if (pDpInfo->iFb < 0)
+ return NULL;
+
+ return CrPMgrFbGetEnabled(pDpInfo->iFb);
+}
+
+static HCR_FRAMEBUFFER crPMgrFbGetNextEnabled(uint32_t i)
+{
+ for (;i < (uint32_t)cr_server.screenCount; ++i)
+ {
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(i);
+ if (hFb)
+ return hFb;
+ }
+
+ return NULL;
+}
+
+static HCR_FRAMEBUFFER crPMgrFbGetNextInitialized(uint32_t i)
+{
+ for (;i < (uint32_t)cr_server.screenCount; ++i)
+ {
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i);
+ if (hFb)
+ return hFb;
+ }
+
+ return NULL;
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled()
+{
+ HCR_FRAMEBUFFER hFb = crPMgrFbGetNextEnabled(0);
+// if (!hFb)
+// WARN(("no enabled framebuffer found"));
+ return hFb;
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb)
+{
+ return crPMgrFbGetNextEnabled(hFb->ScreenInfo.u32ViewIndex+1);
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized()
+{
+ HCR_FRAMEBUFFER hFb = crPMgrFbGetNextInitialized(0);
+// if (!hFb)
+// WARN(("no initialized framebuffer found"));
+ return hFb;
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb)
+{
+ return crPMgrFbGetNextInitialized(hFb->ScreenInfo.u32ViewIndex+1);
+}
+
+HCR_FRAMEBUFFER CrPMgrFbGetEnabledByVramStart(VBOXCMDVBVAOFFSET offVRAM)
+{
+ for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+ if (pScreen->u32StartOffset == offVRAM)
+ return hFb;
+ }
+
+ return NULL;
+}
+
+
+static uint32_t crPMgrModeAdjustVal(uint32_t u32Mode)
+{
+ u32Mode = CR_PMGR_MODE_ALL & u32Mode;
+ if (CR_PMGR_MODE_ROOTVR & u32Mode)
+ u32Mode &= ~CR_PMGR_MODE_WINDOW;
+ return u32Mode;
+}
+
+static int crPMgrCheckInitWindowDisplays(uint32_t idScreen)
+{
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
+ if (pDpInfo->iFb >= 0)
+ {
+ uint32_t u32ModeAdd = g_CrPresenter.u32DisplayMode & (CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR);
+ int rc = crPMgrFbConnectTargetDisplays(&g_CrPresenter.aFramebuffers[pDpInfo->iFb], pDpInfo, u32ModeAdd);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectTargetDisplays failed %d", rc));
+ return rc;
+ }
+ }
+#endif
+ return VINF_SUCCESS;
+}
+
+extern "C" DECLEXPORT(int) VBoxOglSetScaleFactor(uint32_t idScreen, double dScaleFactorW, double dScaleFactorH)
+{
+ if (idScreen >= CR_MAX_GUEST_MONITORS)
+ {
+ crDebug("Can't set scale factor because specified screen ID (%u) is out of range (max=%d).", idScreen, CR_MAX_GUEST_MONITORS);
+ return VERR_INVALID_PARAMETER;
+ }
+
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
+ if (pDpInfo->pDpWin)
+ {
+ CrFbWindow *pWin = pDpInfo->pDpWin->getWindow();
+ if (pWin)
+ {
+ bool rc;
+ crDebug("Set scale factor for initialized display.");
+ rc = pWin->SetScaleFactor((GLdouble)dScaleFactorW, (GLdouble)dScaleFactorH);
+ return rc ? 0 : VERR_LOCK_FAILED;
+ }
+ else
+ crDebug("Can't apply scale factor at the moment bacause overlay window obgect not yet created. Will be chached.");
+ }
+ else
+ crDebug("Can't apply scale factor at the moment bacause display not yet initialized. Will be chached.");
+
+ /* Display output not yet initialized. Let's cache values. */
+ pDpInfo->dInitialScaleFactorW = dScaleFactorW;
+ pDpInfo->dInitialScaleFactorH = dScaleFactorH;
+
+ return 0;
+}
+
+int CrPMgrScreenChanged(uint32_t idScreen)
+{
+ if (idScreen >= CR_MAX_GUEST_MONITORS)
+ {
+ WARN(("invalid idScreen %d", idScreen));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ int rc = VINF_SUCCESS;
+
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
+ HCR_FRAMEBUFFER hFb = pDpInfo->iFb >= 0 ? CrPMgrFbGet(pDpInfo->iFb) : NULL;
+
+ if (hFb && CrFbIsUpdating(hFb))
+ {
+ WARN(("trying to update viewport while framebuffer is being updated"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pDpInfo->pDpWin)
+ {
+ CRASSERT(pDpInfo->pDpWin->getWindow());
+
+ rc = pDpInfo->pDpWin->UpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ pDpInfo->pDpWin->reparent(cr_server.screen[idScreen].winID);
+ pDpInfo->pDpWin->UpdateEnd(hFb);
+ }
+ }
+ else
+ {
+ if (pDpInfo->pWindow)
+ {
+ rc = pDpInfo->pWindow->UpdateBegin();
+ if (RT_SUCCESS(rc))
+ {
+ rc = pDpInfo->pWindow->SetVisible(false);
+ if (RT_SUCCESS(rc))
+ rc = pDpInfo->pWindow->Reparent(cr_server.screen[idScreen].winID);
+
+ pDpInfo->pWindow->UpdateEnd();
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ rc = crPMgrCheckInitWindowDisplays(idScreen);
+ }
+
+ CRASSERT(!rc);
+
+ return rc;
+}
+
+int CrPMgrViewportUpdate(uint32_t idScreen)
+{
+ if (idScreen >= CR_MAX_GUEST_MONITORS)
+ {
+ WARN(("invalid idScreen %d", idScreen));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[idScreen];
+ if (pDpInfo->iFb >= 0)
+ {
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pDpInfo->iFb);
+ if (CrFbIsUpdating(hFb))
+ {
+ WARN(("trying to update viewport while framebuffer is being updated"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pDpInfo->pDpWin)
+ {
+ CRASSERT(pDpInfo->pDpWin->getWindow());
+ int rc = pDpInfo->pDpWin->UpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ pDpInfo->pDpWin->setViewportRect(&cr_server.screenVieport[idScreen].Rect);
+ pDpInfo->pDpWin->UpdateEnd(hFb);
+ }
+ else
+ WARN(("UpdateBegin failed %d", rc));
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrFbDisconnectDisplay(HCR_FRAMEBUFFER hFb, CrFbDisplayBase *pDp)
+{
+ if (pDp->getFramebuffer() != hFb)
+ return VINF_SUCCESS;
+
+ CrFbDisplayBase * pCurDp = (CrFbDisplayBase*)CrFbDisplayGet(hFb);
+ if (!pCurDp)
+ {
+ WARN(("no display set, unexpected"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ if (pCurDp == pDp)
+ {
+ pDp->setFramebuffer(NULL);
+ CrFbDisplaySet(hFb, NULL);
+ return VINF_SUCCESS;
+ }
+
+ uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+ if (pFbInfo->pDpComposite != pCurDp)
+ {
+ WARN(("misconfig, expectig the curret framebuffer to be present, and thus composite is expected"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ if (pDp->getContainer() == pFbInfo->pDpComposite)
+ {
+ pFbInfo->pDpComposite->remove(pDp);
+ uint32_t cDisplays = pFbInfo->pDpComposite->getDisplayCount();
+ if (cDisplays <= 1)
+ {
+ Assert(cDisplays == 1);
+ CrFbDisplayBase *pDpFirst = pFbInfo->pDpComposite->first();
+ if (pDpFirst)
+ pFbInfo->pDpComposite->remove(pDpFirst, false);
+ CrFbDisplaySet(hFb, pDpFirst);
+ }
+ return VINF_SUCCESS;
+ }
+
+ WARN(("misconfig"));
+ return VERR_INTERNAL_ERROR;
+}
+
+static int crPMgrFbConnectDisplay(HCR_FRAMEBUFFER hFb, CrFbDisplayBase *pDp)
+{
+ if (pDp->getFramebuffer() == hFb)
+ return VINF_SUCCESS;
+
+ CrFbDisplayBase * pCurDp = (CrFbDisplayBase*)CrFbDisplayGet(hFb);
+ if (!pCurDp)
+ {
+ pDp->setFramebuffer(hFb);
+ CrFbDisplaySet(hFb, pDp);
+ return VINF_SUCCESS;
+ }
+
+ if (pCurDp == pDp)
+ {
+ WARN(("misconfig, current framebuffer is not expected to be set"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+ if (pFbInfo->pDpComposite != pCurDp)
+ {
+ if (!pFbInfo->pDpComposite)
+ {
+ pFbInfo->pDpComposite = new CrFbDisplayComposite();
+ pFbInfo->pDpComposite->setFramebuffer(hFb);
+ }
+
+ pFbInfo->pDpComposite->add(pCurDp);
+ CrFbDisplaySet(hFb, pFbInfo->pDpComposite);
+ }
+
+ pFbInfo->pDpComposite->add(pDp);
+ return VINF_SUCCESS;
+}
+
+static int crPMgrFbDisconnectTarget(HCR_FRAMEBUFFER hFb, uint32_t i)
+{
+ uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
+ if (pDpInfo->iFb != idFb)
+ {
+ WARN(("target not connected"));
+ Assert(!ASMBitTest(pFbInfo->aTargetMap, i));
+ return VINF_SUCCESS;
+ }
+
+ Assert(ASMBitTest(pFbInfo->aTargetMap, i));
+
+ int rc = VINF_SUCCESS;
+ if (pDpInfo->pDpVrdp)
+ {
+ rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpVrdp);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectDisplay failed %d", rc));
+ return rc;
+ }
+ }
+
+ if (pDpInfo->pDpWinRootVr)
+ {
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ CrFbWindow *pWindow = pDpInfo->pDpWinRootVr->windowDetach(false);
+ Assert(pWindow == pDpInfo->pWindow);
+#endif
+ rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWinRootVr);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectDisplay failed %d", rc));
+ return rc;
+ }
+ }
+ else if (pDpInfo->pDpWin)
+ {
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ CrFbWindow *pWindow = pDpInfo->pDpWin->windowDetach(false);
+ Assert(pWindow == pDpInfo->pWindow);
+#endif
+ rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWin);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectDisplay failed %d", rc));
+ return rc;
+ }
+ }
+
+ ASMBitClear(pFbInfo->aTargetMap, i);
+ pDpInfo->iFb = -1;
+
+ return VINF_SUCCESS;
+}
+
+static void crPMgrDpWinRootVrCreate(CR_FBDISPLAY_INFO *pDpInfo)
+{
+ if (!pDpInfo->pDpWinRootVr)
+ {
+ if (pDpInfo->pDpWin)
+ {
+ CrFbWindow *pWin = pDpInfo->pDpWin->windowDetach();
+ CRASSERT(pWin);
+ Assert(pWin == pDpInfo->pWindow);
+ delete pDpInfo->pDpWin;
+ pDpInfo->pDpWin = NULL;
+ }
+ else if (!pDpInfo->pWindow)
+ {
+ pDpInfo->pWindow = new CrFbWindow(0);
+ }
+
+ pDpInfo->pDpWinRootVr = new CrFbDisplayWindowRootVr(&cr_server.screenVieport[pDpInfo->u32Id].Rect, cr_server.screen[pDpInfo->u32Id].winID);
+ pDpInfo->pDpWin = pDpInfo->pDpWinRootVr;
+ pDpInfo->pDpWinRootVr->windowAttach(pDpInfo->pWindow);
+
+ /* Set scale factor once it was previously cached when display output was not yet initialized. */
+ if (pDpInfo->dInitialScaleFactorW || pDpInfo->dInitialScaleFactorH)
+ {
+ crDebug("Set cached scale factor for seamless mode.");
+ pDpInfo->pWindow->SetScaleFactor((GLdouble)pDpInfo->dInitialScaleFactorW, (GLdouble)pDpInfo->dInitialScaleFactorH);
+ /* Invalidate cache. */
+ pDpInfo->dInitialScaleFactorW = pDpInfo->dInitialScaleFactorH = 0;
+ }
+ }
+}
+
+static void crPMgrDpWinCreate(CR_FBDISPLAY_INFO *pDpInfo)
+{
+ if (pDpInfo->pDpWinRootVr)
+ {
+ CRASSERT(pDpInfo->pDpWinRootVr == pDpInfo->pDpWin);
+ CrFbWindow *pWin = pDpInfo->pDpWin->windowDetach();
+ CRASSERT(pWin);
+ Assert(pWin == pDpInfo->pWindow);
+ delete pDpInfo->pDpWinRootVr;
+ pDpInfo->pDpWinRootVr = NULL;
+ pDpInfo->pDpWin = NULL;
+ }
+
+ if (!pDpInfo->pDpWin)
+ {
+ if (!pDpInfo->pWindow)
+ pDpInfo->pWindow = new CrFbWindow(0);
+
+ pDpInfo->pDpWin = new CrFbDisplayWindow(&cr_server.screenVieport[pDpInfo->u32Id].Rect, cr_server.screen[pDpInfo->u32Id].winID);
+ pDpInfo->pDpWin->windowAttach(pDpInfo->pWindow);
+
+ /* Set scale factor once it was previously cached when display output was not yet initialized. */
+ if (pDpInfo->dInitialScaleFactorW || pDpInfo->dInitialScaleFactorH)
+ {
+ crDebug("Set cached scale factor for host window.");
+ pDpInfo->pWindow->SetScaleFactor((GLdouble)pDpInfo->dInitialScaleFactorW, (GLdouble)pDpInfo->dInitialScaleFactorH);
+ /* Invalidate cache. */
+ pDpInfo->dInitialScaleFactorW = pDpInfo->dInitialScaleFactorH = 0;
+ }
+ }
+}
+
+static int crPMgrFbDisconnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeRemove)
+{
+ int rc = VINF_SUCCESS;
+ if (u32ModeRemove & CR_PMGR_MODE_ROOTVR)
+ {
+ if (pDpInfo->pDpWinRootVr)
+ {
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ CrFbWindow *pWindow = pDpInfo->pDpWinRootVr->windowDetach(false);
+ Assert(pWindow == pDpInfo->pWindow);
+#endif
+ CRASSERT(pDpInfo->pDpWin == pDpInfo->pDpWinRootVr);
+ rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWinRootVr);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectDisplay pDpWinRootVr failed %d", rc));
+ return rc;
+ }
+ }
+ }
+ else if (u32ModeRemove & CR_PMGR_MODE_WINDOW)
+ {
+ CRASSERT(!pDpInfo->pDpWinRootVr);
+ if (pDpInfo->pDpWin)
+ {
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ CrFbWindow *pWindow = pDpInfo->pDpWin->windowDetach(false);
+ Assert(pWindow == pDpInfo->pWindow);
+#endif
+ rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpWin);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectDisplay pDpWin failed %d", rc));
+ return rc;
+ }
+ }
+ }
+
+ if (u32ModeRemove & CR_PMGR_MODE_VRDP)
+ {
+ if (pDpInfo->pDpVrdp)
+ {
+ rc = crPMgrFbDisconnectDisplay(hFb, pDpInfo->pDpVrdp);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectDisplay pDpVrdp failed %d", rc));
+ return rc;
+ }
+ }
+ }
+
+ pDpInfo->u32DisplayMode &= ~u32ModeRemove;
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrFbConnectTargetDisplays(HCR_FRAMEBUFFER hFb, CR_FBDISPLAY_INFO *pDpInfo, uint32_t u32ModeAdd)
+{
+ int rc = VINF_SUCCESS;
+
+ if (u32ModeAdd & CR_PMGR_MODE_ROOTVR)
+ {
+ crPMgrDpWinRootVrCreate(pDpInfo);
+
+ rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpWinRootVr);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectDisplay pDpWinRootVr failed %d", rc));
+ return rc;
+ }
+ }
+ else if (u32ModeAdd & CR_PMGR_MODE_WINDOW)
+ {
+ crPMgrDpWinCreate(pDpInfo);
+
+ rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpWin);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectDisplay pDpWin failed %d", rc));
+ return rc;
+ }
+ }
+
+ if (u32ModeAdd & CR_PMGR_MODE_VRDP)
+ {
+ if (!pDpInfo->pDpVrdp)
+ pDpInfo->pDpVrdp = new CrFbDisplayVrdp();
+
+ rc = crPMgrFbConnectDisplay(hFb, pDpInfo->pDpVrdp);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectDisplay pDpVrdp failed %d", rc));
+ return rc;
+ }
+ }
+
+ pDpInfo->u32DisplayMode |= u32ModeAdd;
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrFbConnectTarget(HCR_FRAMEBUFFER hFb, uint32_t i)
+{
+ uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
+ if (pDpInfo->iFb == idFb)
+ {
+ WARN(("target not connected"));
+ Assert(ASMBitTest(pFbInfo->aTargetMap, i));
+ return VINF_SUCCESS;
+ }
+
+ Assert(!ASMBitTest(pFbInfo->aTargetMap, i));
+
+ int rc = VINF_SUCCESS;
+
+ if (pDpInfo->iFb != -1)
+ {
+ Assert(pDpInfo->iFb < cr_server.screenCount);
+ HCR_FRAMEBUFFER hAssignedFb = CrPMgrFbGet(pDpInfo->iFb);
+ Assert(hAssignedFb);
+ rc = crPMgrFbDisconnectTarget(hAssignedFb, i);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectTarget failed %d", rc));
+ return rc;
+ }
+ }
+
+ rc = crPMgrFbConnectTargetDisplays(hFb, pDpInfo, g_CrPresenter.u32DisplayMode
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ & ~(CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR)
+#endif
+ );
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectTargetDisplays failed %d", rc));
+ return rc;
+ }
+
+ ASMBitSet(pFbInfo->aTargetMap, i);
+ pDpInfo->iFb = idFb;
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrFbDisconnect(HCR_FRAMEBUFFER hFb, const uint32_t *pTargetMap)
+{
+ int rc = VINF_SUCCESS;
+ for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount);
+ i >= 0;
+ i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i))
+ {
+ rc = crPMgrFbDisconnectTarget(hFb, (uint32_t)i);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectTarget failed %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrFbConnect(HCR_FRAMEBUFFER hFb, const uint32_t *pTargetMap)
+{
+ int rc = VINF_SUCCESS;
+ for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount);
+ i >= 0;
+ i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i))
+ {
+ rc = crPMgrFbConnectTarget(hFb, (uint32_t)i);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectTarget failed %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrModeModifyTarget(HCR_FRAMEBUFFER hFb, uint32_t iDisplay, uint32_t u32ModeAdd, uint32_t u32ModeRemove)
+{
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[iDisplay];
+ int rc = crPMgrFbDisconnectTargetDisplays(hFb, pDpInfo, u32ModeRemove);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectTargetDisplays failed %d", rc));
+ return rc;
+ }
+
+ rc = crPMgrFbConnectTargetDisplays(hFb, pDpInfo, u32ModeAdd);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnectTargetDisplays failed %d", rc));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crPMgrModeModify(HCR_FRAMEBUFFER hFb, uint32_t u32ModeAdd, uint32_t u32ModeRemove)
+{
+ int rc = VINF_SUCCESS;
+ uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+ for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount);
+ i >= 0;
+ i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i))
+ {
+ rc = crPMgrModeModifyTarget(hFb, (uint32_t)i, u32ModeAdd, u32ModeRemove);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrModeModifyTarget failed %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+static void crPMgrCleanUnusedDisplays()
+{
+ for (int i = 0; i < cr_server.screenCount; ++i)
+ {
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
+
+ if (pDpInfo->pDpWinRootVr)
+ {
+ if (!pDpInfo->pDpWinRootVr->getFramebuffer())
+ {
+ pDpInfo->pDpWinRootVr->windowDetach(false);
+ delete pDpInfo->pDpWinRootVr;
+ pDpInfo->pDpWinRootVr = NULL;
+ pDpInfo->pDpWin = NULL;
+ if (pDpInfo->pWindow)
+ {
+ delete pDpInfo->pWindow;
+ pDpInfo->pWindow = NULL;
+ }
+ }
+ else
+ WARN(("pDpWinRootVr is used"));
+ }
+ else if (pDpInfo->pDpWin)
+ {
+ if (!pDpInfo->pDpWin->getFramebuffer())
+ {
+ pDpInfo->pDpWin->windowDetach(false);
+ delete pDpInfo->pDpWin;
+ pDpInfo->pDpWin = NULL;
+ if (pDpInfo->pWindow)
+ {
+ delete pDpInfo->pWindow;
+ pDpInfo->pWindow = NULL;
+ }
+ }
+ else
+ WARN(("pDpWin is used"));
+ }
+
+ if (pDpInfo->pDpVrdp)
+ {
+ if (!pDpInfo->pDpVrdp->getFramebuffer())
+ {
+ delete pDpInfo->pDpVrdp;
+ pDpInfo->pDpVrdp = NULL;
+ }
+ else
+ WARN(("pDpVrdp is used"));
+ }
+ }
+}
+
+static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove)
+{
+ uint32_t u32InternalMode = g_CrPresenter.fEnabled ? g_CrPresenter.u32DisplayMode : g_CrPresenter.u32DisabledDisplayMode;
+
+ u32ModeRemove = ((u32ModeRemove | crPMgrModeAdjustVal(u32ModeRemove)) & CR_PMGR_MODE_ALL);
+ u32ModeAdd = crPMgrModeAdjustVal(u32ModeAdd);
+ u32ModeRemove &= u32InternalMode;
+ u32ModeAdd &= ~(u32ModeRemove | u32InternalMode);
+ uint32_t u32ModeResulting = ((u32InternalMode | u32ModeAdd) & ~u32ModeRemove);
+ uint32_t u32Tmp = crPMgrModeAdjustVal(u32ModeResulting);
+ if (u32Tmp != u32ModeResulting)
+ {
+ u32ModeAdd |= (u32Tmp & ~u32ModeResulting);
+ u32ModeRemove |= (~u32Tmp & u32ModeResulting);
+ u32ModeResulting = u32Tmp;
+ Assert(u32ModeResulting == ((u32InternalMode | u32ModeAdd) & ~u32ModeRemove));
+ }
+ if (!u32ModeRemove && !u32ModeAdd)
+ return VINF_SUCCESS;
+
+ uint32_t u32DisplayMode = (g_CrPresenter.u32DisplayMode | u32ModeAdd) & ~u32ModeRemove;
+ if (!g_CrPresenter.fEnabled)
+ {
+ Assert(g_CrPresenter.u32DisplayMode == 0);
+ g_CrPresenter.u32DisabledDisplayMode = u32DisplayMode;
+ return VINF_SUCCESS;
+ }
+
+ g_CrPresenter.u32DisplayMode = u32DisplayMode;
+
+ /* disabled framebuffers may still have displays attached */
+ for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstInitialized();
+ hFb;
+ hFb = CrPMgrFbGetNextInitialized(hFb))
+ {
+ crPMgrModeModify(hFb, u32ModeAdd, u32ModeRemove);
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrClearRegionsGlobal()
+{
+ for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ int rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrFbRegionsClear(hFb);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("CrFbRegionsClear failed %d", rc));
+ }
+
+ CrFbUpdateEnd(hFb);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrModeVrdp(bool fEnable)
+{
+ uint32_t u32ModeAdd, u32ModeRemove;
+ if (fEnable)
+ {
+ u32ModeAdd = CR_PMGR_MODE_VRDP;
+ u32ModeRemove = 0;
+ }
+ else
+ {
+ u32ModeAdd = 0;
+ u32ModeRemove = CR_PMGR_MODE_VRDP;
+ }
+ return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove);
+}
+
+int CrPMgrModeRootVr(bool fEnable)
+{
+ uint32_t u32ModeAdd, u32ModeRemove;
+ if (fEnable)
+ {
+ u32ModeAdd = CR_PMGR_MODE_ROOTVR;
+ u32ModeRemove = CR_PMGR_MODE_WINDOW;
+ }
+ else
+ {
+ u32ModeAdd = CR_PMGR_MODE_WINDOW;
+ u32ModeRemove = CR_PMGR_MODE_ROOTVR;
+ }
+
+ return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove);
+}
+
+int CrPMgrModeWinVisible(bool fEnable)
+{
+ if (!g_CrPresenter.fWindowsForceHidden == !!fEnable)
+ return VINF_SUCCESS;
+
+ g_CrPresenter.fWindowsForceHidden = !fEnable;
+
+ for (int i = 0; i < cr_server.screenCount; ++i)
+ {
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
+
+ if (pDpInfo->pDpWin)
+ pDpInfo->pDpWin->winVisibilityChanged();
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrRootVrUpdate()
+{
+ for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ if (!CrFbHas3DData(hFb))
+ continue;
+
+ uint32_t idFb = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+ int rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount);
+ i >= 0;
+ i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i))
+ {
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
+ Assert(pDpInfo->iFb == (int32_t)idFb);
+
+ pDpInfo->pDpWinRootVr->RegionsChanged(hFb);
+ }
+
+ CrFbUpdateEnd(hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed %d", rc));
+ }
+
+ return VINF_SUCCESS;
+}
+
+/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */
+int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap)
+{
+ CrFBmInit(pMap);
+ for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ int rc = CrFbUpdateBegin(hFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("UpdateBegin failed, rc %d", rc));
+ for (HCR_FRAMEBUFFER hTmpFb = CrPMgrFbGetFirstEnabled();
+ hFb != hTmpFb;
+ hTmpFb = CrPMgrFbGetNextEnabled(hTmpFb))
+ {
+ CrFbUpdateEnd(hTmpFb);
+ CrFBmClear(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex);
+ }
+ return rc;
+ }
+
+ CrFBmSet(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex);
+ }
+
+ return VINF_SUCCESS;
+}
+
+/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */
+void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap)
+{
+ for (uint32_t i = 0; i < (uint32_t)cr_server.screenCount; ++i)
+ {
+ if (!CrFBmIsSet(pMap, i))
+ continue;
+
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i);
+ CRASSERT(hFb);
+ CrFbUpdateEnd(hFb);
+ }
+}
+
+int CrPMgrResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM, const uint32_t *pTargetMap)
+{
+ int rc = VINF_SUCCESS;
+
+ if (pScreen->u32ViewIndex == 0xffffffff)
+ {
+ /* this is just a request to disable targets, search and disable */
+ for (int i = ASMBitFirstSet(pTargetMap, cr_server.screenCount);
+ i >= 0;
+ i = ASMBitNextSet(pTargetMap, cr_server.screenCount, i))
+ {
+ CR_FBDISPLAY_INFO *pDpInfo = &g_CrPresenter.aDisplayInfos[i];
+ if (pDpInfo->iFb < 0)
+ continue;
+
+ Assert(pDpInfo->iFb < cr_server.screenCount);
+ HCR_FRAMEBUFFER hAssignedFb = CrPMgrFbGet(pDpInfo->iFb);
+
+ rc = crPMgrFbDisconnectTarget(hAssignedFb, (uint32_t)i);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnectTarget failed %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+ }
+
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pScreen->u32ViewIndex);
+ if (!hFb)
+ {
+ WARN(("CrPMgrFbGet failed"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ const VBVAINFOSCREEN *pFbScreen = CrFbGetScreenInfo(hFb);
+ bool fFbInfoChanged = true;
+
+ if (!memcmp(pFbScreen, pScreen, sizeof (*pScreen)))
+ {
+ if (!pvVRAM || pvVRAM == CrFbGetVRAM(hFb))
+ fFbInfoChanged = false;
+ }
+
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[pScreen->u32ViewIndex];
+
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aRemovedTargetMap);
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aAddedTargetMap);
+
+ bool fDisplaysAdded = false, fDisplaysRemoved = false;
+
+ memcpy(aRemovedTargetMap, pFbInfo->aTargetMap, sizeof (aRemovedTargetMap));
+
+ if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
+ {
+ /* so far there is no need in keeping displays attached to disabled Framebffer,
+ * just disconnect everything */
+ for (int i = 0; i < RT_ELEMENTS(aRemovedTargetMap); ++i)
+ {
+ if (aRemovedTargetMap[i])
+ {
+ fDisplaysRemoved = true;
+ break;
+ }
+ }
+
+ memset(aAddedTargetMap, 0, sizeof (aAddedTargetMap));
+ }
+ else
+ {
+ for (int i = 0; i < RT_ELEMENTS(aRemovedTargetMap); ++i)
+ {
+ aRemovedTargetMap[i] = (aRemovedTargetMap[i] & ~pTargetMap[i]);
+ if (aRemovedTargetMap[i])
+ fDisplaysRemoved = true;
+ }
+
+ memcpy(aAddedTargetMap, pFbInfo->aTargetMap, sizeof (aAddedTargetMap));
+ for (int i = 0; i < RT_ELEMENTS(aAddedTargetMap); ++i)
+ {
+ aAddedTargetMap[i] = (pTargetMap[i] & ~aAddedTargetMap[i]);
+ if (aAddedTargetMap[i])
+ fDisplaysAdded = true;
+ }
+ }
+
+ if (!fFbInfoChanged && !fDisplaysRemoved && !fDisplaysAdded)
+ {
+ crDebug("resize: no changes");
+ return VINF_SUCCESS;
+ }
+
+ if (fDisplaysRemoved)
+ {
+ rc = crPMgrFbDisconnect(hFb, aRemovedTargetMap);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbDisconnect failed %d", rc));
+ return rc;
+ }
+ }
+
+ if (fFbInfoChanged)
+ {
+#ifdef CR_SERVER_WITH_CLIENT_CALLOUTS
+ rc = crPMgrModeModify(hFb, 0, CR_PMGR_MODE_WINDOW | CR_PMGR_MODE_ROOTVR);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crPMgrModeModifyTarget failed %d", rc));
+ return rc;
+ }
+#endif
+ rc = CrFbUpdateBegin(hFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbUpdateBegin failed %d", rc));
+ return rc;
+ }
+
+ crVBoxServerMuralFbResizeBegin(hFb);
+
+ rc = CrFbResize(hFb, pScreen, pvVRAM);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbResize failed %d", rc));
+ }
+
+ crVBoxServerMuralFbResizeEnd(hFb);
+
+ CrFbUpdateEnd(hFb);
+ }
+
+ if (fDisplaysAdded)
+ {
+ rc = crPMgrFbConnect(hFb, aAddedTargetMap);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crPMgrFbConnect failed %d", rc));
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrFbEntrySaveState(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY *hEntry, PSSMHANDLE pSSM)
+{
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry);
+ CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
+ int rc = SSMR3PutU32(pSSM, pFbTex->pTobj->id);
+ AssertRCReturn(rc, rc);
+ uint32_t u32 = 0;
+
+ u32 = CrVrScrCompositorEntryFlagsGet(pEntry);
+ rc = SSMR3PutU32(pSSM, u32);
+ AssertRCReturn(rc, rc);
+
+ const RTRECT *pRect = CrVrScrCompositorEntryRectGet(pEntry);
+
+ rc = SSMR3PutS32(pSSM, pRect->xLeft);
+ AssertRCReturn(rc, rc);
+ rc = SSMR3PutS32(pSSM, pRect->yTop);
+ AssertRCReturn(rc, rc);
+#if 0
+ rc = SSMR3PutS32(pSSM, pRect->xRight);
+ AssertRCReturn(rc, rc);
+ rc = SSMR3PutS32(pSSM, pRect->yBottom);
+ AssertRCReturn(rc, rc);
+#endif
+
+ rc = CrVrScrCompositorEntryRegionsGet(&pFb->Compositor, pEntry, &u32, NULL, NULL, &pRect);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, u32);
+ AssertRCReturn(rc, rc);
+
+ if (u32)
+ {
+ rc = SSMR3PutMem(pSSM, pRect, u32 * sizeof (*pRect));
+ AssertRCReturn(rc, rc);
+ }
+ return rc;
+}
+
+int CrFbSaveState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM)
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter;
+ CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter);
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ uint32_t u32 = 0;
+ while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
+ {
+ CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ CRASSERT(pTexData);
+ CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
+ if (pFbTex->pTobj)
+ ++u32;
+ }
+
+ int rc = SSMR3PutU32(pSSM, u32);
+ AssertRCReturn(rc, rc);
+
+ CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter);
+
+ while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL)
+ {
+ CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
+ if (pFbTex->pTobj)
+ {
+ HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry);
+ rc = CrFbEntrySaveState(pFb, hEntry, pSSM);
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrSaveState(PSSMHANDLE pSSM)
+{
+ int rc;
+ int cDisplays = 0, i;
+
+ for (i = 0; i < cr_server.screenCount; ++i)
+ {
+ if (CrPMgrFbGetEnabled(i))
+ ++cDisplays;
+ }
+
+ rc = SSMR3PutS32(pSSM, cDisplays);
+ AssertRCReturn(rc, rc);
+
+ if (!cDisplays)
+ return VINF_SUCCESS;
+
+ rc = SSMR3PutS32(pSSM, cr_server.screenCount);
+ AssertRCReturn(rc, rc);
+
+ for (i = 0; i < cr_server.screenCount; ++i)
+ {
+ CR_FRAMEBUFFER *hFb = CrPMgrFbGetEnabled(i);
+ if (hFb)
+ {
+ Assert(hFb->ScreenInfo.u32ViewIndex == i);
+ rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32ViewIndex);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginX);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginY);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32StartOffset);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32LineSize);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Width);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Height);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16BitsPerPixel);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16Flags);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32StartOffset);
+ AssertRCReturn(rc, rc);
+
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[hFb->ScreenInfo.u32ViewIndex];
+ rc = SSMR3PutMem(pSSM, pFbInfo->aTargetMap, sizeof (pFbInfo->aTargetMap));
+ AssertRCReturn(rc, rc);
+
+ rc = CrFbSaveState(hFb, pSSM);
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+int CrFbEntryLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version)
+{
+ uint32_t texture;
+ int rc = SSMR3GetU32(pSSM, &texture);
+ AssertRCReturn(rc, rc);
+
+ uint32_t fFlags;
+ rc = SSMR3GetU32(pSSM, &fFlags);
+ AssertRCReturn(rc, rc);
+
+
+ HCR_FRAMEBUFFER_ENTRY hEntry;
+
+ rc = CrFbEntryCreateForTexId(pFb, texture, fFlags, &hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryCreateForTexId Failed"));
+ return rc;
+ }
+
+ Assert(hEntry);
+
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry);
+ CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData);
+
+ RTPOINT Point;
+ rc = SSMR3GetS32(pSSM, &Point.x);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetS32(pSSM, &Point.y);
+ AssertRCReturn(rc, rc);
+
+ uint32_t cRects;
+ rc = SSMR3GetU32(pSSM, &cRects);
+ AssertRCReturn(rc, rc);
+
+ RTRECT * pRects = NULL;
+ if (cRects)
+ {
+ pRects = (RTRECT *)crAlloc(cRects * sizeof (*pRects));
+ AssertReturn(pRects, VERR_NO_MEMORY);
+
+ rc = SSMR3GetMem(pSSM, pRects, cRects * sizeof (*pRects));
+ AssertRCReturn(rc, rc);
+ }
+
+ rc = CrFbEntryRegionsSet(pFb, hEntry, &Point, cRects, pRects, false);
+ AssertRCReturn(rc, rc);
+
+ if (pRects)
+ crFree(pRects);
+
+ CrFbEntryRelease(pFb, hEntry);
+
+ return VINF_SUCCESS;
+}
+
+int CrFbLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version)
+{
+ uint32_t u32 = 0;
+ int rc = SSMR3GetU32(pSSM, &u32);
+ AssertRCReturn(rc, rc);
+
+ if (!u32)
+ return VINF_SUCCESS;
+
+ rc = CrFbUpdateBegin(pFb);
+ AssertRCReturn(rc, rc);
+
+ for (uint32_t i = 0; i < u32; ++i)
+ {
+ rc = CrFbEntryLoadState(pFb, pSSM, version);
+ AssertRCReturn(rc, rc);
+ }
+
+ CrFbUpdateEnd(pFb);
+
+ return VINF_SUCCESS;
+}
+
+int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version)
+{
+ int rc;
+ int cDisplays, screenCount, i;
+
+ rc = SSMR3GetS32(pSSM, &cDisplays);
+ AssertRCReturn(rc, rc);
+
+ if (!cDisplays)
+ return VINF_SUCCESS;
+
+ rc = SSMR3GetS32(pSSM, &screenCount);
+ AssertRCReturn(rc, rc);
+
+ CRASSERT(screenCount == cr_server.screenCount);
+
+ CRScreenInfo screen[CR_MAX_GUEST_MONITORS];
+
+ if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO)
+ {
+ for (i = 0; i < cr_server.screenCount; ++i)
+ {
+ rc = SSMR3GetS32(pSSM, &screen[i].x);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetS32(pSSM, &screen[i].y);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &screen[i].w);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &screen[i].h);
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ for (i = 0; i < cDisplays; ++i)
+ {
+ int iScreen;
+
+ rc = SSMR3GetS32(pSSM, &iScreen);
+ AssertRCReturn(rc, rc);
+
+ CR_FRAMEBUFFER *pFb = CrPMgrFbGet(iScreen);
+ Assert(pFb);
+
+ VBVAINFOSCREEN Screen;
+
+ Screen.u32ViewIndex = iScreen;
+
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
+
+ memset(aTargetMap, 0, sizeof (aTargetMap));
+ ASMBitSet(aTargetMap, iScreen);
+
+ if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO)
+ {
+ memset(&Screen, 0, sizeof (Screen));
+ Screen.u32LineSize = 4 * screen[iScreen].w;
+ Screen.u32Width = screen[iScreen].w;
+ Screen.u32Height = screen[iScreen].h;
+ Screen.u16BitsPerPixel = 4;
+ Screen.u16Flags = VBVA_SCREEN_F_ACTIVE;
+ }
+ else
+ {
+ rc = SSMR3GetS32(pSSM, &Screen.i32OriginX);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetS32(pSSM, &Screen.i32OriginY);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &Screen.u32LineSize);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &Screen.u32Width);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &Screen.u32Height);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU16(pSSM, &Screen.u16BitsPerPixel);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU16(pSSM, &Screen.u16Flags);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset);
+ AssertRCReturn(rc, rc);
+ if (Screen.u32StartOffset == 0xffffffff)
+ {
+ WARN(("not expected offVram"));
+ Screen.u32StartOffset = 0;
+ }
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_MAP_REORDERED)
+ {
+ rc = SSMR3GetMem(pSSM, aTargetMap, sizeof (aTargetMap));
+ AssertRCReturn(rc, rc);
+ }
+
+ if (version == SHCROGL_SSM_VERSION_WITH_SCREEN_MAP)
+ {
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aEmptyTargetMap);
+
+ memset(aEmptyTargetMap, 0, sizeof (aEmptyTargetMap));
+
+ rc = CrPMgrResize(&Screen, cr_server.fCrCmdEnabled ? NULL : CrFbGetVRAM(pFb), aEmptyTargetMap);
+ AssertRCReturn(rc, rc);
+
+ rc = CrFbLoadState(pFb, pSSM, version);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3GetMem(pSSM, aTargetMap, sizeof (aTargetMap));
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ rc = CrPMgrResize(&Screen, cr_server.fCrCmdEnabled ? NULL : CrFbGetVRAM(pFb), aTargetMap);
+ AssertRCReturn(rc, rc);
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_FB_INFO && version != SHCROGL_SSM_VERSION_WITH_SCREEN_MAP)
+ {
+ rc = CrFbLoadState(pFb, pSSM, version);
+ AssertRCReturn(rc, rc);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects)
+{
+ uint32_t idFb = CR_PRESENT_GET_SCREEN(cfg);
+ if (idFb >= CR_MAX_GUEST_MONITORS)
+ {
+ WARN(("Invalid guest screen"));
+ return;
+ }
+
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idFb);
+ if (!hFb)
+ {
+ WARN(("request to present on disabled framebuffer, ignore"));
+ return;
+ }
+
+ HCR_FRAMEBUFFER_ENTRY hEntry;
+ int rc;
+ if (texture)
+ {
+ rc = CrFbEntryCreateForTexId(hFb, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS, &hEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ LOG(("CrFbEntryCreateForTexId Failed"));
+ return;
+ }
+
+ Assert(hEntry);
+
+#if 0
+ if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS))
+ {
+ CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex);
+ }
+#endif
+ }
+ else
+ hEntry = NULL;
+
+ rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS))
+ {
+ RTPOINT Point = {xPos, yPos};
+ rc = CrFbEntryRegionsAdd(hFb, hEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, false);
+ }
+ else
+ {
+ CrFbRegionsClear(hFb);
+ }
+
+ CrFbUpdateEnd(hFb);
+ }
+ else
+ {
+ WARN(("CrFbUpdateBegin Failed"));
+ }
+
+ if (hEntry)
+ CrFbEntryRelease(hFb, hEntry);
+}
+
+DECLINLINE(void) crVBoxPRectUnpack(const VBOXCMDVBVA_RECT *pVbvaRect, RTRECT *pRect)
+{
+ pRect->xLeft = pVbvaRect->xLeft;
+ pRect->yTop = pVbvaRect->yTop;
+ pRect->xRight = pVbvaRect->xRight;
+ pRect->yBottom = pVbvaRect->yBottom;
+}
+
+DECLINLINE(void) crVBoxPRectUnpacks(const VBOXCMDVBVA_RECT *paVbvaRects, RTRECT *paRects, uint32_t cRects)
+{
+ uint32_t i = 0;
+ for (; i < cRects; ++i)
+ {
+ crVBoxPRectUnpack(&paVbvaRects[i], &paRects[i]);
+ }
+}
+
+static RTRECT * crVBoxServerCrCmdBltRecsUnpack(const VBOXCMDVBVA_RECT *pPRects, uint32_t cRects)
+{
+ if (g_CrPresenter.cbTmpBuf < cRects * sizeof (RTRECT))
+ {
+ if (g_CrPresenter.pvTmpBuf)
+ RTMemFree(g_CrPresenter.pvTmpBuf);
+
+ g_CrPresenter.cbTmpBuf = (cRects + 10) * sizeof (RTRECT);
+ g_CrPresenter.pvTmpBuf = RTMemAlloc(g_CrPresenter.cbTmpBuf);
+ if (!g_CrPresenter.pvTmpBuf)
+ {
+ WARN(("RTMemAlloc failed!"));
+ g_CrPresenter.cbTmpBuf = 0;
+ return NULL;
+ }
+ }
+
+ RTRECT *pRects = (RTRECT *)g_CrPresenter.pvTmpBuf;
+ crVBoxPRectUnpacks(pPRects, pRects, cRects);
+
+ return pRects;
+}
+
+static void crPMgrPrimaryUpdateScreen(HCR_FRAMEBUFFER hFb, uint32_t idScreen, uint32_t cRects, const RTRECT *pRects)
+{
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+
+ bool fDirtyEmpty = true;
+ RTRECT dirtyRect = {0};
+ cr_server.CrCmdClientInfo.pfnCltScrUpdateBegin(cr_server.CrCmdClientInfo.hCltScr, idScreen);
+
+ VBVACMDHDR hdr;
+ for (uint32_t i = 0; i < cRects; ++i)
+ {
+ hdr.x = pRects[i].xLeft;
+ hdr.y = pRects[i].yTop;
+ hdr.w = hdr.x + pRects[i].xRight;
+ hdr.h = hdr.y + pRects[i].yBottom;
+
+ cr_server.CrCmdClientInfo.pfnCltScrUpdateProcess(cr_server.CrCmdClientInfo.hCltScr, idScreen, &hdr, sizeof (hdr));
+
+ if (fDirtyEmpty)
+ {
+ /* This is the first rectangle to be added. */
+ dirtyRect.xLeft = pRects[i].xLeft;
+ dirtyRect.yTop = pRects[i].yTop;
+ dirtyRect.xRight = pRects[i].xRight;
+ dirtyRect.yBottom = pRects[i].yBottom;
+ fDirtyEmpty = false;
+ }
+ else
+ {
+ /* Adjust region coordinates. */
+ if (dirtyRect.xLeft > pRects[i].xLeft)
+ {
+ dirtyRect.xLeft = pRects[i].xLeft;
+ }
+
+ if (dirtyRect.yTop > pRects[i].yTop)
+ {
+ dirtyRect.yTop = pRects[i].yTop;
+ }
+
+ if (dirtyRect.xRight < pRects[i].xRight)
+ {
+ dirtyRect.xRight = pRects[i].xRight;
+ }
+
+ if (dirtyRect.yBottom < pRects[i].yBottom)
+ {
+ dirtyRect.yBottom = pRects[i].yBottom;
+ }
+ }
+ }
+
+ if (dirtyRect.xRight - dirtyRect.xLeft)
+ {
+ cr_server.CrCmdClientInfo.pfnCltScrUpdateEnd(cr_server.CrCmdClientInfo.hCltScr, idScreen, pScreen->i32OriginX + dirtyRect.xLeft, pScreen->i32OriginY + dirtyRect.yTop,
+ dirtyRect.xRight - dirtyRect.xLeft, dirtyRect.yBottom - dirtyRect.yTop);
+ }
+ else
+ {
+ cr_server.CrCmdClientInfo.pfnCltScrUpdateEnd(cr_server.CrCmdClientInfo.hCltScr, idScreen, 0, 0, 0, 0);
+ }
+
+}
+
+static void crPMgrPrimaryUpdate(HCR_FRAMEBUFFER hFb, uint32_t cRects, const RTRECT *pRects)
+{
+ if (!cRects)
+ return;
+
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+
+ uint32_t idFb = pScreen->u32ViewIndex;
+ CR_FB_INFO *pFbInfo = &g_CrPresenter.aFbInfos[idFb];
+
+ for (int i = ASMBitFirstSet(pFbInfo->aTargetMap, cr_server.screenCount);
+ i >= 0;
+ i = ASMBitNextSet(pFbInfo->aTargetMap, cr_server.screenCount, i))
+ {
+ crPMgrPrimaryUpdateScreen(hFb, i, cRects, pRects);
+ }
+}
+
+static int8_t crVBoxServerCrCmdBltPrimaryVramGenericProcess(uint32_t u32PrimaryID, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects, bool fToPrimary)
+{
+ CR_BLITTER_IMG Img;
+ int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID);
+ if (!hFb)
+ {
+ WARN(("request to present on disabled framebuffer"));
+ return -1;
+ }
+
+ if (!fToPrimary)
+ {
+ int rc = CrFbBltGetContents(hFb, pPos, cRects, pRects, &Img);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbBltGetContents failed %d", rc));
+ return -1;
+ }
+
+ return 0;
+ }
+
+ int rc = CrFbBltPutContentsNe(hFb, pPos, cRects, pRects, &Img);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbBltPutContentsNe failed %d", rc));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdBltPrimaryProcess(const VBOXCMDVBVA_BLT_PRIMARY *pCmd, uint32_t cbCmd)
+{
+ uint32_t u32PrimaryID = (uint32_t)pCmd->Hdr.Hdr.u.u8PrimaryID;
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID);
+ if (!hFb)
+ {
+ WARN(("request to present on disabled framebuffer, ignore"));
+ return 0;
+ }
+
+ uint32_t cRects;
+ const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
+ if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) % sizeof (VBOXCMDVBVA_RECT))
+ {
+ WARN(("invalid argument size"));
+ return -1;
+ }
+
+ cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) / sizeof (VBOXCMDVBVA_RECT);
+
+ RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
+ if (!pRects)
+ {
+ WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
+ return -1;
+ }
+
+ uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
+
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID)
+ {
+ uint32_t texId = pCmd->alloc.u.id;
+ if (!texId)
+ {
+ WARN(("texId is NULL!\n"));
+ return -1;
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
+ {
+ WARN(("blit from primary to texture not implemented"));
+ return -1;
+ }
+
+ crServerDispatchVBoxTexPresent(texId, u32PrimaryID, pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y, cRects, (const GLint*)pRects);
+
+ return 0;
+ }
+ else
+ {
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+ uint32_t width = pScreen->u32Width, height = pScreen->u32Height;
+ VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc.u.offVRAM;
+
+ bool fToPrymary = !(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2);
+ RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
+ int8_t i8Result = crVBoxServerCrCmdBltPrimaryVramGenericProcess(u32PrimaryID, offVRAM, width, height, &Pos, cRects, pRects, fToPrymary);
+ if (i8Result < 0)
+ {
+ WARN(("crVBoxServerCrCmdBltPrimaryVramGenericProcess failed"));
+ return i8Result;
+ }
+
+ if (!fToPrymary)
+ return 0;
+ }
+
+ crPMgrPrimaryUpdate(hFb, cRects, pRects);
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdBltIdToVramMem(uint32_t hostId, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
+{
+ CR_TEXDATA* pTex = CrFbTexDataAcquire(hostId);
+ if (!pTex)
+ {
+ WARN(("pTex failed for %d", hostId));
+ return -1;
+ }
+
+ const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex);
+ if (!width)
+ {
+ width = pVrTex->width;
+ height = pVrTex->height;
+ }
+
+ CR_BLITTER_IMG Img;
+ int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ int rc = CrTdBltEnter(pTex);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrTdBltEnter failed %d", rc));
+ return -1;
+ }
+
+ rc = crFbTexDataGetContents(pTex, pPos, cRects, pRects, &Img);
+
+ CrTdBltLeave(pTex);
+
+ CrTdRelease(pTex);
+
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crFbTexDataGetContents failed %d", rc));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdBltIdToVram(uint32_t hostId, VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledByVramStart(offVRAM);
+ if (hFb)
+ {
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+ Assert(!width || pScreen->u32Width == width);
+ Assert(!height || pScreen->u32Height == height);
+
+ crServerDispatchVBoxTexPresent(hostId, pScreen->u32ViewIndex, pPos->x, pPos->y, cRects, (const GLint*)pRects);
+ return 0;
+ }
+
+ return crVBoxServerCrCmdBltIdToVramMem(hostId, offVRAM, width, height, pPos, cRects, pRects);
+}
+
+static int8_t crVBoxServerCrCmdBltVramToVramMem(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight, VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight, const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
+{
+ CR_BLITTER_IMG srcImg, dstImg;
+ int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &srcImg);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &dstImg);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ CrMBltImg(&srcImg, pPos, cRects, pRects, &dstImg);
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdBltVramToVram(VBOXCMDVBVAOFFSET offSrcVRAM, uint32_t srcWidth, uint32_t srcHeight,
+ VBOXCMDVBVAOFFSET offDstVRAM, uint32_t dstWidth, uint32_t dstHeight,
+ const RTPOINT *pPos, uint32_t cRects, const RTRECT *pRects)
+{
+ HCR_FRAMEBUFFER hSrcFb = CrPMgrFbGetEnabledByVramStart(offSrcVRAM);
+ HCR_FRAMEBUFFER hDstFb = CrPMgrFbGetEnabledByVramStart(offDstVRAM);
+
+ if (hDstFb)
+ {
+ if (hSrcFb)
+ {
+ LOG(("blit from one framebuffer, wow"));
+
+ int rc = CrFbUpdateBegin(hSrcFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbRegionsClear(hSrcFb);
+
+ CrFbUpdateEnd(hSrcFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed %d", rc));
+ }
+
+ CR_BLITTER_IMG Img;
+ int8_t i8Result = crFbImgFromDimOffVramBGRA(offSrcVRAM, srcWidth, srcHeight, &Img);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hDstFb);
+ if (pScreen->u32Width == dstWidth && pScreen->u32Height == dstHeight)
+ {
+ int rc = CrFbBltPutContentsNe(hDstFb, pPos, cRects, pRects, &Img);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("CrFbBltPutContentsNe failed %d", rc));
+ return -1;
+ }
+ }
+ else
+ {
+ int rc = CrFbUpdateBegin(hDstFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbRegionsClear(hDstFb);
+
+ CrFbUpdateEnd(hDstFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed %d", rc));
+
+ rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc));
+ return -1;
+ }
+ }
+
+ crPMgrPrimaryUpdate(hDstFb, cRects, pRects);
+
+ return 0;
+ }
+ else if (hSrcFb)
+ {
+ CR_BLITTER_IMG Img;
+ int8_t i8Result = crFbImgFromDimOffVramBGRA(offDstVRAM, dstWidth, dstHeight, &Img);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hSrcFb);
+ if (pScreen->u32Width == srcWidth && pScreen->u32Height == srcHeight)
+ {
+ int rc = CrFbBltGetContents(hSrcFb, pPos, cRects, pRects, &Img);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("CrFbBltGetContents failed %d", rc));
+ return -1;
+ }
+ }
+ else
+ {
+ int rc = CrFbUpdateBegin(hSrcFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbRegionsClear(hSrcFb);
+
+ CrFbUpdateEnd(hSrcFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed %d", rc));
+
+ rc = crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerCrCmdBltVramToVramMem failed, %d", rc));
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+
+ return crVBoxServerCrCmdBltVramToVramMem(offSrcVRAM, srcWidth, srcHeight, offDstVRAM, dstWidth, dstHeight, pPos, cRects, pRects);
+}
+
+
+static int8_t crVBoxServerCrCmdBltOffIdProcess(const VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *pCmd, uint32_t cbCmd)
+{
+ uint32_t cRects;
+ const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
+ if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects)) % sizeof (VBOXCMDVBVA_RECT))
+ {
+ WARN(("invalid argument size"));
+ return -1;
+ }
+
+ cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID, aRects)) / sizeof (VBOXCMDVBVA_RECT);
+
+ RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
+ if (!pRects)
+ {
+ WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
+ return -1;
+ }
+
+ uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
+ uint32_t hostId = pCmd->id;
+
+ Assert(u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID);
+
+ if (!hostId)
+ {
+ WARN(("zero host id"));
+ return -1;
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
+ {
+ WARN(("blit from texture to texture not implemented"));
+ return -1;
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
+ {
+ WARN(("blit to texture not implemented"));
+ return -1;
+ }
+
+ VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc.u.offVRAM;
+
+ RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
+ return crVBoxServerCrCmdBltIdToVram(hostId, offVRAM, 0, 0, &Pos, cRects, pRects);
+}
+
+static int8_t crVBoxServerCrCmdBltSameDimOrId(const VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8 *pCmd, uint32_t cbCmd)
+{
+ uint32_t cRects;
+ const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
+ if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT))
+ {
+ WARN(("invalid argument size"));
+ return -1;
+ }
+
+ cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT);
+
+ RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
+ if (!pRects)
+ {
+ WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
+ return -1;
+ }
+
+ uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
+ VBOXCMDVBVAOFFSET offVRAM = pCmd->alloc1.Info.u.offVRAM;
+ uint32_t width = pCmd->alloc1.u16Width;
+ uint32_t height = pCmd->alloc1.u16Height;
+ RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
+
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID)
+ {
+ uint32_t hostId = pCmd->info2.u.id;
+
+ if (!hostId)
+ {
+ WARN(("zero host id"));
+ return -1;
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
+ {
+ WARN(("blit from texture to texture not implemented"));
+ return -1;
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
+ {
+ WARN(("blit to texture not implemented"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdBltIdToVram(hostId, offVRAM, width, height, &Pos, cRects, pRects);
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
+ {
+ if (!(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2))
+ {
+ WARN(("blit to texture not implemented"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdBltIdToVram(pCmd->alloc1.Info.u.id, pCmd->info2.u.offVRAM, width, height, &Pos, cRects, pRects);
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
+ crVBoxServerCrCmdBltVramToVram(offVRAM, width, height, pCmd->info2.u.offVRAM, width, height, &Pos, cRects, pRects);
+ else
+ crVBoxServerCrCmdBltVramToVram(pCmd->info2.u.offVRAM, width, height, offVRAM, width, height, &Pos, cRects, pRects);
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdBltGenericBGRAProcess(const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd)
+{
+ uint32_t cRects;
+ const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
+ if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT))
+ {
+ WARN(("invalid argument size"));
+ return -1;
+ }
+
+ cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT);
+
+ RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
+ if (!pRects)
+ {
+ WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
+ return -1;
+ }
+
+ uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
+ RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
+
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND2_ISID)
+ {
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
+ {
+ WARN(("blit from texture to texture not implemented"));
+ return -1;
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
+ {
+ WARN(("blit to texture not implemented"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdBltIdToVram(pCmd->alloc2.Info.u.id, pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, &Pos, cRects, pRects);
+ }
+ else
+ {
+ if (u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
+ {
+ if (!(u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2))
+ {
+ WARN(("blit to texture not implemented"));
+ return -1;
+ }
+
+ RTPOINT Pos = {pCmd->Hdr.Pos.x, pCmd->Hdr.Pos.y};
+ return crVBoxServerCrCmdBltIdToVram(pCmd->alloc1.Info.u.id, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects);
+ }
+
+ if (u8Flags & VBOXCMDVBVA_OPF_BLT_DIR_IN_2)
+ crVBoxServerCrCmdBltVramToVram(pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, &Pos, cRects, pRects);
+ else
+ crVBoxServerCrCmdBltVramToVram(pCmd->alloc2.Info.u.offVRAM, pCmd->alloc2.u16Width, pCmd->alloc2.u16Height, pCmd->alloc1.Info.u.offVRAM, pCmd->alloc1.u16Width, pCmd->alloc1.u16Height, &Pos, cRects, pRects);
+
+ return 0;
+ }
+}
+
+static int8_t crVBoxServerCrCmdClrFillPrimaryGenericProcess(uint32_t u32PrimaryID, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32PrimaryID);
+ if (!hFb)
+ {
+ WARN(("request to present on disabled framebuffer, ignore"));
+ return 0;
+ }
+
+ int rc = CrFbClrFillNe(hFb, cRects, pRects, u32Color);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbClrFillNe failed %d", rc));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdClrFillVramGenericProcess(VBOXCMDVBVAOFFSET offVRAM, uint32_t width, uint32_t height, const RTRECT *pRects, uint32_t cRects, uint32_t u32Color)
+{
+ CR_BLITTER_IMG Img;
+ int8_t i8Result = crFbImgFromDimOffVramBGRA(offVRAM, width, height, &Img);
+ if (i8Result)
+ {
+ WARN(("invalid param"));
+ return -1;
+ }
+
+ CrMClrFillImg(&Img, cRects, pRects, u32Color);
+
+ return 0;
+}
+
+static int8_t crVBoxServerCrCmdClrFillGenericBGRAProcess(const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8 *pCmd, uint32_t cbCmd)
+{
+ uint32_t cRects;
+ const VBOXCMDVBVA_RECT *pPRects = pCmd->aRects;
+ if ((cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8, aRects)) % sizeof (VBOXCMDVBVA_RECT))
+ {
+ WARN(("invalid argument size"));
+ return -1;
+ }
+
+ cRects = (cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8, aRects)) / sizeof (VBOXCMDVBVA_RECT);
+
+ RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
+ if (!pRects)
+ {
+ WARN(("crVBoxServerCrCmdBltRecsUnpack failed"));
+ return -1;
+ }
+
+// uint8_t u8Flags = pCmd->Hdr.Hdr.u8Flags;
+ int8_t i8Result = crVBoxServerCrCmdClrFillVramGenericProcess(pCmd->dst.Info.u.offVRAM, pCmd->dst.u16Width, pCmd->dst.u16Height, pRects, cRects, pCmd->Hdr.u32Color);
+ if (i8Result < 0)
+ {
+ WARN(("crVBoxServerCrCmdClrFillVramGenericProcess failed"));
+ return i8Result;
+ }
+
+ return 0;
+}
+
+/** @todo RT_UNTRUSTED_VOLATILE_GUEST */
+int8_t crVBoxServerCrCmdClrFillProcess(VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd)
+{
+ VBOXCMDVBVA_CLRFILL_HDR const *pCmd = (VBOXCMDVBVA_CLRFILL_HDR const *)pCmdTodo;
+ uint8_t u8Flags = pCmd->Hdr.u8Flags;
+ uint8_t u8Cmd = (VBOXCMDVBVA_OPF_CLRFILL_TYPE_MASK & u8Flags);
+
+ switch (u8Cmd)
+ {
+ case VBOXCMDVBVA_OPF_CLRFILL_TYPE_GENERIC_A8R8G8B8:
+ {
+ if (cbCmd < sizeof (VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8))
+ {
+ WARN(("VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8: invalid command size"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdClrFillGenericBGRAProcess((const VBOXCMDVBVA_CLRFILL_GENERIC_A8R8G8B8*)pCmd, cbCmd);
+ }
+ default:
+ WARN(("unsupported command"));
+ return -1;
+ }
+
+}
+
+/** @todo RT_UNTRUSTED_VOLATILE_GUEST */
+int8_t crVBoxServerCrCmdBltProcess(VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd)
+{
+ VBOXCMDVBVA_BLT_HDR const *pCmd = (VBOXCMDVBVA_BLT_HDR const *)pCmdTodo;
+ uint8_t u8Flags = pCmd->Hdr.u8Flags;
+ uint8_t u8Cmd = (VBOXCMDVBVA_OPF_BLT_TYPE_MASK & u8Flags);
+
+ switch (u8Cmd)
+ {
+ case VBOXCMDVBVA_OPF_BLT_TYPE_SAMEDIM_A8R8G8B8:
+ {
+ if (cbCmd < sizeof (VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8))
+ {
+ WARN(("VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8: invalid command size"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdBltSameDimOrId((const VBOXCMDVBVA_BLT_SAMEDIM_A8R8G8B8 *)pCmd, cbCmd);
+ }
+ case VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID:
+ {
+ if (cbCmd < sizeof (VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID))
+ {
+ WARN(("VBOXCMDVBVA_OPF_BLT_TYPE_OFFPRIMSZFMT_OR_ID: invalid command size"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdBltOffIdProcess((const VBOXCMDVBVA_BLT_OFFPRIMSZFMT_OR_ID *)pCmd, cbCmd);
+ }
+ case VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8:
+ {
+ if (cbCmd < sizeof (VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8))
+ {
+ WARN(("VBOXCMDVBVA_OPF_BLT_TYPE_GENERIC_A8R8G8B8: invalid command size"));
+ return -1;
+ }
+
+ return crVBoxServerCrCmdBltGenericBGRAProcess((const VBOXCMDVBVA_BLT_GENERIC_A8R8G8B8 *)pCmd, cbCmd);
+ }
+ default:
+ WARN(("unsupported command"));
+ return -1;
+ }
+}
+
+/** @todo RT_UNTRUSTED_VOLATILE_GUEST */
+int8_t crVBoxServerCrCmdFlipProcess(VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *pFlipTodo, uint32_t cbCmd)
+{
+ VBOXCMDVBVA_FLIP const *pFlip = (VBOXCMDVBVA_FLIP const *)pFlipTodo;
+ uint32_t hostId;
+ const VBOXCMDVBVA_RECT *pPRects = pFlip->aRects;
+ uint32_t cRects;
+
+ if (pFlip->Hdr.u8Flags & VBOXCMDVBVA_OPF_OPERAND1_ISID)
+ {
+ hostId = pFlip->src.u.id;
+ if (!hostId)
+ {
+ WARN(("hostId is NULL"));
+ return -1;
+ }
+ }
+ else
+ {
+ WARN(("VBOXCMDVBVA_OPF_ALLOC_SRCID not specified"));
+ hostId = 0;
+ }
+
+ uint32_t idFb = pFlip->Hdr.u.u8PrimaryID;
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idFb);
+ if (!hFb)
+ {
+ WARN(("request to present on disabled framebuffer, ignore"));
+ return 0;
+ }
+
+ cRects = (cbCmd - VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN) / sizeof (VBOXCMDVBVA_RECT);
+ if (cRects > 0)
+ {
+ RTRECT *pRects = crVBoxServerCrCmdBltRecsUnpack(pPRects, cRects);
+ if (pRects)
+ {
+ crServerDispatchVBoxTexPresent(hostId, idFb, 0, 0, cRects, (const GLint*)pRects);
+ return 0;
+ }
+ }
+ else
+ {
+ /* Prior to r100476 guest WDDM driver was not supplying us with sub-rectangles
+ * data obtained in DxgkDdiPresentNew() callback. Therefore, in order to support backward compatibility,
+ * lets play in old way if no rectangles were supplied. */
+ const RTRECT *pRect = CrVrScrCompositorRectGet(&hFb->Compositor);
+ crServerDispatchVBoxTexPresent(hostId, idFb, 0, 0, 1, (const GLint*)pRect);
+ }
+
+ return -1;
+}
+
+typedef struct CRSERVER_CLIENT_CALLOUT
+{
+ VBOXCRCMDCTL_CALLOUT_LISTENTRY Entry;
+ PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb;
+ void*pvCb;
+} CRSERVER_CLIENT_CALLOUT;
+
+static DECLCALLBACK(void) crServerClientCalloutCb(struct VBOXCRCMDCTL_CALLOUT_LISTENTRY *pEntry)
+{
+ CRSERVER_CLIENT_CALLOUT *pCallout = RT_FROM_MEMBER(pEntry, CRSERVER_CLIENT_CALLOUT, Entry);
+ pCallout->pfnCb(pCallout->pvCb);
+ int rc = RTSemEventSignal(cr_server.hCalloutCompletionEvent);
+ if (RT_FAILURE(rc))
+ WARN(("RTSemEventSignal failed rc %d", rc));
+}
+
+static DECLCALLBACK(void) crServerClientCallout(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void*pvCb)
+{
+ Assert(cr_server.pCurrentCalloutCtl);
+ CRSERVER_CLIENT_CALLOUT Callout;
+ Callout.pfnCb = pfnCb;
+ Callout.pvCb = pvCb;
+ cr_server.ClientInfo.pfnCallout(cr_server.ClientInfo.hClient, cr_server.pCurrentCalloutCtl, &Callout.Entry, crServerClientCalloutCb);
+
+ int rc = RTSemEventWait(cr_server.hCalloutCompletionEvent, RT_INDEFINITE_WAIT);
+ if (RT_FAILURE(rc))
+ WARN(("RTSemEventWait failed %d", rc));
+}
+
+
+DECLEXPORT(void) crVBoxServerCalloutEnable(VBOXCRCMDCTL *pCtl)
+{
+#if 1 //def CR_SERVER_WITH_CLIENT_CALLOUTS
+ Assert(!cr_server.pCurrentCalloutCtl);
+ cr_server.pCurrentCalloutCtl = pCtl;
+
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_CLIENT_CALLOUT, 0, 0, (void*)crServerClientCallout);
+#endif
+}
+
+extern DECLEXPORT(void) crVBoxServerCalloutDisable()
+{
+#if 1 //def CR_SERVER_WITH_CLIENT_CALLOUTS
+ Assert(cr_server.pCurrentCalloutCtl);
+
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_CLIENT_CALLOUT, 0, 0, NULL);
+
+ cr_server.pCurrentCalloutCtl = NULL;
+#endif
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h
new file mode 100644
index 00000000..759f8dbd
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h
@@ -0,0 +1,440 @@
+/* $Id: server_presenter.h $ */
+
+/** @file
+ * Presenter API definitions.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef __SERVER_PRESENTER_H__
+#define __SERVER_PRESENTER_H__
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_net.h"
+#include "cr_rand.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+#include <cr_vreg.h>
+#include <cr_htable.h>
+#include <cr_bmpscale.h>
+
+#include "render/renderspu.h"
+
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+#include <iprt/asm.h>
+#include <iprt/mem.h>
+#include <iprt/list.h>
+
+
+class ICrFbDisplay
+{
+ public:
+ virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) = 0;
+ virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) = 0;
+
+ virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0;
+ virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0;
+ virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) = 0;
+ virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0;
+ virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0;
+ virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0;
+ virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0;
+
+ virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) = 0;
+
+ virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) = 0;
+
+ virtual ~ICrFbDisplay() {}
+};
+
+
+typedef struct CR_FRAMEBUFFER
+{
+ VBOXVR_SCR_COMPOSITOR Compositor;
+ struct VBVAINFOSCREEN ScreenInfo;
+ void *pvVram;
+ ICrFbDisplay *pDisplay;
+ RTLISTNODE EntriesList;
+ uint32_t cEntries; /* <- just for debugging */
+ uint32_t cUpdating;
+ CRHTABLE SlotTable;
+} CR_FRAMEBUFFER;
+
+
+typedef union CR_FBENTRY_FLAGS
+{
+ struct {
+ uint32_t fCreateNotified : 1;
+ uint32_t fInList : 1;
+ uint32_t Reserved : 30;
+ };
+ uint32_t Value;
+} CR_FBENTRY_FLAGS;
+
+
+typedef struct CR_FRAMEBUFFER_ENTRY
+{
+ VBOXVR_SCR_COMPOSITOR_ENTRY Entry;
+ RTLISTNODE Node;
+ uint32_t cRefs;
+ CR_FBENTRY_FLAGS Flags;
+ CRHTABLE HTable;
+} CR_FRAMEBUFFER_ENTRY;
+
+
+typedef struct CR_FBTEX
+{
+ CR_TEXDATA Tex;
+ CRTextureObj *pTobj;
+} CR_FBTEX;
+
+
+class CrFbDisplayBase : public ICrFbDisplay
+{
+ public:
+
+ CrFbDisplayBase();
+
+ virtual bool isComposite();
+ class CrFbDisplayComposite* getContainer();
+ bool isInList();
+ bool isUpdating();
+ int setRegionsChanged();
+ int setFramebuffer(struct CR_FRAMEBUFFER *pFb);
+ struct CR_FRAMEBUFFER* getFramebuffer();
+ virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb);
+ virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb);
+ virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry);
+ virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb);
+ virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb);
+ virtual ~CrFbDisplayBase();
+
+ /*@todo: move to protected and switch from RTLISTNODE*/
+ RTLISTNODE mNode;
+ class CrFbDisplayComposite* mpContainer;
+
+ protected:
+
+ virtual void onUpdateEnd();
+ virtual void ueRegions();
+ static DECLCALLBACK(bool) entriesCreateCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);
+ static DECLCALLBACK(bool) entriesDestroyCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);
+ int fbSynchAddAllEntries();
+ int fbCleanupRemoveAllEntries();
+ virtual int setFramebufferBegin(struct CR_FRAMEBUFFER *pFb);
+ virtual void setFramebufferEnd(struct CR_FRAMEBUFFER *pFb);
+ static DECLCALLBACK(void) slotEntryReleaseCB(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);
+ virtual void slotRelease();
+ virtual int fbCleanup();
+ virtual int fbSync();
+ CRHTABLE_HANDLE slotGet();
+
+ private:
+
+ typedef union CR_FBDISPBASE_FLAGS
+ {
+ struct {
+ uint32_t fRegionsShanged : 1;
+ uint32_t Reserved : 31;
+ };
+ uint32_t u32Value;
+ } CR_FBDISPBASE_FLAGS;
+
+ struct CR_FRAMEBUFFER *mpFb;
+ uint32_t mcUpdates;
+ CRHTABLE_HANDLE mhSlot;
+ CR_FBDISPBASE_FLAGS mFlags;
+};
+
+
+class CrFbDisplayComposite : public CrFbDisplayBase
+{
+ public:
+
+ CrFbDisplayComposite();
+ virtual bool isComposite();
+ uint32_t getDisplayCount();
+ bool add(CrFbDisplayBase *pDisplay);
+ bool remove(CrFbDisplayBase *pDisplay, bool fCleanupDisplay = true);
+ CrFbDisplayBase* first();
+ CrFbDisplayBase* next(CrFbDisplayBase* pDisplay);
+ virtual int setFramebuffer(struct CR_FRAMEBUFFER *pFb);
+ virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb);
+ virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb);
+ virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry);
+ virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb);
+ virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb);
+ virtual ~CrFbDisplayComposite();
+ void cleanup(bool fCleanupDisplays = true);
+
+ private:
+
+ RTLISTNODE mDisplays;
+ uint32_t mcDisplays;
+};
+
+
+class CrFbWindow
+{
+ public:
+
+ CrFbWindow(uint64_t parentId);
+ bool IsCreated() const;
+ bool IsVisivle() const;
+ void Destroy();
+ int Reparent(uint64_t parentId);
+ int SetVisible(bool fVisible);
+ int SetSize(uint32_t width, uint32_t height, bool fForced=false);
+ int SetPosition(int32_t x, int32_t y, bool fForced=false);
+ int SetVisibleRegionsChanged();
+ int SetCompositor(const struct VBOXVR_SCR_COMPOSITOR * pCompositor);
+ bool SetScaleFactor(GLdouble scaleFactorW, GLdouble scaleFactorH);
+ bool GetScaleFactor(GLdouble *scaleFactorW, GLdouble *scaleFactorH);
+ int UpdateBegin();
+ void UpdateEnd();
+ uint64_t GetParentId();
+ int Create();
+ ~CrFbWindow();
+
+ protected:
+
+ void checkRegions();
+ bool isPresentNeeded();
+ bool checkInitedUpdating();
+
+ private:
+
+ typedef union CR_FBWIN_FLAGS
+ {
+ struct {
+ uint32_t fVisible : 1;
+ uint32_t fDataPresented : 1;
+ uint32_t fForcePresentOnReenable : 1;
+ uint32_t fCompositoEntriesModified : 1;
+ uint32_t Reserved : 28;
+ };
+ uint32_t Value;
+ } CR_FBWIN_FLAGS;
+
+ GLint mSpuWindow;
+ const struct VBOXVR_SCR_COMPOSITOR * mpCompositor;
+ uint32_t mcUpdates;
+ int32_t mxPos;
+ int32_t myPos;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ CR_FBWIN_FLAGS mFlags;
+ uint64_t mParentId;
+
+ RTSEMRW scaleFactorLock;
+ GLdouble mScaleFactorWStorage;
+ GLdouble mScaleFactorHStorage;
+};
+
+
+class CrFbDisplayWindow : public CrFbDisplayBase
+{
+ public:
+
+ CrFbDisplayWindow(const RTRECT *pViewportRect, uint64_t parentId);
+ virtual ~CrFbDisplayWindow();
+ virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb);
+ virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb);
+ virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb);
+ virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry);
+ virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb);
+ const RTRECT* getViewportRect();
+ virtual int setViewportRect(const RTRECT *pViewportRect);
+ virtual CrFbWindow * windowDetach(bool fCleanup = true);
+ virtual CrFbWindow * windowAttach(CrFbWindow * pNewWindow);
+ virtual int reparent(uint64_t parentId);
+ virtual bool isVisible();
+ int winVisibilityChanged();
+ CrFbWindow* getWindow();
+
+ protected:
+
+ virtual void onUpdateEnd();
+ virtual void ueRegions();
+ virtual int screenChanged();
+ virtual int windowSetCompositor(bool fSet);
+ virtual int windowCleanup();
+ virtual int fbCleanup();
+ bool isActive();
+ int windowDimensionsSync(bool fForceCleanup = false);
+ virtual int windowSync();
+ virtual int fbSync();
+ virtual const struct RTRECT* getRect();
+
+ private:
+
+ typedef union CR_FBDISPWINDOW_FLAGS
+ {
+ struct {
+ uint32_t fNeVisible : 1;
+ uint32_t fNeForce : 1;
+ uint32_t Reserved : 30;
+ };
+ uint32_t u32Value;
+ } CR_FBDISPWINDOW_FLAGS;
+
+ CrFbWindow *mpWindow;
+ RTRECT mViewportRect;
+ CR_FBDISPWINDOW_FLAGS mFlags;
+ uint32_t mu32Screen;
+ uint64_t mParentId;
+};
+
+
+class CrFbDisplayWindowRootVr : public CrFbDisplayWindow
+{
+ public:
+
+ CrFbDisplayWindowRootVr(const RTRECT *pViewportRect, uint64_t parentId);
+ virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry);
+ virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int setViewportRect(const RTRECT *pViewportRect);
+
+ protected:
+
+ virtual int windowSetCompositor(bool fSet);
+ virtual void ueRegions();
+ int compositorMarkUpdated();
+ virtual int screenChanged();
+ virtual const struct RTRECT* getRect();
+ virtual int fbCleanup();
+ virtual int fbSync();
+ VBOXVR_SCR_COMPOSITOR_ENTRY* entryAlloc();
+ void entryFree(VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry);
+ int synchCompositorRegions();
+ virtual int synchCompositor();
+ virtual int clearCompositor();
+ void rootVrTranslateForPos();
+ static DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) rootVrGetCEntry(const VBOXVR_SCR_COMPOSITOR_ENTRY*pEntry, void *pvContext);
+
+ private:
+
+ VBOXVR_SCR_COMPOSITOR mCompositor;
+};
+
+
+class CrFbDisplayVrdp : public CrFbDisplayBase
+{
+ public:
+
+ CrFbDisplayVrdp();
+ virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry);
+ virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb);
+ virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb);
+
+ protected:
+
+ void syncPos();
+ virtual int fbCleanup();
+ virtual int fbSync();
+ void vrdpDestroy(HCR_FRAMEBUFFER_ENTRY hEntry);
+ void vrdpGeometry(HCR_FRAMEBUFFER_ENTRY hEntry);
+ int vrdpRegions(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ int vrdpFrame(HCR_FRAMEBUFFER_ENTRY hEntry);
+ int vrdpRegionsAll(struct CR_FRAMEBUFFER *pFb);
+ int vrdpSynchEntry(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+ int vrdpSyncEntryAll(struct CR_FRAMEBUFFER *pFb);
+ int vrdpCreate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+
+ private:
+
+ RTPOINT mPos;
+};
+
+
+typedef struct CR_FB_INFO
+{
+ CrFbDisplayComposite *pDpComposite;
+ uint32_t u32Id;
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
+} CR_FB_INFO;
+
+typedef struct CR_FBDISPLAY_INFO
+{
+ CrFbDisplayWindow *pDpWin;
+ CrFbDisplayWindowRootVr *pDpWinRootVr;
+ CrFbDisplayVrdp *pDpVrdp;
+ CrFbWindow *pWindow;
+ uint32_t u32DisplayMode;
+ uint32_t u32Id;
+ int32_t iFb;
+
+ /* Cache scaling factor here before display output
+ * initialized (i.e., guest not yet initiated first 3D call).
+ * No synchronization stuff needed here because all the reads
+ * and writes are done in context of 3D HGCM thread. */
+ double dInitialScaleFactorW;
+ double dInitialScaleFactorH;
+} CR_FBDISPLAY_INFO;
+
+typedef struct CR_PRESENTER_GLOBALS
+{
+#ifndef VBOXVDBG_MEMCACHE_DISABLE
+ RTMEMCACHE FbEntryLookasideList;
+ RTMEMCACHE FbTexLookasideList;
+ RTMEMCACHE CEntryLookasideList;
+#endif
+ uint32_t u32DisplayMode;
+ uint32_t u32DisabledDisplayMode;
+ bool fEnabled;
+ CRHashTable *pFbTexMap;
+ CR_FBDISPLAY_INFO aDisplayInfos[CR_MAX_GUEST_MONITORS];
+ CR_FBMAP FramebufferInitMap;
+ CR_FRAMEBUFFER aFramebuffers[CR_MAX_GUEST_MONITORS];
+ CR_FB_INFO aFbInfos[CR_MAX_GUEST_MONITORS];
+ bool fWindowsForceHidden;
+ uint32_t cbTmpBuf;
+ void *pvTmpBuf;
+ uint32_t cbTmpBuf2;
+ void *pvTmpBuf2;
+} CR_PRESENTER_GLOBALS;
+
+extern CR_PRESENTER_GLOBALS g_CrPresenter;
+
+
+HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry);
+
+#endif /* __SERVER_PRESENTER_H__ */
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp
new file mode 100644
index 00000000..dd160996
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp
@@ -0,0 +1,480 @@
+/* $Id: window.cpp $ */
+
+/** @file
+ * Presenter API: window class implementation.
+ */
+
+/*
+ * Copyright (C) 2014-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server_presenter.h"
+#include <VBox/VBoxOGL.h>
+
+CrFbWindow::CrFbWindow(uint64_t parentId) :
+ mSpuWindow(0),
+ mpCompositor(NULL),
+ mcUpdates(0),
+ mxPos(0),
+ myPos(0),
+ mWidth(0),
+ mHeight(0),
+ mParentId(parentId),
+ mScaleFactorWStorage(1.0),
+ mScaleFactorHStorage(1.0)
+{
+ int rc;
+
+ mFlags.Value = 0;
+
+ rc = RTSemRWCreate(&scaleFactorLock);
+ if (!RT_SUCCESS(rc))
+ WARN(("Unable to initialize scaling factor data lock."));
+}
+
+
+bool CrFbWindow::IsCreated() const
+{
+ return !!mSpuWindow;
+}
+
+bool CrFbWindow::IsVisivle() const
+{
+ return mFlags.fVisible;
+}
+
+
+void CrFbWindow::Destroy()
+{
+ CRASSERT(!mcUpdates);
+
+ if (!mSpuWindow)
+ return;
+
+ cr_server.head_spu->dispatch_table.WindowDestroy(mSpuWindow);
+
+ mSpuWindow = 0;
+ mFlags.fDataPresented = 0;
+}
+
+
+int CrFbWindow::Reparent(uint64_t parentId)
+{
+ if (!checkInitedUpdating())
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+
+ crDebug("CrFbWindow: reparent to %p (current mxPos=%d, myPos=%d, mWidth=%u, mHeight=%u)",
+ parentId, mxPos, myPos, mWidth, mHeight);
+
+ uint64_t oldParentId = mParentId;
+
+ mParentId = parentId;
+
+ if (mSpuWindow)
+ {
+ if (oldParentId && !parentId && mFlags.fVisible)
+ cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, false);
+
+ renderspuSetWindowId(mParentId);
+ renderspuReparentWindow(mSpuWindow);
+ renderspuSetWindowId(cr_server.screen[0].winID);
+
+ if (parentId)
+ {
+ if (mFlags.fVisible)
+ cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos);
+ cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, mFlags.fVisible);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbWindow::SetVisible(bool fVisible)
+{
+ if (!checkInitedUpdating())
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+
+ LOG(("CrWIN: Visible [%d]", fVisible));
+
+ if (!fVisible != !mFlags.fVisible)
+ {
+ mFlags.fVisible = fVisible;
+ if (mSpuWindow && mParentId)
+ {
+ if (fVisible)
+ cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos);
+ cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, fVisible);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbWindow::SetSize(uint32_t width, uint32_t height, bool fForced)
+{
+ if (!fForced && !checkInitedUpdating())
+ {
+ crDebug("CrFbWindow: SetSize request dropped because window is currently updating"
+ "(width=%d, height=%d, mWidth=%d, mHeight=%d).", width, height, mWidth, mHeight);
+ return VERR_INVALID_STATE;
+ }
+
+ if (mWidth != width || mHeight != height || fForced)
+ {
+ GLdouble scaleFactorW, scaleFactorH;
+ uint32_t scaledWidth, scaledHeight;
+
+ /* Reset to default values if operation was unsuccessfull. */
+ if (!GetScaleFactor(&scaleFactorW, &scaleFactorH))
+ scaleFactorW = scaleFactorH = 1.0;
+
+ mFlags.fCompositoEntriesModified = 1;
+
+ /* Keep mWidth and mHeight unchanged (not multiplied by scale factor scalar). */
+ mWidth = width;
+ mHeight = height;
+
+ scaledWidth = (uint32_t)((GLdouble)width * scaleFactorW);
+ scaledHeight = (uint32_t)((GLdouble)height * scaleFactorH);
+
+ if (mSpuWindow)
+ {
+ cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, scaledWidth, scaledHeight);
+ crDebug("CrFbWindow: SetSize request performed successfully "
+ "(width=%d, height=%d, scaledWidth=%d, scaledHeight=%d).", width, height, scaledWidth, scaledHeight);
+ }
+ else
+ crDebug("CrFbWindow: SetSize request skipped because mSpuWindow not yet constructed "
+ "(width=%d, height=%d, scaledWidth=%d, scaledHeight=%d).", width, height, scaledWidth, scaledHeight);
+ }
+ else
+ crDebug("CrFbWindow: SetSize request skipped because window arleady has requested size "
+ "(width=%d, height=%d, mWidth=%d, mHeight=%d).", width, height, mWidth, mHeight);
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbWindow::SetPosition(int32_t x, int32_t y, bool fForced)
+{
+ if (!fForced && !checkInitedUpdating())
+ {
+ crDebug("CrFbWindow: SetPosition request dropped because window is currently updating (x=%d, y=%d).", x, y);
+ return VERR_INVALID_STATE;
+ }
+
+ LOG(("CrWIN: Pos [%d ; %d]", x, y));
+// always do WindowPosition to ensure window is adjusted properly
+// if (x != mxPos || y != myPos)
+ {
+ mxPos = x;
+ myPos = y;
+ if (mSpuWindow)
+ cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, x, y);
+ crDebug("CrFbWindow: SetPosition performed successfully (x=%d, y=%d).", x, y);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int CrFbWindow::SetVisibleRegionsChanged()
+{
+ if (!checkInitedUpdating())
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+
+ mFlags.fCompositoEntriesModified = 1;
+ return VINF_SUCCESS;
+}
+
+
+int CrFbWindow::SetCompositor(const struct VBOXVR_SCR_COMPOSITOR * pCompositor)
+{
+ if (!checkInitedUpdating())
+ {
+ WARN(("err"));
+ return VERR_INVALID_STATE;
+ }
+
+ mpCompositor = pCompositor;
+ mFlags.fCompositoEntriesModified = 1;
+
+ return VINF_SUCCESS;
+}
+
+
+bool CrFbWindow::SetScaleFactor(GLdouble scaleFactorW, GLdouble scaleFactorH)
+{
+ int rc;
+
+ /* Simple check for input values. */
+ if ( !( (scaleFactorW >= VBOX_OGL_SCALE_FACTOR_MIN && scaleFactorW <= VBOX_OGL_SCALE_FACTOR_MAX)
+ && (scaleFactorH >= VBOX_OGL_SCALE_FACTOR_MIN && scaleFactorH <= VBOX_OGL_SCALE_FACTOR_MAX)))
+ {
+ crDebug("CrFbWindow: attempt to set scale factor out of valid values range: scaleFactorW=%d, scaleFactorH=%d, multiplier=%d.",
+ (int)(scaleFactorW * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), (int)(scaleFactorH * VBOX_OGL_SCALE_FACTOR_MULTIPLIER),
+ (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER);
+
+ return false;
+ }
+
+ rc = RTSemRWRequestWrite(scaleFactorLock, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ mScaleFactorWStorage = scaleFactorW;
+ mScaleFactorHStorage = scaleFactorH;
+ RTSemRWReleaseWrite(scaleFactorLock);
+
+ crDebug("CrFbWindow: set scale factor: scaleFactorW=%d, scaleFactorH=%d, multiplier=%d.",
+ (int)(scaleFactorW * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), (int)(scaleFactorH * VBOX_OGL_SCALE_FACTOR_MULTIPLIER),
+ (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER);
+
+ /* Update window geometry. Do not wait for GAs to send SetSize() and SetPosition()
+ * events since they might not be running or installed at all. */
+ SetSize(mWidth, mHeight, true);
+ SetPosition(mxPos, myPos, true);
+
+ return true;
+ }
+
+ crDebug("CrFbWindow: unable to set scale factor because RW lock cannot be aquired: scaleFactorW=%d, scaleFactorH=%d, multiplier=%d.",
+ (int)(scaleFactorW * VBOX_OGL_SCALE_FACTOR_MULTIPLIER), (int)(scaleFactorH * VBOX_OGL_SCALE_FACTOR_MULTIPLIER),
+ (int)VBOX_OGL_SCALE_FACTOR_MULTIPLIER);
+
+ return false;
+}
+
+
+bool CrFbWindow::GetScaleFactor(GLdouble *scaleFactorW, GLdouble *scaleFactorH)
+{
+ int rc;
+
+ rc = RTSemRWRequestRead(scaleFactorLock, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ *scaleFactorW = mScaleFactorWStorage;
+ *scaleFactorH = mScaleFactorHStorage;
+ RTSemRWReleaseRead(scaleFactorLock);
+ return true;
+ }
+
+ return false;
+}
+
+
+int CrFbWindow::UpdateBegin()
+{
+ ++mcUpdates;
+ if (mcUpdates > 1)
+ return VINF_SUCCESS;
+
+ Assert(!mFlags.fForcePresentOnReenable);
+
+ crDebug("CrFbWindow::UpdateBegin ENTER, mSpuWindow(0x%X) fDataPresented(%d)", mSpuWindow, mFlags.fDataPresented);
+
+ if (mFlags.fDataPresented)
+ {
+ Assert(mSpuWindow);
+ cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, NULL, NULL);
+ mFlags.fForcePresentOnReenable = isPresentNeeded();
+ }
+
+ crDebug("CrFbWindow::UpdateBegin LEAVE, fForcePresentOnReenable(%d)", mFlags.fForcePresentOnReenable);
+
+ return VINF_SUCCESS;
+}
+
+
+void CrFbWindow::UpdateEnd()
+{
+ --mcUpdates;
+ Assert(mcUpdates < UINT32_MAX/2);
+ if (mcUpdates)
+ return;
+
+ crDebug("CrFbWindow::UpdateEnd ENTER, mSpuWindow(0x%X) mpCompositor(0x%X) fForcePresentOnReenable(%d)", mSpuWindow, mpCompositor, mFlags.fForcePresentOnReenable);
+
+ if (mSpuWindow)
+ {
+ bool fPresentNeeded = isPresentNeeded();
+ GLdouble scaleFactorW, scaleFactorH;
+ /* Reset to default values if operation was unseccessfull. */
+ if (!GetScaleFactor(&scaleFactorW, &scaleFactorH))
+ scaleFactorW = scaleFactorH = 1.0;
+
+ if (mpCompositor)
+ {
+ CrVrScrCompositorSetStretching((VBOXVR_SCR_COMPOSITOR *)mpCompositor, scaleFactorW, scaleFactorH);
+ checkRegions();
+ }
+
+ if (fPresentNeeded || mFlags.fForcePresentOnReenable)
+ {
+ mFlags.fForcePresentOnReenable = false;
+ if (mpCompositor)
+ {
+ cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, mpCompositor, NULL);
+ }
+ else
+ {
+ VBOXVR_SCR_COMPOSITOR TmpCompositor;
+ RTRECT Rect;
+ Rect.xLeft = 0;
+ Rect.yTop = 0;
+ Rect.xRight = (uint32_t)((GLdouble)mWidth * scaleFactorW);
+ Rect.yBottom = (uint32_t)((GLdouble)mHeight * scaleFactorH);
+ CrVrScrCompositorInit(&TmpCompositor, &Rect);
+ CrVrScrCompositorSetStretching((VBOXVR_SCR_COMPOSITOR *)&TmpCompositor, scaleFactorW, scaleFactorH);
+ /* this is a cleanup operation
+ * empty compositor is guarantid to be released on VBoxPresentComposition return */
+ cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, &TmpCompositor, NULL);
+ }
+ g_pLed->Asserted.s.fWriting = 1;
+ }
+
+ /* even if the above branch is entered due to mFlags.fForcePresentOnReenable,
+ * the backend should clean up the compositor as soon as presentation is performed */
+ mFlags.fDataPresented = fPresentNeeded;
+ }
+ else
+ {
+ Assert(!mFlags.fDataPresented);
+ Assert(!mFlags.fForcePresentOnReenable);
+ }
+}
+
+
+uint64_t CrFbWindow::GetParentId()
+{
+ return mParentId;
+}
+
+
+int CrFbWindow::Create()
+{
+ if (mSpuWindow)
+ {
+ //WARN(("window already created"));
+ return VINF_ALREADY_INITIALIZED;
+ }
+
+ crDebug("CrFbWindow::Create ENTER, mParentId(0x%X)\n", mParentId);
+
+ CRASSERT(cr_server.fVisualBitsDefault);
+ renderspuSetWindowId(mParentId);
+ mSpuWindow = cr_server.head_spu->dispatch_table.WindowCreate("", cr_server.fVisualBitsDefault);
+ renderspuSetWindowId(cr_server.screen[0].winID);
+ if (mSpuWindow < 0) {
+ WARN(("WindowCreate failed"));
+ return VERR_GENERAL_FAILURE;
+ }
+
+ GLdouble scaleFactorW, scaleFactorH;
+ /* Reset to default values if operation was unseccessfull. */
+ if (!GetScaleFactor(&scaleFactorW, &scaleFactorH))
+ scaleFactorW = scaleFactorH = 1.0;
+
+ uint32_t scaledWidth, scaledHeight;
+
+ scaledWidth = (uint32_t)((GLdouble)mWidth * scaleFactorW);
+ scaledHeight = (uint32_t)((GLdouble)mHeight * scaleFactorH);
+
+ cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, scaledWidth, scaledHeight);
+ cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos);
+
+ checkRegions();
+
+ if (mParentId && mFlags.fVisible)
+ cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, true);
+
+ crDebug("CrFbWindow::Create LEAVE, mParentId(0x%X) mSpuWindow(0x%X)\n", mParentId, mSpuWindow);
+ return VINF_SUCCESS;
+}
+
+
+CrFbWindow::~CrFbWindow()
+{
+ int rc;
+
+ Destroy();
+
+ rc = RTSemRWDestroy(scaleFactorLock);
+ if (!RT_SUCCESS(rc))
+ WARN(("Unable to release scaling factor data lock."));
+}
+
+
+void CrFbWindow::checkRegions()
+{
+ crDebug("CrFbWindow::checkRegions ENTER, mSpuWindow(0x%X) mpCompositor(0x%X) fCompositoEntriesModified(%d)",
+ mSpuWindow, mpCompositor, mFlags.fCompositoEntriesModified);
+
+ if (!mSpuWindow)
+ return;
+
+ if (!mFlags.fCompositoEntriesModified)
+ return;
+
+ uint32_t cRects;
+ const RTRECT *pRects;
+ if (mpCompositor)
+ {
+ int rc = CrVrScrCompositorRegionsGet(mpCompositor, &cRects, NULL, &pRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc));
+ cRects = 0;
+ pRects = NULL;
+ }
+ }
+ else
+ {
+ cRects = 0;
+ pRects = NULL;
+ }
+
+ cr_server.head_spu->dispatch_table.WindowVisibleRegion(mSpuWindow, cRects, (const GLint*)pRects);
+
+ mFlags.fCompositoEntriesModified = 0;
+
+ crDebug("CrFbWindow::checkRegions LEAVE, cRects(%d)", cRects);
+}
+
+
+bool CrFbWindow::isPresentNeeded()
+{
+ return mFlags.fVisible && mWidth && mHeight && mpCompositor && !CrVrScrCompositorIsEmpty(mpCompositor);
+}
+
+
+bool CrFbWindow::checkInitedUpdating()
+{
+ if (!mcUpdates)
+ {
+ WARN(("not updating"));
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h b/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h
new file mode 100644
index 00000000..2b3c2318
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h
@@ -0,0 +1,718 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved.
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#ifndef CR_SERVER_H
+#define CR_SERVER_H
+
+#include "cr_protocol.h"
+#include "cr_glstate.h"
+#include "spu_dispatch_table.h"
+
+#include "state/cr_currentpointers.h"
+
+#include "cr_server.h"
+#include <cr_htable.h>
+#include <cr_compositor.h>
+
+#ifdef VBOX_WITH_CRHGSMI
+# include <VBoxVideo.h>
+
+#include <iprt/cdefs.h>
+
+RT_C_DECLS_BEGIN
+
+extern uint8_t* g_pvVRamBase;
+extern uint32_t g_cbVRam;
+extern PPDMLED g_pLed;
+extern HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion;
+extern PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion;
+
+#define VBOXCRHGSMI_PTR(_off, _t) ((_t*)(g_pvVRamBase + (_off)))
+#define VBOXCRHGSMI_PTR_SAFE(_off, _cb, _t) ((_t*)crServerCrHgsmiPtrGet(_off, _cb))
+
+DECLINLINE(void*) crServerCrHgsmiPtrGet(VBOXVIDEOOFFSET offBuffer, uint32_t cbBuffer)
+{
+ return ((offBuffer) + (cbBuffer) <= g_cbVRam ? VBOXCRHGSMI_PTR(offBuffer, void) : NULL);
+}
+
+DECLINLINE(void) crServerCrHgsmiCmdComplete(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, int cmdProcessingRc)
+{
+ g_pfnCrHgsmiCompletion(g_hCrHgsmiCompletion, pCmd, cmdProcessingRc);
+}
+
+#define VBOXCRHGSMI_CMD_COMPLETE(_pData, _rc) do { \
+ CRVBOXHGSMI_CMDDATA_ASSERT_ISSET(_pData); \
+ CRVBOXHGSMI_CMDDATA_RC(_pData, _rc); \
+ if (CRVBOXHGSMI_CMDDATA_IS_HGSMICMD(_pData)) { \
+ Assert(CRVBOXHGSMI_CMDDATA_IS_HGSMICMD(_pData)); \
+ crServerCrHgsmiCmdComplete((_pData)->pHgsmiCmd, VINF_SUCCESS); \
+ } \
+ } while (0)
+
+#define VBOXCRHGSMI_CMD_CHECK_COMPLETE(_pData, _rc) do { \
+ if (CRVBOXHGSMI_CMDDATA_IS_SET(_pData)) {\
+ VBOXCRHGSMI_CMD_COMPLETE(_pData, _rc); \
+ } \
+ } while (0)
+
+#endif
+
+/*
+ * This is the base number for window and context IDs
+ */
+#define MAGIC_OFFSET 5000
+
+extern CRServer cr_server;
+
+/* Semaphore wait queue node */
+typedef struct _wqnode {
+ RunQueue *q;
+ struct _wqnode *next;
+} wqnode;
+
+typedef struct {
+ GLuint count;
+ GLuint num_waiting;
+ RunQueue **waiting;
+} CRServerBarrier;
+
+typedef struct {
+ GLuint count;
+ wqnode *waiting, *tail;
+} CRServerSemaphore;
+
+typedef struct {
+ GLuint id;
+ GLint projParamStart;
+ GLfloat projMat[16]; /* projection matrix, accumulated via calls to */
+ /* glProgramLocalParameterARB, glProgramParameterNV */
+} CRServerProgram;
+
+void crServerSetVBoxConfiguration();
+void crServerSetVBoxConfigurationHGCM();
+void crServerInitDispatch(void);
+void crServerReturnValue( const void *payload, unsigned int payload_len );
+void crServerWriteback(void);
+int crServerRecv( CRConnection *conn, CRMessage *msg, unsigned int len );
+void crServerSerializeRemoteStreams(void);
+void crServerAddToRunQueue( CRClient *client );
+void crServerDeleteClient( CRClient *client );
+
+
+void crServerApplyBaseProjection( const CRmatrix *baseProj );
+void crServerApplyViewMatrix( const CRmatrix *view );
+void crServerSetOutputBounds( const CRMuralInfo *mural, int extNum );
+void crServerComputeViewportBounds( const CRViewportState *v, CRMuralInfo *mural );
+
+GLboolean crServerInitializeBucketing(CRMuralInfo *mural);
+
+void crComputeOverlapGeom(double *quads, int nquad, CRPoly ***res);
+void crComputeKnockoutGeom(double *quads, int nquad, int my_quad_idx, CRPoly **res);
+
+int crServerGetCurrentEye(void);
+
+GLboolean crServerClientInBeginEnd(const CRClient *client);
+
+GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID);
+GLint crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID);
+GLint crServerMuralInit(CRMuralInfo *mural, GLboolean fGuestWindow, GLint visBits, GLint preloadWinID);
+void crServerMuralTerm(CRMuralInfo *mural);
+GLboolean crServerMuralSize(CRMuralInfo *mural, GLint width, GLint height);
+void crServerMuralPosition(CRMuralInfo *mural, GLint x, GLint y);
+void crServerMuralVisibleRegion( CRMuralInfo *mural, GLint cRects, const GLint *pRects );
+void crServerMuralShow( CRMuralInfo *mural, GLint state );
+
+GLint crServerGenerateID(GLint *pCounter);
+
+GLint crServerSPUWindowID(GLint serverWindow);
+
+GLuint crServerTranslateProgramID(GLuint id);
+
+CRMuralInfo * crServerGetDummyMural(GLint visualBits);
+
+void crServerCheckMuralGeometry(CRMuralInfo *mural);
+void crServerCheckAllMuralGeometry(CRMuralInfo *pMI);
+GLboolean crServerSupportRedirMuralFBO(void);
+
+void crVBoxServerMuralFbResizeBegin(HCR_FRAMEBUFFER hFb);
+void crVBoxServerMuralFbResizeEnd(HCR_FRAMEBUFFER hFb);
+
+void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void* pvData, uint32_t cbData);
+
+void crServerRedirMuralFbClear(CRMuralInfo *mural);
+
+void crServerWindowReparent(CRMuralInfo *pMural);
+
+void crServerRedirMuralFBO(CRMuralInfo *mural, bool fEnabled);
+void crServerDeleteMuralFBO(CRMuralInfo *mural);
+void crServerPresentFBO(CRMuralInfo *mural);
+GLboolean crServerIsRedirectedToFBO();
+GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer);
+void crServerMuralFBOSwapBuffers(CRMuralInfo *mural);
+
+HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled();
+HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb);
+HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized();
+HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb);
+
+int CrFbRegionsClear(HCR_FRAMEBUFFER hFb);
+
+
+#define CR_SERVER_FBO_BB_IDX(_mural) ((_mural)->iBbBuffer)
+#define CR_SERVER_FBO_FB_IDX(_mural) (((_mural)->iBbBuffer + 1) % ((_mural)->cBuffers))
+/* returns a valid index to be used for negative _idx, i.e. for GL_NONE cases */
+//#define CR_SERVER_FBO_ADJUST_IDX(_mural, _idx) ((_idx) >= 0 ? (_idx) : CR_SERVER_FBO_BB_IDX(_mural))
+/* just a helper that uses CR_SERVER_FBO_ADJUST_IDX for getting mural's FBO id for buffer index*/
+//#define CR_SERVER_FBO_FOR_IDX(_mural, _idx) ((_mural)->aidFBOs[CR_SERVER_FBO_ADJUST_IDX((_mural), (_idx))])
+//#define CR_SERVER_FBO_TEX_FOR_IDX(_mural, _idx) ((_mural)->aidColorTexs[CR_SERVER_FBO_ADJUST_IDX((_mural), (_idx))])
+#define CR_SERVER_FBO_FOR_IDX(_mural, _idx) ((_idx) >= 0 ? (_mural)->aidFBOs[(_idx)] : 0)
+#define CR_SERVER_FBO_TEX_FOR_IDX(_mural, _idx) ((_idx) >= 0 ? (_mural)->aidColorTexs[(_idx)] : 0)
+
+int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer);
+
+void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo );
+
+PCR_BLITTER crServerVBoxBlitterGet();
+PCR_BLITTER crServerVBoxBlitterGetInitialized();
+
+DECLINLINE(void) crServerVBoxBlitterWinInit(CR_BLITTER_WINDOW *win, CRMuralInfo *mural)
+{
+ win->Base.id = mural->spuWindow;
+ win->Base.visualBits = mural->CreateInfo.realVisualBits;
+ win->width = mural->width;
+ win->height = mural->height;
+}
+
+DECLINLINE(void) crServerVBoxBlitterCtxInit(CR_BLITTER_CONTEXT *ctx, CRContextInfo *ctxInfo)
+{
+ ctx->Base.id = ctxInfo->SpuContext;
+ if (ctx->Base.id < 0)
+ ctx->Base.id = cr_server.MainContextInfo.SpuContext;
+ ctx->Base.visualBits = cr_server.curClient->currentCtxInfo->CreateInfo.realVisualBits;
+}
+
+/* display worker thread.
+ * see comments for CR_SERVER_RPW struct definition in cr_server.h */
+DECLINLINE(void) crServerXchgI8(int8_t *pu8Val1, int8_t *pu8Val2)
+{
+ int8_t tmp;
+ tmp = *pu8Val1;
+ *pu8Val1 = *pu8Val2;
+ *pu8Val2 = tmp;
+}
+
+#ifdef DEBUG
+# define CR_GLERR_CHECK(_op) do { \
+ GLenum status; \
+ while ((status = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) {/*Assert(0);*/} \
+ _op \
+ while ((status = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) {Assert(0);} \
+ } while (0)
+#else
+# define CR_GLERR_CHECK(_op) do { \
+ _op \
+ } while (0)
+#endif
+
+#ifdef DEBUG_misha
+# define CR_SERVER_RPW_DEBUG
+#endif
+/* *
+ * _name : Draw, Submitted, Worker, Gpu
+ */
+
+#ifdef CR_SERVER_RPW_DEBUG
+# define crServerRpwEntryDbgVerify(_pE) crServerRpwEntryDbgDoVerify(_pE)
+#else
+# define crServerRpwEntryDbgVerify(_pE) do {} while (0)
+#endif
+
+
+#define CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _name) ((_pEntry)->iTex##_name > 0)
+
+#define CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(_pEntry, _name) do { \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _name)); \
+ (_pEntry)->iTex##_name = -(_pEntry)->iTex##_name; \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ } while (0)
+
+#define CR_SERVER_RPW_ENTRY_TEX_PROMOTE(_pEntry, _fromName, _toName) do { \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
+ Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
+ crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ } while (0)
+
+#define CR_SERVER_RPW_ENTRY_TEX_XCHG_VALID(_pEntry, _fromName, _toName) do { \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
+ crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ } while (0)
+
+
+#define CR_SERVER_RPW_ENTRY_TEX_PROMOTE_KEEPVALID(_pEntry, _fromName, _toName) do { \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
+ Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
+ crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \
+ (_pEntry)->iTex##_fromName = -(_pEntry)->iTex##_fromName; \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
+ crServerRpwEntryDbgVerify(_pEntry); \
+ } while (0)
+
+#define CR_SERVER_RPW_ENTRY_TEX(_pEntry, _name) ((_pEntry)->aidWorkerTexs[(_pEntry)->iTex##_name - 1])
+
+#define CR_SERVER_RPW_ENTRY_PBO_NEXT_ID(_i) (((_i) + 1) % 2)
+#define CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(_pEntry) ((_pEntry)->iCurPBO >= 0)
+#define CR_SERVER_RPW_ENTRY_PBO_CUR(_pEntry) ((_pEntry)->aidPBOs[(_pEntry)->iCurPBO])
+#define CR_SERVER_RPW_ENTRY_PBO_COMPLETED(_pEntry) ((_pEntry)->aidPBOs[CR_SERVER_RPW_ENTRY_PBO_NEXT_ID((_pEntry)->iCurPBO)])
+#define CR_SERVER_RPW_ENTRY_PBO_FLIP(_pEntry) do { \
+ (_pEntry)->iCurPBO = CR_SERVER_RPW_ENTRY_PBO_NEXT_ID((_pEntry)->iCurPBO); \
+ } while (0)
+
+#ifdef CR_SERVER_RPW_DEBUG
+DECLINLINE(void) crServerRpwEntryDbgDoVerify(CR_SERVER_RPW_ENTRY *pEntry)
+{
+ int tstMask = 0;
+ int8_t iVal;
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw));
+
+#define CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(_v) do { \
+ iVal = RT_ABS(_v); \
+ Assert(iVal > 0); \
+ Assert(iVal < 5); \
+ Assert(!(tstMask & (1 << iVal))); \
+ tstMask |= (1 << iVal); \
+ } while (0)
+
+ CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexDraw);
+ CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexSubmitted);
+ CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexWorker);
+ CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexGpu);
+ Assert(tstMask == 0x1E);
+}
+#endif
+
+DECLINLINE(bool) crServerRpwIsInitialized(const CR_SERVER_RPW *pWorker)
+{
+ return !!pWorker->ctxId;
+}
+int crServerRpwInit(CR_SERVER_RPW *pWorker);
+int crServerRpwTerm(CR_SERVER_RPW *pWorker);
+DECLINLINE(bool) crServerRpwEntryIsInitialized(const CR_SERVER_RPW_ENTRY *pEntry)
+{
+ return !!pEntry->pfnData;
+}
+int crServerRpwEntryInit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height, PFNCR_SERVER_RPW_DATA pfnData);
+int crServerRpwEntryCleanup(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
+int crServerRpwEntryResize(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height);
+int crServerRpwEntrySubmit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
+int crServerRpwEntryWaitComplete(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
+int crServerRpwEntryCancel(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
+DECLINLINE(void) crServerRpwEntryDrawSettingsToTex(const CR_SERVER_RPW_ENTRY *pEntry, VBOXVR_TEXTURE *pTex)
+{
+ pTex->width = pEntry->Size.cx;
+ pTex->height = pEntry->Size.cy;
+ pTex->target = GL_TEXTURE_2D;
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw));
+ pTex->hwid = CR_SERVER_RPW_ENTRY_TEX(pEntry, Draw);
+}
+/**/
+
+typedef struct CR_SERVER_CTX_SWITCH
+{
+ GLuint idDrawFBO, idReadFBO;
+ CRContext *pNewCtx;
+ CRContext *pOldCtx;
+} CR_SERVER_CTX_SWITCH;
+
+DECLINLINE(void) crServerCtxSwitchPrepare(CR_SERVER_CTX_SWITCH *pData, CRContext *pNewCtx)
+{
+ CRMuralInfo *pCurrentMural = cr_server.currentMural;
+ CRContextInfo *pCurCtxInfo = cr_server.currentCtxInfo;
+ GLuint idDrawFBO, idReadFBO;
+ CRContext *pCurCtx = pCurCtxInfo ? pCurCtxInfo->pContext : NULL;
+
+ CRASSERT(pCurCtx == crStateGetCurrent());
+
+ if (pCurrentMural)
+ {
+ idDrawFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurDrawBuffer);
+ idReadFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurReadBuffer);
+ }
+ else
+ {
+ idDrawFBO = 0;
+ idReadFBO = 0;
+ }
+
+ crStateSwitchPrepare(pNewCtx, pCurCtx, idDrawFBO, idReadFBO);
+
+ pData->idDrawFBO = idDrawFBO;
+ pData->idReadFBO = idReadFBO;
+ pData->pNewCtx = pNewCtx;
+ pData->pOldCtx = pCurCtx;
+}
+
+DECLINLINE(void) crServerCtxSwitchPostprocess(CR_SERVER_CTX_SWITCH *pData)
+{
+ crStateSwitchPostprocess(pData->pOldCtx, pData->pNewCtx, pData->idDrawFBO, pData->idReadFBO);
+}
+
+void crServerInitTmpCtxDispatch();
+
+typedef struct CR_FBMAP
+{
+ uint8_t Map[(CR_MAX_GUEST_MONITORS+7)/8];
+} CR_FBMAP;
+
+DECLINLINE(void) CrFBmInit(CR_FBMAP *pMap)
+{
+ memset(pMap, 0, sizeof (*pMap));
+}
+
+DECLINLINE(bool) CrFBmIsSet(CR_FBMAP *pMap, uint32_t i)
+{
+ return ASMBitTest(&pMap->Map, i);
+}
+
+DECLINLINE(void) CrFBmSet(CR_FBMAP *pMap, uint32_t i)
+{
+ ASMBitSet(&pMap->Map, i);
+}
+
+DECLINLINE(void) CrFBmSetAtomic(CR_FBMAP *pMap, uint32_t i)
+{
+ ASMAtomicBitSet(&pMap->Map, i);
+}
+
+DECLINLINE(void) CrFBmClear(CR_FBMAP *pMap, uint32_t i)
+{
+ ASMBitClear(&pMap->Map, i);
+}
+
+/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */
+int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap);
+/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */
+void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap);
+HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled();
+HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb);
+HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idFb);
+HCR_FRAMEBUFFER CrPMgrFbGetEnabledForScreen(uint32_t idScreen);
+int CrPMgrModeVrdp(bool fEnable);
+int CrPMgrModeRootVr(bool fEnable);
+int CrPMgrModeWinVisible(bool fEnable);
+int CrPMgrRootVrUpdate();
+int CrPMgrViewportUpdate(uint32_t idScreen);
+int CrPMgrScreenChanged(uint32_t idScreen);
+int CrPMgrResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM, const uint32_t *pTargetMap);
+int CrPMgrSaveState(PSSMHANDLE pSSM);
+int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version);
+HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idScreen);
+int CrPMgrClearRegionsGlobal();
+/*cleanup stuff*/
+
+
+int CrPMgrInit();
+void CrPMgrTerm();
+int CrPMgrDisable();
+int CrPMgrEnable();
+
+typedef DECLCALLBACKPTR(bool, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);
+
+bool CrFbHas3DData(HCR_FRAMEBUFFER hFb);
+void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext);
+int CrFbResize(HCR_FRAMEBUFFER hFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM);
+int CrFbBltGetContentsEx(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg);
+bool CrFbIsEnabled(HCR_FRAMEBUFFER hFb);
+int CrFbEntryCreateForTexId(HCR_FRAMEBUFFER hFb, GLuint idTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry);
+int CrFbEntryCreateForTexData(HCR_FRAMEBUFFER hFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry);
+void CrFbEntryAddRef(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+void CrFbEntryRelease(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb);
+void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb);
+const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(HCR_FRAMEBUFFER hFb);
+const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry);
+
+/* start doing modifications to the framebuffer */
+int CrFbUpdateBegin(HCR_FRAMEBUFFER hFb);
+/*below commands can only be used in Framebuffer update mode, i.e. after the CrFbUpdateBegin succeeded */
+int CrFbEntryRegions(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
+
+/* complete doing modifications to the framebuffer */
+void CrFbUpdateEnd(HCR_FRAMEBUFFER hFb);
+
+int CrFbEntryRegionsAdd(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated);
+int CrFbEntryRegionsSet(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated);
+
+int CrFbEntryTexDataUpdate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex);
+
+CRHTABLE_HANDLE CrFbDDataAllocSlot(HCR_FRAMEBUFFER hFb);
+
+typedef DECLCALLBACKPTR(void, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);
+
+void CrFbDDataReleaseSlot(HCR_FRAMEBUFFER hFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext);
+int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData);
+void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot);
+void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot);
+
+CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex);
+void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased);
+
+int8_t crVBoxServerCrCmdBltProcess(VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd);
+int8_t crVBoxServerCrCmdClrFillProcess(VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd);
+int8_t crVBoxServerCrCmdFlipProcess(VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *pFlip, uint32_t cbCmd);
+
+
+int32_t crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient);
+
+int crServerPendSaveState(PSSMHANDLE pSSM);
+int crServerPendLoadState(PSSMHANDLE pSSM, uint32_t u32Version);
+
+//#define VBOX_WITH_CRSERVER_DUMPER
+#ifdef VBOX_WITH_CRSERVER_DUMPER
+void crServerDumpCheckTerm();
+int crServerDumpCheckInit();
+void crServerDumpBuffer(int idx);
+void crServerDumpTextures();
+void crServerDumpTexture(const VBOXVR_TEXTURE *pTex);
+void crServerDumpShader(GLint id);
+void crServerDumpProgram(GLint id);
+void crServerDumpCurrentProgram();
+void crServerDumpRecompileDumpCurrentProgram();
+void crServerRecompileCurrentProgram();
+void crServerDumpCurrentProgramUniforms();
+void crServerDumpCurrentProgramAttribs();
+void crServerDumpFramesCheck();
+void crServerDumpState();
+void crServerDumpDrawel(const char*pszFormat, ...);
+void crServerDumpDrawelv(GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal);
+
+extern int64_t g_CrDbgDumpPid;
+extern unsigned long g_CrDbgDumpEnabled;
+extern unsigned long g_CrDbgDumpDraw;
+extern unsigned long g_CrDbgDumpDrawFramesSettings;
+extern unsigned long g_CrDbgDumpDrawFramesAppliedSettings;
+extern unsigned long g_CrDbgDumpDrawFramesCount;
+
+extern uint32_t g_CrDbgDumpVertattrFixupOn;
+
+bool crServerDumpFilterDmp(unsigned long event, CR_DUMPER *pDumper);
+bool crServerDumpFilterOpEnter(unsigned long event, CR_DUMPER *pDumper);
+void crServerDumpFilterOpLeave(unsigned long event, CR_DUMPER *pDumper);
+
+//#define CR_SERVER_DUMP_MASK_OP 0x0000fffc
+//#define CR_SERVER_DUMP_OFF_OP 2
+//
+//#define CR_SERVER_DUMP_MASK_DIR 0x00000003
+//#define CR_SERVER_DUMP_OFF_DIR 0
+//
+//#define CR_SERVER_DUMP_MASK_DMP 0xffff0000
+//#define CR_SERVER_DUMP_OFF_DMP 16
+//
+//#define CR_SERVER_DUMP_MAKE_OP(_v) (1 << ((_v) + CR_SERVER_DUMP_OFF_OP))
+//#define CR_SERVER_DUMP_MAKE_DIR(_v) (1 << ((_v) + CR_SERVER_DUMP_OFF_DIR))
+//#define CR_SERVER_DUMP_MAKE_DMP(_v) (1 << ((_v) + CR_SERVER_DUMP_OFF_DMP))
+//
+//#define CR_SERVER_DUMP_GET_OP(_v) ((_v) & CR_SERVER_DUMP_MASK_OP)
+//#define CR_SERVER_DUMP_GET_DMP(_v) ((_v) & CR_SERVER_DUMP_MASK_DMP)
+//#define CR_SERVER_DUMP_GET_DIR(_v) ((_v) & CR_SERVER_DUMP_MASK_DIR)
+//
+//#define CR_SERVER_DUMP_ISANY_OP(_v1, _v2) (!!(CR_SERVER_DUMP_GET_OP(_v1) & CR_SERVER_DUMP_GET_OP(_v2)))
+//#define CR_SERVER_DUMP_ISANY_DIR(_v1, _v2) (!!(CR_SERVER_DUMP_GET_DIR(_v1) & CR_SERVER_DUMP_GET_DIR(_v2)))
+//#define CR_SERVER_DUMP_ISANY_DMP(_v1, _v2) (!!(CR_SERVER_DUMP_GET_DMP(_v1) & CR_SERVER_DUMP_GET_DMP(_v2)))
+//
+//#define CR_SERVER_DUMP_ISANY_OP(_v1, _v2) ((CR_SERVER_DUMP_GET_OP(_v1) & CR_SERVER_DUMP_GET_OP(_v2)) == CR_SERVER_DUMP_GET_OP(_v2))
+//#define CR_SERVER_DUMP_ISANY_DIR(_v1, _v2) ((CR_SERVER_DUMP_GET_DIR(_v1) & CR_SERVER_DUMP_GET_DIR(_v2)) == CR_SERVER_DUMP_GET_DIR(_v2))
+//#define CR_SERVER_DUMP_ISANY_DMP(_v1, _v2) ((CR_SERVER_DUMP_GET_DMP(_v1) & CR_SERVER_DUMP_GET_DMP(_v2)) == CR_SERVER_DUMP_GET_DMP(_v2))
+//
+//#define CR_SERVER_DUMP_F_DIR_ENTER CR_SERVER_DUMP_MAKE_DIR(0)
+//#define CR_SERVER_DUMP_F_DIR_LEAVE CR_SERVER_DUMP_MAKE_DIR(1)
+//
+//#define CR_SERVER_DUMP_F_OP_DRAW CR_SERVER_DUMP_MAKE_OP(0)
+//#define CR_SERVER_DUMP_F_OP_SWAPBUFFERS CR_SERVER_DUMP_MAKE_OP(1)
+//#define CR_SERVER_DUMP_F_OP_LINK_PROGRAM CR_SERVER_DUMP_MAKE_OP(2)
+//#define CR_SERVER_DUMP_F_OP_COMPILE_PROGRAM CR_SERVER_DUMP_MAKE_OP(3)
+//
+//#define CR_SERVER_DUMP_F_DMP_BUFF CR_SERVER_DUMP_MAKE_DMP(0)
+//#define CR_SERVER_DUMP_F_DMP_TEX CR_SERVER_DUMP_MAKE_DMP(0)
+//#define CR_SERVER_DUMP_F_DMP_PROGRAM CR_SERVER_DUMP_MAKE_DMP(0)
+//#define CR_SERVER_DUMP_F_DMP_PROGRAM_UNIFORMS CR_SERVER_DUMP_MAKE_DMP(0)
+//#define CR_SERVER_DUMP_F_DMP_STATE CR_SERVER_DUMP_MAKE_DMP(0)
+//
+//#define CR_SERVER_DUMP_GET_OP(_v) ((_v) & CR_SERVER_DUMP_MASK_OP)
+//#define CR_SERVER_DUMP_GET_DMP(_v) ((_v) & CR_SERVER_DUMP_MASK_DMP)
+//#define CR_SERVER_DUMP_GET_DIR(_v) ((_v) & CR_SERVER_DUMP_MASK_DIR)
+
+#define CR_SERVER_DUMP_F_DRAW_BUFF_ENTER 0x00000001
+#define CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE 0x00000002
+#define CR_SERVER_DUMP_F_DRAW_STATE_ENTER 0x00000004
+#define CR_SERVER_DUMP_F_DRAW_STATE_LEAVE 0x00000008
+#define CR_SERVER_DUMP_F_DRAW_TEX_ENTER 0x00000010
+#define CR_SERVER_DUMP_F_DRAW_TEX_LEAVE 0x00000020
+#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER 0x00000040
+#define CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE 0x00000080
+#define CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER 0x00000100
+#define CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE 0x00000200
+#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER 0x00000400
+#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE 0x00000800
+
+#define CR_SERVER_DUMP_F_DRAW_ENTER_ALL (CR_SERVER_DUMP_F_DRAW_BUFF_ENTER \
+ | CR_SERVER_DUMP_F_DRAW_TEX_ENTER \
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER \
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER \
+ | CR_SERVER_DUMP_F_DRAW_STATE_ENTER \
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER)
+
+#define CR_SERVER_DUMP_F_DRAW_LEAVE_ALL (CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE \
+ | CR_SERVER_DUMP_F_DRAW_TEX_LEAVE \
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE \
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE \
+ | CR_SERVER_DUMP_F_DRAW_STATE_LEAVE \
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE)
+
+#define CR_SERVER_DUMP_F_DRAW_ALL (CR_SERVER_DUMP_F_DRAW_ENTER_ALL | CR_SERVER_DUMP_F_DRAW_LEAVE_ALL)
+
+#define CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER 0x00010000
+#define CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE 0x00020000
+#define CR_SERVER_DUMP_F_TEXPRESENT 0x00040000
+#define CR_SERVER_DUMP_F_DRAWEL 0x00100000
+#define CR_SERVER_DUMP_F_COMPILE_SHADER 0x01000000
+#define CR_SERVER_DUMP_F_SHADER_SOURCE 0x02000000
+#define CR_SERVER_DUMP_F_LINK_PROGRAM 0x04000000
+
+
+#define CR_SERVER_DUMP_DEFAULT_FILTER_OP(_ev) ((((_ev) & g_CrDbgDumpDraw) != 0) \
+ || ((_ev) == CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER && g_CrDbgDumpDrawFramesCount))
+
+#define CR_SERVER_DUMP_DEFAULT_FILTER_DMP(_ev) (((_ev) & g_CrDbgDumpDraw) != 0)
+
+#define CR_SERVER_DUMP_FILTER_OP(_ev, _pDumper) (g_CrDbgDumpEnabled \
+ && (!g_CrDbgDumpPid \
+ || (g_CrDbgDumpPid > 0 && ((uint64_t)g_CrDbgDumpPid) == cr_server.curClient->pid) \
+ || (g_CrDbgDumpPid < 0 && ((uint64_t)(-g_CrDbgDumpPid)) != cr_server.curClient->pid)) \
+ && crServerDumpFilterOpEnter((_ev), (_pDumper)))
+#define CR_SERVER_DUMP_FILTER_DMP(_ev, _pDumper) (crServerDumpFilterDmp((_ev), (_pDumper)))
+
+#define CR_SERVER_DUMP_DRAW_ENTER() do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAW_ENTER_ALL, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_STATE_ENTER, cr_server.Recorder.pDumper)) { crServerDumpState(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgram(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramUniforms(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramAttribs(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_TEX_ENTER, cr_server.Recorder.pDumper)) { crServerDumpTextures(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_BUFF_ENTER, cr_server.Recorder.pDumper)) { crServerDumpBuffer(-1); } \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAW_ENTER_ALL, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_DRAW_LEAVE() do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAW_LEAVE_ALL, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_TEX_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpTextures(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpBuffer(-1); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramUniforms(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramAttribs(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgram(); } \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_STATE_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpState(); } \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAW_LEAVE_ALL, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_COMPILE_SHADER(_id) do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_COMPILE_SHADER, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpShader((_id)); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_COMPILE_SHADER, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_SHADER_SOURCE(_id) do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SHADER_SOURCE, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpShader((_id)); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SHADER_SOURCE, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_LINK_PROGRAM(_id) do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_LINK_PROGRAM, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpProgram((_id)); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_LINK_PROGRAM, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_SWAPBUFFERS_ENTER() do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpBuffer(CR_SERVER_FBO_BB_IDX(cr_server.currentMural)); } \
+ if (g_CrDbgDumpDrawFramesCount) { crServerDumpFramesCheck(); } \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_TEXPRESENT(_pTex) do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_TEXPRESENT, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpTexture((_pTex)); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_TEXPRESENT, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_SWAPBUFFERS_LEAVE() do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE, cr_server.Recorder.pDumper)) break; \
+ crDmpStrF(cr_server.Recorder.pDumper, "==LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_DRAWEL_F(_msg) do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpDrawel _msg; \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper); \
+ } while (0)
+
+#define CR_SERVER_DUMP_DRAWEL_V(_index, _pszElFormat, _cbEl, _pvVal, _cVal) do { \
+ if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper)) break; \
+ crServerDumpCheckInit(); \
+ crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
+ crServerDumpDrawelv((_index), (_pszElFormat), (_cbEl), (_pvVal), (_cVal)); \
+ crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper); \
+ } while (0)
+#else /* if !defined VBOX_WITH_CRSERVER_DUMPER */
+#define CR_SERVER_DUMP_DRAW_ENTER() do {} while (0)
+#define CR_SERVER_DUMP_DRAW_LEAVE() do {} while (0)
+#define CR_SERVER_DUMP_COMPILE_SHADER(_id) do {} while (0)
+#define CR_SERVER_DUMP_LINK_PROGRAM(_id) do {} while (0)
+#define CR_SERVER_DUMP_TEXPRESENT(_pTex) do {} while (0)
+#define CR_SERVER_DUMP_SWAPBUFFERS_ENTER() do {} while (0)
+#define CR_SERVER_DUMP_SWAPBUFFERS_LEAVE() do {} while (0)
+#define CR_SERVER_DUMP_SHADER_SOURCE(_id) do {} while (0)
+#define CR_SERVER_DUMP_DRAWEL_F(_msg) do {} while (0)
+#define CR_SERVER_DUMP_DRAWEL_V(_index, _pszElFormat, _cbEl, _pvVal, _cVal) do {} while (0)
+#endif /* !VBOX_WITH_CRSERVER_DUMPER */
+
+RT_C_DECLS_END
+
+#endif /* CR_SERVER_H */
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_boundsinfo.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_boundsinfo.c
new file mode 100644
index 00000000..8cfa7999
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_boundsinfo.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_error.h"
+#include "cr_unpack.h"
+#include "cr_mem.h"
+#include "state/cr_statetypes.h"
+
+/* This code copied from the tilesorter (fooey) */
+
+typedef struct BucketRegion *BucketRegion_ptr;
+typedef struct BucketRegion {
+ CRbitvalue id;
+ CRrecti extents;
+ BucketRegion_ptr right;
+ BucketRegion_ptr up;
+} BucketRegion;
+
+#define HASHRANGE 256
+
+#define BKT_DOWNHASH(a, range) ((a)*HASHRANGE/(range))
+#define BKT_UPHASH(a, range) ((a)*HASHRANGE/(range) + ((a)*HASHRANGE%(range)?1:0))
+
+struct BucketingInfo {
+ BucketRegion *rhash[HASHRANGE][HASHRANGE];
+ BucketRegion *rlist;
+};
+
+
+/*
+ * At this point we know that the tiles are uniformly sized so we can use
+ * a hash-based bucketing method. Setup the hash table now.
+ */
+static GLboolean
+fillBucketingHash(CRMuralInfo *mural)
+{
+#if 0
+ int i, j, k, m;
+ int r_len = 0;
+ int xinc, yinc;
+ int rlist_alloc = 64 * 128;
+ BucketRegion *rptr;
+ struct BucketingInfo *bucketInfo;
+
+ if (mural->bucketInfo) {
+ crFree(mural->bucketInfo->rlist);
+ crFree(mural->bucketInfo);
+ mural->bucketInfo = NULL;
+ }
+
+ bucketInfo = (struct BucketingInfo *) crCalloc(sizeof(struct BucketingInfo));
+ if (!bucketInfo)
+ return GL_FALSE;
+
+ /* Allocate rlist (don't free it!!!) */
+ bucketInfo->rlist = (BucketRegion *) crAlloc(rlist_alloc * sizeof(BucketRegion));
+
+ for ( i = 0; i < HASHRANGE; i++ )
+ {
+ for ( j = 0; j < HASHRANGE; j++ )
+ {
+ bucketInfo->rhash[i][j] = NULL;
+ }
+ }
+
+ /* Fill the rlist */
+ xinc = mural->extents[0].imagewindow.x2 - mural->extents[0].imagewindow.x1;
+ yinc = mural->extents[0].imagewindow.y2 - mural->extents[0].imagewindow.y1;
+ CRASSERT(xinc > 0 || mural->width == 0);
+ CRASSERT(yinc > 0 || mural->height == 0);
+
+ rptr = bucketInfo->rlist;
+ for (i=0; i < (int) mural->width; i+=xinc)
+ {
+ for (j=0; j < (int) mural->height; j+=yinc)
+ {
+ for (k=0; k < mural->numExtents; k++)
+ {
+ if (mural->extents[k].imagewindow.x1 == i &&
+ mural->extents[k].imagewindow.y1 == j)
+ {
+ rptr->extents = mural->extents[k].imagewindow; /* x1,y1,x2,y2 */
+ rptr->id = k;
+ break;
+ }
+ }
+ if (k == mural->numExtents)
+ {
+ rptr->extents.x1 = i;
+ rptr->extents.y1 = j;
+ rptr->extents.x2 = i + xinc;
+ rptr->extents.y2 = j + yinc;
+ rptr->id = -1;
+ }
+ rptr++;
+ }
+ }
+ r_len = rptr - bucketInfo->rlist;
+
+ /* Fill hash table */
+ for (i = 0; i < r_len; i++)
+ {
+ BucketRegion *r = &bucketInfo->rlist[i];
+
+ for (k=BKT_DOWNHASH(r->extents.x1, (int)mural->width);
+ k<=BKT_UPHASH(r->extents.x2, (int)mural->width) &&
+ k < HASHRANGE;
+ k++)
+ {
+ for (m=BKT_DOWNHASH(r->extents.y1, (int)mural->height);
+ m<=BKT_UPHASH(r->extents.y2, (int)mural->height) &&
+ m < HASHRANGE;
+ m++)
+ {
+ if ( bucketInfo->rhash[m][k] == NULL ||
+ (bucketInfo->rhash[m][k]->extents.x1 > r->extents.x1 &&
+ bucketInfo->rhash[m][k]->extents.y1 > r->extents.y1))
+ {
+ bucketInfo->rhash[m][k] = r;
+ }
+ }
+ }
+ }
+
+ /* Initialize links */
+ for (i=0; i<r_len; i++)
+ {
+ BucketRegion *r = &bucketInfo->rlist[i];
+ r->right = NULL;
+ r->up = NULL;
+ }
+
+ /* Build links */
+ for (i=0; i<r_len; i++)
+ {
+ BucketRegion *r = &bucketInfo->rlist[i];
+ for (j=0; j<r_len; j++)
+ {
+ BucketRegion *q = &bucketInfo->rlist[j];
+ if (r==q)
+ continue;
+
+ /* Right Edge */
+ if (r->extents.x2 == q->extents.x1 &&
+ r->extents.y1 == q->extents.y1 &&
+ r->extents.y2 == q->extents.y2)
+ {
+ r->right = q;
+ }
+
+ /* Upper Edge */
+ if (r->extents.y2 == q->extents.y1 &&
+ r->extents.x1 == q->extents.x1 &&
+ r->extents.x2 == q->extents.x2)
+ {
+ r->up = q;
+ }
+ }
+ }
+
+ mural->bucketInfo = bucketInfo;
+#endif
+ return GL_TRUE;
+}
+
+
+/*
+ * Check if the tiles are the same size. If so, initialize hash-based
+ * bucketing.
+ */
+GLboolean
+crServerInitializeBucketing(CRMuralInfo *mural)
+{
+#if 0
+ int optTileWidth = 0, optTileHeight = 0;
+ int i;
+
+ for (i = 0; i < mural->numExtents; i++)
+ {
+ const int w = mural->extents[i].imagewindow.x2 -
+ mural->extents[i].imagewindow.x1;
+ const int h = mural->extents[i].imagewindow.y2 -
+ mural->extents[i].imagewindow.y1;
+
+ if (optTileWidth == 0 && optTileHeight == 0) {
+ /* First tile */
+ optTileWidth = w;
+ optTileHeight = h;
+ }
+ else
+ {
+ /* Subsequent tile - make sure it's the same size as first and
+ * falls on the expected x/y location.
+ */
+ if (w != optTileWidth || h != optTileHeight) {
+ crWarning("Tile %d, %d .. %d, %d is not the right size!",
+ mural->extents[i].imagewindow.x1, mural->extents[i].imagewindow.y1,
+ mural->extents[i].imagewindow.x2, mural->extents[i].imagewindow.y2);
+ crWarning("All tiles must be same size with optimize_bucket.");
+ crWarning("Turning off optimize_bucket for this mural.");
+ return GL_FALSE;
+ }
+ else if ((mural->extents[i].imagewindow.x1 % optTileWidth) != 0 ||
+ (mural->extents[i].imagewindow.x2 % optTileWidth) != 0 ||
+ (mural->extents[i].imagewindow.y1 % optTileHeight) != 0 ||
+ (mural->extents[i].imagewindow.y2 % optTileHeight) != 0)
+ {
+ crWarning("Tile %d, %d .. %d, %d is not positioned correctly "
+ "to use optimize_bucket.",
+ mural->extents[i].imagewindow.x1, mural->extents[i].imagewindow.y1,
+ mural->extents[i].imagewindow.x2, mural->extents[i].imagewindow.y2);
+ crWarning("Turning off optimize_bucket for this mural.");
+ return GL_FALSE;
+ }
+ }
+ }
+#endif
+ return fillBucketingHash(mural);
+}
+
+
+/**
+ * Process a crBoundsInfoCR message/function. This is a bounding box
+ * followed by a payload of arbitrary Chromium rendering commands.
+ * The tilesort SPU will send this.
+ * Note: the bounding box is in mural pixel coordinates (y=0=bottom)
+ */
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchBoundsInfoCR( const CRrecti *bounds, const GLbyte *payload,
+ GLint len, GLint num_opcodes )
+{
+#if 0
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ char *data_ptr = (char*)(payload + ((num_opcodes + 3 ) & ~0x03));
+ unsigned int bx, by;
+#endif
+
+ /* Save current unpacker state */
+ crUnpackPush();
+#if 0
+ /* pass bounds info to first SPU */
+ {
+ /* bias bounds to extent/window coords */
+ CRrecti bounds2;
+ const int dx = mural->extents[0].imagewindow.x1;
+ const int dy = mural->extents[0].imagewindow.y1;
+ if (bounds->x1 == -CR_MAXINT) {
+ /* "infinite" bounds: convert to full image bounds */
+ bounds2.x1 = 0;
+ bounds2.y1 = 0;
+ bounds2.x2 = mural->extents[0].imagewindow.x2 - dx; /* width */
+ bounds2.y2 = mural->extents[0].imagewindow.y2 - dy; /* height */
+ }
+ else {
+ bounds2.x1 = bounds->x1 - dx;
+ bounds2.y1 = bounds->y1 - dy;
+ bounds2.x2 = bounds->x2 - dx;
+ bounds2.y2 = bounds->y2 - dy;
+ }
+ cr_server.head_spu->dispatch_table.BoundsInfoCR(&bounds2, NULL, 0, 0);
+ }
+
+ if (!mural->viewportValidated) {
+ crServerComputeViewportBounds(&(cr_server.curClient->currentCtxInfo->pContext->viewport),
+ mural);
+ }
+
+ bx = BKT_DOWNHASH(bounds->x1, mural->width);
+ by = BKT_DOWNHASH(bounds->y1, mural->height);
+
+ /* Check for out of bounds, and optimizeBucket to enable */
+ if (mural->optimizeBucket && (bx <= HASHRANGE) && (by <= HASHRANGE))
+ {
+ const struct BucketingInfo *bucketInfo = mural->bucketInfo;
+ const BucketRegion *r;
+ const BucketRegion *p;
+
+ CRASSERT(bucketInfo);
+
+ for (r = bucketInfo->rhash[by][bx]; r && bounds->y2 >= r->extents.y1;
+ r = r->up)
+ {
+ for (p=r; p && bounds->x2 >= p->extents.x1; p = p->right)
+ {
+ if ( p->id != (unsigned int) -1 &&
+ bounds->x1 < p->extents.x2 &&
+ bounds->y1 < p->extents.y2 &&
+ bounds->y2 >= p->extents.y1 )
+ {
+ mural->curExtent = p->id;
+ if (cr_server.run_queue->client->currentCtxInfo && cr_server.run_queue->client->currentCtxInfo->pContext) {
+ crServerSetOutputBounds( mural, mural->curExtent );
+ }
+ crUnpack( data_ptr, NULL, data_ptr-1, num_opcodes, &(cr_server.dispatch) );
+ }
+ }
+ }
+ }
+ else
+ {
+ /* non-optimized bucketing - unpack/render for each tile/extent */
+ int i;
+ for ( i = 0; i < mural->numExtents; i++ )
+ {
+ CRExtent *extent = &mural->extents[i];
+
+ if (cr_server.localTileSpec ||
+ (extent->imagewindow.x2 > bounds->x1 &&
+ extent->imagewindow.x1 < bounds->x2 &&
+ extent->imagewindow.y2 > bounds->y1 &&
+ extent->imagewindow.y1 < bounds->y2))
+ {
+ mural->curExtent = i;
+ if (cr_server.run_queue->client->currentCtxInfo && cr_server.run_queue->client->currentCtxInfo->pContext) {
+ crServerSetOutputBounds( mural, i );
+ }
+ crUnpack( data_ptr, NULL, data_ptr-1, num_opcodes, &(cr_server.dispatch) );
+ }
+ }
+ }
+#endif
+ /* Restore previous unpacker state */
+ crUnpackPop();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c
new file mode 100644
index 00000000..0f898f5f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_unpack.h"
+
+void * SERVER_DISPATCH_APIENTRY
+crServerDispatchMapBufferARB( GLenum target, GLenum access )
+{
+ return NULL;
+}
+
+GLboolean SERVER_DISPATCH_APIENTRY
+crServerDispatchUnmapBufferARB( GLenum target )
+{
+ return GL_FALSE;
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGenBuffersARB(GLsizei n, GLuint *buffers)
+{
+ GLuint *local_buffers;
+ (void) buffers;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenBuffersARB: parameter 'n' is out of range");
+ return;
+ }
+
+ local_buffers = (GLuint *)crCalloc(n * sizeof(*local_buffers));
+
+ if (!local_buffers)
+ {
+ crError("crServerDispatchGenBuffersARB: out of memory");
+ return;
+ }
+
+ crStateGenBuffersARB(n, local_buffers);
+
+ crServerReturnValue( local_buffers, n * sizeof(*local_buffers) );
+ crFree( local_buffers );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteBuffersARB( GLsizei n, const GLuint * buffer )
+{
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint) || !DATA_POINTER_CHECK(n * sizeof(GLuint)))
+ {
+ crError("glDeleteBuffersARB: parameter 'n' is out of range");
+ return;
+ }
+
+ crStateDeleteBuffersARB( n, buffer );
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params)
+{
+ crError( "glGetBufferPointervARB isn't *ever* allowed to be on the wire!" );
+ (void) target;
+ (void) pname;
+ (void) params;
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, void * data)
+{
+ void *b;
+
+ if (size <= 0 || size >= INT32_MAX / 2)
+ {
+ crError("crServerDispatchGetBufferSubDataARB: size is out of range");
+ return;
+ }
+
+ b = crCalloc(size);
+
+ if (b) {
+ cr_server.head_spu->dispatch_table.GetBufferSubDataARB( target, offset, size, b );
+
+ crServerReturnValue( b, size );
+ crFree( b );
+ }
+ else {
+ crError("Out of memory in crServerDispatchGetBufferSubDataARB");
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchBindBufferARB(GLenum target, GLuint buffer)
+{
+ crStateBindBufferARB(target, buffer);
+ cr_server.head_spu->dispatch_table.BindBufferARB(target, crStateGetBufferHWID(buffer));
+}
+
+GLboolean SERVER_DISPATCH_APIENTRY
+crServerDispatchIsBufferARB(GLuint buffer)
+{
+ /* since GenBuffersARB issued to host ogl only on bind + some other ops, the host drivers may not know about them
+ * so use state data*/
+ GLboolean retval = crStateIsBufferARB(buffer);
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c
new file mode 100644
index 00000000..64ef9462
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c
@@ -0,0 +1,492 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+#ifdef VBOXCR_LOGFPS
+#include <iprt/timer.h>
+#include <iprt/ctype.h>
+typedef struct VBOXCRFPS
+{
+ uint64_t mPeriodSum;
+ uint64_t *mpaPeriods;
+ uint64_t mPrevTime;
+ uint64_t mcFrames;
+ uint32_t mcPeriods;
+ uint32_t miPeriod;
+
+ uint64_t mBytesSum;
+ uint32_t *mpaBytes;
+
+ uint64_t mBytesSentSum;
+ uint32_t *mpaBytesSent;
+
+ uint64_t mCallsSum;
+ uint32_t *mpaCalls;
+
+ uint64_t mOpsSum;
+ uint32_t *mpaOps;
+
+ uint64_t mTimeUsedSum;
+ uint64_t *mpaTimes;
+} VBOXCRFPS, *PVBOXCRFPS;
+
+void vboxCrFpsInit(PVBOXCRFPS pFps, uint32_t cPeriods)
+{
+ crMemset(pFps, 0, sizeof (*pFps));
+ pFps->mcPeriods = cPeriods;
+ pFps->mpaPeriods = crCalloc(sizeof (pFps->mpaPeriods[0]) * cPeriods);
+ pFps->mpaBytes = crCalloc(sizeof (pFps->mpaBytes[0]) * cPeriods);
+ pFps->mpaBytesSent = crCalloc(sizeof (pFps->mpaBytesSent[0]) * cPeriods);
+ pFps->mpaCalls = crCalloc(sizeof (pFps->mpaCalls[0]) * cPeriods);
+ pFps->mpaOps = crCalloc(sizeof (pFps->mpaOps[0]) * cPeriods);
+ pFps->mpaTimes = crCalloc(sizeof (pFps->mpaTimes[0]) * cPeriods);
+}
+
+void vboxCrFpsTerm(PVBOXCRFPS pFps)
+{
+ crFree(pFps->mpaPeriods);
+ crFree(pFps->mpaBytes);
+ crFree(pFps->mpaCalls);
+}
+
+void vboxCrFpsReportFrame(PVBOXCRFPS pFps)
+{
+ uint64_t cur = RTTimeNanoTS();
+ uint64_t curBytes, curBytesSent, curCalls, curOps, curTimeUsed;
+ int i;
+
+ curBytes = 0;
+ curBytesSent = 0;
+ curCalls = 0;
+ curOps = 0;
+ curTimeUsed = 0;
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn)
+ {
+ curBytes += cr_server.clients[i]->conn->total_bytes_recv;
+ curBytesSent += cr_server.clients[i]->conn->total_bytes_sent;
+ curCalls += cr_server.clients[i]->conn->recv_count;
+ curOps += cr_server.clients[i]->conn->opcodes_count;
+ curTimeUsed += cr_server.clients[i]->timeUsed;
+ cr_server.clients[i]->conn->total_bytes_recv = 0;
+ cr_server.clients[i]->conn->total_bytes_sent = 0;
+ cr_server.clients[i]->conn->recv_count = 0;
+ cr_server.clients[i]->conn->opcodes_count = 0;
+ cr_server.clients[i]->timeUsed = 0;
+ }
+ }
+
+ if(pFps->mPrevTime)
+ {
+ uint64_t curPeriod = cur - pFps->mPrevTime;
+
+ pFps->mPeriodSum += curPeriod - pFps->mpaPeriods[pFps->miPeriod];
+ pFps->mpaPeriods[pFps->miPeriod] = curPeriod;
+
+ pFps->mBytesSum += curBytes - pFps->mpaBytes[pFps->miPeriod];
+ pFps->mpaBytes[pFps->miPeriod] = curBytes;
+
+ pFps->mBytesSentSum += curBytesSent - pFps->mpaBytesSent[pFps->miPeriod];
+ pFps->mpaBytesSent[pFps->miPeriod] = curBytesSent;
+
+ pFps->mCallsSum += curCalls - pFps->mpaCalls[pFps->miPeriod];
+ pFps->mpaCalls[pFps->miPeriod] = curCalls;
+
+ pFps->mOpsSum += curOps - pFps->mpaOps[pFps->miPeriod];
+ pFps->mpaOps[pFps->miPeriod] = curOps;
+
+ pFps->mTimeUsedSum += curTimeUsed - pFps->mpaTimes[pFps->miPeriod];
+ pFps->mpaTimes[pFps->miPeriod] = curTimeUsed;
+
+ ++pFps->miPeriod;
+ pFps->miPeriod %= pFps->mcPeriods;
+ }
+ pFps->mPrevTime = cur;
+ ++pFps->mcFrames;
+}
+
+uint64_t vboxCrFpsGetEveragePeriod(PVBOXCRFPS pFps)
+{
+ return pFps->mPeriodSum / pFps->mcPeriods;
+}
+
+double vboxCrFpsGetFps(PVBOXCRFPS pFps)
+{
+ return ((double)1000000000.0) / vboxCrFpsGetEveragePeriod(pFps);
+}
+
+double vboxCrFpsGetBps(PVBOXCRFPS pFps)
+{
+ return vboxCrFpsGetFps(pFps) * pFps->mBytesSum / pFps->mcPeriods;
+}
+
+double vboxCrFpsGetBpsSent(PVBOXCRFPS pFps)
+{
+ return vboxCrFpsGetFps(pFps) * pFps->mBytesSentSum / pFps->mcPeriods;
+}
+
+double vboxCrFpsGetCps(PVBOXCRFPS pFps)
+{
+ return vboxCrFpsGetFps(pFps) * pFps->mCallsSum / pFps->mcPeriods;
+}
+
+double vboxCrFpsGetOps(PVBOXCRFPS pFps)
+{
+ return vboxCrFpsGetFps(pFps) * pFps->mOpsSum / pFps->mcPeriods;
+}
+
+double vboxCrFpsGetTimeProcPercent(PVBOXCRFPS pFps)
+{
+ return 100.0*pFps->mTimeUsedSum/pFps->mPeriodSum;
+}
+
+uint64_t vboxCrFpsGetNumFrames(PVBOXCRFPS pFps)
+{
+ return pFps->mcFrames;
+}
+
+#endif
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchClear( GLenum mask )
+{
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ const RunQueue *q = cr_server.run_queue;
+
+ if (cr_server.only_swap_once)
+ {
+ /* NOTE: we only do the clear for the _last_ client in the list.
+ * This is because in multi-threaded apps the zeroeth client may
+ * be idle and never call glClear at all. See threadtest.c
+ * It's pretty likely that the last client will be active.
+ */
+ if ((mask & GL_COLOR_BUFFER_BIT) &&
+ (cr_server.curClient != cr_server.clients[cr_server.numClients - 1]))
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.Clear( mask );
+}
+
+static void __draw_poly(CRPoly *p)
+{
+ int b;
+
+ cr_server.head_spu->dispatch_table.Begin(GL_POLYGON);
+ for (b=0; b<p->npoints; b++)
+ cr_server.head_spu->dispatch_table.Vertex2dv(p->points+2*b);
+ cr_server.head_spu->dispatch_table.End();
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchSwapBuffers( GLint window, GLint flags )
+{
+ CRMuralInfo *mural;
+ CRContext *ctx;
+
+#ifdef VBOXCR_LOGFPS
+ static VBOXCRFPS Fps;
+ static bool bFpsInited = false;
+
+ if (!bFpsInited)
+ {
+ vboxCrFpsInit(&Fps, 64 /* cPeriods */);
+ bFpsInited = true;
+ }
+ vboxCrFpsReportFrame(&Fps);
+ if(!(vboxCrFpsGetNumFrames(&Fps) % 31))
+ {
+ double fps = vboxCrFpsGetFps(&Fps);
+ double bps = vboxCrFpsGetBps(&Fps);
+ double bpsSent = vboxCrFpsGetBpsSent(&Fps);
+ double cps = vboxCrFpsGetCps(&Fps);
+ double ops = vboxCrFpsGetOps(&Fps);
+ double tup = vboxCrFpsGetTimeProcPercent(&Fps);
+ crDebug("fps: %f, rec Mbps: %.1f, send Mbps: %.1f, cps: %.1f, ops: %.0f, host %.1f%%",
+ fps, bps/(1024.0*1024.0), bpsSent/(1024.0*1024.0), cps, ops, tup);
+ }
+#endif
+ mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural) {
+ return;
+ }
+
+
+ if (cr_server.only_swap_once)
+ {
+ /* NOTE: we only do the clear for the _last_ client in the list.
+ * This is because in multi-threaded apps the zeroeth client may
+ * be idle and never call glClear at all. See threadtest.c
+ * It's pretty likely that the last client will be active.
+ */
+ if (cr_server.curClient != cr_server.clients[cr_server.numClients - 1])
+ {
+ return;
+ }
+ }
+
+#if 0
+ if (cr_server.overlapBlending)
+ {
+ int a;
+ CRPoly *p;
+ GLboolean lighting, fog, blend, cull, tex[3];
+ GLenum mm, blendSrc, blendDst;
+ GLcolorf col;
+ CRContext *ctx = crStateGetCurrent();
+ const CRmatrix *baseProj;
+
+ /*
+ * I've probably missed some state here, or it
+ * might be easier just to push/pop it....
+ */
+ lighting = ctx->lighting.lighting;
+ fog = ctx->fog.enable;
+ tex[0] = 0;
+ for (a=0; a<CR_MAX_TEXTURE_UNITS; a++)
+ {
+ if (!ctx->texture.unit[a].enabled1D) continue;
+
+ tex[0] = 1;
+ break;
+ }
+ tex[1] = 0;
+ for (a=0; a<CR_MAX_TEXTURE_UNITS; a++)
+ {
+ if (!ctx->texture.unit[a].enabled2D) continue;
+
+ tex[1] = 1;
+ break;
+ }
+ tex[2] = 0;
+ for (a=0; a<CR_MAX_TEXTURE_UNITS; a++)
+ {
+ if (!ctx->texture.unit[a].enabled3D) continue;
+
+ tex[2] = 1;
+ break;
+ }
+
+ cull = ctx->polygon.cullFace;
+ blend = ctx->buffer.blend;
+ blendSrc = ctx->buffer.blendSrcRGB;
+ blendDst = ctx->buffer.blendDstRGB;
+ mm = ctx->transform.matrixMode;
+ col.r = ctx->current.vertexAttrib[VERT_ATTRIB_COLOR0][0];
+ col.g = ctx->current.vertexAttrib[VERT_ATTRIB_COLOR0][1];
+ col.b = ctx->current.vertexAttrib[VERT_ATTRIB_COLOR0][2];
+ col.a = ctx->current.vertexAttrib[VERT_ATTRIB_COLOR0][3];
+
+ baseProj = &(cr_server.curClient->currentMural->extents[0].baseProjection);
+
+ switch(mm)
+ {
+ case GL_PROJECTION:
+ cr_server.head_spu->dispatch_table.PushMatrix();
+ cr_server.head_spu->dispatch_table.LoadMatrixf((GLfloat *) baseProj);
+ cr_server.head_spu->dispatch_table.MultMatrixf(cr_server.unnormalized_alignment_matrix);
+ cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
+ cr_server.head_spu->dispatch_table.PushMatrix();
+ cr_server.head_spu->dispatch_table.LoadIdentity();
+ break;
+
+ default:
+ cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
+ /* fall through */
+
+ case GL_MODELVIEW:
+ cr_server.head_spu->dispatch_table.PushMatrix();
+ cr_server.head_spu->dispatch_table.LoadIdentity();
+ cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
+ cr_server.head_spu->dispatch_table.PushMatrix();
+ cr_server.head_spu->dispatch_table.LoadMatrixf((GLfloat *) baseProj);
+ cr_server.head_spu->dispatch_table.MultMatrixf(cr_server.unnormalized_alignment_matrix);
+ break;
+ }
+
+ /* fix state */
+ if (lighting)
+ cr_server.head_spu->dispatch_table.Disable(GL_LIGHTING);
+ if (fog)
+ cr_server.head_spu->dispatch_table.Disable(GL_FOG);
+ if (tex[0])
+ cr_server.head_spu->dispatch_table.Disable(GL_TEXTURE_1D);
+ if (tex[1])
+ cr_server.head_spu->dispatch_table.Disable(GL_TEXTURE_2D);
+ if (tex[2])
+ cr_server.head_spu->dispatch_table.Disable(GL_TEXTURE_3D);
+ if (cull)
+ cr_server.head_spu->dispatch_table.Disable(GL_CULL_FACE);
+
+ /* Regular Blending */
+ if (cr_server.overlapBlending == 1)
+ {
+ if (!blend)
+ cr_server.head_spu->dispatch_table.Enable(GL_BLEND);
+ if ((blendSrc != GL_ZERO) && (blendDst != GL_SRC_ALPHA))
+ cr_server.head_spu->dispatch_table.BlendFunc(GL_ZERO, GL_SRC_ALPHA);
+
+ /* draw the blends */
+ for (a=1; a<cr_server.num_overlap_levels; a++)
+ {
+ if (a-1 < cr_server.num_overlap_intens)
+ {
+ cr_server.head_spu->dispatch_table.Color4f(0, 0, 0,
+ cr_server.overlap_intens[a-1]);
+ }
+ else
+ {
+ cr_server.head_spu->dispatch_table.Color4f(0, 0, 0, 1);
+ }
+
+ p = cr_server.overlap_geom[a];
+ while (p)
+ {
+ /* hopefully this isnt concave... */
+ __draw_poly(p);
+ p = p->next;
+ }
+ }
+
+ if (!blend)
+ cr_server.head_spu->dispatch_table.Disable(GL_BLEND);
+ if ((blendSrc != GL_ZERO) && (blendDst != GL_SRC_ALPHA))
+ cr_server.head_spu->dispatch_table.BlendFunc(blendSrc, blendDst);
+ }
+ else
+ /* Knockout Blending */
+ {
+ cr_server.head_spu->dispatch_table.Color4f(0, 0, 0, 1);
+
+ if (blend)
+ cr_server.head_spu->dispatch_table.Disable(GL_BLEND);
+ p = cr_server.overlap_knockout;
+ while (p)
+ {
+ __draw_poly(p);
+ p = p->next;
+ }
+ if (blend)
+ cr_server.head_spu->dispatch_table.Enable(GL_BLEND);
+ }
+
+
+ /* return things to normal */
+ switch (mm)
+ {
+ case GL_PROJECTION:
+ cr_server.head_spu->dispatch_table.PopMatrix();
+ cr_server.head_spu->dispatch_table.MatrixMode(GL_PROJECTION);
+ cr_server.head_spu->dispatch_table.PopMatrix();
+ break;
+ case GL_MODELVIEW:
+ cr_server.head_spu->dispatch_table.PopMatrix();
+ cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
+ cr_server.head_spu->dispatch_table.PopMatrix();
+ break;
+ default:
+ cr_server.head_spu->dispatch_table.PopMatrix();
+ cr_server.head_spu->dispatch_table.MatrixMode(GL_MODELVIEW);
+ cr_server.head_spu->dispatch_table.PopMatrix();
+ cr_server.head_spu->dispatch_table.MatrixMode(mm);
+ break;
+ }
+
+ if (lighting)
+ cr_server.head_spu->dispatch_table.Enable(GL_LIGHTING);
+ if (fog)
+ cr_server.head_spu->dispatch_table.Enable(GL_FOG);
+ if (tex[0])
+ cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_1D);
+ if (tex[1])
+ cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_2D);
+ if (tex[2])
+ cr_server.head_spu->dispatch_table.Enable(GL_TEXTURE_3D);
+ if (cull)
+ cr_server.head_spu->dispatch_table.Enable(GL_CULL_FACE);
+
+ cr_server.head_spu->dispatch_table.Color4f(col.r, col.g, col.b, col.a);
+ }
+#endif
+
+ /* Check if using a file network */
+ if (!cr_server.clients[0]->conn->actual_network && window == MAGIC_OFFSET)
+ window = 0;
+
+ ctx = crStateGetCurrent();
+
+ CRASSERT(cr_server.curClient && cr_server.curClient->currentMural == mural);
+
+ if (ctx->framebufferobject.drawFB
+ || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT))
+ mural->bFbDraw = GL_FALSE;
+
+ CR_SERVER_DUMP_SWAPBUFFERS_ENTER();
+
+ if (crServerIsRedirectedToFBO())
+ {
+ crServerMuralFBOSwapBuffers(mural);
+ crServerPresentFBO(mural);
+ }
+ else
+ {
+ cr_server.head_spu->dispatch_table.SwapBuffers( mural->spuWindow, flags );
+ }
+
+ CR_SERVER_DUMP_SWAPBUFFERS_LEAVE();
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchFlush(void)
+{
+ CRContext *ctx = crStateGetCurrent();
+ cr_server.head_spu->dispatch_table.Flush();
+
+ if (cr_server.curClient && cr_server.curClient->currentMural)
+ {
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ if (mural->bFbDraw)
+ {
+ if (crServerIsRedirectedToFBO())
+ crServerPresentFBO(mural);
+ }
+
+ if (ctx->framebufferobject.drawFB
+ || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT))
+ mural->bFbDraw = GL_FALSE;
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchFinish(void)
+{
+ CRContext *ctx = crStateGetCurrent();
+
+ cr_server.head_spu->dispatch_table.Finish();
+
+ if (cr_server.curClient && cr_server.curClient->currentMural)
+ {
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ if (mural->bFbDraw)
+ {
+ if (crServerIsRedirectedToFBO())
+ crServerPresentFBO(mural);
+ }
+
+ if (ctx->framebufferobject.drawFB
+ || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT))
+ mural->bFbDraw = GL_FALSE;
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clip.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clip.c
new file mode 100644
index 00000000..03143b0d
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clip.c
@@ -0,0 +1,588 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+/*
+ * This code contributed by Karl Rasche <rkarl@vr.clemson.edu>
+ */
+
+
+#include <math.h>
+
+#include "cr_server.h"
+#include "cr_mem.h"
+#include "server.h"
+
+
+static void
+__find_intersection(double *s, double *e, double *clp, double *clp_next,
+ double *intr)
+{
+ double v1[2], v2[2];
+ double A, B, T;
+
+ v1[0] = e[0] - s[0];
+ v1[1] = e[1] - s[1];
+ v2[0] = clp_next[0] - clp[0];
+ v2[1] = clp_next[1] - clp[1];
+
+ if ((v1[1]) && (v2[0]))
+ {
+ A = (clp[1]-s[1])/v1[1] + (v2[1]/v1[1])*(s[0]-clp[0])/v2[0];
+ B = 1.-(v2[1]/v1[1])*(v1[0]/v2[0]);
+ if (B)
+ T = A/B;
+ else
+ {
+ T = 0;
+ }
+
+ intr[0] = s[0]+T*v1[0];
+ intr[1] = s[1]+T*v1[1];
+ }
+ else
+ if (v1[1])
+ {
+ /* clp -> clp_next is vertical */
+ T = (clp[0]-s[0])/v1[0];
+
+ intr[0] = s[0]+T*v1[0];
+ intr[1] = s[1]+T*v1[1];
+ }
+ else
+ {
+ /* s -> e is horizontal */
+ T = (s[1]-clp[1])/v2[1];
+
+ intr[0] = clp[0]+T*v2[0];
+ intr[1] = clp[1]+T*v2[1];
+ }
+
+}
+
+static void
+ __clip_one_side(double *poly, int npnts, double *clp, double *clp_next,
+ double *norm,
+ double **new_poly_in, int *new_npnts_in,
+ double **new_poly_out, int *new_npnts_out)
+{
+ int a, sin, ein;
+ double *s, *e, intr[2];
+
+ *new_poly_in = (double *)crAlloc(2*npnts*2*sizeof(double));
+ *new_npnts_in = 0;
+
+ *new_poly_out = (double *)crAlloc(2*npnts*2*sizeof(double));
+ *new_npnts_out = 0;
+
+ s = poly;
+
+ for (a=0; a<npnts; a++)
+ {
+ e = poly+2*((a+1)%npnts);
+
+ if (((e[0]-clp[0])*norm[0]) + ((e[1]-clp[1])*norm[1]) >= 0)
+ ein = 0;
+ else
+ ein = 1;
+
+ if (((s[0]-clp[0])*norm[0]) + ((s[1]-clp[1])*norm[1]) >= 0)
+ sin = 0;
+ else
+ sin = 1;
+
+ if (sin && ein)
+ {
+ /* case 1: */
+ crMemcpy(*new_poly_in+2*(*new_npnts_in), e, 2*sizeof(double));
+ (*new_npnts_in)++;
+ }
+ else
+ if (sin && (!ein))
+ {
+ /* case 2: */
+
+ __find_intersection(s, e, clp, clp_next, intr);
+
+ crMemcpy(*new_poly_in+2*(*new_npnts_in), intr, 2*sizeof(double));
+ (*new_npnts_in)++;
+
+ crMemcpy(*new_poly_out+2*(*new_npnts_out), intr, 2*sizeof(double));
+ (*new_npnts_out)++;
+ crMemcpy(*new_poly_out+2*(*new_npnts_out), e, 2*sizeof(double));
+ (*new_npnts_out)++;
+ }
+ else
+ if ((!sin) && ein)
+ {
+ /* case 4: */
+ __find_intersection(s, e, clp, clp_next, intr);
+
+ crMemcpy((*new_poly_in)+2*(*new_npnts_in), intr, 2*sizeof(double));
+ (*new_npnts_in)++;
+ crMemcpy((*new_poly_in)+2*(*new_npnts_in), e, 2*sizeof(double));
+ (*new_npnts_in)++;
+
+ crMemcpy(*new_poly_out+2*(*new_npnts_out), intr, 2*sizeof(double));
+ (*new_npnts_out)++;
+ }
+ else
+ {
+ crMemcpy(*new_poly_out+2*(*new_npnts_out), e, 2*sizeof(double));
+ (*new_npnts_out)++;
+ }
+
+ s = e;
+ }
+}
+
+/*
+ * Sutherland/Hodgman clipping for interior & exterior regions.
+ * length_of((*new_vert_out)[a]) == nclip_to_vert
+ */
+static void
+__clip(double *poly, int nvert, double *clip_to_poly, int nclip_to_vert,
+ double **new_vert_in, int *nnew_vert_in,
+ double ***new_vert_out, int **nnew_vert_out)
+{
+ int a, side, *nout;
+ double *clip_normals, *s, *e, *n, *new_vert_src;
+ double *norm, *clp, *clp_next;
+ double **out;
+
+ *new_vert_out = (double **)crAlloc(nclip_to_vert*sizeof(double *));
+ *nnew_vert_out = (int *)crAlloc(nclip_to_vert*sizeof(int));
+
+ /*
+ * First, compute normals for the clip poly. This
+ * breaks for multiple (3+) adjacent colinear vertices
+ */
+ clip_normals = (double *)crAlloc(nclip_to_vert*2*sizeof(double));
+ for (a=0; a<nclip_to_vert; a++)
+ {
+ s = clip_to_poly+2*a;
+ e = clip_to_poly+2*((a+1)%nclip_to_vert);
+ n = clip_to_poly+2*((a+2)%nclip_to_vert);
+
+ norm = clip_normals+2*a;
+ norm[0] = e[1]-s[1];
+ norm[1] = -1*(e[0]-s[0]);
+
+ /*
+ * if dot(norm, n-e) > 0), the normals are backwards,
+ * assuming the clip region is convex
+ */
+ if (norm[0]*(n[0]-e[0]) + norm[1]*(n[1]-e[1]) > 0)
+ {
+ norm[0] *= -1;
+ norm[1] *= -1;
+ }
+ }
+
+ new_vert_src = (double *)crAlloc(nvert*nclip_to_vert*2*sizeof(double));
+ crMemcpy(new_vert_src, poly, 2*nvert*sizeof(double));
+
+ for (side=0; side<nclip_to_vert; side++)
+ {
+ clp = clip_to_poly+2*side;
+ clp_next = clip_to_poly+2*((side+1)%nclip_to_vert);
+ norm = clip_normals+2*side;
+ *nnew_vert_in = 0;
+
+ nout = (*nnew_vert_out)+side;
+ out = (*new_vert_out)+side;
+
+ __clip_one_side(new_vert_src, nvert, clp, clp_next, norm,
+ new_vert_in, nnew_vert_in,
+ out, nout);
+
+ crMemcpy(new_vert_src, (*new_vert_in), 2*(*nnew_vert_in)*sizeof(double));
+ if (side != nclip_to_vert-1)
+ crFree(*new_vert_in);
+ nvert = *nnew_vert_in;
+ }
+}
+
+/*
+ * Given a bitmap and a group of 'base' polygons [the quads we are testing],
+ * perform the unions and differences specified by the map and return
+ * the resulting geometry
+ */
+static void
+__execute_combination(CRPoly **base, int n, int *mask, CRPoly **head)
+{
+ int a, b, got_intr;
+ int nin, *nout, last;
+ double *in, **out;
+ CRPoly *intr, *diff, *p;
+
+ *head = NULL;
+
+ intr = (CRPoly *)crAlloc(sizeof(CRPoly));
+ intr->next = NULL;
+
+ got_intr = 0;
+
+ /* first, intersect the first 2 polys marked */
+ for (a=0; a<n; a++)
+ if (mask[a]) break;
+ for (b=a+1; b<n; b++)
+ if (mask[b]) break;
+
+ __clip(base[a]->points, base[a]->npoints,
+ base[b]->points, base[b]->npoints,
+ &in, &nin, &out, &nout);
+ last = b;
+
+ crFree (nout);
+ for (a=0; a<base[last]->npoints; a++)
+ if (out[a])
+ crFree(out[a]);
+ crFree(out);
+
+
+ if (nin)
+ {
+ intr->npoints = nin;
+ intr->points = in;
+ got_intr = 1;
+ }
+
+ while (1)
+ {
+ for (a=last+1; a<n; a++)
+ if (mask[a]) break;
+
+ if (a == n) break;
+
+ if (got_intr)
+ {
+ __clip(base[a]->points, base[a]->npoints,
+ intr->points, intr->npoints,
+ &in, &nin, &out, &nout);
+
+ crFree (nout);
+ for (b=0; b<intr->npoints; b++)
+ if (out[b])
+ crFree(out[b]);
+ crFree(out);
+
+ if (nin)
+ {
+ intr->npoints = nin;
+ intr->points = in;
+ }
+ else
+ {
+ got_intr = 0;
+ break;
+ }
+ }
+ else
+ {
+ __clip(base[a]->points, base[a]->npoints,
+ base[last]->points, base[last]->npoints,
+ &in, &nin, &out, &nout);
+
+ crFree (nout);
+ for (b=0; b<base[last]->npoints; b++)
+ {
+ if (out[b])
+ crFree(out[b]);
+ }
+ crFree(out);
+
+
+ if (nin)
+ {
+ intr->npoints = nin;
+ intr->points = in;
+ got_intr = 1;
+ }
+ }
+
+ last = a;
+ if (a == n) break;
+ }
+
+ /* can't subtract something from nothing! */
+ if (got_intr)
+ *head = intr;
+ else
+ return;
+
+ /* find the first item to subtract */
+ for (a=0; a<n; a++)
+ if (!mask[a]) break;
+
+ if (a == n) return;
+ last = a;
+
+ /* and subtract it */
+ diff = NULL;
+ __clip(intr->points, intr->npoints,
+ base[last]->points, base[last]->npoints,
+ &in, &nin, &out, &nout);
+
+ crFree(in);
+
+ for (a=0; a<base[last]->npoints; a++)
+ {
+ if (!nout[a]) continue;
+
+ p = (CRPoly *)crAlloc(sizeof(CRPoly));
+ p->npoints = nout[a];
+ p->points = out[a];
+ p->next = diff;
+ diff = p;
+ }
+ *head = diff;
+
+ while (1)
+ {
+ intr = diff;
+ diff = NULL;
+
+ for (a=last+1; a<n; a++)
+ if (!mask[a]) break;
+ if (a == n) return;
+
+ last = a;
+
+ /* subtract mask[a] from everything in intr and
+ * plop it into diff */
+ while (intr)
+ {
+ __clip(intr->points, intr->npoints,
+ base[last]->points, base[last]->npoints,
+ &in, &nin, &out, &nout);
+
+ crFree(in);
+
+ for (a=0; a<base[last]->npoints; a++)
+ {
+ if (!nout[a]) continue;
+
+ p = (CRPoly *)crAlloc(sizeof(CRPoly));
+ p->npoints = nout[a];
+ p->points = out[a];
+ p->next = diff;
+ diff = p;
+ }
+
+ intr = intr->next;
+ }
+
+ *head = diff;
+ }
+
+}
+
+/*
+ * Here we generate all valid bitmaps to represent union/difference
+ * combinations. Each bitmap is N elements long, where N is the
+ * number of polys [quads] that we are testing for overlap
+ */
+static void
+__generate_masks(int n, int ***mask, int *nmasks)
+{
+ int a, b, c, d, e;
+ int i, idx, isec_size, add;
+
+ *mask = (int **)crAlloc((unsigned int)pow(2, n)*sizeof(int));
+ for (a=0; a<pow(2, n); a++)
+ (*mask)[a] = (int *)crAlloc(n*sizeof(int));
+
+ /* compute combinations */
+ idx = 0;
+ for (isec_size=1; isec_size<n; isec_size++)
+ {
+ for (a=0; a<n; a++)
+ {
+ for (b=a+1; b<n; b++)
+ {
+ crMemset((*mask)[idx], 0, n*sizeof(int));
+ (*mask)[idx][a] = 1;
+
+ add = 1;
+ for (c=0; c<isec_size; c++)
+ {
+ i = (b+c) % n;
+ if (i == a) add = 0;
+
+ (*mask)[idx][i] = 1;
+ }
+
+ /* dup check */
+ if ((add) && (idx))
+ {
+ for (d=0; d<idx; d++)
+ {
+ add = 0;
+ for (e=0; e<n; e++)
+ {
+ if ((*mask)[idx][e] != (*mask)[d][e])
+ add = 1;
+ }
+
+ if (!add)
+ break;
+ }
+ }
+
+ if (add)
+ idx++;
+ }
+ }
+ }
+
+ *nmasks = idx;
+}
+
+/*
+ * To compute the overlap between a series of quads (This should work
+ * for n-gons, but we'll only need quads..), first generate a series of
+ * bitmaps that represent which elements to union together, and which
+ * to difference. This goes into 'mask'. We then evaluate each bitmap with
+ * Sutherland-Hodgman clipping to find the interior (union) and exterior
+ * (difference) regions.
+ *
+ * In the map, 1 == union, 0 == difference
+ *
+ * (*res)[a] is the head of a poly list for all the polys that convert
+ * regions of overlap between a+1 polys ((*res)[0] == NULL)
+ */
+void
+crComputeOverlapGeom(double *quads, int nquad, CRPoly ***res)
+{
+ int a, b, idx, isec_size, **mask;
+ CRPoly *p, *next, **base;
+
+ base = (CRPoly **)crAlloc(nquad*sizeof(CRPoly *));
+ for (a=0; a<nquad; a++)
+ {
+ p = (CRPoly *)crAlloc(sizeof(CRPoly));
+ p->npoints = 4;
+ p->points = (double *)crAlloc(8*sizeof(double));
+ for (b=0; b<8; b++)
+ {
+ p->points[b] = quads[8*a+b];
+ }
+ p->next = NULL;
+ base[a] = p;
+ }
+
+ *res = (CRPoly **)crAlloc(nquad*sizeof(CRPoly *));
+ for (a=0; a<nquad; a++)
+ (*res)[a] = NULL;
+
+ __generate_masks(nquad, &mask, &idx);
+
+ for (a=0; a<idx; a++)
+ {
+ isec_size = 0;
+ for (b=0; b<nquad; b++)
+ if (mask[a][b]) isec_size++;
+ isec_size--;
+
+ __execute_combination(base, nquad, mask[a], &p);
+
+ while (p)
+ {
+ next = p->next;
+
+ p->next = (*res)[isec_size];
+ (*res)[isec_size] = p;
+
+ p = next;
+ }
+ }
+
+ for (a=0; a<nquad; a++)
+ {
+ crFree(base[a]->points);
+ crFree(base[a]);
+ }
+ crFree(base);
+
+}
+
+/*
+ * This is similar to ComputeOverlapGeom above, but for "knockout"
+ * edge blending.
+ *
+ * my_quad_idx is an index of quads indicating which display tile
+ * we are computing geometry for. From this, we either generate
+ * geometry, or not, such that all geometry can be drawn in black
+ * and only one tile will show through the blend as non-black.
+ *
+ * To add a combination to our set of geom, we must test that:
+ * + mask[a][my_quad_idx] is set
+ * + mask[a][my_quad_idx] is not the first element set in
+ * mask[a].
+ * If these conditions hold, execute mask[a] and draw the resulting
+ * geometry in black
+ *
+ * Unlike ComputeOverlapGeom, res is just a list of polys to draw in black
+ */
+void
+crComputeKnockoutGeom(double *quads, int nquad, int my_quad_idx, CRPoly **res)
+{
+ int a, b, idx, first, **mask;
+ CRPoly *p, *next, **base;
+
+ base = (CRPoly **) crAlloc(nquad*sizeof(CRPoly *));
+ for (a=0; a<nquad; a++)
+ {
+ p = (CRPoly *) crAlloc(sizeof(CRPoly));
+ p->npoints = 4;
+ p->points = (double *) crAlloc(8*sizeof(double));
+ for (b=0; b<8; b++)
+ {
+ p->points[b] = quads[8*a+b];
+ }
+ p->next = NULL;
+ base[a] = p;
+ }
+
+ (*res) = NULL;
+
+ __generate_masks(nquad, &mask, &idx);
+
+ for (a=0; a<idx; a++)
+ {
+ /* test for above conditions */
+ if (!mask[a][my_quad_idx]) continue;
+
+ first = -1;
+ for (b=0; b<nquad; b++)
+ if (mask[a][b])
+ {
+ first = b;
+ break;
+ }
+ if (first == my_quad_idx) continue;
+
+
+ __execute_combination(base, nquad, mask[a], &p);
+
+ while (p)
+ {
+ next = p->next;
+
+ p->next = *res;
+ *res = p;
+
+ p = next;
+ }
+ }
+
+ for (a=0; a<nquad; a++)
+ {
+ crFree(base[a]->points);
+ crFree(base[a]);
+ }
+ crFree(base);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c
new file mode 100644
index 00000000..ce1546a0
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c
@@ -0,0 +1,404 @@
+ /* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include <string.h>
+#include "cr_mem.h"
+#include "cr_environment.h"
+#include "cr_string.h"
+#include "cr_error.h"
+#include "cr_glstate.h"
+#include "server.h"
+
+#ifdef WINDOWS
+#pragma warning( disable: 4706 )
+#endif
+
+static void
+setDefaults(void)
+{
+ if (!cr_server.tcpip_port)
+ cr_server.tcpip_port = DEFAULT_SERVER_PORT;
+ cr_server.run_queue = NULL;
+ cr_server.optimizeBucket = 1;
+ cr_server.useL2 = 0;
+ cr_server.maxBarrierCount = 0;
+ cr_server.ignore_papi = 0;
+ cr_server.only_swap_once = 0;
+ cr_server.overlapBlending = 0;
+ cr_server.debug_barriers = 0;
+ cr_server.sharedDisplayLists = 0;
+ cr_server.sharedTextureObjects = 0;
+ cr_server.sharedPrograms = 0;
+ cr_server.sharedWindows = 0;
+ cr_server.useDMX = 0;
+ cr_server.vpProjectionMatrixParameter = -1;
+ cr_server.vpProjectionMatrixVariable = NULL;
+ cr_server.currentProgram = 0;
+
+ cr_server.num_overlap_intens = 0;
+ cr_server.overlap_intens = 0;
+ crMemset(&cr_server.MainContextInfo, 0, sizeof (cr_server.MainContextInfo));
+
+ crMatrixInit(&cr_server.viewMatrix[0]);
+ crMatrixInit(&cr_server.viewMatrix[1]);
+ crMatrixInit(&cr_server.projectionMatrix[0]);
+ crMatrixInit(&cr_server.projectionMatrix[1]);
+ cr_server.currentEye = -1;
+
+ cr_server.uniqueWindows = 0;
+
+ cr_server.screenCount = 0;
+ cr_server.bUsePBOForReadback = GL_FALSE;
+ cr_server.bWindowsInitiallyHidden = GL_FALSE;
+
+ cr_server.pfnNotifyEventCB = NULL;
+}
+
+/* Check if host reports minimal OpenGL capabilities.
+ *
+ * Require OpenGL 2.1 or later.
+ *
+ * For example, on Windows host this may happen if host has no graphics
+ * card drivers installed or drivers were not properly signed or VBox
+ * is running via remote desktop session etc. Currently, we take care
+ * about Windows host only when specific RENDERER and VERSION strings
+ * returned in this case. Later this check should be expanded to the
+ * rest of hosts. */
+static bool crServerHasInsufficientCaps()
+{
+ const char *pszRealVersion;
+ int rc;
+ uint32_t u32VerMajor = 0;
+ uint32_t u32VerMinor = 0;
+ char *pszNext = NULL;
+
+ if (!cr_server.head_spu)
+ return true;
+
+ pszRealVersion = (const char *)cr_server.head_spu->dispatch_table.GetString(GL_REAL_VERSION);
+ if (!pszRealVersion)
+ return true; /* No version == insufficient. */
+
+ rc = RTStrToUInt32Ex(pszRealVersion, &pszNext, 10, &u32VerMajor);
+ if ( RT_SUCCESS(rc)
+ && *pszNext == '.')
+ RTStrToUInt32Ex(pszNext + 1, NULL, 10, &u32VerMinor);
+
+ crInfo("Host supports version %d.%d [%s]", u32VerMajor, u32VerMinor, pszRealVersion);
+
+ if ( u32VerMajor > 2
+ || (u32VerMajor == 2 && u32VerMinor >= 1))
+ return false; /* >= 2.1, i.e. good enough. */
+
+ return true; /* Insufficient. */
+}
+
+void crServerSetVBoxConfiguration()
+{
+ CRMuralInfo *defaultMural;
+ char response[8096];
+
+ char **spuchain;
+ int num_spus;
+ int *spu_ids;
+ char **spu_names;
+ char *spu_dir = NULL;
+ int i;
+ /* Quadrics defaults */
+ int my_rank = 0;
+ int low_context = CR_QUADRICS_DEFAULT_LOW_CONTEXT;
+ int high_context = CR_QUADRICS_DEFAULT_HIGH_CONTEXT;
+ unsigned char key[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+ char hostname[1024];
+ char **clientchain, **clientlist;
+ GLint dims[4];
+ const char * env;
+
+ defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
+ CRASSERT(defaultMural);
+
+ setDefaults();
+
+ /*
+ * Get my hostname
+ */
+ if (crGetHostname(hostname, sizeof(hostname)))
+ {
+ crError("CRServer: Couldn't get my own hostname?");
+ }
+
+#ifdef VBOX_WITH_CR_DISPLAY_LISTS
+ strcpy(response, "1 0 expando");
+#else
+ strcpy(response, "1 0 render");
+#endif
+ crDebug("CRServer: my SPU chain: %s", response);
+
+ /* response will describe the SPU chain.
+ * Example "2 5 wet 6 render"
+ */
+ spuchain = crStrSplit(response, " ");
+ num_spus = crStrToInt(spuchain[0]);
+ spu_ids = (int *) crAlloc(num_spus * sizeof(*spu_ids));
+ spu_names = (char **) crAlloc((num_spus + 1) * sizeof(*spu_names));
+ for (i = 0; i < num_spus; i++)
+ {
+ spu_ids[i] = crStrToInt(spuchain[2 * i + 1]);
+ spu_names[i] = crStrdup(spuchain[2 * i + 2]);
+ crDebug("SPU %d/%d: (%d) \"%s\"", i + 1, num_spus, spu_ids[i],
+ spu_names[i]);
+ }
+ spu_names[i] = NULL;
+
+ crNetSetRank(0);
+ crNetSetContextRange(32, 35);
+ crNetSetNodeRange("iam0", "iamvis20");
+ crNetSetKey(key,sizeof(key));
+ crNetSetKey(key,sizeof(key));
+ cr_server.tcpip_port = 7000;
+
+ crDebug("CRServer: my port number is %d", cr_server.tcpip_port);
+
+ /*
+ * Load the SPUs
+ */
+ cr_server.head_spu =
+ crSPULoadChain(num_spus, spu_ids, spu_names, spu_dir, &cr_server);
+
+ env = crGetenv( "CR_SERVER_DEFAULT_VISUAL_BITS" );
+ if (env != NULL && env[0] != '\0')
+ {
+ unsigned int bits = (unsigned int)crStrParseI32(env, 0);
+ if (bits <= CR_ALL_BITS)
+ cr_server.fVisualBitsDefault = bits;
+ else
+ crWarning("invalid bits option %c", bits);
+ }
+ else
+ cr_server.fVisualBitsDefault = CR_RGB_BIT | CR_ALPHA_BIT | CR_DOUBLE_BIT;
+
+ env = crGetenv("CR_SERVER_CAPS");
+ if (env && env[0] != '\0')
+ {
+ cr_server.u32Caps = crStrParseI32(env, 0);
+ cr_server.u32Caps &= CR_VBOX_CAPS_ALL;
+ }
+ else
+ {
+ cr_server.u32Caps = CR_VBOX_CAP_TEX_PRESENT
+ | CR_VBOX_CAP_CMDVBVA
+ | CR_VBOX_CAP_CMDBLOCKS
+ | CR_VBOX_CAP_GETATTRIBSLOCATIONS
+ | CR_VBOX_CAP_CMDBLOCKS_FLUSH
+ ;
+ }
+
+ if (crServerHasInsufficientCaps())
+ {
+ crDebug("Cfg: report minimal OpenGL capabilities");
+ cr_server.u32Caps |= CR_VBOX_CAP_HOST_CAPS_NOT_SUFFICIENT;
+ }
+
+ crInfo("Cfg: u32Caps(%#x), fVisualBitsDefault(%#x)",
+ cr_server.u32Caps,
+ cr_server.fVisualBitsDefault);
+
+ /* Need to do this as early as possible */
+
+ cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_POSITION_CR, 0, GL_INT, 2, &dims[0]);
+ cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, 0, GL_INT, 2, &dims[2]);
+
+ defaultMural->gX = dims[0];
+ defaultMural->gY = dims[1];
+ defaultMural->width = dims[2];
+ defaultMural->height = dims[3];
+
+ crFree(spu_ids);
+ crFreeStrings(spu_names);
+ crFreeStrings(spuchain);
+ if (spu_dir)
+ crFree(spu_dir);
+
+ cr_server.mtu = 1024 * 30;
+
+ /*
+ * Get a list of all the clients talking to me.
+ */
+ if (cr_server.vncMode) {
+ /* we're inside a vnc viewer */
+ /*if (!crMothershipSendString( conn, response, "getvncclient %s", hostname ))
+ crError( "Bad Mothership response: %s", response );*/
+ }
+ else {
+ //crMothershipGetClients(conn, response);
+ strcpy(response, "1 tcpip 1");
+ }
+
+ crDebug("CRServer: my clients: %s", response);
+
+ /*
+ * 'response' will now contain a number indicating the number of clients
+ * of this server, followed by a comma-separated list of protocol/SPU ID
+ * pairs.
+ * Example: "3 tcpip 1,gm 2,via 10"
+ */
+ clientchain = crStrSplitn(response, " ", 1);
+ cr_server.numClients = crStrToInt(clientchain[0]);
+ if (cr_server.numClients == 0)
+ {
+ crError("I have no clients! What's a poor server to do?");
+ }
+ clientlist = crStrSplit(clientchain[1], ",");
+
+ /*
+ * Connect to initial set of clients.
+ * Call crNetAcceptClient() for each client.
+ * Also, look for a client that's _not_ using the file: protocol.
+ */
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ CRClient *newClient = (CRClient *) crCalloc(sizeof(CRClient));
+#ifdef VBOX
+ sscanf(clientlist[i], "%1023s %d", cr_server.protocol, &(newClient->spu_id));
+#else
+ sscanf(clientlist[i], "%s %d", cr_server.protocol, &(newClient->spu_id));
+#endif
+ newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
+ cr_server.tcpip_port,
+ cr_server.mtu, 0);
+ newClient->currentCtxInfo = &cr_server.MainContextInfo;
+ crServerAddToRunQueue(newClient);
+
+ cr_server.clients[i] = newClient;
+ }
+
+ /* set default client and mural */
+ if (cr_server.numClients > 0) {
+ cr_server.curClient = cr_server.clients[0];
+ cr_server.curClient->currentMural = defaultMural;
+ cr_server.client_spu_id =cr_server.clients[0]->spu_id;
+ }
+
+ crFreeStrings(clientchain);
+ crFreeStrings(clientlist);
+
+ /* Ask the mothership for the tile info */
+ //crServerGetTileInfoFromMothership(conn, defaultMural);
+
+ if (cr_server.vncMode) {
+ /* In vnc mode, we reset the mothership configuration so that it can be
+ * used by subsequent OpenGL apps without having to spawn a new mothership
+ * on a new port.
+ */
+ crDebug("CRServer: Resetting mothership to initial state");
+ //crMothershipReset(conn);
+ }
+
+ //crMothershipDisconnect(conn);
+}
+
+void crServerSetVBoxConfigurationHGCM()
+{
+ CRMuralInfo *defaultMural;
+
+#ifdef VBOX_WITH_CR_DISPLAY_LISTS
+ int spu_ids[1] = {0};
+ char *spu_names[1] = {"expando"};
+#else
+ int spu_ids[1] = {0};
+ char *spu_names[1] = {"render"};
+#endif
+ char *spu_dir = NULL;
+ int i;
+ GLint dims[4];
+ const char * env;
+
+ defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
+ CRASSERT(defaultMural);
+
+ /// @todo should be moved to addclient so we have a chain for each client
+
+ setDefaults();
+
+ /* Load the SPUs */
+ cr_server.head_spu = crSPULoadChain(1, spu_ids, spu_names, spu_dir, &cr_server);
+
+ if (!cr_server.head_spu)
+ return;
+
+
+ env = crGetenv( "CR_SERVER_DEFAULT_VISUAL_BITS" );
+ if (env != NULL && env[0] != '\0')
+ {
+ unsigned int bits = (unsigned int)crStrParseI32(env, 0);
+ if (bits <= CR_ALL_BITS)
+ cr_server.fVisualBitsDefault = bits;
+ else
+ crWarning("invalid bits option %c", bits);
+ }
+ else
+ cr_server.fVisualBitsDefault = CR_RGB_BIT | CR_ALPHA_BIT | CR_DOUBLE_BIT;
+
+
+ env = crGetenv("CR_SERVER_CAPS");
+ if (env && env[0] != '\0')
+ {
+ cr_server.u32Caps = crStrParseI32(env, 0);
+ cr_server.u32Caps &= CR_VBOX_CAPS_ALL;
+ }
+ else
+ {
+ cr_server.u32Caps = CR_VBOX_CAP_TEX_PRESENT
+ | CR_VBOX_CAP_CMDVBVA
+ | CR_VBOX_CAP_CMDBLOCKS
+ | CR_VBOX_CAP_GETATTRIBSLOCATIONS
+ | CR_VBOX_CAP_CMDBLOCKS_FLUSH
+ ;
+ }
+
+ if (crServerHasInsufficientCaps())
+ {
+ crDebug("Cfg: report minimal OpenGL capabilities");
+ cr_server.u32Caps |= CR_VBOX_CAP_HOST_CAPS_NOT_SUFFICIENT;
+ }
+
+ crInfo("Cfg: u32Caps(%#x), fVisualBitsDefault(%#x)",
+ cr_server.u32Caps,
+ cr_server.fVisualBitsDefault);
+
+ cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_POSITION_CR, 0, GL_INT, 2, &dims[0]);
+ cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, 0, GL_INT, 2, &dims[2]);
+
+ defaultMural->gX = dims[0];
+ defaultMural->gY = dims[1];
+ defaultMural->width = dims[2];
+ defaultMural->height = dims[3];
+
+ cr_server.mtu = 1024 * 250;
+
+ cr_server.numClients = 0;
+ strcpy(cr_server.protocol, "vboxhgcm");
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ CRClient *newClient = (CRClient *) crCalloc(sizeof(CRClient));
+ newClient->spu_id = 0;
+ newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
+ cr_server.tcpip_port,
+ cr_server.mtu, 0);
+ newClient->currentCtxInfo = &cr_server.MainContextInfo;
+ crServerAddToRunQueue(newClient);
+
+ cr_server.clients[i] = newClient;
+ }
+
+ /* set default client and mural */
+ if (cr_server.numClients > 0) {
+ cr_server.curClient = cr_server.clients[0];
+ cr_server.curClient->currentMural = defaultMural;
+ cr_server.client_spu_id =cr_server.clients[0]->spu_id;
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c
new file mode 100644
index 00000000..afa2a208
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c
@@ -0,0 +1,481 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved.
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_net.h"
+#include "cr_rand.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+
+GLint SERVER_DISPATCH_APIENTRY
+crServerDispatchCreateContext(const char *dpyName, GLint visualBits, GLint shareCtx)
+{
+ return crServerDispatchCreateContextEx(dpyName, visualBits, shareCtx, -1, -1);
+}
+
+GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID)
+{
+ GLint retVal = -1;
+ CRContext *newCtx;
+ CRContextInfo *pContextInfo;
+ GLboolean fFirst = GL_FALSE;
+
+ dpyName = "";
+
+ if (shareCtx > 0) {
+ crWarning("CRServer: context sharing not implemented.");
+ shareCtx = 0;
+ }
+
+ pContextInfo = (CRContextInfo *) crAlloc(sizeof (CRContextInfo));
+ if (!pContextInfo)
+ {
+ crWarning("failed to alloc context info!");
+ return -1;
+ }
+
+ pContextInfo->currentMural = NULL;
+
+ pContextInfo->CreateInfo.requestedVisualBits = visualBits;
+
+ if (cr_server.fVisualBitsDefault)
+ visualBits = cr_server.fVisualBitsDefault;
+
+ pContextInfo->CreateInfo.realVisualBits = visualBits;
+
+ /* Since the Cr server serialized all incoming clients/contexts into
+ * one outgoing GL stream, we only need to create one context for the
+ * head SPU. We'll only have to make it current once too, below.
+ */
+ if (cr_server.firstCallCreateContext) {
+ cr_server.MainContextInfo.CreateInfo.realVisualBits = visualBits;
+ cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
+ CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, shareCtx);
+ if (cr_server.MainContextInfo.SpuContext < 0) {
+ crWarning("crServerDispatchCreateContext() failed.");
+ crFree(pContextInfo);
+ return -1;
+ }
+ cr_server.MainContextInfo.pContext = crStateCreateContext(&cr_server.limits, visualBits, NULL);
+ CRASSERT(cr_server.MainContextInfo.pContext);
+ cr_server.firstCallCreateContext = GL_FALSE;
+ fFirst = GL_TRUE;
+
+ cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_SET_DEFAULT_SHARED_CTX, cr_server.MainContextInfo.SpuContext);
+ }
+ else {
+ /* second or third or ... context */
+ if (!cr_server.bUseMultipleContexts && ((visualBits & cr_server.MainContextInfo.CreateInfo.realVisualBits) != visualBits)) {
+ int oldSpuContext;
+ /* should never be here */
+ CRASSERT(0);
+ /* the new context needs new visual attributes */
+ cr_server.MainContextInfo.CreateInfo.realVisualBits |= visualBits;
+ crWarning("crServerDispatchCreateContext requires new visual (0x%x).",
+ cr_server.MainContextInfo.CreateInfo.realVisualBits);
+
+ /* Here, we used to just destroy the old rendering context.
+ * Unfortunately, this had the side effect of destroying
+ * all display lists and textures that had been loaded on
+ * the old context as well.
+ *
+ * Now, first try to create a new context, with a suitable
+ * visual, sharing display lists and textures with the
+ * old context. Then destroy the old context.
+ */
+
+ /* create new rendering context with suitable visual */
+ oldSpuContext = cr_server.MainContextInfo.SpuContext;
+ cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table.
+ CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext);
+ /* destroy old rendering context */
+ cr_server.head_spu->dispatch_table.DestroyContext(oldSpuContext);
+ if (cr_server.MainContextInfo.SpuContext < 0) {
+ crWarning("crServerDispatchCreateContext() failed.");
+ crFree(pContextInfo);
+ return -1;
+ }
+
+ /* we do not need to clean up the old default context explicitly, since the above cr_server.head_spu->dispatch_table.DestroyContext call
+ * will do that for us */
+ cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_SET_DEFAULT_SHARED_CTX, cr_server.MainContextInfo.SpuContext);
+ }
+ }
+
+ if (cr_server.bUseMultipleContexts) {
+ pContextInfo->SpuContext = cr_server.head_spu->dispatch_table.
+ CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext);
+ if (pContextInfo->SpuContext < 0) {
+ crWarning("crServerDispatchCreateContext() failed.");
+ crStateEnableDiffOnMakeCurrent(GL_TRUE);
+ cr_server.bUseMultipleContexts = GL_FALSE;
+ if (!fFirst)
+ crError("creating shared context failed, while it is expected to work!");
+ }
+ else if (fFirst)
+ {
+ crStateEnableDiffOnMakeCurrent(GL_FALSE);
+ }
+ }
+ else
+ {
+ pContextInfo->SpuContext = -1;
+ }
+
+ /* Now create a new state-tracker context and initialize the
+ * dispatch function pointers.
+ */
+ newCtx = crStateCreateContextEx(&cr_server.limits, visualBits, NULL, internalID);
+ if (newCtx) {
+ crStateSetCurrentPointers( newCtx, &(cr_server.current) );
+ crStateResetCurrentPointers(&(cr_server.current));
+ retVal = preloadCtxID<0 ? (GLint)crHashtableAllocKeys( cr_server.contextTable, 1 ) : preloadCtxID;
+
+ pContextInfo->pContext = newCtx;
+ Assert(pContextInfo->CreateInfo.realVisualBits == visualBits);
+ pContextInfo->CreateInfo.externalID = retVal;
+ pContextInfo->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
+ crHashtableAdd(cr_server.contextTable, retVal, pContextInfo);
+ }
+
+ if (retVal != -1 && !cr_server.bIsInLoadingState) {
+ int pos;
+ for (pos = 0; pos < CR_MAX_CONTEXTS; pos++) {
+ if (cr_server.curClient->contextList[pos] == 0) {
+ cr_server.curClient->contextList[pos] = retVal;
+ break;
+ }
+ }
+ }
+
+ crServerReturnValue( &retVal, sizeof(retVal) );
+
+ return retVal;
+}
+
+static int crServerRemoveClientContext(CRClient *pClient, GLint ctx)
+{
+ int pos;
+
+ for (pos = 0; pos < CR_MAX_CONTEXTS; ++pos)
+ {
+ if (pClient->contextList[pos] == ctx)
+ {
+ pClient->contextList[pos] = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void crServerCleanupMuralCtxUsageCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *mural = (CRMuralInfo *) data1;
+ CRContext *ctx = (CRContext *) data2;
+
+ CR_STATE_SHAREDOBJ_USAGE_CLEAR(mural, ctx);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchDestroyContext( GLint ctx )
+{
+ CRContextInfo *crCtxInfo;
+ CRContext *crCtx;
+ int32_t client;
+ CRClientNode *pNode;
+ int found=false;
+
+ crCtxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, ctx);
+ if (!crCtxInfo) {
+ crWarning("CRServer: DestroyContext invalid context %d", ctx);
+ return;
+ }
+ crCtx = crCtxInfo->pContext;
+ CRASSERT(crCtx);
+
+ crDebug("CRServer: DestroyContext context %d", ctx);
+
+ if (cr_server.currentCtxInfo == crCtxInfo)
+ {
+ CRMuralInfo *dummyMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ crServerPerformMakeCurrent(dummyMural, &cr_server.MainContextInfo);
+ CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
+ }
+
+ crHashtableWalk(cr_server.muralTable, crServerCleanupMuralCtxUsageCB, crCtx);
+ crCtxInfo->currentMural = NULL;
+ crHashtableDelete(cr_server.contextTable, ctx, NULL);
+ crStateDestroyContext( crCtx );
+
+ if (crCtxInfo->CreateInfo.pszDpyName)
+ crFree(crCtxInfo->CreateInfo.pszDpyName);
+
+ if (crCtxInfo->SpuContext >= 0)
+ cr_server.head_spu->dispatch_table.DestroyContext(crCtxInfo->SpuContext);
+
+ crFree(crCtxInfo);
+
+ if (cr_server.curClient)
+ {
+ /* If we delete our current context, default back to the null context */
+ if (cr_server.curClient->currentCtxInfo == crCtxInfo) {
+ cr_server.curClient->currentContextNumber = -1;
+ cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
+ }
+
+ found = crServerRemoveClientContext(cr_server.curClient, ctx);
+
+ /*Some application call destroy context not in a thread where it was created...have do deal with it.*/
+ if (!found)
+ {
+ for (client=0; client<cr_server.numClients; ++client)
+ {
+ if (cr_server.clients[client]==cr_server.curClient)
+ continue;
+
+ found = crServerRemoveClientContext(cr_server.clients[client], ctx);
+
+ if (found) break;
+ }
+ }
+
+ if (!found)
+ {
+ pNode=cr_server.pCleanupClient;
+
+ while (pNode && !found)
+ {
+ found = crServerRemoveClientContext(pNode->pClient, ctx);
+ pNode = pNode->next;
+ }
+ }
+
+ CRASSERT(found);
+ }
+
+ /*Make sure this context isn't active in other clients*/
+ for (client=0; client<cr_server.numClients; ++client)
+ {
+ if (cr_server.clients[client]->currentCtxInfo == crCtxInfo)
+ {
+ cr_server.clients[client]->currentContextNumber = -1;
+ cr_server.clients[client]->currentCtxInfo = &cr_server.MainContextInfo;
+ }
+ }
+
+ pNode=cr_server.pCleanupClient;
+ while (pNode)
+ {
+ if (pNode->pClient->currentCtxInfo == crCtxInfo)
+ {
+ pNode->pClient->currentContextNumber = -1;
+ pNode->pClient->currentCtxInfo = &cr_server.MainContextInfo;
+ }
+ pNode = pNode->next;
+ }
+
+ CRASSERT(cr_server.currentCtxInfo != crCtxInfo);
+}
+
+void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo )
+{
+ CRMuralInfo *oldMural;
+ CRContext *ctx, *oldCtx = NULL;
+ GLuint idDrawFBO, idReadFBO;
+ GLint context = ctxInfo->CreateInfo.externalID;
+ GLint window = mural->CreateInfo.externalID;
+
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
+
+ ctx = ctxInfo->pContext;
+ CRASSERT(ctx);
+
+ oldMural = cr_server.currentMural;
+
+ /* Ubuntu 11.04 hosts misbehave if context window switch is
+ * done with non-default framebuffer object settings.
+ * crStateSwitchPrepare & crStateSwitchPostprocess are supposed to work around this problem
+ * crStateSwitchPrepare restores the FBO state to its default values before the context window switch,
+ * while crStateSwitchPostprocess restores it back to the original values */
+ oldCtx = crStateGetCurrent();
+ if (oldMural && oldMural->fRedirected && crServerSupportRedirMuralFBO())
+ {
+ idDrawFBO = CR_SERVER_FBO_FOR_IDX(oldMural, oldMural->iCurDrawBuffer);
+ idReadFBO = CR_SERVER_FBO_FOR_IDX(oldMural, oldMural->iCurReadBuffer);
+ }
+ else
+ {
+ idDrawFBO = 0;
+ idReadFBO = 0;
+ }
+ crStateSwitchPrepare(cr_server.bUseMultipleContexts ? NULL : ctx, oldCtx, idDrawFBO, idReadFBO);
+
+ if (cr_server.curClient)
+ {
+ /*
+ crDebug("**** %s client %d curCtx=%d curWin=%d", __func__,
+ cr_server.curClient->number, ctxPos, window);
+ */
+ cr_server.curClient->currentContextNumber = context;
+ cr_server.curClient->currentCtxInfo = ctxInfo;
+ cr_server.curClient->currentMural = mural;
+ cr_server.curClient->currentWindow = window;
+
+ CRASSERT(cr_server.curClient->currentCtxInfo);
+ CRASSERT(cr_server.curClient->currentCtxInfo->pContext);
+ }
+
+ /* This is a hack to force updating the 'current' attribs */
+ crStateUpdateColorBits();
+
+ if (ctx)
+ crStateSetCurrentPointers( ctx, &(cr_server.current) );
+
+ /* check if being made current for first time, update viewport */
+#if 0
+ if (ctx) {
+ /* initialize the viewport */
+ if (ctx->viewport.viewportW == 0) {
+ ctx->viewport.viewportW = mural->width;
+ ctx->viewport.viewportH = mural->height;
+ ctx->viewport.scissorW = mural->width;
+ ctx->viewport.scissorH = mural->height;
+ }
+ }
+#endif
+
+ /*
+ crDebug("**** %s currentWindow %d newWindow %d", __func__,
+ cr_server.currentWindow, window);
+ */
+
+ if (1/*cr_server.firstCallMakeCurrent ||
+ cr_server.currentWindow != window ||
+ cr_server.currentNativeWindow != nativeWindow*/) {
+ /* Since the cr server serialized all incoming contexts/clients into
+ * one output stream of GL commands, we only need to call the head
+ * SPU's MakeCurrent() function once.
+ * BUT, if we're rendering to multiple windows, we do have to issue
+ * MakeCurrent() calls sometimes. The same GL context will always be
+ * used though.
+ */
+ cr_server.head_spu->dispatch_table.MakeCurrent( mural->spuWindow,
+ 0,
+ ctxInfo->SpuContext >= 0
+ ? ctxInfo->SpuContext
+ : cr_server.MainContextInfo.SpuContext);
+
+ CR_STATE_SHAREDOBJ_USAGE_SET(mural, ctx);
+ if (cr_server.currentCtxInfo)
+ cr_server.currentCtxInfo->currentMural = NULL;
+ ctxInfo->currentMural = mural;
+
+ cr_server.firstCallMakeCurrent = GL_FALSE;
+ cr_server.currentCtxInfo = ctxInfo;
+ cr_server.currentWindow = window;
+ cr_server.currentNativeWindow = 0;
+ cr_server.currentMural = mural;
+ }
+
+ /* This used to be earlier, after crStateUpdateColorBits() call */
+ crStateMakeCurrent( ctx );
+
+ if (mural && mural->fRedirected && crServerSupportRedirMuralFBO())
+ {
+ GLuint id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
+ if (id != mural->iCurDrawBuffer)
+ {
+ crDebug("DBO draw buffer changed on make current");
+ mural->iCurDrawBuffer = id;
+ }
+
+ id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
+ if (id != mural->iCurReadBuffer)
+ {
+ crDebug("DBO read buffer changed on make current");
+ mural->iCurReadBuffer = id;
+ }
+
+ idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer);
+ idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer);
+ }
+ else
+ {
+ idDrawFBO = 0;
+ idReadFBO = 0;
+ }
+ crStateSwitchPostprocess(ctx, cr_server.bUseMultipleContexts ? NULL : oldCtx, idDrawFBO, idReadFBO);
+
+ if (!ctx->framebufferobject.drawFB
+ && (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT)
+ && cr_server.curClient)
+ cr_server.curClient->currentMural->bFbDraw = GL_TRUE;
+
+ if (!mural->fRedirected)
+ {
+ ctx->buffer.width = mural->width;
+ ctx->buffer.height = mural->height;
+ }
+ else
+ {
+ ctx->buffer.width = 0;
+ ctx->buffer.height = 0;
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context )
+{
+ CRMuralInfo *mural;
+ CRContextInfo *ctxInfo = NULL;
+
+ if (context >= 0 && window >= 0) {
+ mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural)
+ {
+ crWarning("CRServer: invalid window %d passed to crServerDispatchMakeCurrent()", window);
+ return;
+ }
+
+ /* Update the state tracker's current context */
+ ctxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, context);
+ if (!ctxInfo) {
+ crWarning("CRserver: NULL context in MakeCurrent %d", context);
+ return;
+ }
+ }
+ else {
+#if 0
+ oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow);
+ if (oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO())
+ {
+ if (!crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
+ }
+ if (!crStateGetCurrent()->framebufferobject.readFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
+ }
+ }
+
+ ctxInfo = &cr_server.MainContextInfo;
+ window = -1;
+ mural = NULL;
+#endif
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
+ return;
+ }
+
+ crServerPerformMakeCurrent( mural, ctxInfo );
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py
new file mode 100755
index 00000000..de765f04
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py
@@ -0,0 +1,137 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys, string, re
+
+import apiutil
+
+
+
+apiutil.CopyrightC()
+
+print("""
+/* DO NOT EDIT - THIS FILE AUTOMATICALLY GENERATED BY server_dispatch.py SCRIPT */
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_unpack.h"
+
+CRCurrentStatePointers crServerCurrent;
+""")
+
+
+for func_name in apiutil.AllSpecials( sys.argv[1]+"/../state_tracker/state" ):
+ params = apiutil.Parameters(func_name)
+ if (apiutil.FindSpecial( "server", func_name ) or
+ "get" in apiutil.Properties(func_name)):
+ continue
+
+ wrap = apiutil.GetCategoryWrapper(func_name)
+ if wrap:
+ print('#if defined(CR_%s)' % wrap)
+ print('void SERVER_DISPATCH_APIENTRY crServerDispatch%s(%s)' % ( func_name, apiutil.MakeDeclarationString( params ) ))
+ print('{')
+ print('\tcrState%s(%s);' % (func_name, apiutil.MakeCallString( params ) ))
+ print('\tcr_server.head_spu->dispatch_table.%s(%s);' % (func_name, apiutil.MakeCallString( params ) ))
+ print('}')
+ if wrap:
+ print('#endif')
+
+
+keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt")
+for func_name in keys:
+ current = 0
+ array = ""
+ condition = ""
+ m = re.search( r"^(Color|Normal)([1234])(ub|b|us|s|ui|i|f|d)$", func_name )
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = m.group(3) + m.group(2)
+ m = re.search( r"^(SecondaryColor)(3)(ub|b|us|s|ui|i|f|d)(EXT)$", func_name )
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = m.group(3) + m.group(2)
+ m = re.search( r"^(TexCoord)([1234])(ub|b|us|s|ui|i|f|d)$", func_name )
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = m.group(3) + m.group(2)
+ array = "[0]"
+ m = re.search( r"^(MultiTexCoord)([1234])(ub|b|us|s|ui|i|f|d)ARB$", func_name )
+ if m :
+ current = 1
+ name = "texCoord"
+ type = m.group(3) + m.group(2)
+ array = "[texture-GL_TEXTURE0_ARB]"
+ condition = "if (texture >= GL_TEXTURE0_ARB && texture < GL_TEXTURE0_ARB + CR_MAX_TEXTURE_UNITS)"
+ m = re.match( r"^(Index)(ub|b|us|s|ui|i|f|d)$", func_name )
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = m.group(2) + "1"
+ m = re.match( r"^(EdgeFlag)$", func_name )
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = "l1"
+ m = re.match( r"^(FogCoord)(f|d)(EXT)$", func_name)
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = m.group(2) + "1"
+
+ # Vertex attribute commands w/ some special cases
+ m = re.search( r"^(VertexAttrib)([1234])(s|i|f|d)ARB$", func_name )
+ if m :
+ current = 1
+ name = m.group(1)[:1].lower() + m.group(1)[1:]
+ type = m.group(3) + m.group(2)
+ array = "[index]"
+ condition = "if (index < CR_MAX_VERTEX_ATTRIBS)"
+ if func_name == "VertexAttrib4NubARB":
+ current = 1
+ name = "vertexAttrib"
+ type = "ub4"
+ array = "[index]"
+ condition = "if (index < CR_MAX_VERTEX_ATTRIBS)"
+
+ if current:
+ params = apiutil.Parameters(func_name)
+ print('void SERVER_DISPATCH_APIENTRY crServerDispatch%s(%s)' % ( func_name, apiutil.MakeDeclarationString(params) ))
+ print('{')
+ print('\t%s' % (condition))
+ print('\t{')
+ print('\t\tcr_server.head_spu->dispatch_table.%s(%s);' % (func_name, apiutil.MakeCallString(params) ))
+ print("\t\tcr_server.current.c.%s.%s%s = cr_unpackData;" % (name,type,array))
+ print('\t}')
+ print('}\n')
+
+print("""
+void crServerInitDispatch(void)
+{
+ crSPUInitDispatchTable( &(cr_server.dispatch) );
+ crSPUCopyDispatchTable( &(cr_server.dispatch), &(cr_server.head_spu->dispatch_table ) );
+""")
+
+for func_name in keys:
+ if ("get" in apiutil.Properties(func_name) or
+ apiutil.FindSpecial( "server", func_name ) or
+ apiutil.FindSpecial( sys.argv[1]+"/../state_tracker/state", func_name )):
+
+ wrap = apiutil.GetCategoryWrapper(func_name)
+ if wrap:
+ print('#if defined(CR_%s)' % wrap)
+
+ print('\tcr_server.dispatch.%s = crServerDispatch%s;' % (func_name, func_name))
+ if wrap:
+ print('#endif')
+
+print('}')
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py
new file mode 100755
index 00000000..7db1a1ef
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py
@@ -0,0 +1,51 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys
+
+import apiutil
+
+apiutil.CopyrightC()
+
+print("""
+/* DO NOT EDIT - THIS FILE AUTOMATICALLY GENERATED BY server_dispatch_header.py SCRIPT */
+#ifndef SERVER_DISPATCH_HEADER
+#define SERVER_DISPATCH_HEADER
+
+#ifdef WINDOWS
+#define SERVER_DISPATCH_APIENTRY __stdcall
+#else
+#define SERVER_DISPATCH_APIENTRY
+#endif
+
+#include "chromium.h"
+#include "state/cr_statetypes.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+""")
+
+keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt")
+
+for func_name in keys:
+ if ("get" in apiutil.Properties(func_name) or
+ apiutil.FindSpecial( "server", func_name ) or
+ apiutil.FindSpecial( sys.argv[1]+"/../state_tracker/state", func_name )):
+
+ params = apiutil.Parameters(func_name)
+ return_type = apiutil.ReturnType(func_name)
+
+ print('%s SERVER_DISPATCH_APIENTRY crServerDispatch%s(%s);' % (return_type, func_name, apiutil.MakeDeclarationString( params )))
+
+print("""
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* SERVER_DISPATCH_HEADER */
+""")
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c
new file mode 100644
index 00000000..8f3886a6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c
@@ -0,0 +1,237 @@
+/* $Id: server_framebuffer.c $ */
+/** @file
+ * VBox OpenGL: EXT_framebuffer_object
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_unpack.h"
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGenFramebuffersEXT(GLsizei n, GLuint *framebuffers)
+{
+ GLuint *local_buffers;
+ (void) framebuffers;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenFramebuffersEXT: parameter 'n' is out of range");
+ return;
+ }
+
+ local_buffers = (GLuint *)crCalloc(n * sizeof(*local_buffers));
+
+ crStateGenFramebuffersEXT(n, local_buffers);
+
+ crServerReturnValue(local_buffers, n * sizeof(*local_buffers));
+ crFree(local_buffers);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers)
+{
+ GLuint *local_buffers;
+ (void) renderbuffers;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenRenderbuffersEXT: parameter 'n' is out of range");
+ return;
+ }
+
+ local_buffers = (GLuint *)crCalloc(n * sizeof(*local_buffers));
+
+ crStateGenRenderbuffersEXT(n, local_buffers);
+
+ crServerReturnValue(local_buffers, n * sizeof(*local_buffers));
+ crFree(local_buffers);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ crStateFramebufferTexture1DEXT(target, attachment, textarget, texture, level);
+ cr_server.head_spu->dispatch_table.FramebufferTexture1DEXT(target, attachment, textarget, crStateGetTextureHWID(texture), level);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ crStateFramebufferTexture2DEXT(target, attachment, textarget, texture, level);
+ cr_server.head_spu->dispatch_table.FramebufferTexture2DEXT(target, attachment, textarget, crStateGetTextureHWID(texture), level);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
+{
+ crStateFramebufferTexture3DEXT(target, attachment, textarget, texture, level, zoffset);
+ cr_server.head_spu->dispatch_table.FramebufferTexture3DEXT(target, attachment, textarget, crStateGetTextureHWID(texture), level, zoffset);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBindFramebufferEXT(GLenum target, GLuint framebuffer)
+{
+#ifdef DEBUG_misha
+ GLint rfb = 0, dfb = 0;
+#endif
+ crStateBindFramebufferEXT(target, framebuffer);
+
+ if (0==framebuffer)
+ {
+ CRContext *ctx = crStateGetCurrent();
+ if (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT || ctx->buffer.drawBuffer == GL_FRONT_RIGHT)
+ cr_server.curClient->currentMural->bFbDraw = GL_TRUE;
+ }
+
+ if (0==framebuffer && crServerIsRedirectedToFBO())
+ {
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ if (target == GL_FRAMEBUFFER)
+ {
+ GLuint idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer);
+ GLuint idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer);
+ if (idDrawFBO == idReadFBO)
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_FRAMEBUFFER, idDrawFBO);
+ else
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO);
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO);
+ }
+ }
+ else if (target == GL_READ_FRAMEBUFFER)
+ {
+ GLuint idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer);
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO);
+ }
+ else if (target == GL_DRAW_FRAMEBUFFER)
+ {
+ GLuint idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer);
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO);
+ }
+ else
+ {
+ crWarning("unknown target %d", target);
+ }
+#ifdef DEBUG_misha
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb);
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb);
+ if (GL_FRAMEBUFFER_EXT == target)
+ {
+ Assert(rfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ Assert(dfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
+ }
+ else if (GL_READ_FRAMEBUFFER_EXT == target)
+ {
+ Assert(rfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ }
+ else if (GL_DRAW_FRAMEBUFFER_EXT == target)
+ {
+ Assert(dfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
+ }
+ else
+ {
+ Assert(0);
+ }
+#endif
+ }
+ else
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(target, crStateGetFramebufferHWID(framebuffer));
+#ifdef DEBUG_misha
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb);
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb);
+ if (GL_FRAMEBUFFER_EXT == target)
+ {
+ Assert(rfb == crStateGetFramebufferHWID(framebuffer));
+ Assert(dfb == crStateGetFramebufferHWID(framebuffer));
+ }
+ else if (GL_READ_FRAMEBUFFER_EXT == target)
+ {
+ Assert(rfb == crStateGetFramebufferHWID(framebuffer));
+ }
+ else if (GL_DRAW_FRAMEBUFFER_EXT == target)
+ {
+ Assert(dfb == crStateGetFramebufferHWID(framebuffer));
+ }
+ else
+ {
+ Assert(0);
+ }
+#endif
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBindRenderbufferEXT(GLenum target, GLuint renderbuffer)
+{
+ crStateBindRenderbufferEXT(target, renderbuffer);
+ cr_server.head_spu->dispatch_table.BindRenderbufferEXT(target, crStateGetRenderbufferHWID(renderbuffer));
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteFramebuffersEXT(GLsizei n, const GLuint * framebuffers)
+{
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint) || !DATA_POINTER_CHECK(n * sizeof(GLuint)))
+ {
+ crError("crStateDeleteFramebuffersEXT: parameter 'n' is out of range");
+ return;
+ }
+
+ crStateDeleteFramebuffersEXT(n, framebuffers);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteRenderbuffersEXT(GLsizei n, const GLuint * renderbuffers)
+{
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint) || !DATA_POINTER_CHECK(n * sizeof(GLuint)))
+ {
+ crError("glDeleteRenderbuffersEXT: parameter 'n' is out of range");
+ return;
+ }
+
+ crStateDeleteRenderbuffersEXT(n, renderbuffers);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ crStateFramebufferRenderbufferEXT(target, attachment, renderbuffertarget, renderbuffer);
+ cr_server.head_spu->dispatch_table.FramebufferRenderbufferEXT(target, attachment, renderbuffertarget, crStateGetRenderbufferHWID(renderbuffer));
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, GLenum pname, GLint * params)
+{
+ GLint local_params[1];
+ (void) params;
+ crStateGetFramebufferAttachmentParameterivEXT(target, attachment, pname, local_params);
+
+ crServerReturnValue(&(local_params[0]), 1*sizeof(GLint));
+}
+
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsFramebufferEXT( GLuint framebuffer )
+{
+ /* since GenFramebuffers/Renderbuffers issued to host ogl only on bind + some other ops, the host drivers may not know about them
+ * so use state data*/
+ GLboolean retval = crStateIsFramebufferEXT(framebuffer);
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsRenderbufferEXT( GLuint renderbuffer )
+{
+ /* since GenFramebuffers/Renderbuffers issued to host ogl only on bind + some other ops, the host drivers may not know about them
+ * so use state data*/
+ GLboolean retval = crStateIsRenderbufferEXT(renderbuffer);
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_gentextures.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_gentextures.c
new file mode 100644
index 00000000..88cf6812
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_gentextures.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGenTextures( GLsizei n, GLuint *textures )
+{
+ GLuint *local_textures;
+ (void) textures;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenTextures: parameter 'n' is out of range");
+ return;
+ }
+
+ local_textures = (GLuint *)crCalloc(n * sizeof(*local_textures));
+
+ if (!local_textures)
+ {
+ crError("crServerDispatchGenTextures: out of memory");
+ return;
+ }
+
+ crStateGenTextures(n, local_textures);
+
+ crServerReturnValue(local_textures, n*sizeof(*local_textures));
+ crFree( local_textures );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGenProgramsNV( GLsizei n, GLuint * ids )
+{
+ GLuint *local_progs;
+ (void) ids;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenProgramsNV: parameter 'n' is out of range");
+ return;
+ }
+
+ local_progs = (GLuint *)crCalloc(n * sizeof(*local_progs));
+
+ if (!local_progs)
+ {
+ crError("crServerDispatchGenProgramsNV: out of memory");
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GenProgramsNV( n, local_progs );
+ crServerReturnValue( local_progs, n*sizeof( *local_progs ) );
+ crFree( local_progs );
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGenFencesNV( GLsizei n, GLuint * ids )
+{
+ GLuint *local_fences;
+ (void) ids;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenFencesNV: parameter 'n' is out of range");
+ return;
+ }
+
+ local_fences = (GLuint *)crCalloc(n * sizeof(*local_fences));
+
+ if (!local_fences)
+ {
+ crError("crServerDispatchGenFencesNV: out of memory");
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GenFencesNV( n, local_fences );
+ crServerReturnValue( local_fences, n*sizeof( *local_fences ) );
+ crFree( local_fences );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGenProgramsARB( GLsizei n, GLuint * ids )
+{
+ GLuint *local_progs;
+ GLsizei i;
+ (void) ids;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenProgramsARB: parameter 'n' is out of range");
+ return;
+ }
+
+ local_progs = (GLuint *)crCalloc(n * sizeof(*local_progs));
+
+ if (!local_progs)
+ {
+ crError("crServerDispatchGenProgramsARB: out of money");
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GenProgramsARB( n, local_progs );
+
+ /* see comments in crServerDispatchGenTextures */
+ for (i=0; i<n; ++i)
+ {
+ GLuint tID = crServerTranslateProgramID(local_progs[i]);
+ while (crStateIsProgramARB(tID))
+ {
+ cr_server.head_spu->dispatch_table.GenProgramsARB(1, &tID);
+ local_progs[i] = tID;
+ tID = crServerTranslateProgramID(tID);
+ }
+ }
+
+ crServerReturnValue( local_progs, n * sizeof( *local_progs ) );
+ crFree( local_progs );
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchCopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+ GLsizei tw, th;
+
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &tw);
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &th);
+
+ /* Workaround for a wine or ati bug. Host drivers crash unless we first provide texture bounds. */
+ if (((tw!=width) || (th!=height)) && (internalFormat==GL_DEPTH_COMPONENT24))
+ {
+ crServerDispatchTexImage2D(target, level, internalFormat, width, height, border, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+ }
+
+ crStateCopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
+ cr_server.head_spu->dispatch_table.CopyTexImage2D(target, level, internalFormat, x, y, width, height, border);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py
new file mode 100755
index 00000000..8463a1f7
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py
@@ -0,0 +1,145 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys
+
+import apiutil
+
+
+apiutil.CopyrightC()
+
+print("""
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+""")
+
+max_components = {
+ 'GetClipPlane': 4,
+ 'GetCombinerStageParameterfvNV': 4,
+ 'GetCombinerStageParameterivNV': 4,
+ 'GetCombinerOutputParameterfvNV': 4,
+ 'GetCombinerOutputParameterivNV': 4,
+ 'GetCombinerInputParameterfvNV': 4,
+ 'GetCombinerInputParameterivNV': 4,
+ 'GetFinalCombinerInputParameterfvNV': 4,
+ 'GetFinalCombinerInputParameterivNV': 4,
+ 'GetLightfv': 4,
+ 'GetLightiv': 4,
+ 'GetMaterialfv': 4,
+ 'GetMaterialiv': 4,
+ 'GetPolygonStipple': 32*32/8,
+ 'GetTexEnvfv': 4,
+ 'GetTexEnviv': 4,
+ 'GetTexGendv': 4,
+ 'GetTexGenfv': 4,
+ 'GetTexGeniv': 4,
+ 'GetTexLevelParameterfv': 1,
+ 'GetTexLevelParameteriv': 1,
+ 'GetTexParameterfv': 4,
+ 'GetTexParameteriv': 4,
+ 'GetProgramParameterdvNV': 4,
+ 'GetProgramParameterfvNV': 4,
+ 'GetProgramivNV': 1,
+ 'GetTrackMatrixivNV': 1,
+ 'GetVertexAttribPointervNV': 1,
+ 'GetVertexAttribdvNV': 4,
+ 'GetVertexAttribfvNV': 4,
+ 'GetVertexAttribivNV': 4,
+ 'GetFenceivNV': 1,
+ 'GetVertexAttribdvARB': 4,
+ 'GetVertexAttribfvARB': 4,
+ 'GetVertexAttribivARB': 4,
+ 'GetVertexAttribPointervARB': 1,
+ 'GetProgramNamedParameterdvNV': 4,
+ 'GetProgramNamedParameterfvNV': 4,
+ 'GetProgramLocalParameterdvARB': 4,
+ 'GetProgramLocalParameterfvARB': 4,
+ 'GetProgramEnvParameterdvARB': 4,
+ 'GetProgramEnvParameterfvARB': 4,
+ 'GetProgramivARB': 1,
+ 'AreProgramsResidentNV': 1,
+ 'GetBufferParameterivARB': 1,
+ 'GetBufferPointervARB': 1,
+ 'GetQueryObjectivARB' : 1,
+ 'GetQueryObjectuivARB' : 1,
+ 'GetQueryivARB' : 1,
+ 'GetProgramiv' : 1,
+ 'GetShaderiv' : 1,
+ 'GetObjectParameterfvARB': 1,
+ 'GetObjectParameterivARB': 1,
+ 'GetRenderbufferParameterivEXT': 1,
+ 'GetFramebufferAttachmentParameterivEXT': 1
+}
+
+no_pnames = [
+ 'GetClipPlane',
+ 'GetPolygonStipple',
+ 'GetProgramLocalParameterdvARB',
+ 'GetProgramLocalParameterfvARB',
+ 'GetProgramNamedParameterdvNV',
+ 'GetProgramNamedParameterfvNV',
+ 'GetProgramNamedParameterdvNV',
+ 'GetProgramNamedParameterfvNV',
+ 'GetProgramEnvParameterdvARB',
+ 'GetProgramEnvParameterfvARB',
+ 'GetProgramivARB',
+ 'AreProgramsResidentNV',
+ 'GetProgramiv',
+ 'GetShaderiv',
+ 'GetObjectParameterfvARB',
+ 'GetObjectParameterivARB',
+ 'GetRenderbufferParameterivEXT',
+ 'GetFramebufferAttachmentParameterivEXT'
+];
+
+convert_bufferid = [
+ 'GetVertexAttribdvARB',
+ 'GetVertexAttribdvNV',
+ 'GetVertexAttribfvARB',
+ 'GetVertexAttribfvNV',
+ 'GetVertexAttribivARB',
+ 'GetVertexAttribivNV'
+];
+
+keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt")
+for func_name in keys:
+ #(return_type, arg_names, arg_types) = gl_mapping[func_name]
+ if ("get" in apiutil.Properties(func_name) and
+ apiutil.ReturnType(func_name) == "void" and
+ not apiutil.FindSpecial( "server", func_name )):
+
+ params = apiutil.Parameters(func_name)
+
+ print('void SERVER_DISPATCH_APIENTRY crServerDispatch%s(%s)' % (func_name, apiutil.MakeDeclarationString( params ) ))
+ print('{')
+
+ lastParam = params[-1]
+ assert apiutil.IsPointer(lastParam[1])
+ local_argtype = apiutil.PointerType(lastParam[1])
+ local_argname = 'local_%s' % lastParam[0]
+
+ print('\t%s %s[%d];' % ( local_argtype, local_argname, max_components[func_name] ))
+ print('\t(void) %s;' % lastParam[0])
+
+ params[-1] = (local_argname, local_argtype, 0)
+
+ print('\tcr_server.head_spu->dispatch_table.%s(%s);' % ( func_name, apiutil.MakeCallString(params) ))
+
+ if func_name in convert_bufferid:
+ print('\tif (pname==GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB){')
+ print('\t\tlocal_params[0]=(%s)crStateBufferHWIDtoID((GLint)local_params[0]);' % (local_argtype))
+ print('\t}')
+
+ if func_name in no_pnames:
+ print('\tcrServerReturnValue(&(%s[0]), %d*sizeof(%s));' % (local_argname, max_components[func_name], local_argtype ))
+ else:
+ print('\tcrServerReturnValue(&(%s[0]), crStateHlpComponentsCount(pname)*sizeof(%s));' % (local_argname, local_argtype ))
+ print ('}\n')
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getmap.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getmap.c
new file mode 100644
index 00000000..b8123e32
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getmap.c
@@ -0,0 +1,247 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+static GLuint __evaluator_components( GLenum target )
+{
+ switch (target) {
+ case GL_MAP1_VERTEX_3: return 3;
+ case GL_MAP1_VERTEX_4: return 4;
+ case GL_MAP1_INDEX: return 1;
+ case GL_MAP1_COLOR_4: return 4;
+ case GL_MAP1_NORMAL: return 3;
+ case GL_MAP1_TEXTURE_COORD_1: return 1;
+ case GL_MAP1_TEXTURE_COORD_2: return 2;
+ case GL_MAP1_TEXTURE_COORD_3: return 3;
+ case GL_MAP1_TEXTURE_COORD_4: return 4;
+ case GL_MAP2_VERTEX_3: return 3;
+ case GL_MAP2_VERTEX_4: return 4;
+ case GL_MAP2_INDEX: return 1;
+ case GL_MAP2_COLOR_4: return 4;
+ case GL_MAP2_NORMAL: return 3;
+ case GL_MAP2_TEXTURE_COORD_1: return 1;
+ case GL_MAP2_TEXTURE_COORD_2: return 2;
+ case GL_MAP2_TEXTURE_COORD_3: return 3;
+ case GL_MAP2_TEXTURE_COORD_4: return 4;
+ default: return 0;
+ }
+}
+
+static GLuint __evaluator_dimension( GLenum target )
+{
+ switch( target )
+ {
+ case GL_MAP1_COLOR_4:
+ case GL_MAP1_INDEX:
+ case GL_MAP1_NORMAL:
+ case GL_MAP1_TEXTURE_COORD_1:
+ case GL_MAP1_TEXTURE_COORD_2:
+ case GL_MAP1_TEXTURE_COORD_3:
+ case GL_MAP1_TEXTURE_COORD_4:
+ case GL_MAP1_VERTEX_3:
+ case GL_MAP1_VERTEX_4:
+ return 1;
+
+ case GL_MAP2_COLOR_4:
+ case GL_MAP2_INDEX:
+ case GL_MAP2_NORMAL:
+ case GL_MAP2_TEXTURE_COORD_1:
+ case GL_MAP2_TEXTURE_COORD_2:
+ case GL_MAP2_TEXTURE_COORD_3:
+ case GL_MAP2_TEXTURE_COORD_4:
+ case GL_MAP2_VERTEX_3:
+ case GL_MAP2_VERTEX_4:
+ return 2;
+
+ default:
+ return 0;
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetMapdv( GLenum target, GLenum query, GLdouble *v )
+{
+ GLdouble *coeffs = NULL;
+ GLdouble *retptr = NULL;
+ GLdouble order[2] = {0};
+ GLdouble domain[4] = {0};
+ GLint tempOrder[2] = {0};
+ int dimension, evalcomp;
+ unsigned int size = sizeof(GLdouble);
+ (void) v;
+
+ evalcomp = __evaluator_components(target);
+ dimension = __evaluator_dimension(target);
+
+ if (evalcomp == 0 || dimension == 0)
+ {
+ crError( "Bad target in crServerDispatchGetMapdv: %d", target );
+ return;
+ }
+
+ switch(query)
+ {
+ case GL_ORDER:
+ cr_server.head_spu->dispatch_table.GetMapdv( target, query, order );
+ retptr = &(order[0]);
+ size *= dimension;
+ break;
+ case GL_DOMAIN:
+ cr_server.head_spu->dispatch_table.GetMapdv( target, query, domain );
+ retptr = &(domain[0]);
+ size *= dimension * 2;
+ break;
+ case GL_COEFF:
+ cr_server.head_spu->dispatch_table.GetMapiv( target, GL_ORDER, tempOrder );
+ size *= evalcomp * tempOrder[0];
+ if (dimension == 2)
+ size *= tempOrder[1];
+
+ if (size)
+ coeffs = (GLdouble *) crCalloc( size );
+
+ if (coeffs)
+ {
+ cr_server.head_spu->dispatch_table.GetMapdv( target, query, coeffs );
+ retptr = coeffs;
+ }
+ break;
+ default:
+ crError( "Bad query in crServerDispatchGetMapdv: %d", query );
+ return;
+ }
+
+ crServerReturnValue( retptr, size );
+ if (coeffs)
+ {
+ crFree(coeffs);
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetMapfv( GLenum target, GLenum query, GLfloat *v )
+{
+ GLfloat *coeffs = NULL;
+ GLfloat *retptr = NULL;
+ GLfloat order[2] = {0};
+ GLfloat domain[4] = {0};
+ GLint tempOrder[2] = {0};
+ int dimension, evalcomp;
+ unsigned int size = sizeof(GLfloat);
+ (void) v;
+
+ evalcomp = __evaluator_components(target);
+ dimension = __evaluator_dimension(target);
+
+ if (evalcomp == 0 || dimension == 0)
+ {
+ crError( "Bad target in crServerDispatchGetMapfv: %d", target );
+ return;
+ }
+
+ switch(query)
+ {
+ case GL_ORDER:
+ cr_server.head_spu->dispatch_table.GetMapfv( target, query, order );
+ retptr = &(order[0]);
+ size *= dimension;
+ break;
+ case GL_DOMAIN:
+ cr_server.head_spu->dispatch_table.GetMapfv( target, query, domain );
+ retptr = &(domain[0]);
+ size *= dimension * 2;
+ break;
+ case GL_COEFF:
+ cr_server.head_spu->dispatch_table.GetMapiv( target, GL_ORDER, tempOrder );
+ size *= evalcomp * tempOrder[0];
+ if (dimension == 2)
+ size *= tempOrder[1];
+
+ if (size)
+ coeffs = (GLfloat *) crCalloc( size );
+
+ if (coeffs)
+ {
+ cr_server.head_spu->dispatch_table.GetMapfv( target, query, coeffs );
+ retptr = coeffs;
+ }
+ break;
+ default:
+ crError( "Bad query in crServerDispatchGetMapfv: %d", query );
+ return;
+ }
+
+ crServerReturnValue( retptr, size );
+ if (coeffs)
+ {
+ crFree(coeffs);
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetMapiv( GLenum target, GLenum query, GLint *v )
+{
+ GLint *coeffs = NULL;
+ GLint *retptr = NULL;
+ GLint order[2] = {0};
+ GLint domain[4] = {0};
+ GLint tempOrder[2] = {0};
+ int dimension, evalcomp;
+ unsigned int size = sizeof(GLint);
+ (void) v;
+
+ evalcomp = __evaluator_components(target);
+ dimension = __evaluator_dimension(target);
+
+ if (evalcomp == 0 || dimension == 0)
+ {
+ crError( "Bad target in crServerDispatchGetMapiv: %d", target );
+ return;
+ }
+
+ switch(query)
+ {
+ case GL_ORDER:
+ cr_server.head_spu->dispatch_table.GetMapiv( target, query, order );
+ retptr = &(order[0]);
+ size *= dimension;
+ break;
+ case GL_DOMAIN:
+ cr_server.head_spu->dispatch_table.GetMapiv( target, query, domain );
+ retptr = &(domain[0]);
+ size *= dimension * 2;
+ break;
+ case GL_COEFF:
+ cr_server.head_spu->dispatch_table.GetMapiv( target, GL_ORDER, tempOrder );
+ size *= evalcomp * tempOrder[0];
+ if (dimension == 2)
+ size *= tempOrder[1];
+
+ if (size)
+ coeffs = (GLint *) crCalloc( size );
+
+ if (coeffs)
+ {
+ cr_server.head_spu->dispatch_table.GetMapiv( target, query, coeffs );
+ retptr = coeffs;
+ }
+ break;
+ default:
+ crError( "Bad query in crServerDispatchGetMapiv: %d", query );
+ break;
+ }
+
+ crServerReturnValue( retptr, size );
+ if (coeffs)
+ {
+ crFree(coeffs);
+ }
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpixelmap.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpixelmap.c
new file mode 100644
index 00000000..79c37866
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpixelmap.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+static GLint __sizeQuery( GLenum map )
+{
+ GLint get_values;
+ /* Windows compiler gets mad if variables might be uninitialized */
+ GLenum newmap = GL_PIXEL_MAP_I_TO_I_SIZE;
+
+ switch( map )
+ {
+ case GL_PIXEL_MAP_I_TO_I:
+ newmap = GL_PIXEL_MAP_I_TO_I_SIZE;
+ break;
+ case GL_PIXEL_MAP_S_TO_S:
+ newmap = GL_PIXEL_MAP_S_TO_S_SIZE;
+ break;
+ case GL_PIXEL_MAP_I_TO_R:
+ newmap = GL_PIXEL_MAP_I_TO_R_SIZE;
+ break;
+ case GL_PIXEL_MAP_I_TO_G:
+ newmap = GL_PIXEL_MAP_I_TO_G_SIZE;
+ break;
+ case GL_PIXEL_MAP_I_TO_B:
+ newmap = GL_PIXEL_MAP_I_TO_B_SIZE;
+ break;
+ case GL_PIXEL_MAP_I_TO_A:
+ newmap = GL_PIXEL_MAP_I_TO_A_SIZE;
+ break;
+ case GL_PIXEL_MAP_R_TO_R:
+ newmap = GL_PIXEL_MAP_R_TO_R_SIZE;
+ break;
+ case GL_PIXEL_MAP_G_TO_G:
+ newmap = GL_PIXEL_MAP_G_TO_G_SIZE;
+ break;
+ case GL_PIXEL_MAP_B_TO_B:
+ newmap = GL_PIXEL_MAP_B_TO_B_SIZE;
+ break;
+ case GL_PIXEL_MAP_A_TO_A:
+ newmap = GL_PIXEL_MAP_A_TO_A_SIZE;
+ break;
+ default:
+ crError( "Bad map in crServerDispatchGetPixelMap: %d", map );
+ break;
+ }
+
+ cr_server.head_spu->dispatch_table.GetIntegerv( newmap, &get_values );
+
+ return get_values;
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetPixelMapfv( GLenum map, GLfloat *values )
+{
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ pbo_offset = (GLfloat*) ((uintptr_t) *((GLint*)values));
+
+ cr_server.head_spu->dispatch_table.GetPixelMapfv( map, pbo_offset );
+ }
+ else
+#endif
+ {
+ int size = sizeof( GLfloat );
+ int tabsize = __sizeQuery( map );
+ GLfloat *local_values;
+
+ size *= tabsize;
+ local_values = (GLfloat*)crAlloc( size );
+
+ cr_server.head_spu->dispatch_table.GetPixelMapfv( map, local_values );
+ crServerReturnValue( local_values, size );
+ crFree( local_values );
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetPixelMapuiv( GLenum map, GLuint *values )
+{
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ pbo_offset = (GLuint*) ((uintptr_t) *((GLint*)values));
+
+ cr_server.head_spu->dispatch_table.GetPixelMapuiv( map, pbo_offset );
+ }
+ else
+#endif
+ {
+ int size = sizeof( GLuint );
+ int tabsize = __sizeQuery( map );
+ GLuint *local_values;
+
+ size *= tabsize;
+ local_values = (GLuint*)crAlloc( size );
+
+ cr_server.head_spu->dispatch_table.GetPixelMapuiv( map, local_values );
+ crServerReturnValue( local_values, size );
+ crFree( local_values );
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetPixelMapusv( GLenum map, GLushort *values )
+{
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ pbo_offset = (GLushort*) ((uintptr_t) *((GLint*)values));
+
+ cr_server.head_spu->dispatch_table.GetPixelMapusv( map, pbo_offset );
+ }
+ else
+#endif
+ {
+ int size = sizeof( GLushort );
+ int tabsize = __sizeQuery( map );
+ GLushort *local_values;
+
+ size *= tabsize;
+ local_values = (GLushort*)crAlloc( size );
+
+ cr_server.head_spu->dispatch_table.GetPixelMapusv( map, local_values );
+ crServerReturnValue( local_values, size );
+ crFree( local_values );
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpointer.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpointer.c
new file mode 100644
index 00000000..bc14298a
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpointer.c
@@ -0,0 +1,32 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "chromium.h"
+#include "cr_error.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetPointerv( GLenum pname, GLvoid **pointer )
+{
+ crError( "glGetPointerv isn't *ever* allowed to be on the wire!" );
+ (void) pname;
+ (void) pointer;
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetVertexAttribPointervNV( GLuint index, GLenum pname, GLvoid ** pointer )
+{
+ crError( "glGetVertexAttribPointervNV isn't *ever* allowed to be on the wire!" );
+ (void) pname;
+ (void) pointer;
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetVertexAttribPointervARB( GLuint index, GLenum pname, GLvoid ** pointer )
+{
+ crError( "glGetVertexAttribPointervNV isn't *ever* allowed to be on the wire!" );
+ (void) pname;
+ (void) pointer;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
new file mode 100644
index 00000000..8a657d43
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c
@@ -0,0 +1,395 @@
+/* $Id: server_getshaders.c $ */
+/** @file
+ * VBox OpenGL GLSL related get functions
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+#include <iprt/assert.h>
+
+#ifdef CR_OPENGL_VERSION_2_0
+
+typedef struct _crGetActive_t
+{
+ GLsizei length;
+ GLint size;
+ GLenum type;
+} crGetActive_t;
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetActiveAttrib(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, char *name)
+{
+ crGetActive_t *pLocal = NULL;
+
+ if (bufSize > 0 && bufSize < INT32_MAX / 2)
+ pLocal = (crGetActive_t*)crCalloc(bufSize + sizeof(crGetActive_t));
+
+ if (!pLocal)
+ {
+ crGetActive_t zero;
+ zero.length = 0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GetActiveAttrib(crStateGetProgramHWID(program), index, bufSize, &pLocal->length, &pLocal->size, &pLocal->type, (char*)&pLocal[1]);
+ crServerReturnValue(pLocal, pLocal->length+1+sizeof(crGetActive_t));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetActiveUniform(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, char *name)
+{
+ crGetActive_t *pLocal = NULL;
+
+ if (bufSize > 0 && bufSize < INT32_MAX / 2)
+ pLocal = (crGetActive_t*) crCalloc(bufSize + sizeof(crGetActive_t));
+
+ if (!pLocal)
+ {
+ crGetActive_t zero;
+ zero.length = 0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GetActiveUniform(crStateGetProgramHWID(program), index, bufSize, &pLocal->length, &pLocal->size, &pLocal->type, (char*)&pLocal[1]);
+ crServerReturnValue(pLocal, pLocal->length+1+sizeof(crGetActive_t));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders)
+{
+ GLsizei *pLocal = NULL;
+
+ if (maxCount > 0 && maxCount < INT32_MAX / sizeof(GLuint) / 2)
+ pLocal = (GLsizei*) crCalloc(maxCount * sizeof(GLuint) + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+ /* initial (fallback )value */
+ *pLocal = 0;
+ cr_server.head_spu->dispatch_table.GetAttachedShaders(crStateGetProgramHWID(program), maxCount, pLocal, (GLuint*)&pLocal[1]);
+
+ {
+ GLsizei i;
+ GLuint *ids=(GLuint*)&pLocal[1];
+
+ for (i=0; i<*pLocal; ++i)
+ ids[i] = crStateGLSLShaderHWIDtoID(ids[i]);
+ }
+
+ crServerReturnValue(pLocal, (*pLocal)*sizeof(GLuint)+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedObjectsARB(VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * count, VBoxGLhandleARB * obj)
+{
+ GLsizei *pLocal = NULL;
+
+ if (maxCount > 0 && maxCount < INT32_MAX / sizeof(VBoxGLhandleARB) / 2)
+ pLocal = (GLsizei*) crCalloc(maxCount * sizeof(VBoxGLhandleARB) + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+ /* initial (fallback )value */
+ *pLocal = 0;
+ cr_server.head_spu->dispatch_table.GetAttachedObjectsARB(crStateGetProgramHWID(containerObj), maxCount, pLocal, (VBoxGLhandleARB*)&pLocal[1]);
+
+ {
+ GLsizei i;
+ GLuint *ids=(GLuint*)&pLocal[1];
+
+ for (i=0; i<*pLocal; ++i)
+ ids[i] = crStateGLSLShaderHWIDtoID(ids[i]);
+ }
+
+ crServerReturnValue(pLocal, (*pLocal)*sizeof(VBoxGLhandleARB)+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+AssertCompile(sizeof(GLsizei) == 4);
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetInfoLogARB(VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog)
+{
+ GLsizei *pLocal = NULL;
+ GLuint hwid;
+
+ if (maxLength > 0 && maxLength < INT32_MAX / 2)
+ pLocal = (GLsizei*) crCalloc(maxLength + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+ /* initial (fallback )value */
+ *pLocal = 0;
+ /** @todo recheck*/
+ hwid = crStateGetProgramHWID(obj);
+ if (!hwid) hwid = crStateGetShaderHWID(obj);
+ cr_server.head_spu->dispatch_table.GetInfoLogARB(hwid, maxLength, pLocal, (char*)&pLocal[1]);
+ CRASSERT((*pLocal) <= maxLength);
+ crServerReturnValue(pLocal, (*pLocal)+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ GLsizei *pLocal = NULL;
+
+ if (bufSize > 0 && bufSize < INT32_MAX / 2)
+ pLocal = (GLsizei*) crCalloc(bufSize + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+ /* initial (fallback )value */
+ *pLocal = 0;
+ cr_server.head_spu->dispatch_table.GetShaderInfoLog(crStateGetShaderHWID(shader), bufSize, pLocal, (char*)&pLocal[1]);
+ crServerReturnValue(pLocal, pLocal[0]+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ GLsizei *pLocal = NULL;
+
+ if (bufSize > 0 && bufSize < INT32_MAX / 2)
+ pLocal = (GLsizei*) crCalloc(bufSize + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+ /* initial (fallback )value */
+ *pLocal = 0;
+ cr_server.head_spu->dispatch_table.GetProgramInfoLog(crStateGetProgramHWID(program), bufSize, pLocal, (char*)&pLocal[1]);
+ CRASSERT(pLocal[0] <= bufSize);
+ crServerReturnValue(pLocal, pLocal[0]+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetShaderSource(GLuint shader, GLsizei bufSize, GLsizei *length, char *source)
+{
+ GLsizei *pLocal = NULL;
+
+ if (bufSize > 0 && bufSize < INT32_MAX / 2)
+ pLocal = (GLsizei*) crCalloc(bufSize + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+ /* initial (fallback )value */
+ *pLocal = 0;
+ cr_server.head_spu->dispatch_table.GetShaderSource(crStateGetShaderHWID(shader), bufSize, pLocal, (char*)&pLocal[1]);
+ CRASSERT(pLocal[0] <= bufSize);
+ crServerReturnValue(pLocal, pLocal[0]+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetUniformsLocations(GLuint program, GLsizei maxcbData, GLsizei * cbData, GLvoid * pData)
+{
+ GLsizei *pLocal = NULL;
+
+ (void) cbData;
+ (void) pData;
+
+ if (maxcbData > 0 && maxcbData < INT32_MAX / 2)
+ pLocal = (GLsizei*) crCalloc(maxcbData + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+
+ /* initial (fallback )value */
+ *pLocal = 0;
+ crStateGLSLProgramCacheUniforms(program, maxcbData, pLocal, (char*)&pLocal[1]);
+
+ crServerReturnValue(pLocal, (*pLocal)+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetAttribsLocations(GLuint program, GLsizei maxcbData, GLsizei * cbData, GLvoid * pData)
+{
+ GLsizei *pLocal = NULL;
+
+ (void) cbData;
+ (void) pData;
+
+ if (maxcbData > 0 && maxcbData < INT32_MAX / 2)
+ pLocal = (GLsizei*) crCalloc(maxcbData + sizeof(GLsizei));
+
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+
+ /* initial (fallback )value */
+ *pLocal = 0;
+ crStateGLSLProgramCacheAttribs(program, maxcbData, pLocal, (char*)&pLocal[1]);
+
+ crServerReturnValue(pLocal, (*pLocal)+sizeof(GLsizei));
+ crFree(pLocal);
+}
+
+static GLint __GetUniformSize(GLuint program, GLint location)
+{
+ GLint size = 0;
+ GLenum type = 0;
+
+ /** @todo check if index and location is the same*/
+ cr_server.head_spu->dispatch_table.GetActiveUniform(crStateGetProgramHWID(program), location, 0, NULL, &size, &type, NULL);
+
+ return crStateGetUniformSize(type);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetUniformfv(GLuint program, GLint location, GLfloat *params)
+{
+ int size = __GetUniformSize(program, location) * sizeof(GLfloat);
+ GLfloat *pLocal;
+
+ pLocal = (GLfloat*) crCalloc(size);
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GetUniformfv(crStateGetProgramHWID(program), location, pLocal);
+
+ crServerReturnValue(pLocal, size);
+ crFree(pLocal);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetUniformiv(GLuint program, GLint location, GLint *params)
+{
+ int size = __GetUniformSize(program, location) * sizeof(GLint);
+ GLint *pLocal;
+
+ pLocal = (GLint*) crCalloc(size);
+ if (!pLocal)
+ {
+ GLsizei zero=0;
+ crServerReturnValue(&zero, sizeof(zero));
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GetUniformiv(crStateGetProgramHWID(program), location, pLocal);
+
+ crServerReturnValue(pLocal, size);
+ crFree(pLocal);
+}
+
+GLuint SERVER_DISPATCH_APIENTRY crServerDispatchCreateShader(GLenum type)
+{
+ GLuint retval, hwVal;
+ hwVal = cr_server.head_spu->dispatch_table.CreateShader(type);
+ retval = crStateCreateShader(hwVal, type);
+ crServerReturnValue(&retval, sizeof(retval));
+ return retval; /* ignored */
+}
+
+GLuint SERVER_DISPATCH_APIENTRY crServerDispatchCreateProgram(void)
+{
+ GLuint retval, hwVal;
+ hwVal = cr_server.head_spu->dispatch_table.CreateProgram();
+ retval = crStateCreateProgram(hwVal);
+ crServerReturnValue(&retval, sizeof(retval));
+ return retval; /* ignored */
+}
+
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsShader(GLuint shader)
+{
+ GLboolean retval;
+ retval = cr_server.head_spu->dispatch_table.IsShader(crStateGetShaderHWID(shader));
+ crServerReturnValue(&retval, sizeof(retval));
+ return retval; /* ignored */
+}
+
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsProgram(GLuint program)
+{
+ GLboolean retval;
+ retval = cr_server.head_spu->dispatch_table.IsProgram(crStateGetProgramHWID(program));
+ crServerReturnValue(&retval, sizeof(retval));
+ return retval; /* ignored */
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterfvARB( VBoxGLhandleARB obj, GLenum pname, GLfloat * params )
+{
+ GLfloat local_params[1];
+ GLuint hwid = crStateGetProgramHWID(obj);
+ (void) params;
+
+ if (!hwid)
+ {
+ hwid = crStateGetShaderHWID(obj);
+ if (!hwid)
+ {
+ crWarning("Unknown object %i, in crServerDispatchGetObjectParameterfvARB", obj);
+ }
+ }
+
+ cr_server.head_spu->dispatch_table.GetObjectParameterfvARB( hwid, pname, local_params );
+ crServerReturnValue( &(local_params[0]), 1*sizeof(GLfloat) );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterivARB( VBoxGLhandleARB obj, GLenum pname, GLint * params )
+{
+ GLint local_params[1];
+ GLuint hwid = crStateGetProgramHWID(obj);
+ if (!hwid)
+ {
+ hwid = crStateGetShaderHWID(obj);
+ if (!hwid)
+ {
+ crWarning("Unknown object %i, in crServerDispatchGetObjectParameterivARB", obj);
+ }
+ }
+
+ (void) params;
+ cr_server.head_spu->dispatch_table.GetObjectParameterivARB( hwid, pname, local_params );
+ crServerReturnValue( &(local_params[0]), 1*sizeof(GLint) );
+}
+#endif /* #ifdef CR_OPENGL_VERSION_2_0 */
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getstring.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getstring.c
new file mode 100644
index 00000000..18fad4e6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getstring.c
@@ -0,0 +1,38 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "chromium.h"
+#include "cr_error.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_string.h"
+
+const GLubyte * SERVER_DISPATCH_APIENTRY crServerDispatchGetString( GLenum name )
+{
+ const GLubyte *retval;
+ retval = cr_server.head_spu->dispatch_table.GetString( name );
+ if (retval)
+ crServerReturnValue( retval, crStrlen((char *)retval) + 1 );
+ else
+ crServerReturnValue( "", 1 ); /* empty string */
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetProgramStringNV( GLuint id, GLenum pname, GLubyte * program )
+{
+ crError( "glGetProgramStringNV isn't *ever* allowed to be on the wire!" );
+ (void) id;
+ (void) pname;
+ (void) program;
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetProgramStringARB( GLuint id, GLenum pname, void * program )
+{
+ crError( "glGetProgramStringARB isn't *ever* allowed to be on the wire!" );
+ (void) id;
+ (void) pname;
+ (void) program;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getteximage.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getteximage.c
new file mode 100644
index 00000000..288de27b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getteximage.c
@@ -0,0 +1,156 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_pixeldata.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetTexImage(GLenum target, GLint level, GLenum format,
+ GLenum type, GLvoid * pixels)
+{
+ GLsizei width, height, depth, size;
+ GLvoid *buffer = NULL;
+
+
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ /*pixels are actually a pointer to location of 8byte network pointer in hgcm buffer
+ regardless of guest/host bitness we're using only 4lower bytes as there're no
+ pbo>4gb (yet?)
+ */
+ pbo_offset = (GLvoid*) ((uintptr_t) *((GLint*)pixels));
+
+ cr_server.head_spu->dispatch_table.GetTexImage(target, level, format, type, pbo_offset);
+
+ return;
+ }
+#endif
+
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
+
+ size = crTextureSize(format, type, width, height, depth);
+
+#if 0
+ {
+ CRContext *ctx = crStateGetCurrent();
+ CRTextureObj *tobj;
+ CRTextureLevel *tl;
+ GLint id;
+
+ crDebug("GetTexImage: %d, %i, %d, %d", target, level, format, type);
+ crDebug("===StateTracker===");
+ crDebug("Current TU: %i", ctx->texture.curTextureUnit);
+
+ if (target==GL_TEXTURE_2D)
+ {
+ tobj = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D;
+ CRASSERT(tobj);
+ tl = &tobj->level[0][level];
+ crDebug("Texture %i(hw %i), w=%i, h=%i", tobj->id, tobj->hwid, tl->width, tl->height, tl->depth);
+ }
+ else
+ {
+ crDebug("Not 2D tex");
+ }
+
+ crDebug("===GPU===");
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_ACTIVE_TEXTURE, &id);
+ crDebug("Current TU: %i", id);
+ if (target==GL_TEXTURE_2D)
+ {
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_TEXTURE_BINDING_2D, &id);
+ crDebug("Texture: %i, w=%i, h=%i, d=%i", id, width, height, depth);
+ }
+ }
+#endif
+
+ if (size && (buffer = crCalloc(size))) {
+ /* Note, the other pixel PACK parameters (default values) should
+ * be OK at this point.
+ */
+ cr_server.head_spu->dispatch_table.PixelStorei(GL_PACK_ALIGNMENT, 1);
+ cr_server.head_spu->dispatch_table.GetTexImage(target, level, format, type, buffer);
+ crServerReturnValue( buffer, size );
+ crFree(buffer);
+ }
+ else {
+ /* need to return _something_ to avoid blowing up */
+ GLuint dummy = 0;
+ crServerReturnValue( (GLvoid *) &dummy, sizeof(dummy) );
+ }
+}
+
+
+#if CR_ARB_texture_compression
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGetCompressedTexImageARB(GLenum target, GLint level,
+ GLvoid *img)
+{
+ GLint size;
+ GLvoid *buffer=NULL;
+
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ pbo_offset = (GLvoid*) ((uintptr_t) *((GLint*)img));
+
+ cr_server.head_spu->dispatch_table.GetCompressedTexImageARB(target, level, pbo_offset);
+
+ return;
+ }
+#endif
+
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(target, level, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &size);
+
+ if (size && (buffer = crCalloc(size))) {
+ /* XXX the pixel PACK parameter should be OK at this point */
+ cr_server.head_spu->dispatch_table.GetCompressedTexImageARB(target, level, buffer);
+ crServerReturnValue( buffer, size );
+ crFree(buffer);
+ }
+ else {
+ /* need to return _something_ to avoid blowing up */
+ GLuint dummy = 0;
+ crServerReturnValue( (GLvoid *) &dummy, sizeof(dummy) );
+ }
+}
+
+#endif /* CR_ARB_texture_compression */
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetPolygonStipple( GLubyte * mask )
+{
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ pbo_offset = (GLubyte*) ((uintptr_t) *((GLint*)mask));
+
+ cr_server.head_spu->dispatch_table.GetPolygonStipple(pbo_offset);
+ }
+ else
+#endif
+ {
+ GLubyte local_mask[128];
+
+ memset(local_mask, 0, sizeof(local_mask));
+
+ cr_server.head_spu->dispatch_table.GetPolygonStipple( local_mask );
+ crServerReturnValue( &(local_mask[0]), 128*sizeof(GLubyte) );
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c
new file mode 100644
index 00000000..a5a915ab
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c
@@ -0,0 +1,262 @@
+/* $Id: server_glsl.c $ */
+/** @file
+ * VBox OpenGL - GLSL related functions
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+#ifdef CR_OPENGL_VERSION_2_0
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchShaderSource(GLuint shader, GLsizei count, const char ** string, const GLint * length)
+{
+ /*@todo?crStateShaderSource(shader...);*/
+#ifdef DEBUG_misha
+ GLenum err = cr_server.head_spu->dispatch_table.GetError();
+#endif
+ cr_server.head_spu->dispatch_table.ShaderSource(crStateGetShaderHWID(shader), count, string, length);
+#ifdef DEBUG_misha
+ err = cr_server.head_spu->dispatch_table.GetError();
+ CRASSERT(err == GL_NO_ERROR);
+#endif
+ CR_SERVER_DUMP_SHADER_SOURCE(shader);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchCompileShader(GLuint shader)
+{
+#ifdef DEBUG_misha
+ GLint iCompileStatus = GL_FALSE;
+#endif
+ crStateCompileShader(shader);
+ cr_server.head_spu->dispatch_table.CompileShader(crStateGetShaderHWID(shader));
+#ifdef DEBUG_misha
+ cr_server.head_spu->dispatch_table.GetShaderiv(crStateGetShaderHWID(shader), GL_COMPILE_STATUS, &iCompileStatus);
+ Assert(iCompileStatus == GL_TRUE);
+#endif
+ CR_SERVER_DUMP_COMPILE_SHADER(shader);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteShader(GLuint shader)
+{
+ GLuint shaderHW = crStateGetShaderHWID(shader);
+ crStateDeleteShader(shader);
+ if (shaderHW)
+ cr_server.head_spu->dispatch_table.DeleteShader(shaderHW);
+ else
+ crWarning("crServerDispatchDeleteShader: hwid not found for shader(%d)", shader);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchAttachShader(GLuint program, GLuint shader)
+{
+ crStateAttachShader(program, shader);
+ cr_server.head_spu->dispatch_table.AttachShader(crStateGetProgramHWID(program), crStateGetShaderHWID(shader));
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDetachShader(GLuint program, GLuint shader)
+{
+ crStateDetachShader(program, shader);
+ cr_server.head_spu->dispatch_table.DetachShader(crStateGetProgramHWID(program), crStateGetShaderHWID(shader));
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchLinkProgram(GLuint program)
+{
+ crStateLinkProgram(program);
+ cr_server.head_spu->dispatch_table.LinkProgram(crStateGetProgramHWID(program));
+ CR_SERVER_DUMP_LINK_PROGRAM(program);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchUseProgram(GLuint program)
+{
+ crStateUseProgram(program);
+ cr_server.head_spu->dispatch_table.UseProgram(crStateGetProgramHWID(program));
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteProgram(GLuint program)
+{
+ GLuint hwId = crStateGetProgramHWID(program);
+ crStateDeleteProgram(program);
+ if (hwId)
+ cr_server.head_spu->dispatch_table.DeleteProgram(hwId);
+ else
+ crWarning("crServerDispatchDeleteProgram: hwid not found for program(%d)", program);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchValidateProgram(GLuint program)
+{
+ crStateValidateProgram(program);
+ cr_server.head_spu->dispatch_table.ValidateProgram(crStateGetProgramHWID(program));
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBindAttribLocation(GLuint program, GLuint index, const char * name)
+{
+ crStateBindAttribLocation(program, index, name);
+ cr_server.head_spu->dispatch_table.BindAttribLocation(crStateGetProgramHWID(program), index, name);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteObjectARB(VBoxGLhandleARB obj)
+{
+ GLuint hwid = crStateDeleteObjectARB(obj);
+
+ if (hwid)
+ cr_server.head_spu->dispatch_table.DeleteObjectARB(hwid);
+ else
+ crWarning("zero hwid for object %d", obj);
+}
+
+GLint SERVER_DISPATCH_APIENTRY crServerDispatchGetAttribLocation( GLuint program, const char * name )
+{
+ GLint retval;
+ retval = cr_server.head_spu->dispatch_table.GetAttribLocation(crStateGetProgramHWID(program), name );
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+VBoxGLhandleARB SERVER_DISPATCH_APIENTRY crServerDispatchGetHandleARB( GLenum pname )
+{
+ VBoxGLhandleARB retval;
+ retval = cr_server.head_spu->dispatch_table.GetHandleARB(pname);
+ if (pname==GL_PROGRAM_OBJECT_ARB)
+ {
+ retval = crStateGLSLProgramHWIDtoID(retval);
+ }
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+GLint SERVER_DISPATCH_APIENTRY crServerDispatchGetUniformLocation(GLuint program, const char * name)
+{
+ GLint retval;
+ retval = cr_server.head_spu->dispatch_table.GetUniformLocation(crStateGetProgramHWID(program), name);
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetProgramiv( GLuint program, GLenum pname, GLint * params )
+{
+ GLint local_params[1];
+ (void) params;
+ cr_server.head_spu->dispatch_table.GetProgramiv(crStateGetProgramHWID(program), pname, local_params);
+ crServerReturnValue( &(local_params[0]), 1*sizeof(GLint) );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetShaderiv( GLuint shader, GLenum pname, GLint * params )
+{
+ GLint local_params[1];
+ (void) params;
+ cr_server.head_spu->dispatch_table.GetShaderiv( crStateGetShaderHWID(shader), pname, local_params );
+ crServerReturnValue( &(local_params[0]), 1*sizeof(GLint) );
+}
+#endif /* #ifdef CR_OPENGL_VERSION_2_0 */
+
+/* XXXX Note: shared/separate Program ID numbers aren't totally implemented! */
+GLuint crServerTranslateProgramID( GLuint id )
+{
+ if (!cr_server.sharedPrograms && id) {
+ int client = cr_server.curClient->number;
+ return id + client * 100000;
+ }
+ return id;
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteProgramsARB(GLsizei n, const GLuint * programs)
+{
+ GLuint *pLocalProgs;
+ GLint i;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchDeleteProgramsARB: parameter 'n' is out of range");
+ return;
+ }
+
+ pLocalProgs = (GLuint *)crAlloc(n * sizeof(GLuint));
+
+ if (!pLocalProgs) {
+ crError("crServerDispatchDeleteProgramsARB: out of memory");
+ return;
+ }
+ for (i = 0; i < n; i++) {
+ pLocalProgs[i] = crServerTranslateProgramID(programs[i]);
+ }
+ crStateDeleteProgramsARB(n, pLocalProgs);
+ cr_server.head_spu->dispatch_table.DeleteProgramsARB(n, pLocalProgs);
+ crFree(pLocalProgs);
+}
+
+
+/** @todo will fail for progs loaded from snapshot */
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsProgramARB( GLuint program )
+{
+ GLboolean retval;
+ program = crServerTranslateProgramID(program);
+ retval = cr_server.head_spu->dispatch_table.IsProgramARB( program );
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+
+GLboolean SERVER_DISPATCH_APIENTRY
+crServerDispatchAreProgramsResidentNV(GLsizei n, const GLuint *programs,
+ GLboolean *residences)
+{
+ GLboolean retval = GL_FALSE;
+ GLboolean *res;
+ GLsizei i;
+ (void) residences;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchAreProgramsResidentNV: parameter 'n' is out of range");
+ return GL_FALSE;
+ }
+
+ res = (GLboolean *)crCalloc(n * sizeof(GLboolean));
+
+ if (!res) {
+ crError("crServerDispatchAreProgramsResidentNV: out of memory");
+ return GL_FALSE;
+ }
+
+ if (!cr_server.sharedTextureObjects) {
+ GLuint *programs2 = (GLuint *) crCalloc(n * sizeof(GLuint));
+ if (programs2)
+ {
+ for (i = 0; i < n; i++)
+ programs2[i] = crServerTranslateProgramID(programs[i]);
+
+ retval = cr_server.head_spu->dispatch_table.AreProgramsResidentNV(n, programs2, res);
+ crFree(programs2);
+ }
+ else
+ {
+ crError("crServerDispatchAreProgramsResidentNV: out of memory");
+ }
+ }
+ else {
+ retval = cr_server.head_spu->dispatch_table.AreProgramsResidentNV(n, programs, res);
+ }
+
+ crServerReturnValue(res, n * sizeof(GLboolean));
+ crFree(res);
+
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c
new file mode 100644
index 00000000..a7a47ab5
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c
@@ -0,0 +1,284 @@
+/* Copyright (c) 2001-2003, Stanford University
+ All rights reserved.
+
+ See the file LICENSE.txt for information on redistributing this software. */
+
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_mem.h"
+
+
+/*
+ * Notes on ID translation:
+ *
+ * If a server has multiple clients (in the case of parallel applications)
+ * and N of the clients all create a display list with ID K, does K name
+ * one display list or N different display lists?
+ *
+ * By default, there is one display list named K. If the clients put
+ * identical commands into list K, then this is fine. But if the clients
+ * each put something different into list K when they created it, then this
+ * is a serious problem.
+ *
+ * By zeroing the 'shared_display_lists' configuration option, we can tell
+ * the server to make list K be unique for all N clients. We do this by
+ * translating K into a new, unique ID dependent on which client we're
+ * talking to (curClient->number).
+ *
+ * Same story for texture objects, vertex programs, etc.
+ *
+ * The application can also dynamically switch between shared and private
+ * display lists with:
+ * glChromiumParameteri(GL_SHARED_DISPLAY_LISTS_CR, GL_TRUE)
+ * and
+ * glChromiumParameteri(GL_SHARED_DISPLAY_LISTS_CR, GL_FALSE)
+ *
+ */
+
+
+
+static GLuint TranslateListID( GLuint id )
+{
+#ifndef VBOX_WITH_CR_DISPLAY_LISTS
+ if (!cr_server.sharedDisplayLists) {
+ int client = cr_server.curClient->number;
+ return id + client * 100000;
+ }
+#endif
+ return id;
+}
+
+
+GLuint SERVER_DISPATCH_APIENTRY crServerDispatchGenLists( GLsizei range )
+{
+ GLuint retval;
+ retval = cr_server.head_spu->dispatch_table.GenLists( range );
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchNewList( GLuint list, GLenum mode )
+{
+ if (mode == GL_COMPILE_AND_EXECUTE)
+ crWarning("using glNewList(GL_COMPILE_AND_EXECUTE) can confuse the crserver");
+
+ list = TranslateListID( list );
+ crStateNewList( list, mode );
+ cr_server.head_spu->dispatch_table.NewList( list, mode );
+}
+
+static void crServerQueryHWState()
+{
+ if (!cr_server.bUseMultipleContexts)
+ {
+ GLuint fbFbo, bbFbo;
+ CRClient *client = cr_server.curClient;
+ CRMuralInfo *mural = client ? client->currentMural : NULL;
+ if (mural && mural->fRedirected)
+ {
+ fbFbo = mural->aidFBOs[CR_SERVER_FBO_FB_IDX(mural)];
+ bbFbo = mural->aidFBOs[CR_SERVER_FBO_BB_IDX(mural)];
+ }
+ else
+ {
+ fbFbo = bbFbo = 0;
+ }
+ crStateQueryHWState(fbFbo, bbFbo);
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchEndList(void)
+{
+ CRContext *g = crStateGetCurrent();
+ CRListsState *l = &(g->lists);
+
+ cr_server.head_spu->dispatch_table.EndList();
+ crStateEndList();
+
+#ifndef IN_GUEST
+ if (l->mode==GL_COMPILE)
+ {
+ crServerQueryHWState();
+ }
+#endif
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchCallList( GLuint list )
+{
+ list = TranslateListID( list );
+
+ if (cr_server.curClient->currentCtxInfo->pContext->lists.mode == 0) {
+ /* we're not compiling, so execute the list now */
+ /* Issue the list as-is */
+ cr_server.head_spu->dispatch_table.CallList( list );
+ crServerQueryHWState();
+ }
+ else {
+ /* we're compiling glCallList into another list - just pass it through */
+ cr_server.head_spu->dispatch_table.CallList( list );
+ }
+}
+
+
+#ifndef VBOX_WITH_CR_DISPLAY_LISTS
+/**
+ * Translate an array of display list IDs from various datatypes to GLuint
+ * IDs while adding the per-client offset.
+ */
+static void
+TranslateListIDs(GLsizei n, GLenum type, const GLvoid *lists, GLuint *newLists)
+{
+ int offset = cr_server.curClient->number * 100000;
+ GLsizei i;
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ {
+ const GLubyte *src = (const GLubyte *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = src[i] + offset;
+ }
+ }
+ break;
+ case GL_BYTE:
+ {
+ const GLbyte *src = (const GLbyte *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = src[i] + offset;
+ }
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ {
+ const GLushort *src = (const GLushort *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = src[i] + offset;
+ }
+ }
+ break;
+ case GL_SHORT:
+ {
+ const GLshort *src = (const GLshort *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = src[i] + offset;
+ }
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ {
+ const GLuint *src = (const GLuint *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = src[i] + offset;
+ }
+ }
+ break;
+ case GL_INT:
+ {
+ const GLint *src = (const GLint *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = src[i] + offset;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ const GLfloat *src = (const GLfloat *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = (GLuint) src[i] + offset;
+ }
+ }
+ break;
+ case GL_2_BYTES:
+ {
+ const GLubyte *src = (const GLubyte *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = (src[i*2+0] * 256 +
+ src[i*2+1]) + offset;
+ }
+ }
+ break;
+ case GL_3_BYTES:
+ {
+ const GLubyte *src = (const GLubyte *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = (src[i*3+0] * 256 * 256 +
+ src[i*3+1] * 256 +
+ src[i*3+2]) + offset;
+ }
+ }
+ break;
+ case GL_4_BYTES:
+ {
+ const GLubyte *src = (const GLubyte *) lists;
+ for (i = 0; i < n; i++) {
+ newLists[i] = (src[i*4+0] * 256 * 256 * 256 +
+ src[i*4+1] * 256 * 256 +
+ src[i*4+2] * 256 +
+ src[i*4+3]) + offset;
+ }
+ }
+ break;
+ default:
+ crWarning("CRServer: invalid display list datatype 0x%x", type);
+ }
+}
+#endif
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchCallLists( GLsizei n, GLenum type, const GLvoid *lists )
+{
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchCallLists: parameter 'n' is out of range");
+ return;
+ }
+
+#ifndef VBOX_WITH_CR_DISPLAY_LISTS
+ if (!cr_server.sharedDisplayLists) {
+ /* need to translate IDs */
+ GLuint *newLists = (GLuint *) crAlloc(n * sizeof(GLuint));
+ if (newLists) {
+ TranslateListIDs(n, type, lists, newLists);
+ }
+ lists = newLists;
+ type = GL_UNSIGNED_INT;
+ }
+#endif
+
+ if (cr_server.curClient->currentCtxInfo->pContext->lists.mode == 0) {
+ /* we're not compiling, so execute the list now */
+ /* Issue the list as-is */
+ cr_server.head_spu->dispatch_table.CallLists( n, type, lists );
+ crServerQueryHWState();
+ }
+ else {
+ /* we're compiling glCallList into another list - just pass it through */
+ cr_server.head_spu->dispatch_table.CallLists( n, type, lists );
+ }
+
+#ifndef VBOX_WITH_CR_DISPLAY_LISTS
+ if (!cr_server.sharedDisplayLists) {
+ crFree((void *) lists); /* malloc'd above */
+ }
+#endif
+}
+
+
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsList( GLuint list )
+{
+ GLboolean retval;
+ list = TranslateListID( list );
+ retval = cr_server.head_spu->dispatch_table.IsList( list );
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval;
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteLists( GLuint list, GLsizei range )
+{
+ list = TranslateListID( list );
+ crStateDeleteLists( list, range );
+ cr_server.head_spu->dispatch_table.DeleteLists( list, range );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
new file mode 100644
index 00000000..5e1b7267
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c
@@ -0,0 +1,4039 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server.h"
+#include "cr_net.h"
+#include "cr_unpack.h"
+#include "cr_error.h"
+#include "cr_glstate.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_hash.h"
+#include "cr_vreg.h"
+#include "cr_environment.h"
+#include "cr_pixeldata.h"
+
+#ifdef VBOX_WITH_CR_DISPLAY_LISTS
+# include "cr_dlm.h"
+#endif
+
+#include "server_dispatch.h"
+#include "state/cr_texture.h"
+#include "render/renderspu.h"
+#include <signal.h>
+#include <stdlib.h>
+#define DEBUG_FP_EXCEPTIONS 0
+#if DEBUG_FP_EXCEPTIONS
+#include <fpu_control.h>
+#include <math.h>
+#endif
+#include <iprt/assert.h>
+#include <VBox/err.h>
+#include <VBox/log.h>
+#include <VBox/AssertGuest.h>
+
+#ifdef VBOXCR_LOGFPS
+#include <iprt/timer.h>
+#endif
+
+#ifdef VBOX_WITH_CRHGSMI
+# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
+uint8_t* g_pvVRamBase = NULL;
+uint32_t g_cbVRam = 0;
+PPDMLED g_pLed = NULL;
+
+HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion = NULL;
+PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion = NULL;
+#endif
+
+/**
+ * \mainpage CrServerLib
+ *
+ * \section CrServerLibIntroduction Introduction
+ *
+ * Chromium consists of all the top-level files in the cr
+ * directory. The core module basically takes care of API dispatch,
+ * and OpenGL state management.
+ */
+
+
+/**
+ * CRServer global data
+ */
+CRServer cr_server;
+
+int tearingdown = 0; /* can't be static */
+
+static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr,
+ const VBOXCMDVBVA_HDR RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd);
+
+DECLINLINE(CRClient*) crVBoxServerClientById(uint32_t u32ClientID)
+{
+ int32_t i;
+
+ if (cr_server.fCrCmdEnabled)
+ return CrHTableGet(&cr_server.clientTable, u32ClientID);
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn
+ && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
+ {
+ return cr_server.clients[i];
+ }
+ }
+
+ return NULL;
+}
+
+int32_t crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient)
+{
+ CRClient *pClient = NULL;
+
+ pClient = crVBoxServerClientById(u32ClientID);
+
+ if (!pClient)
+ {
+ WARN(("client not found!"));
+ *ppClient = NULL;
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (!pClient->conn->vMajor)
+ {
+ WARN(("no major version specified for client!"));
+ *ppClient = NULL;
+ return VERR_NOT_SUPPORTED;
+ }
+
+ *ppClient = pClient;
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Return pointer to server's first SPU.
+ */
+SPU*
+crServerHeadSPU(void)
+{
+ return cr_server.head_spu;
+}
+
+
+
+static void DeleteBarrierCallback( void *data )
+{
+ CRServerBarrier *barrier = (CRServerBarrier *) data;
+ crFree(barrier->waiting);
+ crFree(barrier);
+}
+
+
+static void deleteContextInfoCallback( void *data )
+{
+ CRContextInfo *c = (CRContextInfo *) data;
+ crStateDestroyContext(c->pContext);
+ if (c->CreateInfo.pszDpyName)
+ crFree(c->CreateInfo.pszDpyName);
+ crFree(c);
+}
+
+static void deleteMuralInfoCallback( void *data )
+{
+ CRMuralInfo *m = (CRMuralInfo *) data;
+ if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed,
+ * and renderspu will destroy it up itself*/
+ {
+ crServerMuralTerm(m);
+ }
+ crFree(m);
+}
+
+static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData);
+
+static void crServerTearDown( void )
+{
+ GLint i;
+ CRClientNode *pNode, *pNext;
+ GLboolean fOldEnableDiff;
+ GLboolean fContextsDeleted = GL_FALSE;
+
+ /* avoid a race condition */
+ if (tearingdown)
+ return;
+
+ tearingdown = 1;
+
+ if (cr_server.fCrCmdEnabled)
+ {
+ VBOXCRCMDCTL_HGCMENABLE_DATA EnableData;
+ /* crVBoxServerHgcmEnable will erase the DisableData, preserve it here */
+ VBOXCRCMDCTL_HGCMDISABLE_DATA DisableData = cr_server.DisableData;
+ int rc;
+
+ CRASSERT(DisableData.pfnNotifyTerm);
+ rc = DisableData.pfnNotifyTerm(DisableData.hNotifyTerm, &EnableData);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("pfnNotifyTerm failed %d", rc));
+ return;
+ }
+
+ crVBoxServerCrCmdDisablePostProcess(&EnableData);
+ fContextsDeleted = GL_TRUE;
+
+ CRASSERT(DisableData.pfnNotifyTermDone);
+ DisableData.pfnNotifyTermDone(DisableData.hNotifyTerm);
+
+ Assert(!cr_server.fCrCmdEnabled);
+ }
+
+ crStateSetCurrent( NULL );
+
+ cr_server.curClient = NULL;
+ cr_server.run_queue = NULL;
+
+ crFree( cr_server.overlap_intens );
+ cr_server.overlap_intens = NULL;
+
+ /* needed to make sure window dummy mural not get created on mural destruction
+ * and generally this should be zeroed up */
+ cr_server.currentCtxInfo = NULL;
+ cr_server.currentWindow = -1;
+ cr_server.currentNativeWindow = 0;
+ cr_server.currentMural = NULL;
+
+ if (!fContextsDeleted)
+ {
+#ifndef VBOX_WITH_CR_DISPLAY_LISTS
+ /* sync our state with renderspu,
+ * do it before mural & context deletion to avoid deleting currently set murals/contexts*/
+ cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+#endif
+ }
+
+ /* Deallocate all semaphores */
+ crFreeHashtable(cr_server.semaphores, crFree);
+ cr_server.semaphores = NULL;
+
+ /* Deallocate all barriers */
+ crFreeHashtable(cr_server.barriers, DeleteBarrierCallback);
+ cr_server.barriers = NULL;
+
+#if 0 /** @todo @bugref{8662} -- can trigger SEGFAULTs during savestate */
+ /* Free all context info */
+ crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback);
+#endif
+
+ /* synchronize with reality */
+ if (!fContextsDeleted)
+ {
+ fOldEnableDiff = crStateEnableDiffOnMakeCurrent(GL_FALSE);
+ if(cr_server.MainContextInfo.pContext)
+ crStateMakeCurrent(cr_server.MainContextInfo.pContext);
+ crStateEnableDiffOnMakeCurrent(fOldEnableDiff);
+ }
+
+ /* Free vertex programs */
+ crFreeHashtable(cr_server.programTable, crFree);
+
+ /* Free murals */
+ crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback);
+
+ CrPMgrTerm();
+
+ if (CrBltIsInitialized(&cr_server.Blitter))
+ {
+ CrBltTerm(&cr_server.Blitter);
+ }
+
+ /* Free dummy murals */
+ crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback);
+
+ for (i = 0; i < cr_server.numClients; i++) {
+ if (cr_server.clients[i]) {
+ CRConnection *conn = cr_server.clients[i]->conn;
+ crNetFreeConnection(conn);
+ crFree(cr_server.clients[i]);
+ }
+ }
+ cr_server.numClients = 0;
+
+ pNode = cr_server.pCleanupClient;
+ while (pNode)
+ {
+ pNext=pNode->next;
+ crFree(pNode->pClient);
+ crFree(pNode);
+ pNode=pNext;
+ }
+ cr_server.pCleanupClient = NULL;
+
+ if (crServerRpwIsInitialized(&cr_server.RpwWorker))
+ {
+ crServerRpwTerm(&cr_server.RpwWorker);
+ }
+
+#if 1
+ /* disable these two lines if trying to get stack traces with valgrind */
+ crSPUUnloadChain(cr_server.head_spu);
+ cr_server.head_spu = NULL;
+#endif
+
+ crStateDestroy();
+
+ crNetTearDown();
+
+ VBoxVrListClear(&cr_server.RootVr);
+
+ VBoxVrTerm();
+
+ RTSemEventDestroy(cr_server.hCalloutCompletionEvent);
+}
+
+static void crServerClose( unsigned int id )
+{
+ crError( "Client disconnected!" );
+ (void) id;
+}
+
+static void crServerCleanup( int sigio )
+{
+ crServerTearDown();
+
+ tearingdown = 0;
+}
+
+
+void
+crServerSetPort(int port)
+{
+ cr_server.tcpip_port = port;
+}
+
+
+
+static void
+crPrintHelp(void)
+{
+ printf("Usage: crserver [OPTIONS]\n");
+ printf("Options:\n");
+ printf(" -mothership URL Specifies URL for contacting the mothership.\n");
+ printf(" URL is of the form [protocol://]hostname[:port]\n");
+ printf(" -port N Specifies the port number this server will listen to.\n");
+ printf(" -help Prints this information.\n");
+}
+
+
+/**
+ * Do CRServer initializations. After this, we can begin servicing clients.
+ */
+void
+crServerInit(int argc, char *argv[])
+{
+ int i;
+ const char*env;
+ char *mothership = NULL;
+ CRMuralInfo *defaultMural;
+ int rc = VBoxVrInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("VBoxVrInit failed, rc %d", rc);
+ return;
+ }
+
+ for (i = 1 ; i < argc ; i++)
+ {
+ if (!crStrcmp( argv[i], "-mothership" ))
+ {
+ if (i == argc - 1)
+ {
+ crError( "-mothership requires an argument" );
+ }
+ mothership = argv[i+1];
+ i++;
+ }
+ else if (!crStrcmp( argv[i], "-port" ))
+ {
+ /* This is the port on which we'll accept client connections */
+ if (i == argc - 1)
+ {
+ crError( "-port requires an argument" );
+ }
+ cr_server.tcpip_port = crStrToInt(argv[i+1]);
+ i++;
+ }
+ else if (!crStrcmp( argv[i], "-vncmode" ))
+ {
+ cr_server.vncMode = 1;
+ }
+ else if (!crStrcmp( argv[i], "-help" ))
+ {
+ crPrintHelp();
+ exit(0);
+ }
+ }
+
+ signal( SIGTERM, crServerCleanup );
+ signal( SIGINT, crServerCleanup );
+#ifndef WINDOWS
+ signal( SIGPIPE, SIG_IGN );
+#endif
+
+#if DEBUG_FP_EXCEPTIONS
+ {
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
+ | _FPU_MASK_OM | _FPU_MASK_UM);
+ _FPU_SETCW(mask);
+ }
+#endif
+
+ cr_server.fCrCmdEnabled = GL_FALSE;
+ cr_server.fProcessingPendedCommands = GL_FALSE;
+ CrHTableCreate(&cr_server.clientTable, CR_MAX_CLIENTS);
+
+ cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
+
+ if (cr_server.bUseMultipleContexts)
+ {
+ crInfo("Info: using multiple contexts!");
+ crDebug("Debug: using multiple contexts!");
+ }
+
+ cr_server.firstCallCreateContext = GL_TRUE;
+ cr_server.firstCallMakeCurrent = GL_TRUE;
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
+
+ /*
+ * Create default mural info and hash table.
+ */
+ cr_server.muralTable = crAllocHashtable();
+ defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
+ crHashtableAdd(cr_server.muralTable, 0, defaultMural);
+
+ cr_server.programTable = crAllocHashtable();
+
+ crNetInit(crServerRecv, crServerClose);
+ crStateInit();
+
+ crServerSetVBoxConfiguration();
+
+ crStateLimitsInit( &(cr_server.limits) );
+
+ /*
+ * Default context
+ */
+ cr_server.contextTable = crAllocHashtable();
+ cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo;
+
+ cr_server.dummyMuralTable = crAllocHashtable();
+
+ CrPMgrInit();
+
+ cr_server.fRootVrOn = GL_FALSE;
+ VBoxVrListInit(&cr_server.RootVr);
+ crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
+
+ crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
+
+ env = crGetenv("CR_SERVER_BFB");
+ if (env)
+ {
+ cr_server.fBlitterMode = env[0] - '0';
+ }
+ else
+ {
+ cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
+ }
+ crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
+
+ crServerInitDispatch();
+ crServerInitTmpCtxDispatch();
+ crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
+
+#ifdef VBOX_WITH_CRSERVER_DUMPER
+ crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder));
+ crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter));
+ crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper));
+ crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper));
+ cr_server.pDumper = NULL;
+#endif
+
+ crUnpackSetReturnPointer( &(cr_server.return_ptr) );
+ crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
+
+ cr_server.barriers = crAllocHashtable();
+ cr_server.semaphores = crAllocHashtable();
+}
+
+void crVBoxServerTearDown(void)
+{
+ crServerTearDown();
+}
+
+/**
+ * Do CRServer initializations. After this, we can begin servicing clients.
+ */
+GLboolean crVBoxServerInit(void)
+{
+ CRMuralInfo *defaultMural;
+ const char*env;
+ int rc = VBoxVrInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("VBoxVrInit failed, rc %d", rc);
+ return GL_FALSE;
+ }
+
+#if DEBUG_FP_EXCEPTIONS
+ {
+ fpu_control_t mask;
+ _FPU_GETCW(mask);
+ mask &= ~(_FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM
+ | _FPU_MASK_OM | _FPU_MASK_UM);
+ _FPU_SETCW(mask);
+ }
+#endif
+
+ cr_server.fCrCmdEnabled = GL_FALSE;
+ cr_server.fProcessingPendedCommands = GL_FALSE;
+ CrHTableCreate(&cr_server.clientTable, CR_MAX_CLIENTS);
+
+ cr_server.bUseMultipleContexts = (crGetenv( "CR_SERVER_ENABLE_MULTIPLE_CONTEXTS" ) != NULL);
+
+ if (cr_server.bUseMultipleContexts)
+ {
+ crInfo("Info: using multiple contexts!");
+ crDebug("Debug: using multiple contexts!");
+ }
+
+ crNetInit(crServerRecv, crServerClose);
+
+ cr_server.firstCallCreateContext = GL_TRUE;
+ cr_server.firstCallMakeCurrent = GL_TRUE;
+
+ cr_server.bIsInLoadingState = GL_FALSE;
+ cr_server.bIsInSavingState = GL_FALSE;
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
+
+ cr_server.pCleanupClient = NULL;
+
+ rc = RTSemEventCreate(&cr_server.hCalloutCompletionEvent);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("RTSemEventCreate failed %d", rc));
+ return GL_FALSE;
+ }
+
+ /*
+ * Create default mural info and hash table.
+ */
+ cr_server.muralTable = crAllocHashtable();
+ defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID;
+ crHashtableAdd(cr_server.muralTable, 0, defaultMural);
+
+ cr_server.programTable = crAllocHashtable();
+
+ crStateInit();
+
+ crStateLimitsInit( &(cr_server.limits) );
+
+ cr_server.barriers = crAllocHashtable();
+ cr_server.semaphores = crAllocHashtable();
+
+ crUnpackSetReturnPointer( &(cr_server.return_ptr) );
+ crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) );
+
+ /*
+ * Default context
+ */
+ cr_server.contextTable = crAllocHashtable();
+
+ cr_server.dummyMuralTable = crAllocHashtable();
+
+ CrPMgrInit();
+
+ cr_server.fRootVrOn = GL_FALSE;
+ VBoxVrListInit(&cr_server.RootVr);
+ crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
+
+ crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker));
+
+ env = crGetenv("CR_SERVER_BFB");
+ if (env)
+ {
+ cr_server.fBlitterMode = env[0] - '0';
+ }
+ else
+ {
+ cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED;
+ }
+ crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter));
+
+ crServerSetVBoxConfigurationHGCM();
+
+ if (!cr_server.head_spu)
+ {
+ crStateDestroy();
+ return GL_FALSE;
+ }
+
+ crServerInitDispatch();
+ crServerInitTmpCtxDispatch();
+ crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
+
+#ifdef VBOX_WITH_CRSERVER_DUMPER
+ crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder));
+ crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter));
+ crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper));
+ crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper));
+ cr_server.pDumper = NULL;
+#endif
+
+ /*Check for PBO support*/
+ if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object)
+ {
+ cr_server.bUsePBOForReadback=GL_TRUE;
+ }
+
+ return GL_TRUE;
+}
+
+static int32_t crVBoxServerAddClientObj(uint32_t u32ClientID, CRClient **ppNewClient)
+{
+ CRClient *newClient;
+
+ if (cr_server.numClients>=CR_MAX_CLIENTS)
+ {
+ if (ppNewClient)
+ *ppNewClient = NULL;
+ return VERR_MAX_THRDS_REACHED;
+ }
+
+ newClient = (CRClient *) crCalloc(sizeof(CRClient));
+ crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
+
+ newClient->spu_id = 0;
+ newClient->currentCtxInfo = &cr_server.MainContextInfo;
+ newClient->currentContextNumber = -1;
+ newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
+ cr_server.tcpip_port,
+ cr_server.mtu, 0);
+ newClient->conn->u32ClientID = u32ClientID;
+
+ cr_server.clients[cr_server.numClients++] = newClient;
+
+ crServerAddToRunQueue(newClient);
+
+ if (ppNewClient)
+ *ppNewClient = newClient;
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerAddClient(uint32_t u32ClientID)
+{
+ CRClient *newClient;
+
+ if (cr_server.numClients>=CR_MAX_CLIENTS)
+ {
+ return VERR_MAX_THRDS_REACHED;
+ }
+
+ newClient = (CRClient *) crCalloc(sizeof(CRClient));
+ crDebug("crServer: AddClient u32ClientID=%d", u32ClientID);
+
+ newClient->spu_id = 0;
+ newClient->currentCtxInfo = &cr_server.MainContextInfo;
+ newClient->currentContextNumber = -1;
+ newClient->conn = crNetAcceptClient(cr_server.protocol, NULL,
+ cr_server.tcpip_port,
+ cr_server.mtu, 0);
+ newClient->conn->u32ClientID = u32ClientID;
+
+ cr_server.clients[cr_server.numClients++] = newClient;
+
+ crServerAddToRunQueue(newClient);
+
+ return VINF_SUCCESS;
+}
+
+static void crVBoxServerRemoveClientObj(CRClient *pClient)
+{
+#ifdef VBOX_WITH_CRHGSMI
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+#endif
+
+ /* Disconnect the client */
+ pClient->conn->Disconnect(pClient->conn);
+
+ /* Let server clear client from the queue */
+ crServerDeleteClient(pClient);
+}
+
+static void crVBoxServerRemoveAllClients()
+{
+ int32_t i;
+ for (i = cr_server.numClients - 1; i >= 0; --i)
+ {
+ Assert(cr_server.clients[i]);
+ crVBoxServerRemoveClientObj(cr_server.clients[i]);
+ }
+}
+
+void crVBoxServerRemoveClient(uint32_t u32ClientID)
+{
+ CRClient *pClient=NULL;
+ int32_t i;
+
+ crDebug("crServer: RemoveClient u32ClientID=%d", u32ClientID);
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn
+ && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
+ {
+ pClient = cr_server.clients[i];
+ break;
+ }
+ }
+ //if (!pClient) return VERR_INVALID_PARAMETER;
+ if (!pClient)
+ {
+ WARN(("Invalid client id %u passed to crVBoxServerRemoveClient", u32ClientID));
+ return;
+ }
+
+ crVBoxServerRemoveClientObj(pClient);
+}
+
+static void crVBoxServerInternalClientWriteRead(CRClient *pClient)
+{
+#ifdef VBOXCR_LOGFPS
+ uint64_t tstart, tend;
+#endif
+
+ /*crDebug("=>crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
+
+
+#ifdef VBOXCR_LOGFPS
+ tstart = RTTimeNanoTS();
+#endif
+
+ /* This should be setup already */
+ CRASSERT(pClient->conn->pBuffer);
+ CRASSERT(pClient->conn->cbBuffer);
+#ifdef VBOX_WITH_CRHGSMI
+ CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&pClient->conn->CmdData);
+#endif
+
+ if (
+#ifdef VBOX_WITH_CRHGSMI
+ !CRVBOXHGSMI_CMDDATA_IS_SET(&pClient->conn->CmdData) &&
+#endif
+ cr_server.run_queue->client != pClient
+ && crServerClientInBeginEnd(cr_server.run_queue->client))
+ {
+ crDebug("crServer: client %d blocked, allow_redir_ptr = 0", pClient->conn->u32ClientID);
+ pClient->conn->allow_redir_ptr = 0;
+ }
+ else
+ {
+ pClient->conn->allow_redir_ptr = 1;
+ }
+
+ crNetRecv();
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ crServerServiceClients();
+ crStateResetCurrentPointers(&cr_server.current);
+
+#ifndef VBOX_WITH_CRHGSMI
+ CRASSERT(!pClient->conn->allow_redir_ptr || crNetNumMessages(pClient->conn)==0);
+#endif
+
+#ifdef VBOXCR_LOGFPS
+ tend = RTTimeNanoTS();
+ pClient->timeUsed += tend-tstart;
+#endif
+ /*crDebug("<=crServer: ClientWrite u32ClientID=%d", u32ClientID);*/
+}
+
+
+int32_t crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer)
+{
+ CRClient *pClient=NULL;
+ int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+ CRASSERT(pBuffer);
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+#ifdef VBOX_WITH_CRHGSMI
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+#endif
+
+ crVBoxServerInternalClientWriteRead(pClient);
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer)
+{
+ if (pClient->conn->cbHostBuffer > *pcbBuffer)
+ {
+ crDebug("crServer: [%lx] ClientRead u32ClientID=%d FAIL, host buffer too small %d of %d",
+ crThreadID(), pClient->conn->u32ClientID, *pcbBuffer, pClient->conn->cbHostBuffer);
+
+ /* Return the size of needed buffer */
+ *pcbBuffer = pClient->conn->cbHostBuffer;
+
+ return VERR_BUFFER_OVERFLOW;
+ }
+
+ *pcbBuffer = pClient->conn->cbHostBuffer;
+
+ if (*pcbBuffer)
+ {
+ CRASSERT(pClient->conn->pHostBuffer);
+
+ crMemcpy(pBuffer, pClient->conn->pHostBuffer, *pcbBuffer);
+ pClient->conn->cbHostBuffer = 0;
+ }
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer)
+{
+ CRClient *pClient=NULL;
+ int32_t rc = crVBoxServerClientGet(u32ClientID, &pClient);
+
+ if (RT_FAILURE(rc))
+ return rc;
+
+#ifdef VBOX_WITH_CRHGSMI
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+#endif
+
+ return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer);
+}
+
+extern DECLEXPORT(int32_t) crVBoxServerClientGetCapsLegacy(uint32_t u32ClientID, uint32_t *pu32Caps)
+{
+ uint32_t u32Caps = cr_server.u32Caps;
+ u32Caps &= ~CR_VBOX_CAP_CMDVBVA;
+ *pu32Caps = u32Caps;
+ return VINF_SUCCESS;
+}
+
+extern DECLEXPORT(int32_t) crVBoxServerClientGetCapsNew(uint32_t u32ClientID, CR_CAPS_INFO *pInfo)
+{
+ pInfo->u32Caps = cr_server.u32Caps;
+ pInfo->u32CmdVbvaVersion = CR_CMDVBVA_VERSION;
+ return VINF_SUCCESS;
+}
+
+static int32_t crVBoxServerClientObjSetVersion(CRClient *pClient, uint32_t vMajor, uint32_t vMinor)
+{
+ pClient->conn->vMajor = vMajor;
+ pClient->conn->vMinor = vMinor;
+
+ if (vMajor != CR_PROTOCOL_VERSION_MAJOR
+ || vMinor != CR_PROTOCOL_VERSION_MINOR)
+ return VERR_NOT_SUPPORTED;
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor)
+{
+ CRClient *pClient=NULL;
+ int32_t i;
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn
+ && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
+ {
+ pClient = cr_server.clients[i];
+ break;
+ }
+ }
+ if (!pClient) return VERR_INVALID_PARAMETER;
+
+ return crVBoxServerClientObjSetVersion(pClient, vMajor, vMinor);
+}
+
+static int32_t crVBoxServerClientObjSetPID(CRClient *pClient, uint64_t pid)
+{
+ pClient->pid = pid;
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid)
+{
+ CRClient *pClient=NULL;
+ int32_t i;
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn
+ && cr_server.clients[i]->conn->u32ClientID==u32ClientID)
+ {
+ pClient = cr_server.clients[i];
+ break;
+ }
+ }
+ if (!pClient) return VERR_INVALID_PARAMETER;
+
+ return crVBoxServerClientObjSetPID(pClient, pid);
+}
+
+int
+CRServerMain(int argc, char *argv[])
+{
+ crServerInit(argc, argv);
+
+ crServerSerializeRemoteStreams();
+
+ crServerTearDown();
+
+ tearingdown = 0;
+
+ return 0;
+}
+
+static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+ PSSMHANDLE pSSM = (PSSMHANDLE) data2;
+ int32_t rc;
+
+ CRASSERT(pMI && pSSM);
+
+ /* Don't store default mural */
+ if (!key) return;
+
+ rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ CRASSERT(rc == VINF_SUCCESS);
+
+ rc = SSMR3PutMem(pSSM, pMI, RT_UOFFSETOF(CRMuralInfo, CreateInfo));
+ CRASSERT(rc == VINF_SUCCESS);
+
+ if (pMI->pVisibleRects)
+ {
+ rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects);
+ }
+
+ rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage));
+ CRASSERT(rc == VINF_SUCCESS);
+}
+
+/** @todo add hashtable walker with result info and intermediate abort */
+static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *data2)
+{
+ CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *)data1;
+ PSSMHANDLE pSSM = (PSSMHANDLE) data2;
+ int32_t rc;
+
+ CRASSERT(pCreateInfo && pSSM);
+
+ /* Don't store default mural create info */
+ if (!key) return;
+
+ rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ CRASSERT(rc == VINF_SUCCESS);
+
+ rc = SSMR3PutMem(pSSM, pCreateInfo, sizeof(*pCreateInfo));
+ CRASSERT(rc == VINF_SUCCESS);
+
+ if (pCreateInfo->pszDpyName)
+ {
+ rc = SSMR3PutStrZ(pSSM, pCreateInfo->pszDpyName);
+ CRASSERT(rc == VINF_SUCCESS);
+ }
+}
+
+static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMural = (CRMuralInfo *)data1;
+ CRCreateInfo_t CreateInfo;
+ CreateInfo.pszDpyName = pMural->CreateInfo.pszDpyName;
+ CreateInfo.visualBits = pMural->CreateInfo.requestedVisualBits;
+ CreateInfo.externalID = pMural->CreateInfo.externalID;
+ crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
+}
+
+static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *)data1;
+ CRCreateInfo_t CreateInfo;
+ CreateInfo.pszDpyName = pContextInfo->CreateInfo.pszDpyName;
+ CreateInfo.visualBits = pContextInfo->CreateInfo.requestedVisualBits;
+ /* saved state contains internal id */
+ CreateInfo.externalID = pContextInfo->pContext->id;
+ crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2);
+}
+
+static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data2)
+{
+ CRTextureObj *pTexture = (CRTextureObj *) data1;
+ CRContext *pContext = (CRContext *) data2;
+
+ CRASSERT(pTexture && pContext);
+ crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE);
+}
+
+typedef struct CRVBOX_SAVE_STATE_GLOBAL
+{
+ /* context id -> mural association
+ * on context data save, each context will be made current with the corresponding mural from this table
+ * thus saving the mural front & back buffer data */
+ CRHashTable *contextMuralTable;
+ /* mural id -> context info
+ * for murals that do not have associated context in contextMuralTable
+ * we still need to save*/
+ CRHashTable *additionalMuralContextTable;
+
+ PSSMHANDLE pSSM;
+
+ int rc;
+} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL;
+
+
+typedef struct CRVBOX_CTXWND_CTXWALKER_CB
+{
+ PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
+ CRHashTable *usedMuralTable;
+ GLuint cAdditionalMurals;
+} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB;
+
+static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo * pMural = (CRMuralInfo *) data1;
+ PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
+ CRContextInfo *pContextInfo = NULL;
+
+ if (!pMural->CreateInfo.externalID)
+ {
+ CRASSERT(!key);
+ return;
+ }
+
+ if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
+ {
+ Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
+ return;
+ }
+
+ Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL));
+
+ if (cr_server.MainContextInfo.CreateInfo.realVisualBits == pMural->CreateInfo.realVisualBits)
+ {
+ pContextInfo = &cr_server.MainContextInfo;
+ }
+ else
+ {
+ crWarning("different visual bits not implemented!");
+ pContextInfo = &cr_server.MainContextInfo;
+ }
+
+ crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo);
+}
+
+
+typedef struct CRVBOX_CTXWND_WNDWALKER_CB
+{
+ PCRVBOX_SAVE_STATE_GLOBAL pGlobal;
+ CRHashTable *usedMuralTable;
+ CRContextInfo *pContextInfo;
+ CRMuralInfo * pMural;
+} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB;
+
+static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo * pMural = (CRMuralInfo *) data1;
+ PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2;
+
+ Assert(pData->pMural != pMural);
+ Assert(pData->pContextInfo);
+
+ if (pData->pMural)
+ return;
+
+ if (!pMural->CreateInfo.externalID)
+ {
+ CRASSERT(!key);
+ return;
+ }
+
+ if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext))
+ return;
+
+ if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID))
+ return;
+
+ CRASSERT(pMural->CreateInfo.realVisualBits == pData->pContextInfo->CreateInfo.realVisualBits);
+ pData->pMural = pMural;
+}
+
+static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *)data1;
+ PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
+
+ if (!pContextInfo->currentMural)
+ return;
+
+ crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural);
+ crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural);
+}
+
+CRMuralInfo * crServerGetDummyMural(GLint visualBits)
+{
+ CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits);
+ if (!pMural)
+ {
+ GLint id;
+ pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ if (!pMural)
+ {
+ crWarning("crCalloc failed!");
+ return NULL;
+ }
+ id = crServerMuralInit(pMural, GL_FALSE, visualBits, 0);
+ if (id < 0)
+ {
+ crWarning("crServerMuralInit failed!");
+ crFree(pMural);
+ return NULL;
+ }
+
+ crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural);
+ }
+
+ return pMural;
+}
+
+static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *)data1;
+ PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2;
+ CRMuralInfo * pMural = NULL;
+
+ if (pContextInfo->currentMural)
+ return;
+
+ Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1);
+ if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1)
+ {
+ CRVBOX_CTXWND_WNDWALKER_CB MuralData;
+ MuralData.pGlobal = pData->pGlobal;
+ MuralData.usedMuralTable = pData->usedMuralTable;
+ MuralData.pContextInfo = pContextInfo;
+ MuralData.pMural = NULL;
+
+ crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData);
+
+ pMural = MuralData.pMural;
+
+ }
+
+ if (!pMural)
+ {
+ pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
+ if (!pMural)
+ {
+ crWarning("crServerGetDummyMural failed");
+ return;
+ }
+ }
+ else
+ {
+ crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural);
+ ++pData->cAdditionalMurals;
+ }
+
+ crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural);
+}
+
+static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal)
+{
+ CRVBOX_CTXWND_CTXWALKER_CB Data;
+ GLuint cMurals;
+ pGlobal->contextMuralTable = crAllocHashtable();
+ pGlobal->additionalMuralContextTable = crAllocHashtable();
+ /* 1. go through all contexts and match all having currentMural set */
+ Data.pGlobal = pGlobal;
+ Data.usedMuralTable = crAllocHashtable();
+ Data.cAdditionalMurals = 0;
+ crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data);
+
+ cMurals = crHashtableNumElements(pGlobal->contextMuralTable);
+ CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable));
+ CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
+ CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable));
+ if (cMurals < crHashtableNumElements(cr_server.contextTable))
+ {
+ Data.cAdditionalMurals = 0;
+ crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data);
+ }
+
+ CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable));
+ CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1);
+ if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1)
+ {
+ crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data);
+ CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1);
+ }
+
+ crFreeHashtable(Data.usedMuralTable, NULL);
+}
+
+static void crVBoxServerFBImageDataTerm(CRFBData *pData)
+{
+ GLuint i;
+ for (i = 0; i < pData->cElements; ++i)
+ {
+ CRFBDataElement * pEl = &pData->aElements[i];
+ if (pEl->pvData)
+ {
+ crFree(pEl->pvData);
+ /* sanity */
+ pEl->pvData = NULL;
+ }
+ }
+ pData->cElements = 0;
+}
+
+static int crVBoxAddFBDataElement(CRFBData *pData, GLint idFBO, GLenum enmBuffer, GLint width, GLint height, GLenum enmFormat, GLenum enmType)
+{
+ CRFBDataElement *pEl;
+
+ AssertCompile(sizeof (GLfloat) == 4);
+ AssertCompile(sizeof (GLuint) == 4);
+
+ pEl = &pData->aElements[pData->cElements];
+ pEl->idFBO = idFBO;
+ pEl->enmBuffer = enmBuffer;
+ pEl->posX = 0;
+ pEl->posY = 0;
+ pEl->width = width;
+ pEl->height = height;
+ pEl->enmFormat = enmFormat;
+ pEl->enmType = enmType;
+ pEl->cbData = width * height * 4;
+
+ pEl->pvData = crCalloc(pEl->cbData);
+ if (!pEl->pvData)
+ {
+ crVBoxServerFBImageDataTerm(pData);
+ crWarning(": crCalloc failed");
+ return VERR_NO_MEMORY;
+ }
+
+ ++pData->cElements;
+
+ return VINF_SUCCESS;
+}
+
+/* Add framebuffer image elements arrording to SSM version. Please refer to cr_version.h
+ * in order to distinguish between versions. */
+static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight)
+{
+ CRContext *pContext;
+ GLuint i;
+ GLfloat *pF;
+ GLuint width;
+ GLuint height;
+ int rc;
+
+ crMemset(pData, 0, sizeof (*pData));
+
+ pContext = pCtxInfo->pContext;
+
+ /* the version should be always actual when we do reads,
+ * i.e. it could differ on writes when snapshot is getting loaded */
+ CRASSERT(fWrite || version == SHCROGL_SSM_VERSION);
+
+ width = overrideWidth ? overrideWidth : pMural->width;
+ height = overrideHeight ? overrideHeight : pMural->height;
+
+ if (!width || !height)
+ return VINF_SUCCESS;
+
+ if (pMural)
+ {
+ if (fWrite)
+ {
+ if (!pContext->framebufferobject.drawFB)
+ pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurDrawBuffer);
+ }
+ else
+ {
+ if (!pContext->framebufferobject.readFB)
+ pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurReadBuffer);
+ }
+ }
+
+ pData->u32Version = version;
+
+ pData->cElements = 0;
+
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
+ pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+
+ /* There is a lot of code that assumes we have double buffering, just assert here to print a warning in the log
+ * so that we know that something irregular is going on. */
+ CRASSERT(pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT);
+
+ if (( pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT)
+ || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL) /* <- Older version had a typo which lead to back always being used,
+ * no matter what the visual bits are. */
+ {
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0,
+ pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK, width, height, GL_RGBA, GL_UNSIGNED_BYTE);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+ }
+
+ if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
+ return VINF_SUCCESS;
+
+ if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL)
+ {
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
+ pMural ? pMural->idDepthStencilRB : 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+
+ /* Init to default depth value, just in case. "pData->cElements - 1" because we incremented counter in crVBoxAddFBDataElement(). */
+ pF = (GLfloat*)pData->aElements[pData->cElements - 1].pvData;
+ for (i = 0; i < width * height; ++i)
+ pF[i] = 1.;
+
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
+ pMural ? pMural->idDepthStencilRB : 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_INT);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+
+ return VINF_SUCCESS;
+ }
+
+ if (version < SHCROGL_SSM_VERSION_WITH_SEPARATE_DEPTH_STENCIL_BUFFERS)
+ {
+ /* Use GL_DEPTH_STENCIL only in case if both CR_STENCIL_BIT and CR_DEPTH_BIT specified. */
+ if ( (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
+ && (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT))
+ {
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0, 0,
+ width, height, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+ }
+
+ return VINF_SUCCESS;
+ }
+
+ /* Current SSM verion (SHCROGL_SSM_VERSION_WITH_SEPARATE_DEPTH_STENCIL_BUFFERS). */
+
+ if (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT)
+ {
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
+ pMural ? pMural->idDepthStencilRB : 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+
+ /* Init to default depth value, just in case. "pData->cElements - 1" because we incremented counter in crVBoxAddFBDataElement(). */
+ pF = (GLfloat*)pData->aElements[pData->cElements - 1].pvData;
+ for (i = 0; i < width * height; ++i)
+ pF[i] = 1.;
+ }
+
+ if (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT)
+ {
+ rc = crVBoxAddFBDataElement(pData, pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0,
+ pMural ? pMural->idDepthStencilRB : 0, width, height, GL_STENCIL_INDEX, GL_UNSIGNED_INT);
+ AssertReturn(rc == VINF_SUCCESS, rc);
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM)
+{
+ CRContextInfo *pCtxInfo;
+ CRContext *pContext;
+ CRMuralInfo *pMural;
+ int32_t rc;
+ GLuint i;
+ struct
+ {
+ CRFBData data;
+ CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
+ } Data;
+
+ Assert(sizeof (Data) >= RT_UOFFSETOF(CRFBData, aElements[4]));
+
+ pCtxInfo = cr_server.currentCtxInfo;
+ pContext = pCtxInfo->pContext;
+ pMural = pCtxInfo->currentMural;
+
+ rc = crVBoxServerFBImageDataInitEx(&Data.data, pCtxInfo, pMural, GL_FALSE, SHCROGL_SSM_VERSION, 0, 0);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
+ return rc;
+ }
+
+ rc = crStateAcquireFBImage(pContext, &Data.data);
+ AssertRCReturn(rc, rc);
+
+ for (i = 0; i < Data.data.cElements; ++i)
+ {
+ CRFBDataElement * pEl = &Data.data.aElements[i];
+ rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData);
+ AssertRCReturn(rc, rc);
+ }
+
+ crVBoxServerFBImageDataTerm(&Data.data);
+
+ return VINF_SUCCESS;
+}
+
+#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \
+ if(!RT_SUCCESS((_rc))) { \
+ AssertFailed(); \
+ return; \
+ } \
+ } while (0)
+
+static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *) data1;
+ PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
+ CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
+ PSSMHANDLE pSSM = pData->pSSM;
+ CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
+ CRMuralInfo *pInitialCurMural = pContextInfo->currentMural;
+
+ crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
+
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ crServerPerformMakeCurrent(pMural, pContextInfo);
+
+ pData->rc = crVBoxServerSaveFBImage(pSSM);
+
+ /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
+ crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
+ pContextInfo->currentMural = pInitialCurMural;
+
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+}
+
+static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *pContextInfo = (CRContextInfo *) data1;
+ CRContext *pContext = pContextInfo->pContext;
+ PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2;
+ PSSMHANDLE pSSM = pData->pSSM;
+ CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key);
+ CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural;
+ const int32_t i32Dummy = 0;
+
+ AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ CRASSERT(pContext && pSSM);
+ CRASSERT(pMural);
+ CRASSERT(pMural->CreateInfo.externalID);
+
+ /* We could have skipped saving the key and use similar callback to load context states back,
+ * but there's no guarantee we'd traverse hashtable in same order after loading.
+ */
+ pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+#ifdef DEBUG_misha
+ {
+ unsigned long id;
+ if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id))
+ crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID);
+ else
+ CRASSERT(id == key);
+ }
+#endif
+
+#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
+ if (pContextInfo->currentMural
+ || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */
+ )
+ {
+ CRASSERT(pMural->CreateInfo.externalID);
+ CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
+ pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID));
+ }
+ else
+ {
+ /* this is a dummy mural */
+ CRASSERT(!pMural->width);
+ CRASSERT(!pMural->height);
+ CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID));
+ pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID));
+ }
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext));
+ CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural);
+ CRASSERT(cr_server.curClient);
+
+ crServerPerformMakeCurrent(pMural, pContextInfo);
+#endif
+
+ pData->rc = crStateSaveContext(pContext, pSSM);
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ pData->rc = crVBoxServerSaveFBImage(pSSM);
+ CRSERVER_ASSERTRC_RETURN_VOID(pData->rc);
+
+ /* restore the initial current mural */
+ pContextInfo->currentMural = pContextCurrentMural;
+}
+
+static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0;
+
+static int32_t crVBoxServerSaveStatePerform(PSSMHANDLE pSSM)
+{
+ int32_t rc, i;
+ uint32_t ui32;
+ GLboolean b;
+ unsigned long key;
+ GLenum err;
+#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
+ CRClient *curClient;
+ CRMuralInfo *curMural = NULL;
+ CRContextInfo *curCtxInfo = NULL;
+#endif
+ CRVBOX_SAVE_STATE_GLOBAL Data;
+
+ crMemset(&Data, 0, sizeof (Data));
+
+#if 0
+ crVBoxServerCheckConsistency();
+#endif
+
+ /* We shouldn't be called if there's no clients at all*/
+ CRASSERT(cr_server.numClients > 0);
+
+ /** @todo it's hack atm */
+ /* We want to be called only once to save server state but atm we're being called from svcSaveState
+ * for every connected client (e.g. guest opengl application)
+ */
+ if (!cr_server.bIsInSavingState) /* It's first call */
+ {
+ cr_server.bIsInSavingState = GL_TRUE;
+
+ /* Store number of clients */
+ rc = SSMR3PutU32(pSSM, (uint32_t) cr_server.numClients);
+ AssertRCReturn(rc, rc);
+
+ /* we get called only once for CrCmd case, so disable the hack */
+ g_hackVBoxServerSaveLoadCallsLeft = cr_server.fCrCmdEnabled ? 1 : cr_server.numClients;
+ }
+
+ g_hackVBoxServerSaveLoadCallsLeft--;
+
+ /* Do nothing until we're being called last time */
+ if (g_hackVBoxServerSaveLoadCallsLeft>0)
+ {
+ return VINF_SUCCESS;
+ }
+
+#ifdef DEBUG_misha
+#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart"
+#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop"
+
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START);
+#endif
+
+ /* Save rendering contexts creation info */
+ ui32 = crHashtableNumElements(cr_server.contextTable);
+ rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
+ AssertRCReturn(rc, rc);
+ crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM);
+
+#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
+ curClient = cr_server.curClient;
+ /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */
+ if (curClient)
+ {
+ curCtxInfo = cr_server.curClient->currentCtxInfo;
+ curMural = cr_server.curClient->currentMural;
+ }
+ else if (cr_server.numClients)
+ {
+ cr_server.curClient = cr_server.clients[0];
+ }
+#endif
+
+ /* first save windows info */
+ /* Save windows creation info */
+ ui32 = crHashtableNumElements(cr_server.muralTable);
+ /* There should be default mural always */
+ CRASSERT(ui32>=1);
+ rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
+ AssertRCReturn(rc, rc);
+ crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM);
+
+ /* Save cr_server.muralTable
+ * @todo we don't need it all, just geometry info actually
+ */
+ rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1);
+ AssertRCReturn(rc, rc);
+ crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM);
+
+ /* we need to save front & backbuffer data for each mural first create a context -> mural association */
+ crVBoxServerBuildSaveStateGlobal(&Data);
+
+ rc = crStateSaveGlobals(pSSM);
+ AssertRCReturn(rc, rc);
+
+ Data.pSSM = pSSM;
+ /* Save contexts state tracker data */
+ /** @todo For now just some blind data dumps,
+ * but I've a feeling those should be saved/restored in a very strict sequence to
+ * allow diff_api to work correctly.
+ * Should be tested more with multiply guest opengl apps working when saving VM snapshot.
+ */
+ crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data);
+ AssertRCReturn(Data.rc, Data.rc);
+
+ ui32 = crHashtableNumElements(Data.additionalMuralContextTable);
+ rc = SSMR3PutU32(pSSM, (uint32_t) ui32);
+ AssertRCReturn(rc, rc);
+
+ crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data);
+ AssertRCReturn(Data.rc, Data.rc);
+
+#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE
+ cr_server.curClient = curClient;
+ /* Restore original win and ctx IDs*/
+ if (curClient && curMural && curCtxInfo)
+ {
+ crServerPerformMakeCurrent(curMural, curCtxInfo);
+ }
+ else
+ {
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
+ }
+#endif
+
+ /* Save clients info */
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn)
+ {
+ CRClient *pClient = cr_server.clients[i];
+
+ rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
+ AssertRCReturn(rc, rc);
+
+ if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0)
+ {
+ b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key);
+ CRASSERT(b);
+ rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ AssertRCReturn(rc, rc);
+ }
+
+ if (pClient->currentMural && pClient->currentWindow > 0)
+ {
+ b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key);
+ CRASSERT(b);
+ rc = SSMR3PutMem(pSSM, &key, sizeof(key));
+ AssertRCReturn(rc, rc);
+ }
+ }
+ }
+
+ rc = crServerPendSaveState(pSSM);
+ AssertRCReturn(rc, rc);
+
+ rc = CrPMgrSaveState(pSSM);
+ AssertRCReturn(rc, rc);
+
+#ifdef VBOX_WITH_CR_DISPLAY_LISTS
+ if (cr_server.head_spu->dispatch_table.spu_save_state)
+ {
+ rc = cr_server.head_spu->dispatch_table.spu_save_state((void *)pSSM);
+ AssertRCReturn(rc, rc);
+ }
+ else
+ crDebug("Do not save %s SPU state: no interface exported.", cr_server.head_spu->name);
+#endif
+
+ /* all context gl error states should have now be synced with chromium erro states,
+ * reset the error if any */
+ while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
+ crWarning("crServer: glGetError %d after saving snapshot", err);
+
+ cr_server.bIsInSavingState = GL_FALSE;
+
+#ifdef DEBUG_misha
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP);
+#endif
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM)
+{
+ if (cr_server.fCrCmdEnabled)
+ {
+ WARN(("we should not be called with cmd enabled!"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ return crVBoxServerSaveStatePerform(pSSM);
+}
+
+static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData)
+{
+ CRContextInfo* pContextInfo = (CRContextInfo*)pvData;
+ CRASSERT(pContextInfo);
+ CRASSERT(pContextInfo->pContext);
+ return pContextInfo->pContext;
+}
+
+typedef struct CR_SERVER_LOADSTATE_READER
+{
+ PSSMHANDLE pSSM;
+ uint32_t cbBuffer;
+ uint32_t cbData;
+ uint32_t offData;
+ uint8_t *pu8Buffer;
+} CR_SERVER_LOADSTATE_READER;
+
+static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM)
+{
+ memset(pReader, 0, sizeof (*pReader));
+ pReader->pSSM = pSSM;
+}
+
+static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader)
+{
+ if (pReader->pu8Buffer)
+ RTMemFree(pReader->pu8Buffer);
+
+ /* sanity */
+ memset(pReader, 0, sizeof (*pReader));
+}
+
+static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
+{
+ int rc = VINF_SUCCESS;
+ uint32_t cbRemaining = cbBuffer;
+ if (pReader->cbData)
+ {
+ uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer);
+ memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData);
+ pReader->cbData -= cbData;
+ pReader->offData += cbData;
+
+ cbRemaining -= cbData;
+ pvBuffer = ((uint8_t*)pvBuffer) + cbData;
+ }
+
+ if (cbRemaining)
+ {
+ rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining);
+ AssertRC(rc);
+ }
+
+ return rc;
+}
+
+static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32)
+{
+ return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32));
+}
+
+static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer)
+{
+ if (!pReader->cbData && pReader->cbBuffer >= cbBuffer)
+ {
+ pReader->offData = 0;
+ pReader->cbData = cbBuffer;
+ memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
+ }
+ else if (pReader->offData >= cbBuffer)
+ {
+ pReader->offData -= cbBuffer;
+ pReader->cbData += cbBuffer;
+ memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer);
+ }
+ else
+ {
+ uint8_t *pu8Buffer = pReader->pu8Buffer;
+
+ pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData);
+ if (!pReader->pu8Buffer)
+ {
+ crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData);
+ return VERR_NO_MEMORY;
+ }
+
+ memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer);
+ if (pu8Buffer)
+ {
+ memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData);
+ RTMemFree(pu8Buffer);
+ }
+ else
+ {
+ Assert(!pReader->cbData);
+ }
+ pReader->offData = 0;
+ pReader->cbData += cbBuffer;
+ }
+
+ return VINF_SUCCESS;
+}
+
+/* data to be skipped */
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_2
+{
+ void*ListHead_pNext;
+ void*ListHead_pPrev;
+ uint32_t cEntries;
+} CR_SERVER_BUGGY_MURAL_DATA_2;
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_1
+{
+ /* VBOXVR_COMPOSITOR_ENTRY Ce; */
+ void*Ce_Node_pNext;
+ void*Ce_Node_pPrev;
+ CR_SERVER_BUGGY_MURAL_DATA_2 Vr;
+ /* VBOXVR_TEXTURE Tex; */
+ uint32_t Tex_width;
+ uint32_t Tex_height;
+ uint32_t Tex_target;
+ uint32_t Tex_hwid;
+ /* RTPOINT Pos; */
+ uint32_t Pos_x;
+ uint32_t Pos_y;
+ uint32_t fChanged;
+ uint32_t cRects;
+ void* paSrcRects;
+ void* paDstRects;
+} CR_SERVER_BUGGY_MURAL_DATA_1;
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_4
+{
+ uint32_t u32Magic;
+ int32_t cLockers;
+ RTNATIVETHREAD NativeThreadOwner;
+ int32_t cNestings;
+ uint32_t fFlags;
+ void* EventSem;
+ R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec;
+ RTHCPTR Alignment;
+} CR_SERVER_BUGGY_MURAL_DATA_4;
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA_3
+{
+ void*Compositor_List_pNext;
+ void*Compositor_List_pPrev;
+ void*Compositor_pfnEntryRemoved;
+ float StretchX;
+ float StretchY;
+ uint32_t cRects;
+ uint32_t cRectsBuffer;
+ void*paSrcRects;
+ void*paDstRects;
+ CR_SERVER_BUGGY_MURAL_DATA_4 CritSect;
+} CR_SERVER_BUGGY_MURAL_DATA_3;
+
+typedef struct CR_SERVER_BUGGY_MURAL_DATA
+{
+ uint8_t fRootVrOn;
+ CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry;
+ CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor;
+} CR_SERVER_BUGGY_MURAL_DATA;
+
+AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient));
+
+static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version)
+{
+ unsigned long key;
+ uint32_t ui, uiNumElems;
+ bool fBuggyMuralData = false;
+ /* Load windows */
+ int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems);
+ AssertLogRelRCReturn(rc, rc);
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRCreateInfo_t createInfo;
+ char psz[200];
+ GLint winID;
+ unsigned long key;
+
+ rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
+ AssertLogRelRCReturn(rc, rc);
+ rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo));
+ AssertLogRelRCReturn(rc, rc);
+
+ CRASSERT(!pReader->cbData);
+
+ if (createInfo.pszDpyName)
+ {
+ rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL);
+ AssertLogRelRCReturn(rc, rc);
+ createInfo.pszDpyName = psz;
+ }
+
+ winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key);
+ CRASSERT((int64_t)winID == (int64_t)key);
+ }
+
+ /* Load cr_server.muralTable */
+ rc = SSMR3GetU32(pReader->pSSM, &uiNumElems);
+ AssertLogRelRCReturn(rc, rc);
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRMuralInfo muralInfo;
+ CRMuralInfo *pActualMural = NULL;
+
+ rc = crServerLsrDataGetMem(pReader, &key, sizeof(key));
+ AssertLogRelRCReturn(rc, rc);
+ rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_UOFFSETOF(CRMuralInfo, CreateInfo));
+ AssertLogRelRCReturn(rc, rc);
+
+ if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING)
+ muralInfo.bFbDraw = GL_TRUE;
+
+ if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO)
+ {
+ /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */
+ union
+ {
+ void * apv[1];
+ CR_SERVER_BUGGY_MURAL_DATA Data;
+ /* need to chak spuWindow, so taking the offset of filed following it*/
+ uint8_t au8[RT_UOFFSETOF(CRMuralInfo, screenId)];
+ RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)];
+ } LaBuf;
+
+ do {
+ /* first value is bool (uint8_t) value followed by pointer-size-based alignment.
+ * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */
+ rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf));
+ AssertLogRelRCReturn(rc, rc);
+ if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void *)(uintptr_t)1))
+ break;
+
+ /* check that the pointers are either valid or NULL */
+ if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext))
+ break;
+ if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev))
+ break;
+ if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext))
+ break;
+ if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev))
+ break;
+
+ /* the entry can can be the only one within the (mural) compositor,
+ * so its compositor entry node can either contain NULL pNext and pPrev,
+ * or both of them pointing to compositor's list head */
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
+ break;
+
+ /* can either both or none be NULL */
+ if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
+ break;
+
+ if (!LaBuf.Data.fRootVrOn)
+ {
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)
+ break;
+
+ /* either non-initialized (zeroed) or empty list */
+ if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
+ break;
+
+ if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
+ break;
+ }
+ else
+ {
+ /* the entry should be initialized */
+ if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)
+ break;
+ if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)
+ break;
+
+ if (LaBuf.Data.RootVrCEntry.Vr.cEntries)
+ {
+ /* entry should be in compositor list*/
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL)
+ break;
+ CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
+ }
+ else
+ {
+ /* entry should NOT be in compositor list*/
+ if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL)
+ break;
+ CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext);
+ }
+ }
+
+ /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */
+ fBuggyMuralData = true;
+ break;
+
+ } while (0);
+
+ rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf));
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ if (fBuggyMuralData)
+ {
+ CR_SERVER_BUGGY_MURAL_DATA Tmp;
+ rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp));
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ if (muralInfo.pVisibleRects)
+ {
+ muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects);
+ if (!muralInfo.pVisibleRects)
+ {
+ return VERR_NO_MEMORY;
+ }
+
+ rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key);
+ CRASSERT(pActualMural);
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE)
+ {
+ rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage));
+ CRASSERT(rc == VINF_SUCCESS);
+ }
+
+ /* Restore windows geometry info */
+ crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height);
+ crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY);
+ /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/
+ if (muralInfo.bReceivedRects)
+ {
+ crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects);
+ }
+ crServerDispatchWindowShow(key, muralInfo.bVisible);
+
+ if (muralInfo.pVisibleRects)
+ {
+ crFree(muralInfo.pVisibleRects);
+ }
+ }
+
+ CRASSERT(RT_SUCCESS(rc));
+ return VINF_SUCCESS;
+}
+
+static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version,
+ CRContextInfo* pContextInfo, CRMuralInfo *pMural)
+{
+ CRContext *pContext = pContextInfo->pContext;
+ int32_t rc = VINF_SUCCESS;
+ GLuint i;
+ /* can apply the data right away */
+ struct
+ {
+ CRFBData data;
+ CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */
+ } Data;
+
+ Assert(sizeof (Data) >= RT_UOFFSETOF(CRFBData, aElements[4]));
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER)
+ {
+ if (!pMural->width || !pMural->height)
+ return VINF_SUCCESS;
+
+ rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
+ return rc;
+ }
+ }
+ else
+ {
+ GLint storedWidth, storedHeight;
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRASSERT(cr_server.currentCtxInfo == pContextInfo);
+ CRASSERT(cr_server.currentMural == pMural);
+ storedWidth = pMural->width;
+ storedHeight = pMural->height;
+ }
+ else
+ {
+ storedWidth = pContext->buffer.storedWidth;
+ storedHeight = pContext->buffer.storedHeight;
+ }
+
+ if (!storedWidth || !storedHeight)
+ return VINF_SUCCESS;
+
+ rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crVBoxServerFBImageDataInit failed rc %d", rc);
+ return rc;
+ }
+ }
+
+ CRASSERT(Data.data.cElements);
+
+ for (i = 0; i < Data.data.cElements; ++i)
+ {
+ CRFBDataElement * pEl = &Data.data.aElements[i];
+ rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRBufferState *pBuf = &pContext->buffer;
+ /* can apply the data right away */
+ CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo);
+ CRASSERT(cr_server.currentMural);
+
+ cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow,
+ 0,
+ pContextInfo->SpuContext >= 0
+ ? pContextInfo->SpuContext
+ : cr_server.MainContextInfo.SpuContext);
+ crStateApplyFBImage(pContext, &Data.data);
+ CRASSERT(!pBuf->pFrontImg);
+ CRASSERT(!pBuf->pBackImg);
+ crVBoxServerFBImageDataTerm(&Data.data);
+
+ crServerPresentFBO(pMural);
+
+ CRASSERT(cr_server.currentMural);
+ cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow,
+ 0,
+ cr_server.currentCtxInfo->SpuContext >= 0
+ ? cr_server.currentCtxInfo->SpuContext
+ : cr_server.MainContextInfo.SpuContext);
+ }
+ else
+ {
+ CRBufferState *pBuf = &pContext->buffer;
+ CRASSERT(!pBuf->pFrontImg);
+ CRASSERT(!pBuf->pBackImg);
+ CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */
+
+ if (Data.data.cElements)
+ {
+ CRFBData *pLazyData = crAlloc(RT_UOFFSETOF_DYN(CRFBData, aElements[Data.data.cElements]));
+ if (!RT_SUCCESS(rc))
+ {
+ crVBoxServerFBImageDataTerm(&Data.data);
+ crWarning("crAlloc failed");
+ return VERR_NO_MEMORY;
+ }
+
+ crMemcpy(pLazyData, &Data.data, RT_UOFFSETOF_DYN(CRFBData, aElements[Data.data.cElements]));
+ pBuf->pFrontImg = pLazyData;
+ }
+ }
+
+ CRASSERT(RT_SUCCESS(rc));
+ return VINF_SUCCESS;
+}
+
+static int32_t crVBoxServerLoadStatePerform(PSSMHANDLE pSSM, uint32_t version)
+{
+ int32_t rc, i;
+ uint32_t ui, uiNumElems;
+ unsigned long key;
+ GLenum err;
+ CR_SERVER_LOADSTATE_READER Reader;
+
+ if (!cr_server.bIsInLoadingState)
+ {
+ /* AssertRCReturn(...) will leave us in loading state, but it doesn't matter as we'd be failing anyway */
+ cr_server.bIsInLoadingState = GL_TRUE;
+
+ /* Read number of clients */
+ rc = SSMR3GetU32(pSSM, &g_hackVBoxServerSaveLoadCallsLeft);
+ AssertLogRelRCReturn(rc, rc);
+
+ Assert(g_hackVBoxServerSaveLoadCallsLeft);
+ /* we get called only once for CrCmd */
+ if (cr_server.fCrCmdEnabled)
+ g_hackVBoxServerSaveLoadCallsLeft = 1;
+ }
+
+ g_hackVBoxServerSaveLoadCallsLeft--;
+
+ /* Do nothing until we're being called last time */
+ if (g_hackVBoxServerSaveLoadCallsLeft>0)
+ {
+ return VINF_SUCCESS;
+ }
+
+ if (version < SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS)
+ {
+ return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
+ }
+
+ crServerLsrInit(&Reader, pSSM);
+
+#ifdef DEBUG_misha
+#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart"
+#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop"
+
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START);
+#endif
+
+ /* Load and recreate rendering contexts */
+ rc = SSMR3GetU32(pSSM, &uiNumElems);
+ AssertLogRelRCReturn(rc, rc);
+ for (ui = 0; ui < uiNumElems; ++ui)
+ {
+ CRCreateInfo_t createInfo;
+ char psz[200];
+ GLint ctxID;
+ CRContextInfo* pContextInfo;
+ CRContext* pContext;
+
+ rc = SSMR3GetMem(pSSM, &key, sizeof(key));
+ AssertLogRelRCReturn(rc, rc);
+ rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo));
+ AssertLogRelRCReturn(rc, rc);
+
+ if (createInfo.pszDpyName)
+ {
+ rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL);
+ AssertLogRelRCReturn(rc, rc);
+ createInfo.pszDpyName = psz;
+ }
+
+ ctxID = crServerDispatchCreateContextEx(createInfo.pszDpyName, createInfo.visualBits, 0, key, createInfo.externalID /* <-saved state stores internal id here*/);
+ CRASSERT((int64_t)ctxID == (int64_t)key);
+
+ pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
+ CRASSERT(pContextInfo);
+ CRASSERT(pContextInfo->pContext);
+ pContext = pContextInfo->pContext;
+ pContext->shared->id=-1;
+ }
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRASSERT(!Reader.pu8Buffer);
+ /* we have a mural data here */
+ rc = crVBoxServerLoadMurals(&Reader, version);
+ AssertLogRelRCReturn(rc, rc);
+ CRASSERT(!Reader.pu8Buffer);
+ }
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems)
+ {
+ /* set the current client to allow doing crServerPerformMakeCurrent later */
+ CRASSERT(cr_server.numClients);
+ cr_server.curClient = cr_server.clients[0];
+ }
+
+ rc = crStateLoadGlobals(pSSM, version);
+ AssertLogRelRCReturn(rc, rc);
+
+ if (uiNumElems)
+ {
+ /* ensure we have main context set up as current */
+ CRMuralInfo *pMural;
+ CRASSERT(cr_server.MainContextInfo.SpuContext > 0);
+ CRASSERT(!cr_server.currentCtxInfo);
+ CRASSERT(!cr_server.currentMural);
+ pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ CRASSERT(pMural);
+ crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo);
+ }
+
+ /* Restore context state data */
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRContextInfo* pContextInfo;
+ CRContext *pContext;
+ CRMuralInfo *pMural = NULL;
+ int32_t winId = 0;
+
+ rc = SSMR3GetMem(pSSM, &key, sizeof(key));
+ AssertLogRelRCReturn(rc, rc);
+
+ pContextInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, key);
+ CRASSERT(pContextInfo);
+ CRASSERT(pContextInfo->pContext);
+ pContext = pContextInfo->pContext;
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ rc = SSMR3GetMem(pSSM, &winId, sizeof(winId));
+ AssertLogRelRCReturn(rc, rc);
+
+ if (winId)
+ {
+ pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId);
+ CRASSERT(pMural);
+ }
+ else
+ {
+ /* null winId means a dummy mural, get it */
+ pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits);
+ CRASSERT(pMural);
+ }
+ }
+
+ rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version);
+ AssertLogRelRCReturn(rc, rc);
+
+ /*Restore front/back buffer images*/
+ rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA)
+ {
+ CRContextInfo *pContextInfo;
+ CRMuralInfo *pMural;
+ GLint ctxId;
+
+ rc = SSMR3GetU32(pSSM, &uiNumElems);
+ AssertLogRelRCReturn(rc, rc);
+ for (ui=0; ui<uiNumElems; ++ui)
+ {
+ CRbitvalue initialCtxUsage[CR_MAX_BITARRAY];
+ CRMuralInfo *pInitialCurMural;
+
+ rc = SSMR3GetMem(pSSM, &key, sizeof(key));
+ AssertLogRelRCReturn(rc, rc);
+
+ rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId));
+ AssertLogRelRCReturn(rc, rc);
+
+ pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key);
+ CRASSERT(pMural);
+ if (ctxId)
+ {
+ pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId);
+ CRASSERT(pContextInfo);
+ }
+ else
+ pContextInfo = &cr_server.MainContextInfo;
+
+ crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage));
+ pInitialCurMural = pContextInfo->currentMural;
+
+ rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */
+ crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage));
+ pContextInfo->currentMural = pInitialCurMural;
+ }
+
+ CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo);
+
+ cr_server.curClient = NULL;
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE;
+ }
+ else
+ {
+ CRServerFreeIDsPool_t dummyIdsPool;
+
+ CRASSERT(!Reader.pu8Buffer);
+
+ /* we have a mural data here */
+ rc = crVBoxServerLoadMurals(&Reader, version);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* not used any more, just read it out and ignore */
+ rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool));
+ CRASSERT(rc == VINF_SUCCESS);
+ }
+
+ /* Load clients info */
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i] && cr_server.clients[i]->conn)
+ {
+ CRClient *pClient = cr_server.clients[i];
+ CRClient client;
+ unsigned long ctxID=-1, winID=-1;
+
+ rc = crServerLsrDataGetU32(&Reader, &ui);
+ AssertLogRelRCReturn(rc, rc);
+ /* If this assert fires, then we should search correct client in the list first*/
+ CRASSERT(ui == pClient->conn->u32ClientID);
+
+ if (version>=4)
+ {
+ rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor);
+ AssertLogRelRCReturn(rc, rc);
+
+ rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client));
+ CRASSERT(rc == VINF_SUCCESS);
+
+ client.conn = pClient->conn;
+ /* We can't reassign client number, as we'd get wrong results in TranslateTextureID
+ * and fail to bind old textures.
+ */
+ /*client.number = pClient->number;*/
+ *pClient = client;
+
+ pClient->currentContextNumber = -1;
+ pClient->currentCtxInfo = &cr_server.MainContextInfo;
+ pClient->currentMural = NULL;
+ pClient->currentWindow = -1;
+
+ cr_server.curClient = pClient;
+
+ if (client.currentCtxInfo && client.currentContextNumber > 0)
+ {
+ rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID));
+ AssertLogRelRCReturn(rc, rc);
+ client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID);
+ CRASSERT(client.currentCtxInfo);
+ CRASSERT(client.currentCtxInfo->pContext);
+ //pClient->currentCtx = client.currentCtx;
+ //pClient->currentContextNumber = ctxID;
+ }
+
+ if (client.currentMural && client.currentWindow > 0)
+ {
+ rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID));
+ AssertLogRelRCReturn(rc, rc);
+ client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID);
+ CRASSERT(client.currentMural);
+ //pClient->currentMural = client.currentMural;
+ //pClient->currentWindow = winID;
+ }
+
+ CRASSERT(!Reader.cbData);
+
+ /* Restore client active context and window */
+ crServerDispatchMakeCurrent(winID, 0, ctxID);
+ }
+ }
+
+ cr_server.curClient = NULL;
+
+ rc = crServerPendLoadState(pSSM, version);
+ AssertLogRelRCReturn(rc, rc);
+
+ if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO)
+ {
+ rc = CrPMgrLoadState(pSSM, version);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+#ifdef VBOX_WITH_CR_DISPLAY_LISTS
+ if (version >= SHCROGL_SSM_VERSION_WITH_DISPLAY_LISTS)
+ {
+ if (cr_server.head_spu->dispatch_table.spu_load_state)
+ {
+ rc = cr_server.head_spu->dispatch_table.spu_load_state((void *)pSSM);
+ AssertLogRelRCReturn(rc, rc);
+ }
+ else
+ crDebug("Do not load %s SPU state: no interface exported.", cr_server.head_spu->name);
+ }
+#endif
+
+ while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR)
+ crWarning("crServer: glGetError %d after loading snapshot", err);
+
+ cr_server.bIsInLoadingState = GL_FALSE;
+
+#ifdef DEBUG_misha
+ if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY)
+ cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP);
+#endif
+
+ CRASSERT(!Reader.cbData);
+ crServerLsrTerm(&Reader);
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version)
+{
+ if (cr_server.fCrCmdEnabled)
+ {
+ WARN(("CrCmd enabled"));
+ return VERR_INTERNAL_ERROR;
+ }
+
+ return crVBoxServerLoadStatePerform(pSSM, version);
+}
+
+#define SCREEN(i) (cr_server.screen[i])
+#define MAPPED(screen) ((screen).winID != 0)
+
+extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb)
+{
+ cr_server.pfnNotifyEventCB = pfnCb;
+}
+
+void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void* pvData, uint32_t cbData)
+{
+ /* this is something unexpected, but just in case */
+ if (idScreen >= cr_server.screenCount)
+ {
+ crWarning("invalid screen id %d", idScreen);
+ return;
+ }
+
+ cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData, cbData);
+}
+
+void crServerWindowReparent(CRMuralInfo *pMural)
+{
+ pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID;
+
+ renderspuReparentWindow(pMural->spuWindow);
+}
+
+DECLEXPORT(void) crServerSetUnscaledHiDPI(bool fEnable)
+{
+ renderspuSetUnscaledHiDPI(fEnable);
+}
+
+static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+ int *sIndex = (int*) data2;
+
+ if (pMI->screenId == *sIndex)
+ {
+ crServerWindowReparent(pMI);
+ }
+}
+
+DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount)
+{
+ int i;
+
+ if (sCount > CR_MAX_GUEST_MONITORS)
+ return VERR_INVALID_PARAMETER;
+
+ /*Shouldn't happen yet, but to be safe in future*/
+ for (i = 0; i < cr_server.screenCount; /*++i - unreachable code*/)
+ {
+ if (MAPPED(SCREEN(i)))
+ WARN(("Screen count is changing, but screen[%i] is still mapped", i));
+ return VERR_NOT_IMPLEMENTED;
+ }
+
+ cr_server.screenCount = sCount;
+
+ for (i=0; i<sCount; ++i)
+ {
+ SCREEN(i).winID = 0;
+ }
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex)
+{
+ crDebug("crVBoxServerUnmapScreen(%i)", sIndex);
+
+ if (sIndex<0 || sIndex>=cr_server.screenCount)
+ return VERR_INVALID_PARAMETER;
+
+ if (MAPPED(SCREEN(sIndex)))
+ {
+ SCREEN(sIndex).winID = 0;
+ renderspuSetWindowId(0);
+
+ crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
+
+ crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
+
+ CrPMgrScreenChanged((uint32_t)sIndex);
+ }
+
+ renderspuSetWindowId(SCREEN(0).winID);
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID)
+{
+ crDebug("crVBoxServerMapScreen(%i) [%i,%i:%u,%u %x]", sIndex, x, y, w, h, winID);
+
+ if (sIndex<0 || sIndex>=cr_server.screenCount)
+ return VERR_INVALID_PARAMETER;
+
+ if (MAPPED(SCREEN(sIndex)) && SCREEN(sIndex).winID!=winID)
+ {
+ crDebug("Mapped screen[%i] is being remapped.", sIndex);
+ crVBoxServerUnmapScreen(sIndex);
+ }
+
+ SCREEN(sIndex).winID = winID;
+ SCREEN(sIndex).x = x;
+ SCREEN(sIndex).y = y;
+ SCREEN(sIndex).w = w;
+ SCREEN(sIndex).h = h;
+
+ renderspuSetWindowId(SCREEN(sIndex).winID);
+ crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex);
+
+ crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex);
+ renderspuSetWindowId(SCREEN(0).winID);
+
+#ifndef WINDOWS
+ /*Restore FB content for clients, which have current window on a screen being remapped*/
+ {
+ GLint i;
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ cr_server.curClient = cr_server.clients[i];
+ if (cr_server.curClient->currentCtxInfo
+ && cr_server.curClient->currentCtxInfo->pContext
+ && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg)
+ && cr_server.curClient->currentMural
+ && cr_server.curClient->currentMural->screenId == sIndex
+ && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h
+ && cr_server.curClient->currentCtxInfo->pContext->buffer.storedWidth == w)
+ {
+ int clientWindow = cr_server.curClient->currentWindow;
+ int clientContext = cr_server.curClient->currentContextNumber;
+ CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg;
+
+ if (clientWindow && clientWindow != cr_server.currentWindow)
+ {
+ crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
+ }
+
+ crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData);
+ crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext);
+ }
+ }
+ cr_server.curClient = NULL;
+ }
+#endif
+
+ CrPMgrScreenChanged((uint32_t)sIndex);
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects)
+{
+ int32_t rc = VINF_SUCCESS;
+ GLboolean fOldRootVrOn = cr_server.fRootVrOn;
+
+ /* non-zero rects pointer indicate rects are present and switched on
+ * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions,
+ * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */
+ if (pRects)
+ {
+ crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint));
+ rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("VBoxVrListRectsSet failed! rc %d", rc);
+ return rc;
+ }
+
+ cr_server.fRootVrOn = GL_TRUE;
+ }
+ else
+ {
+ if (!cr_server.fRootVrOn)
+ return VINF_SUCCESS;
+
+ VBoxVrListClear(&cr_server.RootVr);
+
+ cr_server.fRootVrOn = GL_FALSE;
+ }
+
+ if (!fOldRootVrOn != !cr_server.fRootVrOn)
+ {
+ rc = CrPMgrModeRootVr(cr_server.fRootVrOn);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrPMgrModeRootVr failed rc %d", rc);
+ return rc;
+ }
+ }
+ else if (cr_server.fRootVrOn)
+ {
+ rc = CrPMgrRootVrUpdate();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrPMgrRootVrUpdate failed rc %d", rc);
+ return rc;
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value)
+{
+ return CrPMgrModeVrdp(value);
+}
+
+DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks)
+{
+ /* No need for a synchronization as this is single threaded. */
+ if (pCallbacks)
+ {
+ cr_server.outputRedirect = *pCallbacks;
+ }
+ else
+ {
+ memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect));
+ }
+
+ return VINF_SUCCESS;
+}
+
+DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h)
+{
+ CRScreenViewportInfo *pViewport;
+ RTRECT NewRect;
+ int rc;
+
+ crDebug("crVBoxServerSetScreenViewport(%i)", sIndex);
+
+ if (sIndex<0 || sIndex>=cr_server.screenCount)
+ {
+ crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex);
+ return VERR_INVALID_PARAMETER;
+ }
+
+ NewRect.xLeft = x;
+ NewRect.yTop = y;
+ NewRect.xRight = x + w;
+ NewRect.yBottom = y + h;
+
+ pViewport = &cr_server.screenVieport[sIndex];
+ /*always do viewport updates no matter whether the rectangle actually changes,
+ * this is needed to ensure window is adjusted properly on OSX */
+ pViewport->Rect = NewRect;
+ rc = CrPMgrViewportUpdate((uint32_t)sIndex);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrPMgrViewportUpdate failed %d", rc);
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+static void crVBoxServerDeleteMuralCb(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *h = (CRHashTable*)data2;
+ CRMuralInfo *m = (CRMuralInfo *) data1;
+ if (m->spuWindow == CR_RENDER_DEFAULT_WINDOW_ID)
+ return;
+
+ crHashtableDelete(h, key, NULL);
+ crServerMuralTerm(m);
+ crFree(m);
+}
+
+static void crVBoxServerDefaultContextClear()
+{
+ HCR_FRAMEBUFFER hFb;
+ int rc = CrPMgrDisable();
+ if (RT_FAILURE(rc))
+ {
+ WARN(("CrPMgrDisable failed %d", rc));
+ return;
+ }
+
+ for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ int rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbRegionsClear(hFb);
+ CrFbUpdateEnd(hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed %d", rc));
+ }
+
+ cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
+ crStateCleanupCurrent();
+
+ /* note: we need to clean all contexts, since otherwise renderspu leanup won't work,
+ * i.e. renderspu would need to clean up its own internal windows, it won't be able to do that if
+ * some those windows is associated with any context. */
+ if (cr_server.MainContextInfo.SpuContext)
+ {
+ cr_server.head_spu->dispatch_table.DestroyContext(cr_server.MainContextInfo.SpuContext);
+ crStateDestroyContext(cr_server.MainContextInfo.pContext);
+ if (cr_server.MainContextInfo.CreateInfo.pszDpyName)
+ crFree(cr_server.MainContextInfo.CreateInfo.pszDpyName);
+
+ memset(&cr_server.MainContextInfo, 0, sizeof (cr_server.MainContextInfo));
+ }
+
+ cr_server.firstCallCreateContext = GL_TRUE;
+ cr_server.firstCallMakeCurrent = GL_TRUE;
+ cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE;
+
+ CRASSERT(!cr_server.curClient);
+
+ cr_server.currentCtxInfo = NULL;
+ cr_server.currentWindow = 0;
+ cr_server.currentNativeWindow = 0;
+ cr_server.currentMural = NULL;
+
+ crStateDestroy();
+// crStateCleanupCurrent();
+
+ if (CrBltIsInitialized(&cr_server.Blitter))
+ {
+ CrBltTerm(&cr_server.Blitter);
+ Assert(!CrBltIsInitialized(&cr_server.Blitter));
+ }
+
+ crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerDeleteMuralCb, cr_server.dummyMuralTable);
+
+ cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 0);
+}
+
+static void crVBoxServerDefaultContextSet()
+{
+ cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_RENDERTHREAD_INFORM, 1);
+
+ CRASSERT(!cr_server.MainContextInfo.SpuContext);
+
+// crStateSetCurrent(NULL);
+ crStateInit();
+ crStateDiffAPI( &(cr_server.head_spu->dispatch_table) );
+
+ CrPMgrEnable();
+}
+
+#ifdef VBOX_WITH_CRHGSMI
+
+/** @todo RT_UNTRUSTED_VOLATILE_GUEST */
+static int32_t crVBoxServerCmdVbvaCrCmdProcess(VBOXCMDVBVA_CRCMD_CMD const RT_UNTRUSTED_VOLATILE_GUEST *pCmdTodo, uint32_t cbCmd)
+{
+ VBOXCMDVBVA_CRCMD_CMD const *pCmd = (VBOXCMDVBVA_CRCMD_CMD const *)pCmdTodo;
+ int32_t rc;
+ uint32_t cBuffers = pCmd->cBuffers;
+ uint32_t cParams;
+ uint32_t cbHdr;
+ CRVBOXHGSMIHDR *pHdr;
+ uint32_t u32Function;
+ uint32_t u32ClientID;
+ CRClient *pClient;
+
+ if (!g_pvVRamBase)
+ {
+ WARN(("g_pvVRamBase is not initialized"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (!cBuffers)
+ {
+ WARN(("zero buffers passed in!"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ cParams = cBuffers-1;
+
+ if (cbCmd < RT_UOFFSETOF_DYN(VBOXCMDVBVA_CRCMD_CMD, aBuffers[cBuffers]))
+ {
+ WARN(("invalid buffer size"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ cbHdr = pCmd->aBuffers[0].cbBuffer;
+ pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
+ if (!pHdr)
+ {
+ WARN(("invalid header buffer!"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ if (cbHdr < sizeof (*pHdr))
+ {
+ WARN(("invalid header buffer size!"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ u32Function = pHdr->u32Function;
+ u32ClientID = pHdr->u32ClientID;
+
+ switch (u32Function)
+ {
+ case SHCRGL_GUEST_FN_WRITE:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
+
+ /** @todo Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
+ const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ WARN(("invalid write cmd buffer size!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ WARN(("invalid buffer data received from guest!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerClientGet failed %d", rc));
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
+ crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return VINF_SUCCESS;
+ }
+
+ WARN(("invalid number of args"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_INJECT:
+ {
+ WARN(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
+
+ /** @todo Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
+ /* Fetch parameters. */
+ uint32_t u32InjectClientID = pFnCmd->u32ClientID;
+ const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ WARN(("invalid inject cmd buffer size!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ WARN(("invalid buffer data received from guest!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerClientGet failed %d", rc));
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false);
+ crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return VINF_SUCCESS;
+ }
+
+ WARN(("invalid number of args"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
+
+ /** @todo Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
+ const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ WARN(("invalid read cmd buffer size!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ if (!pBuffer)
+ {
+ WARN(("invalid buffer data received from guest!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerClientGet failed %d", rc));
+ break;
+ }
+
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
+
+ /* Return the required buffer size always */
+ pFnCmd->cbBuffer = cbBuffer;
+
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ /* the read command is never pended, complete it right away */
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerInternalClientRead failed %d", rc));
+ break;
+ }
+
+ break;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_WRITE_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
+
+ /** @todo Verify */
+ if (cParams == 2)
+ {
+ CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
+ const VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1];
+ const VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2];
+
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ uint32_t cbWriteback = pWbBuf->cbBuffer;
+ char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ WARN(("invalid write_read cmd buffer size!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ WARN(("invalid write buffer data received from guest!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbWriteback);
+ if (!pWriteback)
+ {
+ WARN(("invalid writeback buffer data received from guest!"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerClientGet failed %d", rc));
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false);
+ crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return VINF_SUCCESS;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_VERSION:
+ {
+ WARN(("SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_PID:
+ {
+ WARN(("SHCRGL_GUEST_FN_SET_PID: invalid function"));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ default:
+ {
+ WARN(("invalid function, %d", u32Function));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ }
+
+ pHdr->result = rc;
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo)
+{
+ Assert(!cr_server.fCrCmdEnabled);
+ Assert(!cr_server.numClients);
+
+ cr_server.CrCmdClientInfo = *pInfo;
+
+ crVBoxServerDefaultContextSet();
+
+ cr_server.fCrCmdEnabled = GL_TRUE;
+
+ crInfo("crCmd ENABLED");
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr)
+{
+ Assert(cr_server.fCrCmdEnabled);
+
+ crVBoxServerRemoveAllClients();
+
+ CrHTableEmpty(&cr_server.clientTable);
+
+ crVBoxServerDefaultContextClear();
+
+ memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo));
+
+ cr_server.fCrCmdEnabled = GL_FALSE;
+
+ crInfo("crCmd DISABLED");
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd)
+{
+ return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd);
+}
+
+static int crVBoxCrDisconnect(uint32_t u32Client)
+{
+ CRClient *pClient = (CRClient*)CrHTableRemove(&cr_server.clientTable, u32Client);
+ if (!pClient)
+ {
+ WARN(("invalid client id"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ crVBoxServerRemoveClientObj(pClient);
+
+ return VINF_SUCCESS;
+}
+
+static int crVBoxCrConnectEx(VBOXCMDVBVA_3DCTL_CONNECT RT_UNTRUSTED_VOLATILE_GUEST *pConnect, uint32_t u32ClientId)
+{
+ CRClient *pClient;
+ int rc;
+ uint32_t const uMajorVersion = pConnect->u32MajorVersion;
+ uint32_t const uMinorVersion = pConnect->u32MinorVersion;
+ uint64_t const uPid = pConnect->u64Pid;
+ RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
+
+ if (u32ClientId == CRHTABLE_HANDLE_INVALID)
+ {
+ /* allocate client id */
+ u32ClientId = CrHTablePut(&cr_server.clientTable, (void *)(uintptr_t)1);
+ if (u32ClientId == CRHTABLE_HANDLE_INVALID)
+ {
+ WARN(("CrHTablePut failed"));
+ return VERR_NO_MEMORY;
+ }
+ }
+
+ rc = crVBoxServerAddClientObj(u32ClientId, &pClient);
+ if (RT_SUCCESS(rc))
+ {
+ rc = crVBoxServerClientObjSetVersion(pClient, uMajorVersion, uMinorVersion);
+ if (RT_SUCCESS(rc))
+ {
+ rc = crVBoxServerClientObjSetPID(pClient, uPid);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrHTablePutToSlot(&cr_server.clientTable, u32ClientId, pClient);
+ if (RT_SUCCESS(rc))
+ {
+ pConnect->Hdr.u32CmdClientId = u32ClientId;
+ return VINF_SUCCESS;
+ }
+ WARN(("CrHTablePutToSlot failed %d", rc));
+ }
+ else
+ WARN(("crVBoxServerClientObjSetPID failed %d", rc));
+ }
+ else
+ WARN(("crVBoxServerClientObjSetVersion failed %d", rc));
+
+ crVBoxServerRemoveClientObj(pClient);
+ }
+ else
+ WARN(("crVBoxServerAddClientObj failed %d", rc));
+
+ CrHTableRemove(&cr_server.clientTable, u32ClientId);
+
+ return rc;
+}
+
+static int crVBoxCrConnect(VBOXCMDVBVA_3DCTL_CONNECT RT_UNTRUSTED_VOLATILE_GUEST *pConnect)
+{
+ return crVBoxCrConnectEx(pConnect, CRHTABLE_HANDLE_INVALID);
+}
+
+/**
+ * @interface_method_impl{VBOXCRCMD_SVRINFO,pfnGuestCtl}
+ */
+static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t RT_UNTRUSTED_VOLATILE_GUEST *pbCmd, uint32_t cbCmd)
+{
+ /*
+ * Toplevel input validation.
+ */
+ ASSERT_GUEST_LOGREL_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_3DCTL), VERR_INVALID_PARAMETER);
+ {
+ VBOXCMDVBVA_3DCTL RT_UNTRUSTED_VOLATILE_GUEST *pCtl = (VBOXCMDVBVA_3DCTL RT_UNTRUSTED_VOLATILE_GUEST*)pbCmd;
+ const uint32_t uType = pCtl->u32Type;
+ RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
+
+ ASSERT_GUEST_LOGREL_RETURN( uType == VBOXCMDVBVA3DCTL_TYPE_CMD
+ || uType == VBOXCMDVBVA3DCTL_TYPE_CONNECT
+ || uType == VBOXCMDVBVA3DCTL_TYPE_DISCONNECT
+ , VERR_INVALID_PARAMETER);
+ RT_UNTRUSTED_VALIDATED_FENCE();
+
+ /*
+ * Call worker abd process the request.
+ */
+ switch (uType)
+ {
+ case VBOXCMDVBVA3DCTL_TYPE_CMD:
+ ASSERT_GUEST_LOGREL_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_3DCTL_CMD), VERR_INVALID_PARAMETER);
+ {
+ VBOXCMDVBVA_3DCTL_CMD RT_UNTRUSTED_VOLATILE_GUEST *p3DCmd
+ = (VBOXCMDVBVA_3DCTL_CMD RT_UNTRUSTED_VOLATILE_GUEST *)pbCmd;
+ return crVBoxCrCmdCmd(NULL, &p3DCmd->Cmd, cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_3DCTL_CMD, Cmd));
+ }
+
+ case VBOXCMDVBVA3DCTL_TYPE_CONNECT:
+ ASSERT_GUEST_LOGREL_RETURN(cbCmd == sizeof(VBOXCMDVBVA_3DCTL_CONNECT), VERR_INVALID_PARAMETER);
+ return crVBoxCrConnect((VBOXCMDVBVA_3DCTL_CONNECT RT_UNTRUSTED_VOLATILE_GUEST *)pCtl);
+
+ case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT:
+ ASSERT_GUEST_LOGREL_RETURN(cbCmd == sizeof(VBOXCMDVBVA_3DCTL), VERR_INVALID_PARAMETER);
+ {
+ uint32_t idClient = pCtl->u32CmdClientId;
+ RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
+ return crVBoxCrDisconnect(idClient);
+ }
+
+ default:
+ AssertFailedReturn(VERR_IPE_NOT_REACHED_DEFAULT_CASE);
+ }
+ }
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdResize(HVBOXCRCMDSVR hSvr, const struct VBVAINFOSCREEN *pScreen, const uint32_t *pTargetMap)
+{
+ CRASSERT(cr_server.fCrCmdEnabled);
+ return CrPMgrResize(pScreen, NULL, pTargetMap);
+}
+
+static const char* gszVBoxOGLSSMMagic = "***OpenGL state data***";
+
+static int crVBoxCrCmdSaveClients(PSSMHANDLE pSSM)
+{
+ int i;
+ int rc = SSMR3PutU32(pSSM, cr_server.numClients);
+ AssertRCReturn(rc, rc);
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ CRClient * pClient = cr_server.clients[i];
+ Assert(pClient);
+
+ rc = SSMR3PutU32(pSSM, pClient->conn->u32ClientID);
+ AssertRCReturn(rc, rc);
+ rc = SSMR3PutU32(pSSM, pClient->conn->vMajor);
+ AssertRCReturn(rc, rc);
+ rc = SSMR3PutU32(pSSM, pClient->conn->vMinor);
+ AssertRCReturn(rc, rc);
+ rc = SSMR3PutU64(pSSM, pClient->pid);
+ AssertRCReturn(rc, rc);
+ }
+
+ return VINF_SUCCESS;
+}
+
+static int crVBoxCrCmdLoadClients(PSSMHANDLE pSSM, uint32_t u32Version)
+{
+ uint32_t i;
+ uint32_t u32;
+ VBOXCMDVBVA_3DCTL_CONNECT Connect;
+ int rc = SSMR3GetU32(pSSM, &u32);
+ AssertLogRelRCReturn(rc, rc);
+
+ for (i = 0; i < u32; i++)
+ {
+ uint32_t u32ClientID;
+ Connect.Hdr.u32Type = VBOXCMDVBVA3DCTL_TYPE_CONNECT;
+ Connect.Hdr.u32CmdClientId = 0;
+
+ rc = SSMR3GetU32(pSSM, &u32ClientID);
+ AssertLogRelRCReturn(rc, rc);
+ rc = SSMR3GetU32(pSSM, &Connect.u32MajorVersion);
+ AssertLogRelRCReturn(rc, rc);
+ rc = SSMR3GetU32(pSSM, &Connect.u32MinorVersion);
+ AssertLogRelRCReturn(rc, rc);
+ rc = SSMR3GetU64(pSSM, &Connect.u64Pid);
+ AssertLogRelRCReturn(rc, rc);
+
+ rc = crVBoxCrConnectEx(&Connect, u32ClientID);
+ AssertLogRelRCReturn(rc, rc);
+ }
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM)
+{
+ int rc = VINF_SUCCESS;
+
+ Assert(cr_server.fCrCmdEnabled);
+
+ /* Start*/
+ rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
+ AssertRCReturn(rc, rc);
+
+ if (!cr_server.numClients)
+ {
+ rc = SSMR3PutU32(pSSM, 0);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
+ AssertRCReturn(rc, rc);
+
+ return VINF_SUCCESS;
+ }
+
+ rc = SSMR3PutU32(pSSM, 1);
+ AssertRCReturn(rc, rc);
+
+ /* Version */
+ rc = SSMR3PutU32(pSSM, (uint32_t) SHCROGL_SSM_VERSION);
+ AssertRCReturn(rc, rc);
+
+ rc = crVBoxCrCmdSaveClients(pSSM);
+ AssertRCReturn(rc, rc);
+
+ /* The state itself */
+ rc = crVBoxServerSaveStatePerform(pSSM);
+ AssertRCReturn(rc, rc);
+
+ /* Save svc buffers info */
+ {
+ rc = SSMR3PutU32(pSSM, 0);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutU32(pSSM, 0);
+ AssertRCReturn(rc, rc);
+ }
+
+ /* End */
+ rc = SSMR3PutStrZ(pSSM, gszVBoxOGLSSMMagic);
+ AssertRCReturn(rc, rc);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version)
+{
+ int rc = VINF_SUCCESS;
+
+ char szBuf[2000];
+ uint32_t ui32;
+
+ Assert(cr_server.fCrCmdEnabled);
+
+ /* Start of data */
+ rc = SSMR3GetStrZEx(pSSM, szBuf, sizeof(szBuf), NULL);
+ AssertLogRelRCReturn(rc, rc);
+ AssertLogRelMsgReturn(!strcmp(gszVBoxOGLSSMMagic, szBuf), ("Unexpected data1: '%s'\n", szBuf), VERR_SSM_UNEXPECTED_DATA);
+
+ /* num clients */
+ rc = SSMR3GetU32(pSSM, &ui32);
+ AssertLogRelRCReturn(rc, rc);
+
+ if (!ui32)
+ {
+ /* no clients, dummy stub */
+ rc = SSMR3GetStrZEx(pSSM, szBuf, sizeof(szBuf), NULL);
+ AssertLogRelRCReturn(rc, rc);
+ AssertLogRelMsgReturn(!strcmp(gszVBoxOGLSSMMagic, szBuf), ("Unexpected data2: '%s'\n", szBuf), VERR_SSM_UNEXPECTED_DATA);
+
+ return VINF_SUCCESS;
+ }
+ AssertLogRelMsgReturn(ui32 == 1, ("Invalid client count: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
+
+ /* Version */
+ rc = SSMR3GetU32(pSSM, &ui32);
+ AssertLogRelRCReturn(rc, rc);
+ AssertLogRelMsgReturn(ui32 >= SHCROGL_SSM_VERSION_CRCMD, ("Unexpected version: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
+
+ rc = crVBoxCrCmdLoadClients(pSSM, u32Version);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* The state itself */
+ rc = crVBoxServerLoadStatePerform(pSSM, ui32);
+ AssertLogRelRCReturn(rc, rc);
+
+ /* Save svc buffers info */
+ {
+ rc = SSMR3GetU32(pSSM, &ui32);
+ AssertLogRelRCReturn(rc, rc);
+ AssertLogRelMsgReturn(ui32 == 0, ("Unexpected data3: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
+
+ rc = SSMR3GetU32(pSSM, &ui32);
+ AssertLogRelRCReturn(rc, rc);
+ AssertLogRelMsgReturn(ui32 == 0, ("Unexpected data4: %#x\n", ui32), VERR_SSM_UNEXPECTED_DATA);
+ }
+
+ /* End */
+ rc = SSMR3GetStrZEx(pSSM, szBuf, sizeof(szBuf), NULL);
+ AssertLogRelRCReturn(rc, rc);
+ AssertLogRelMsgReturn(!strcmp(gszVBoxOGLSSMMagic, szBuf), ("Unexpected data5: '%s'\n", szBuf), VERR_SSM_UNEXPECTED_DATA);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{VBOXCRCMD_SVRINFO,pfnCmd}
+ */
+static DECLCALLBACK(int8_t) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr,
+ const VBOXCMDVBVA_HDR RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd)
+{
+ uint8_t bOpcode = pCmd->u8OpCode;
+ RT_UNTRUSTED_NONVOLATILE_COPY_FENCE();
+ ASSERT_GUEST_LOGREL_MSG_RETURN( bOpcode == VBOXCMDVBVA_OPTYPE_CRCMD
+ || bOpcode == VBOXCMDVBVA_OPTYPE_FLIP
+ || bOpcode == VBOXCMDVBVA_OPTYPE_BLT
+ || bOpcode == VBOXCMDVBVA_OPTYPE_CLRFILL,
+ ("%#x\n", bOpcode), -1);
+ RT_UNTRUSTED_VALIDATED_FENCE();
+
+ switch (bOpcode)
+ {
+ case VBOXCMDVBVA_OPTYPE_CRCMD:
+ ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_CRCMD), ("cbCmd=%u\n", cbCmd), -1);
+ {
+ VBOXCMDVBVA_CRCMD const RT_UNTRUSTED_VOLATILE_GUEST *pCrCmdDr
+ = (VBOXCMDVBVA_CRCMD const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd;
+ VBOXCMDVBVA_CRCMD_CMD const RT_UNTRUSTED_VOLATILE_GUEST *pCrCmd = &pCrCmdDr->Cmd;
+ int rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd, cbCmd - RT_UOFFSETOF(VBOXCMDVBVA_CRCMD, Cmd));
+ ASSERT_GUEST_LOGREL_RC_RETURN(rc, -1);
+ return 0;
+ }
+
+ case VBOXCMDVBVA_OPTYPE_FLIP:
+ ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= VBOXCMDVBVA_SIZEOF_FLIPSTRUCT_MIN, ("cbCmd=%u\n", cbCmd), -1);
+ {
+ VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *pFlip
+ = (VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd;
+ return crVBoxServerCrCmdFlipProcess(pFlip, cbCmd);
+ }
+
+ case VBOXCMDVBVA_OPTYPE_BLT:
+ ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_BLT_HDR), ("cbCmd=%u\n", cbCmd), -1);
+ return crVBoxServerCrCmdBltProcess((VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd, cbCmd);
+
+ case VBOXCMDVBVA_OPTYPE_CLRFILL:
+ ASSERT_GUEST_LOGREL_MSG_RETURN(cbCmd >= sizeof(VBOXCMDVBVA_CLRFILL_HDR), ("cbCmd=%u\n", cbCmd), -1);
+ return crVBoxServerCrCmdClrFillProcess((VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *)pCmd, cbCmd);
+
+ default:
+ AssertFailedReturn(-1);
+ }
+ /* not reached */
+}
+
+/* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place.
+ *
+ * For now we need the notion of CrHgdmi commands in the crserver_lib to be able to complete it asynchronously once it is really processed.
+ * This help avoiding the "blocked-client" issues. The client is blocked if another client is doing begin-end stuff.
+ * For now we eliminated polling that could occur on block, which caused a higher-priority thread (in guest) polling for the blocked command complition
+ * to block the lower-priority thread trying to complete the blocking command.
+ * And removed extra memcpy done on blocked command arrival.
+ *
+ * In the future we will extend CrHgsmi functionality to maintain texture data directly in CrHgsmi allocation to avoid extra memcpy-ing with PBO,
+ * implement command completion and stuff necessary for GPU scheduling to work properly for WDDM Windows guests, etc.
+ *
+ * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command!
+ * */
+
+
+int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd)
+{
+
+ int32_t rc;
+ uint32_t cBuffers = pCmd->cBuffers;
+ uint32_t cParams;
+ uint32_t cbHdr;
+ CRVBOXHGSMIHDR *pHdr;
+ uint32_t u32Function;
+ uint32_t u32ClientID;
+ CRClient *pClient;
+
+ if (!g_pvVRamBase)
+ {
+ WARN(("g_pvVRamBase is not initialized"));
+
+ crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE);
+ return VINF_SUCCESS;
+ }
+
+ if (!cBuffers)
+ {
+ WARN(("zero buffers passed in!"));
+
+ crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
+ return VINF_SUCCESS;
+ }
+
+ cParams = cBuffers-1;
+
+ cbHdr = pCmd->aBuffers[0].cbBuffer;
+ pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR);
+ if (!pHdr)
+ {
+ WARN(("invalid header buffer!"));
+
+ crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
+ return VINF_SUCCESS;
+ }
+
+ if (cbHdr < sizeof (*pHdr))
+ {
+ WARN(("invalid header buffer size!"));
+
+ crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER);
+ return VINF_SUCCESS;
+ }
+
+ u32Function = pHdr->u32Function;
+ u32ClientID = pHdr->u32ClientID;
+
+ switch (u32Function)
+ {
+ case SHCRGL_GUEST_FN_WRITE:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n"));
+
+ /** @todo Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr;
+ VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid write cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ crWarning("invalid buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
+ crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_INJECT:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n"));
+
+ /** @todo Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr;
+ /* Fetch parameters. */
+ uint32_t u32InjectClientID = pFnCmd->u32ClientID;
+ VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid inject cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ crWarning("invalid buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32InjectClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true);
+ crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return VINF_SUCCESS;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_READ\n"));
+
+ /** @todo Verify */
+ if (cParams == 1)
+ {
+ CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr;
+ VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid read cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+
+ if (!pBuffer)
+ {
+ crWarning("invalid buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ break;
+ }
+
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer);
+
+ /* Return the required buffer size always */
+ pFnCmd->cbBuffer = cbBuffer;
+
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ /* the read command is never pended, complete it right away */
+ pHdr->result = rc;
+
+ crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
+ return VINF_SUCCESS;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_WRITE_READ:
+ {
+ Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n"));
+
+ /** @todo Verify */
+ if (cParams == 2)
+ {
+ CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr;
+ VBOXVDMACMD_CHROMIUM_BUFFER *pBuf = &pCmd->aBuffers[1];
+ VBOXVDMACMD_CHROMIUM_BUFFER *pWbBuf = &pCmd->aBuffers[2];
+
+ /* Fetch parameters. */
+ uint32_t cbBuffer = pBuf->cbBuffer;
+ uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t);
+
+ uint32_t cbWriteback = pWbBuf->cbBuffer;
+ char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char);
+
+ if (cbHdr < sizeof (*pFnCmd))
+ {
+ crWarning("invalid write_read cmd buffer size!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+
+ CRASSERT(cbBuffer);
+ if (!pBuffer)
+ {
+ crWarning("invalid write buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ CRASSERT(cbWriteback);
+ if (!pWriteback)
+ {
+ crWarning("invalid writeback buffer data received from guest!");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+ rc = crVBoxServerClientGet(u32ClientID, &pClient);
+ if (RT_FAILURE(rc))
+ {
+ pHdr->result = rc;
+ crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
+ return rc;
+ }
+
+ /* This should never fire unless we start to multithread */
+ CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+
+ pClient->conn->pBuffer = pBuffer;
+ pClient->conn->cbBuffer = cbBuffer;
+ CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true);
+ crVBoxServerInternalClientWriteRead(pClient);
+ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData);
+ return VINF_SUCCESS;
+ }
+
+ crWarning("invalid number of args");
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_VERSION:
+ {
+ WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_VERSION: invalid function"));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ case SHCRGL_GUEST_FN_SET_PID:
+ {
+ WARN(("crVBoxServerCrHgsmiCmd, SHCRGL_GUEST_FN_SET_PID: invalid function"));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ default:
+ {
+ WARN(("crVBoxServerCrHgsmiCmd: invalid functionm %d", u32Function));
+ rc = VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ }
+
+ /* we can be on fail only here */
+ CRASSERT(RT_FAILURE(rc));
+ pHdr->result = rc;
+
+ crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS);
+ return rc;
+
+}
+
+
+static DECLCALLBACK(bool) crVBoxServerHasDataForScreen(uint32_t u32ScreenID)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledForScreen(u32ScreenID);
+ if (hFb)
+ return CrFbHas3DData(hFb);
+
+ return false;
+}
+
+
+static DECLCALLBACK(bool) crVBoxServerHasData(void)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled();
+ for (;
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ if (CrFbHas3DData(hFb))
+ return true;
+ }
+
+ return false;
+}
+
+int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl)
+{
+ int rc = VINF_SUCCESS;
+
+ switch (pCtl->enmType)
+ {
+ case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP:
+ {
+ PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl;
+ g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase;
+ g_cbVRam = pSetup->cbVRam;
+
+ g_pLed = pSetup->pLed;
+
+ cr_server.ClientInfo = pSetup->CrClientInfo;
+
+ pSetup->CrCmdServerInfo.hSvr = NULL;
+ pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable;
+ pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable;
+ pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd;
+ pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl;
+ pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl;
+ pSetup->CrCmdServerInfo.pfnResize = crVBoxCrCmdResize;
+ pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState;
+ pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState;
+ rc = VINF_SUCCESS;
+ break;
+ }
+ case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_BEGIN:
+ case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END:
+ rc = VINF_SUCCESS;
+ break;
+ case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB:
+ {
+ PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl;
+ g_hCrHgsmiCompletion = pSetup->hCompletion;
+ g_pfnCrHgsmiCompletion = pSetup->pfnCompletion;
+
+ pSetup->MainInterface.pfnHasData = crVBoxServerHasData;
+ pSetup->MainInterface.pfnHasDataForScreen = crVBoxServerHasDataForScreen;
+
+ rc = VINF_SUCCESS;
+ break;
+ }
+ default:
+ AssertMsgFailed(("invalid param %d", pCtl->enmType));
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ /* NOTE: Control commands can NEVER be pended here, this is why its a task of a caller (Main)
+ * to complete them accordingly.
+ * This approach allows using host->host and host->guest commands in the same way here
+ * making the command completion to be the responsibility of the command originator.
+ * E.g. ctl commands can be both Hgcm Host synchronous commands that do not require completion at all,
+ * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */
+ return rc;
+}
+
+static int crVBoxServerCrCmdDisablePostProcess(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
+{
+ int rc = VINF_SUCCESS;
+ uint8_t* pCtl;
+ uint32_t cbCtl;
+ HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd = pData->hRHCmd;
+ PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd = pData->pfnRHCmd;
+
+ Assert(!cr_server.fCrCmdEnabled);
+
+ if (cr_server.numClients)
+ {
+ WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients));
+ return VERR_INVALID_STATE;
+ }
+
+ for (pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc); pCtl; pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc))
+ {
+ rc = crVBoxCrCmdHostCtl(NULL, pCtl, cbCtl);
+ }
+
+ memset(&cr_server.DisableData, 0, sizeof (cr_server.DisableData));
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerHgcmEnable(VBOXCRCMDCTL_HGCMENABLE_DATA *pData)
+{
+ int rc = crVBoxServerCrCmdDisablePostProcess(pData);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxServerCrCmdDisablePostProcess failed %d", rc));
+ return rc;
+ }
+
+ crVBoxServerDefaultContextSet();
+
+ return VINF_SUCCESS;
+}
+
+int32_t crVBoxServerHgcmDisable(VBOXCRCMDCTL_HGCMDISABLE_DATA *pData)
+{
+ Assert(!cr_server.fCrCmdEnabled);
+
+ Assert(!cr_server.numClients);
+
+ crVBoxServerRemoveAllClients();
+
+ CRASSERT(!cr_server.numClients);
+
+ crVBoxServerDefaultContextClear();
+
+ cr_server.DisableData = *pData;
+
+ return VINF_SUCCESS;
+}
+
+#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c
new file mode 100644
index 00000000..b9b53008
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c
@@ -0,0 +1,2016 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+#include "cr_pixeldata.h"
+#ifdef VBOX_WITH_CRDUMPER
+# include "cr_dump.h"
+#endif
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchSelectBuffer( GLsizei size, GLuint *buffer )
+{
+ (void) size;
+ (void) buffer;
+ crError( "Unsupported network glSelectBuffer call." );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetChromiumParametervCR(GLenum target, GLuint index, GLenum type, GLsizei count, GLvoid *values)
+{
+ GLubyte local_storage[4096];
+ GLint bytes = 0;
+ GLint cbType = 1; /* One byte by default. */
+
+ memset(local_storage, 0, sizeof(local_storage));
+
+ switch (type) {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE:
+ cbType = sizeof(GLbyte);
+ break;
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT:
+ cbType = sizeof(GLshort);
+ break;
+ case GL_INT:
+ case GL_UNSIGNED_INT:
+ cbType = sizeof(GLint);
+ break;
+ case GL_FLOAT:
+ cbType = sizeof(GLfloat);
+ break;
+ case GL_DOUBLE:
+ cbType = sizeof(GLdouble);
+ break;
+ default:
+ crError("Bad type in crServerDispatchGetChromiumParametervCR");
+ }
+
+ if (count < 0) /* 'GLsizei' is usually an 'int'. */
+ count = 0;
+ else if ((size_t)count > sizeof(local_storage) / cbType)
+ count = sizeof(local_storage) / cbType;
+
+ bytes = count * cbType;
+
+ CRASSERT(bytes >= 0);
+ CRASSERT(bytes < 4096);
+
+ switch (target)
+ {
+ case GL_DBG_CHECK_BREAK_CR:
+ {
+ if (bytes > 0)
+ {
+ GLubyte *pbRc = local_storage;
+ GLuint *puRc = (GLuint *)(bytes >=4 ? local_storage : NULL);
+ int rc;
+ memset(local_storage, 0, bytes);
+ if (cr_server.RcToGuestOnce)
+ {
+ rc = cr_server.RcToGuestOnce;
+ cr_server.RcToGuestOnce = 0;
+ }
+ else
+ {
+ rc = cr_server.RcToGuest;
+ }
+ if (puRc)
+ *puRc = rc;
+ else
+ *pbRc = !!rc;
+ }
+ else
+ {
+ crWarning("zero bytes for GL_DBG_CHECK_BREAK_CR");
+ }
+ break;
+ }
+ case GL_HH_SET_DEFAULT_SHARED_CTX:
+ WARN(("Recieved GL_HH_SET_DEFAULT_SHARED_CTX from guest, ignoring"));
+ break;
+ case GL_HH_SET_CLIENT_CALLOUT:
+ WARN(("Recieved GL_HH_SET_CLIENT_CALLOUT from guest, ignoring"));
+ break;
+ default:
+ cr_server.head_spu->dispatch_table.GetChromiumParametervCR( target, index, type, count, local_storage );
+ break;
+ }
+
+ crServerReturnValue( local_storage, bytes );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target, GLenum type, GLsizei count, const GLvoid *values)
+{
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ static int gather_connect_count = 0;
+
+ switch (target) {
+ case GL_SHARE_LISTS_CR:
+ {
+ CRContextInfo *pCtx[2];
+ GLint *ai32Values;
+ int i;
+ if (count != 2)
+ {
+ WARN(("GL_SHARE_LISTS_CR invalid cound %d", count));
+ return;
+ }
+
+ if (type != GL_UNSIGNED_INT && type != GL_INT)
+ {
+ WARN(("GL_SHARE_LISTS_CR invalid type %d", type));
+ return;
+ }
+
+ ai32Values = (GLint*)values;
+
+ for (i = 0; i < 2; ++i)
+ {
+ const int32_t val = ai32Values[i];
+
+ if (val == 0)
+ {
+ WARN(("GL_SHARE_LISTS_CR invalid value[%d] %d", i, val));
+ return;
+ }
+
+ pCtx[i] = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, val);
+ if (!pCtx[i])
+ {
+ WARN(("GL_SHARE_LISTS_CR invalid pCtx1 for value[%d] %d", i, val));
+ return;
+ }
+
+ if (!pCtx[i]->pContext)
+ {
+ WARN(("GL_SHARE_LISTS_CR invalid pCtx1 pContext for value[%d] %d", i, val));
+ return;
+ }
+ }
+
+ crStateShareLists(pCtx[0]->pContext, pCtx[1]->pContext);
+
+ break;
+ }
+
+ case GL_SET_MAX_VIEWPORT_CR:
+ {
+ GLint *maxDims = (GLint *)values;
+ cr_server.limits.maxViewportDims[0] = maxDims[0];
+ cr_server.limits.maxViewportDims[1] = maxDims[1];
+ }
+ break;
+
+ case GL_TILE_INFO_CR:
+ /* message from tilesort SPU to set new tile bounds */
+ {
+ GLint numTiles, muralWidth, muralHeight, server, tiles;
+ GLint *tileBounds;
+ CRASSERT(count >= 4);
+ CRASSERT((count - 4) % 4 == 0); /* must be multiple of four */
+ CRASSERT(type == GL_INT);
+ numTiles = (count - 4) / 4;
+ tileBounds = (GLint *) values;
+ server = tileBounds[0];
+ muralWidth = tileBounds[1];
+ muralHeight = tileBounds[2];
+ tiles = tileBounds[3];
+ CRASSERT(tiles == numTiles);
+ tileBounds += 4; /* skip over header values */
+ /*crServerNewMuralTiling(mural, muralWidth, muralHeight, numTiles, tileBounds);
+ mural->viewportValidated = GL_FALSE;*/
+ }
+ break;
+
+ case GL_GATHER_DRAWPIXELS_CR:
+ if (cr_server.only_swap_once && cr_server.curClient != cr_server.clients[0])
+ break;
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values );
+ break;
+
+ case GL_GATHER_CONNECT_CR:
+ /*
+ * We want the last connect to go through,
+ * otherwise we might deadlock in CheckWindowSize()
+ * in the readback spu
+ */
+ gather_connect_count++;
+ if (cr_server.only_swap_once && (gather_connect_count != cr_server.numClients))
+ {
+ break;
+ }
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values );
+ gather_connect_count = 0;
+ break;
+
+ case GL_SERVER_VIEW_MATRIX_CR:
+ /* Set this server's view matrix which will get premultiplied onto the
+ * modelview matrix. For non-planar tilesort and stereo.
+ */
+ CRASSERT(count == 18);
+ CRASSERT(type == GL_FLOAT);
+ /* values[0] is the server index. Ignored here but used in tilesort SPU */
+ /* values[1] is the left/right eye index (0 or 1) */
+ {
+ const GLfloat *v = (const GLfloat *) values;
+ const int eye = v[1] == 0.0 ? 0 : 1;
+ crMatrixInitFromFloats(&cr_server.viewMatrix[eye], v + 2);
+
+ crDebug("Got GL_SERVER_VIEW_MATRIX_CR:\n"
+ " %f %f %f %f\n"
+ " %f %f %f %f\n"
+ " %f %f %f %f\n"
+ " %f %f %f %f",
+ cr_server.viewMatrix[eye].m00,
+ cr_server.viewMatrix[eye].m10,
+ cr_server.viewMatrix[eye].m20,
+ cr_server.viewMatrix[eye].m30,
+ cr_server.viewMatrix[eye].m01,
+ cr_server.viewMatrix[eye].m11,
+ cr_server.viewMatrix[eye].m21,
+ cr_server.viewMatrix[eye].m31,
+ cr_server.viewMatrix[eye].m02,
+ cr_server.viewMatrix[eye].m12,
+ cr_server.viewMatrix[eye].m22,
+ cr_server.viewMatrix[eye].m32,
+ cr_server.viewMatrix[eye].m03,
+ cr_server.viewMatrix[eye].m13,
+ cr_server.viewMatrix[eye].m23,
+ cr_server.viewMatrix[eye].m33);
+ }
+ cr_server.viewOverride = GL_TRUE;
+ break;
+
+ case GL_SERVER_PROJECTION_MATRIX_CR:
+ /* Set this server's projection matrix which will get replace the user's
+ * projection matrix. For non-planar tilesort and stereo.
+ */
+ CRASSERT(count == 18);
+ CRASSERT(type == GL_FLOAT);
+ /* values[0] is the server index. Ignored here but used in tilesort SPU */
+ /* values[1] is the left/right eye index (0 or 1) */
+ {
+ const GLfloat *v = (const GLfloat *) values;
+ const int eye = v[1] == 0.0 ? 0 : 1;
+ crMatrixInitFromFloats(&cr_server.projectionMatrix[eye], v + 2);
+
+ crDebug("Got GL_SERVER_PROJECTION_MATRIX_CR:\n"
+ " %f %f %f %f\n"
+ " %f %f %f %f\n"
+ " %f %f %f %f\n"
+ " %f %f %f %f",
+ cr_server.projectionMatrix[eye].m00,
+ cr_server.projectionMatrix[eye].m10,
+ cr_server.projectionMatrix[eye].m20,
+ cr_server.projectionMatrix[eye].m30,
+ cr_server.projectionMatrix[eye].m01,
+ cr_server.projectionMatrix[eye].m11,
+ cr_server.projectionMatrix[eye].m21,
+ cr_server.projectionMatrix[eye].m31,
+ cr_server.projectionMatrix[eye].m02,
+ cr_server.projectionMatrix[eye].m12,
+ cr_server.projectionMatrix[eye].m22,
+ cr_server.projectionMatrix[eye].m32,
+ cr_server.projectionMatrix[eye].m03,
+ cr_server.projectionMatrix[eye].m13,
+ cr_server.projectionMatrix[eye].m23,
+ cr_server.projectionMatrix[eye].m33);
+
+ if (cr_server.projectionMatrix[eye].m33 == 0.0f) {
+ float x = cr_server.projectionMatrix[eye].m00;
+ float y = cr_server.projectionMatrix[eye].m11;
+ float a = cr_server.projectionMatrix[eye].m20;
+ float b = cr_server.projectionMatrix[eye].m21;
+ float c = cr_server.projectionMatrix[eye].m22;
+ float d = cr_server.projectionMatrix[eye].m32;
+ float znear = -d / (1.0f - c);
+ float zfar = (c - 1.0f) * znear / (c + 1.0f);
+ float left = znear * (a - 1.0f) / x;
+ float right = 2.0f * znear / x + left;
+ float bottom = znear * (b - 1.0f) / y;
+ float top = 2.0f * znear / y + bottom;
+ crDebug("Frustum: left, right, bottom, top, near, far: %f, %f, %f, %f, %f, %f", left, right, bottom, top, znear, zfar);
+ }
+ else {
+ /** @todo Add debug output for orthographic projection*/
+ }
+
+ }
+ cr_server.projectionOverride = GL_TRUE;
+ break;
+
+ case GL_HH_SET_TMPCTX_MAKE_CURRENT:
+ /*we should not receive it from the guest! */
+ break;
+
+ case GL_HH_SET_CLIENT_CALLOUT:
+ WARN(("Recieved GL_HH_SET_CLIENT_CALLOUT from guest, ignoring"));
+ break;
+
+ default:
+ /* Pass the parameter info to the head SPU */
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values );
+ break;
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParameteriCR(GLenum target, GLint value)
+{
+ switch (target) {
+ case GL_SHARE_CONTEXT_RESOURCES_CR:
+ crStateShareContext(value);
+ break;
+ case GL_RCUSAGE_TEXTURE_SET_CR:
+ crStateSetTextureUsed(value, GL_TRUE);
+ break;
+ case GL_RCUSAGE_TEXTURE_CLEAR_CR:
+ crStateSetTextureUsed(value, GL_FALSE);
+ break;
+ case GL_PIN_TEXTURE_SET_CR:
+ crStatePinTexture(value, GL_TRUE);
+ break;
+ case GL_PIN_TEXTURE_CLEAR_CR:
+ crStatePinTexture(value, GL_FALSE);
+ break;
+ case GL_SHARED_DISPLAY_LISTS_CR:
+ cr_server.sharedDisplayLists = value;
+ break;
+ case GL_SHARED_TEXTURE_OBJECTS_CR:
+ cr_server.sharedTextureObjects = value;
+ break;
+ case GL_SHARED_PROGRAMS_CR:
+ cr_server.sharedPrograms = value;
+ break;
+ case GL_SERVER_CURRENT_EYE_CR:
+ cr_server.currentEye = value ? 1 : 0;
+ break;
+ case GL_HOST_WND_CREATED_HIDDEN_CR:
+ cr_server.bWindowsInitiallyHidden = value ? 1 : 0;
+ break;
+ case GL_HH_SET_DEFAULT_SHARED_CTX:
+ WARN(("Recieved GL_HH_SET_DEFAULT_SHARED_CTX from guest, ignoring"));
+ break;
+ case GL_HH_RENDERTHREAD_INFORM:
+ WARN(("Recieved GL_HH_RENDERTHREAD_INFORM from guest, ignoring"));
+ break;
+ default:
+ /* Pass the parameter info to the head SPU */
+ cr_server.head_spu->dispatch_table.ChromiumParameteriCR( target, value );
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParameterfCR(GLenum target, GLfloat value)
+{
+ switch (target) {
+ case GL_SHARED_DISPLAY_LISTS_CR:
+ cr_server.sharedDisplayLists = (int) value;
+ break;
+ case GL_SHARED_TEXTURE_OBJECTS_CR:
+ cr_server.sharedTextureObjects = (int) value;
+ break;
+ case GL_SHARED_PROGRAMS_CR:
+ cr_server.sharedPrograms = (int) value;
+ break;
+ default:
+ /* Pass the parameter info to the head SPU */
+ cr_server.head_spu->dispatch_table.ChromiumParameterfCR( target, value );
+ }
+}
+
+GLint crServerGenerateID(GLint *pCounter)
+{
+ return (*pCounter)++;
+}
+
+/*#define CR_DUMP_BLITS*/
+
+#ifdef CR_DUMP_BLITS
+static int blitnum=0;
+static int copynum=0;
+#endif
+
+# ifdef DEBUG_misha
+//# define CR_CHECK_BLITS
+# include <iprt/assert.h>
+# undef CRASSERT /* iprt assert's int3 are inlined that is why are more convenient to use since they can be easily disabled individually */
+# define CRASSERT Assert
+# endif
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ /** @todo pbo/fbo disabled for now as it's slower, check on other gpus*/
+ static int siHavePBO = 0;
+ static int siHaveFBO = 0;
+
+ if ((target!=GL_TEXTURE_2D) || (height>=0))
+ {
+ cr_server.head_spu->dispatch_table.CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+
+#ifdef CR_DUMP_BLITS
+ {
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+ void *img;
+ GLint w, h;
+ char fname[200];
+
+ copynum++;
+
+ gl->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
+ gl->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
+
+ img = crAlloc(w*h*4);
+ CRASSERT(img);
+
+ gl->GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, img);
+ sprintf(fname, "copy_blit%i_copy_%i.tga", blitnum, copynum);
+ crDumpNamedTGA(fname, w, h, img);
+ crFree(img);
+ }
+#endif
+ }
+ else /* negative height, means we have to Yinvert the source pixels while copying */
+ {
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+
+ if (siHavePBO<0)
+ {
+ const char *ext = (const char*)gl->GetString(GL_EXTENSIONS);
+ siHavePBO = crStrstr(ext, "GL_ARB_pixel_buffer_object") ? 1:0;
+ }
+
+ if (siHaveFBO<0)
+ {
+ const char *ext = (const char*)gl->GetString(GL_EXTENSIONS);
+ siHaveFBO = crStrstr(ext, "GL_EXT_framebuffer_object") ? 1:0;
+ }
+
+ if (siHavePBO==0 && siHaveFBO==0)
+ {
+#if 1
+ GLint dRow, sRow;
+ for (dRow=yoffset, sRow=y-height-1; dRow<yoffset-height; dRow++, sRow--)
+ {
+ gl->CopyTexSubImage2D(target, level, xoffset, dRow, x, sRow, width, 1);
+ }
+#else
+ {
+ GLint w, h, i;
+ char *img1, *img2, *sPtr, *dPtr;
+ CRContext *ctx = crStateGetCurrent();
+
+ w = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].width;
+ h = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].height;
+
+ img1 = crAlloc(4*w*h);
+ img2 = crAlloc(4*width*(-height));
+ CRASSERT(img1 && img2);
+
+ gl->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, -height);
+ gl->GetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, img1);
+
+ sPtr=img1+4*xoffset+4*w*yoffset;
+ dPtr=img2+4*width*(-height-1);
+
+ for (i=0; i<-height; ++i)
+ {
+ crMemcpy(dPtr, sPtr, 4*width);
+ sPtr += 4*w;
+ dPtr -= 4*width;
+ }
+
+ gl->TexSubImage2D(target, level, xoffset, yoffset, width, -height, GL_RGBA, GL_UNSIGNED_BYTE, img2);
+
+ crFree(img1);
+ crFree(img2);
+ }
+#endif
+ }
+ else if (siHaveFBO==1) /** @todo more states to set and restore here*/
+ {
+ GLuint tID, fboID;
+ GLenum status;
+ CRContext *ctx = crStateGetCurrent();
+
+ gl->GenTextures(1, &tID);
+ gl->BindTexture(target, tID);
+ gl->CopyTexImage2D(target, level, GL_RGBA, x, y, width, -height, 0);
+ gl->GenFramebuffersEXT(1, &fboID);
+ gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
+ gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target,
+ ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid, level);
+ status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ crWarning("Framebuffer status 0x%x", status);
+ }
+
+ gl->Enable(target);
+ gl->PushAttrib(GL_VIEWPORT_BIT);
+ gl->Viewport(xoffset, yoffset, width, -height);
+ gl->MatrixMode(GL_PROJECTION);
+ gl->PushMatrix();
+ gl->LoadIdentity();
+ gl->MatrixMode(GL_MODELVIEW);
+ gl->PushMatrix();
+ gl->LoadIdentity();
+
+ gl->Disable(GL_DEPTH_TEST);
+ gl->Disable(GL_CULL_FACE);
+ gl->Disable(GL_STENCIL_TEST);
+ gl->Disable(GL_SCISSOR_TEST);
+
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ gl->Begin(GL_QUADS);
+ gl->TexCoord2f(0.0f, 1.0f);
+ gl->Vertex2f(-1.0, -1.0);
+
+ gl->TexCoord2f(0.0f, 0.0f);
+ gl->Vertex2f(-1.0f, 1.0f);
+
+ gl->TexCoord2f(1.0f, 0.0f);
+ gl->Vertex2f(1.0f, 1.0f);
+
+ gl->TexCoord2f(1.0f, 1.0f);
+ gl->Vertex2f(1.0f, -1.0f);
+ gl->End();
+
+ gl->PopMatrix();
+ gl->MatrixMode(GL_PROJECTION);
+ gl->PopMatrix();
+ gl->PopAttrib();
+
+ gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, 0, level);
+ gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0);
+ gl->BindTexture(target, ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid);
+ gl->DeleteFramebuffersEXT(1, &fboID);
+ gl->DeleteTextures(1, &tID);
+
+#if 0
+ {
+ GLint dRow, sRow, w, h;
+ void *img1, *img2;
+
+ w = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].width;
+ h = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].height;
+
+ img1 = crAlloc(4*w*h);
+ img2 = crAlloc(4*w*h);
+ CRASSERT(img1 && img2);
+
+ gl->GetTexImage(target, level, GL_BGRA, GL_UNSIGNED_BYTE, img1);
+
+
+ for (dRow=yoffset, sRow=y-height-1; dRow<yoffset-height; dRow++, sRow--)
+ {
+ gl->CopyTexSubImage2D(target, level, xoffset, dRow, x, sRow, width, 1);
+ }
+
+ gl->GetTexImage(target, level, GL_BGRA, GL_UNSIGNED_BYTE, img2);
+
+ if (crMemcmp(img1, img2, 4*w*h))
+ {
+ crDebug("MISMATCH! (%x, %i, ->%i,%i <-%i, %i [%ix%i])", target, level, xoffset, yoffset, x, y, width, height);
+ crDumpTGA(w, h, img1);
+ crDumpTGA(w, h, img2);
+ DebugBreak();
+ }
+ crFree(img1);
+ crFree(img2);
+ }
+#endif
+ }
+ else
+ {
+ GLint dRow;
+ GLuint pboId, sRow;
+ CRContext *ctx = crStateGetCurrent();
+
+ gl->GenBuffersARB(1, &pboId);
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId);
+ gl->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, -width*height*4, 0, GL_STATIC_COPY_ARB);
+
+#if 1
+ gl->ReadPixels(x, y, width, -height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
+
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboId);
+ for (dRow=yoffset, sRow=-height-1; dRow<yoffset-height; dRow++, sRow--)
+ {
+ gl->TexSubImage2D(target, level, xoffset, dRow, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)((uintptr_t)sRow*width*4));
+ }
+#else /*few times slower again*/
+ for (dRow=0, sRow=y-height-1; dRow<-height; dRow++, sRow--)
+ {
+ gl->ReadPixels(x, sRow, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)((uintptr_t)dRow*width*4));
+ }
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
+
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboId);
+ gl->TexSubImage2D(target, level, xoffset, yoffset, width, -height, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+#endif
+
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid);
+ gl->DeleteBuffersARB(1, &pboId);
+ }
+ }
+}
+
+#ifdef CR_CHECK_BLITS
+void crDbgFree(void *pvData)
+{
+ crFree(pvData);
+}
+
+void crDbgGetTexImage2D(GLint texTarget, GLint texName, GLvoid **ppvImage, GLint *pw, GLint *ph)
+{
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+ GLint ppb, pub, dstw, dsth, otex;
+ GLint pa, pr, psp, psr, ua, ur, usp, usr;
+ GLvoid *pvImage;
+ GLint rfb, dfb, rb, db;
+
+ gl->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb);
+ gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb);
+ gl->GetIntegerv(GL_READ_BUFFER, &rb);
+ gl->GetIntegerv(GL_DRAW_BUFFER, &db);
+
+ gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER_BINDING_EXT, 0);
+ gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_BINDING_EXT, 0);
+ gl->ReadBuffer(GL_BACK);
+ gl->DrawBuffer(GL_BACK);
+
+ gl->GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &ppb);
+ gl->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &pub);
+ gl->GetIntegerv(GL_TEXTURE_BINDING_2D, &otex);
+
+ gl->GetIntegerv(GL_PACK_ROW_LENGTH, &pr);
+ gl->GetIntegerv(GL_PACK_ALIGNMENT, &pa);
+ gl->GetIntegerv(GL_PACK_SKIP_PIXELS, &psp);
+ gl->GetIntegerv(GL_PACK_SKIP_ROWS, &psr);
+
+ gl->GetIntegerv(GL_UNPACK_ROW_LENGTH, &ur);
+ gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &ua);
+ gl->GetIntegerv(GL_UNPACK_SKIP_PIXELS, &usp);
+ gl->GetIntegerv(GL_UNPACK_SKIP_ROWS, &usr);
+
+ gl->BindTexture(texTarget, texName);
+ gl->GetTexLevelParameteriv(texTarget, 0, GL_TEXTURE_WIDTH, &dstw);
+ gl->GetTexLevelParameteriv(texTarget, 0, GL_TEXTURE_HEIGHT, &dsth);
+
+ gl->PixelStorei(GL_PACK_ROW_LENGTH, 0);
+ gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
+ gl->PixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ gl->PixelStorei(GL_PACK_SKIP_ROWS, 0);
+
+ gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ gl->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ gl->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER, 0);
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ pvImage = crAlloc(4*dstw*dsth);
+ gl->GetTexImage(texTarget, 0, GL_BGRA, GL_UNSIGNED_BYTE, pvImage);
+
+ gl->BindTexture(texTarget, otex);
+
+ gl->PixelStorei(GL_PACK_ROW_LENGTH, pr);
+ gl->PixelStorei(GL_PACK_ALIGNMENT, pa);
+ gl->PixelStorei(GL_PACK_SKIP_PIXELS, psp);
+ gl->PixelStorei(GL_PACK_SKIP_ROWS, psr);
+
+ gl->PixelStorei(GL_UNPACK_ROW_LENGTH, ur);
+ gl->PixelStorei(GL_UNPACK_ALIGNMENT, ua);
+ gl->PixelStorei(GL_UNPACK_SKIP_PIXELS, usp);
+ gl->PixelStorei(GL_UNPACK_SKIP_ROWS, usr);
+
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER, ppb);
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER, pub);
+
+ gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER_BINDING_EXT, rfb);
+ gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_BINDING_EXT, dfb);
+ gl->ReadBuffer(rb);
+ gl->DrawBuffer(db);
+
+ *ppvImage = pvImage;
+ *pw = dstw;
+ *ph = dsth;
+}
+
+DECLEXPORT(void) crDbgPrint(const char *format, ... )
+{
+ va_list args;
+ static char txt[8092];
+
+ va_start(args, format);
+ vsprintf(txt, format, args);
+ va_end(args);
+
+ OutputDebugString(txt);
+}
+
+void crDbgDumpImage2D(const char* pszDesc, const void *pvData, uint32_t width, uint32_t height, uint32_t bpp, uint32_t pitch)
+{
+ crDbgPrint("<?dml?><exec cmd=\"!vbvdbg.ms 0x%p 0n%d 0n%d 0n%d 0n%d\">%s</exec>, ( !vbvdbg.ms 0x%p 0n%d 0n%d 0n%d 0n%d )\n",
+ pvData, width, height, bpp, pitch,
+ pszDesc,
+ pvData, width, height, bpp, pitch);
+}
+
+void crDbgDumpTexImage2D(const char* pszDesc, GLint texTarget, GLint texName, GLboolean fBreak)
+{
+ GLvoid *pvImage;
+ GLint w, h;
+ crDbgGetTexImage2D(texTarget, texName, &pvImage, &w, &h);
+ crDbgPrint("%s target(%d), name(%d), width(%d), height(%d)", pszDesc, texTarget, texName, w, h);
+ crDbgDumpImage2D("texture data", pvImage, w, h, 32, (32 * w)/8);
+ if (fBreak)
+ {
+ CRASSERT(0);
+ }
+ crDbgFree(pvImage);
+}
+#endif
+
+PCR_BLITTER crServerVBoxBlitterGet()
+{
+ if (!CrBltIsInitialized(&cr_server.Blitter))
+ {
+ CR_BLITTER_CONTEXT Ctx;
+ int rc;
+ CRASSERT(cr_server.MainContextInfo.SpuContext);
+ Ctx.Base.id = cr_server.MainContextInfo.SpuContext;
+ Ctx.Base.visualBits = cr_server.MainContextInfo.CreateInfo.realVisualBits;
+ rc = CrBltInit(&cr_server.Blitter, &Ctx, true, true, NULL, &cr_server.TmpCtxDispatch);
+ if (RT_SUCCESS(rc))
+ {
+ CRASSERT(CrBltIsInitialized(&cr_server.Blitter));
+ }
+ else
+ {
+ crWarning("CrBltInit failed, rc %d", rc);
+ CRASSERT(!CrBltIsInitialized(&cr_server.Blitter));
+ return NULL;
+ }
+ }
+
+ if (!CrBltMuralGetCurrentInfo(&cr_server.Blitter)->Base.id)
+ {
+ CRMuralInfo *dummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ CR_BLITTER_WINDOW DummyInfo;
+ CRASSERT(dummy);
+ crServerVBoxBlitterWinInit(&DummyInfo, dummy);
+ CrBltMuralSetCurrentInfo(&cr_server.Blitter, &DummyInfo);
+ }
+
+ return &cr_server.Blitter;
+}
+
+PCR_BLITTER crServerVBoxBlitterGetInitialized()
+{
+ if (CrBltIsInitialized(&cr_server.Blitter))
+ return &cr_server.Blitter;
+ return NULL;
+}
+
+
+int crServerVBoxBlitterTexInit(CRContext *ctx, CRMuralInfo *mural, PVBOXVR_TEXTURE pTex, GLboolean fDraw)
+{
+ CRTextureObj *tobj;
+ CRFramebufferObjectState *pBuf = &ctx->framebufferobject;
+ GLenum enmBuf;
+ CRFBOAttachmentPoint *pAp;
+ GLuint idx;
+ CRTextureLevel *tl;
+ CRFramebufferObject *pFBO = fDraw ? pBuf->drawFB : pBuf->readFB;
+
+ if (!pFBO)
+ {
+ GLuint hwid;
+
+ if (!mural->fRedirected)
+ {
+ WARN(("mural not redirected!"));
+ return VERR_NOT_IMPLEMENTED;
+ }
+
+ enmBuf = fDraw ? ctx->buffer.drawBuffer : ctx->buffer.readBuffer;
+ switch (enmBuf)
+ {
+ case GL_BACK:
+ case GL_BACK_RIGHT:
+ case GL_BACK_LEFT:
+ hwid = mural->aidColorTexs[CR_SERVER_FBO_BB_IDX(mural)];
+ break;
+ case GL_FRONT:
+ case GL_FRONT_RIGHT:
+ case GL_FRONT_LEFT:
+ hwid = mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)];
+ break;
+ default:
+ WARN(("unsupported enum buf %d", enmBuf));
+ return VERR_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (!hwid)
+ {
+ crWarning("offscreen render tex hwid is null");
+ return VERR_INVALID_STATE;
+ }
+
+ pTex->width = mural->width;
+ pTex->height = mural->height;
+ pTex->target = GL_TEXTURE_2D;
+ pTex->hwid = hwid;
+ return VINF_SUCCESS;
+ }
+
+ enmBuf = fDraw ? pFBO->drawbuffer[0] : pFBO->readbuffer;
+ idx = enmBuf - GL_COLOR_ATTACHMENT0_EXT;
+ if (idx >= CR_MAX_COLOR_ATTACHMENTS)
+ {
+ crWarning("idx is invalid %d, using 0", idx);
+ }
+
+ pAp = &pFBO->color[idx];
+
+ if (!pAp->name)
+ {
+ crWarning("no collor draw attachment");
+ return VERR_INVALID_STATE;
+ }
+
+ if (pAp->level)
+ {
+ WARN(("non-zero level not implemented"));
+ return VERR_NOT_IMPLEMENTED;
+ }
+
+ tobj = (CRTextureObj*)crHashtableSearch(ctx->shared->textureTable, pAp->name);
+ if (!tobj)
+ {
+ crWarning("no texture object found for name %d", pAp->name);
+ return VERR_INVALID_STATE;
+ }
+
+ if (tobj->target != GL_TEXTURE_2D && tobj->target != GL_TEXTURE_RECTANGLE_NV)
+ {
+ WARN(("non-texture[rect|2d] not implemented"));
+ return VERR_NOT_IMPLEMENTED;
+ }
+
+ CRASSERT(tobj->hwid);
+
+ tl = tobj->level[0];
+ pTex->width = tl->width;
+ pTex->height = tl->height;
+ pTex->target = tobj->target;
+ pTex->hwid = tobj->hwid;
+
+ return VINF_SUCCESS;
+}
+
+int crServerVBoxBlitterBlitCurrentCtx(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ PCR_BLITTER pBlitter;
+ CR_BLITTER_CONTEXT Ctx;
+ CRMuralInfo *mural;
+ CRContext *ctx = crStateGetCurrent();
+ PVBOXVR_TEXTURE pDrawTex, pReadTex;
+ VBOXVR_TEXTURE DrawTex, ReadTex;
+ int rc;
+ GLuint idDrawFBO, idReadFBO;
+ CR_BLITTER_WINDOW BltInfo;
+
+ if (mask != GL_COLOR_BUFFER_BIT)
+ {
+ WARN(("not supported blit mask %d", mask));
+ return VERR_NOT_IMPLEMENTED;
+ }
+
+ if (!cr_server.curClient)
+ {
+ crWarning("no current client");
+ return VERR_INVALID_STATE;
+ }
+ mural = cr_server.curClient->currentMural;
+ if (!mural)
+ {
+ crWarning("no current mural");
+ return VERR_INVALID_STATE;
+ }
+
+ rc = crServerVBoxBlitterTexInit(ctx, mural, &DrawTex, GL_TRUE);
+ if (RT_SUCCESS(rc))
+ {
+ pDrawTex = &DrawTex;
+ }
+ else
+ {
+ crWarning("crServerVBoxBlitterTexInit failed for draw");
+ return rc;
+ }
+
+ rc = crServerVBoxBlitterTexInit(ctx, mural, &ReadTex, GL_FALSE);
+ if (RT_SUCCESS(rc))
+ {
+ pReadTex = &ReadTex;
+ }
+ else
+ {
+// crWarning("crServerVBoxBlitterTexInit failed for read");
+ return rc;
+ }
+
+ pBlitter = crServerVBoxBlitterGet();
+ if (!pBlitter)
+ {
+ crWarning("crServerVBoxBlitterGet failed");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ crServerVBoxBlitterWinInit(&BltInfo, mural);
+
+ crServerVBoxBlitterCtxInit(&Ctx, cr_server.curClient->currentCtxInfo);
+
+ CrBltMuralSetCurrentInfo(pBlitter, &BltInfo);
+
+ idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer);
+ idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer);
+
+ crStateSwitchPrepare(NULL, ctx, idDrawFBO, idReadFBO);
+
+ rc = CrBltEnter(pBlitter);
+ if (RT_SUCCESS(rc))
+ {
+ RTRECT ReadRect, DrawRect;
+ ReadRect.xLeft = srcX0;
+ ReadRect.yTop = srcY0;
+ ReadRect.xRight = srcX1;
+ ReadRect.yBottom = srcY1;
+ DrawRect.xLeft = dstX0;
+ DrawRect.yTop = dstY0;
+ DrawRect.xRight = dstX1;
+ DrawRect.yBottom = dstY1;
+ CrBltBlitTexTex(pBlitter, pReadTex, &ReadRect, pDrawTex, &DrawRect, 1, CRBLT_FLAGS_FROM_FILTER(filter));
+ CrBltLeave(pBlitter);
+ }
+ else
+ {
+ crWarning("CrBltEnter failed rc %d", rc);
+ }
+
+ crStateSwitchPostprocess(ctx, NULL, idDrawFBO, idReadFBO);
+
+ return rc;
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchBlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ CRContext *ctx = crStateGetCurrent();
+ bool fTryBlitter = false;
+#ifdef CR_CHECK_BLITS
+// {
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+ GLint rfb=0, dfb=0, dtex=0, dlev=-1, rtex=0, rlev=-1, rb=0, db=0, ppb=0, pub=0, vp[4], otex, dstw, dsth;
+ GLint sdtex=0, srtex=0;
+ GLenum dStatus, rStatus;
+
+ CRTextureObj *tobj = 0;
+ CRTextureLevel *tl = 0;
+ GLint id, tuId, pbufId, pbufIdHw, ubufId, ubufIdHw, width, height, depth;
+
+ crDebug("===StateTracker===");
+ crDebug("Current TU: %i", ctx->texture.curTextureUnit);
+
+ tobj = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D;
+ CRASSERT(tobj);
+ tl = &tobj->level[0][0];
+ crDebug("Texture %i(hw %i), w=%i, h=%i", tobj->id, tobj->hwid, tl->width, tl->height, tl->depth);
+
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ pbufId = ctx->bufferobject.packBuffer->hwid;
+ }
+ else
+ {
+ pbufId = 0;
+ }
+ crDebug("Pack BufferId %i", pbufId);
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ ubufId = ctx->bufferobject.unpackBuffer->hwid;
+ }
+ else
+ {
+ ubufId = 0;
+ }
+ crDebug("Unpack BufferId %i", ubufId);
+
+ crDebug("===GPU===");
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_ACTIVE_TEXTURE, &tuId);
+ crDebug("Current TU: %i", tuId - GL_TEXTURE0_ARB);
+ CRASSERT(tuId - GL_TEXTURE0_ARB == ctx->texture.curTextureUnit);
+
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_TEXTURE_BINDING_2D, &id);
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+ cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_DEPTH, &depth);
+ crDebug("Texture: %i, w=%i, h=%i, d=%i", id, width, height, depth);
+ CRASSERT(id == tobj->hwid);
+ CRASSERT(width == tl->width);
+ CRASSERT(height == tl->height);
+ CRASSERT(depth == tl->depth);
+
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &pbufIdHw);
+ crDebug("Hw Pack BufferId %i", pbufIdHw);
+ CRASSERT(pbufIdHw == pbufId);
+
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &ubufIdHw);
+ crDebug("Hw Unpack BufferId %i", ubufIdHw);
+ CRASSERT(ubufIdHw == ubufId);
+
+ gl->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb);
+ gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb);
+ gl->GetIntegerv(GL_READ_BUFFER, &rb);
+ gl->GetIntegerv(GL_DRAW_BUFFER, &db);
+
+ gl->GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &ppb);
+ gl->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &pub);
+
+ gl->GetIntegerv(GL_VIEWPORT, &vp[0]);
+
+ gl->GetIntegerv(GL_TEXTURE_BINDING_2D, &otex);
+
+ gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &dtex);
+ gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &dlev);
+ dStatus = gl->CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
+
+ gl->GetFramebufferAttachmentParameterivEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &rtex);
+ gl->GetFramebufferAttachmentParameterivEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &rlev);
+ rStatus = gl->CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
+
+ if (dtex)
+ {
+ CRASSERT(!dlev);
+ }
+
+ if (rtex)
+ {
+ CRASSERT(!rlev);
+ }
+
+ if (ctx->framebufferobject.drawFB)
+ {
+ CRASSERT(dfb);
+ CRASSERT(ctx->framebufferobject.drawFB->hwid == dfb);
+ CRASSERT(ctx->framebufferobject.drawFB->drawbuffer[0] == db);
+
+ CRASSERT(dStatus==GL_FRAMEBUFFER_COMPLETE_EXT);
+ CRASSERT(db==GL_COLOR_ATTACHMENT0_EXT);
+
+ CRASSERT(ctx->framebufferobject.drawFB->color[0].type == GL_TEXTURE);
+ CRASSERT(ctx->framebufferobject.drawFB->color[0].level == 0);
+ sdtex = ctx->framebufferobject.drawFB->color[0].name;
+ sdtex = crStateGetTextureHWID(sdtex);
+
+ CRASSERT(sdtex);
+ }
+ else
+ {
+ CRASSERT(!dfb);
+ }
+
+ if (ctx->framebufferobject.readFB)
+ {
+ CRASSERT(rfb);
+ CRASSERT(ctx->framebufferobject.readFB->hwid == rfb);
+
+ CRASSERT(rStatus==GL_FRAMEBUFFER_COMPLETE_EXT);
+
+ CRASSERT(ctx->framebufferobject.readFB->color[0].type == GL_TEXTURE);
+ CRASSERT(ctx->framebufferobject.readFB->color[0].level == 0);
+ srtex = ctx->framebufferobject.readFB->color[0].name;
+ srtex = crStateGetTextureHWID(srtex);
+
+ CRASSERT(srtex);
+ }
+ else
+ {
+ CRASSERT(!rfb);
+ }
+
+ CRASSERT(sdtex == dtex);
+ CRASSERT(srtex == rtex);
+
+// crDbgDumpTexImage2D("==> src tex:", GL_TEXTURE_2D, rtex, true);
+// crDbgDumpTexImage2D("==> dst tex:", GL_TEXTURE_2D, dtex, true);
+
+// }
+#endif
+#ifdef CR_DUMP_BLITS
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+ GLint rfb=0, dfb=0, dtex=0, dlev=-1, rb=0, db=0, ppb=0, pub=0, vp[4], otex, dstw, dsth;
+ GLenum status;
+ char fname[200];
+ void *img;
+
+ blitnum++;
+
+ crDebug("[%i]BlitFramebufferEXT(%i, %i, %i, %i, %i, %i, %i, %i, %x, %x)", blitnum, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ crDebug("%i, %i <-> %i, %i", srcX1-srcX0, srcY1-srcY0, dstX1-dstX0, dstY1-dstY0);
+
+ gl->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb);
+ gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb);
+ gl->GetIntegerv(GL_READ_BUFFER, &rb);
+ gl->GetIntegerv(GL_DRAW_BUFFER, &db);
+
+ gl->GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &ppb);
+ gl->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &pub);
+
+ gl->GetIntegerv(GL_VIEWPORT, &vp[0]);
+
+ gl->GetIntegerv(GL_TEXTURE_BINDING_2D, &otex);
+
+ CRASSERT(!rfb && dfb);
+ gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &dtex);
+ gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &dlev);
+ status = gl->CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
+
+ CRASSERT(status==GL_FRAMEBUFFER_COMPLETE_EXT
+ && db==GL_COLOR_ATTACHMENT0_EXT
+ && (rb==GL_FRONT || rb==GL_BACK)
+ && !rfb && dfb && dtex && !dlev
+ && !ppb && !pub);
+
+ crDebug("Src[rb 0x%x, fbo %i] Dst[db 0x%x, fbo %i(0x%x), tex %i.%i]", rb, rfb, db, dfb, status, dtex, dlev);
+ crDebug("Viewport [%i, %i, %i, %i]", vp[0], vp[1], vp[2], vp[3]);
+
+ gl->PixelStorei(GL_PACK_ROW_LENGTH, 0);
+ gl->PixelStorei(GL_PACK_ALIGNMENT, 1);
+ gl->PixelStorei(GL_PACK_SKIP_PIXELS, 0);
+ gl->PixelStorei(GL_PACK_SKIP_ROWS, 0);
+
+ gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ gl->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ gl->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+
+ gl->BindTexture(GL_TEXTURE_2D, dtex);
+ gl->GetTexLevelParameteriv(GL_TEXTURE_2D, dlev, GL_TEXTURE_WIDTH, &dstw);
+ gl->GetTexLevelParameteriv(GL_TEXTURE_2D, dlev, GL_TEXTURE_HEIGHT, &dsth);
+ gl->BindTexture(GL_TEXTURE_2D, otex);
+ crDebug("Dst is %i, %i", dstw, dsth);
+
+ CRASSERT(vp[2]>=dstw && vp[3]>=dsth);
+ img = crAlloc(vp[2]*vp[3]*4);
+ CRASSERT(img);
+
+ gl->ReadPixels(0, 0, vp[2], vp[3], GL_BGRA, GL_UNSIGNED_BYTE, img);
+ sprintf(fname, "blit%iA_src.tga", blitnum);
+ crDumpNamedTGA(fname, vp[2], vp[3], img);
+
+ gl->BindTexture(GL_TEXTURE_2D, dtex);
+ gl->GetTexImage(GL_TEXTURE_2D, dlev, GL_BGRA, GL_UNSIGNED_BYTE, img);
+ sprintf(fname, "blit%iB_dst.tga", blitnum);
+ crDumpNamedTGA(fname, dstw, dsth, img);
+ gl->BindTexture(GL_TEXTURE_2D, otex);
+#endif
+
+ if (srcY0 > srcY1)
+ {
+ /* work around Intel driver bug on Linux host */
+ if (1 || dstY0 > dstY1)
+ {
+ /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */
+ int32_t tmp = srcY0;
+ srcY0 = srcY1;
+ srcY1 = tmp;
+ tmp = dstY0;
+ dstY0 = dstY1;
+ dstY1 = tmp;
+ }
+ }
+
+ if (srcX0 > srcX1)
+ {
+ if (dstX0 > dstX1)
+ {
+ /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */
+ int32_t tmp = srcX0;
+ srcX0 = srcX1;
+ srcX1 = tmp;
+ tmp = dstX0;
+ dstX0 = dstX1;
+ dstX1 = tmp;
+ }
+ }
+
+ if (cr_server.fBlitterMode)
+ {
+ fTryBlitter = true;
+ }
+
+ if (fTryBlitter)
+ {
+ int rc = crServerVBoxBlitterBlitCurrentCtx(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ if (RT_SUCCESS(rc))
+ goto my_exit;
+ }
+
+ if (ctx->viewport.scissorTest)
+ cr_server.head_spu->dispatch_table.Disable(GL_SCISSOR_TEST);
+
+ cr_server.head_spu->dispatch_table.BlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+
+ if (ctx->viewport.scissorTest)
+ cr_server.head_spu->dispatch_table.Enable(GL_SCISSOR_TEST);
+
+
+my_exit:
+
+//#ifdef CR_CHECK_BLITS
+// crDbgDumpTexImage2D("<== src tex:", GL_TEXTURE_2D, rtex, true);
+// crDbgDumpTexImage2D("<== dst tex:", GL_TEXTURE_2D, dtex, true);
+//#endif
+#ifdef CR_DUMP_BLITS
+ gl->BindTexture(GL_TEXTURE_2D, dtex);
+ gl->GetTexImage(GL_TEXTURE_2D, dlev, GL_BGRA, GL_UNSIGNED_BYTE, img);
+ sprintf(fname, "blit%iC_res.tga", blitnum);
+ crDumpNamedTGA(fname, dstw, dsth, img);
+ gl->BindTexture(GL_TEXTURE_2D, otex);
+ crFree(img);
+#endif
+ return;
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDrawBuffer( GLenum mode )
+{
+ crStateDrawBuffer( mode );
+
+ if (!crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ if (mode == GL_FRONT || mode == GL_FRONT_LEFT || mode == GL_FRONT_RIGHT)
+ cr_server.curClient->currentMural->bFbDraw = GL_TRUE;
+
+ if (crServerIsRedirectedToFBO()
+ && cr_server.curClient->currentMural->aidFBOs[0])
+ {
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ GLint iBufferNeeded = -1;
+ switch (mode)
+ {
+ case GL_BACK:
+ case GL_BACK_LEFT:
+ case GL_BACK_RIGHT:
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ case GL_FRONT:
+ case GL_FRONT_LEFT:
+ case GL_FRONT_RIGHT:
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_FB_IDX(mural);
+ break;
+ case GL_NONE:
+ crDebug("DrawBuffer: GL_NONE");
+ break;
+ case GL_AUX0:
+ crDebug("DrawBuffer: GL_AUX0");
+ break;
+ case GL_AUX1:
+ crDebug("DrawBuffer: GL_AUX1");
+ break;
+ case GL_AUX2:
+ crDebug("DrawBuffer: GL_AUX2");
+ break;
+ case GL_AUX3:
+ crDebug("DrawBuffer: GL_AUX3");
+ break;
+ case GL_LEFT:
+ crWarning("DrawBuffer: GL_LEFT not supported properly");
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ case GL_RIGHT:
+ crWarning("DrawBuffer: GL_RIGHT not supported properly");
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ case GL_FRONT_AND_BACK:
+ crWarning("DrawBuffer: GL_FRONT_AND_BACK not supported properly");
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ default:
+ crWarning("DrawBuffer: unexpected mode! 0x%x", mode);
+ iBufferNeeded = mural->iCurDrawBuffer;
+ break;
+ }
+
+ if (iBufferNeeded != mural->iCurDrawBuffer)
+ {
+ mural->iCurDrawBuffer = iBufferNeeded;
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, iBufferNeeded));
+ }
+ }
+ }
+
+ cr_server.head_spu->dispatch_table.DrawBuffer( mode );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDrawBuffers( GLsizei n, const GLenum* bufs )
+{
+ if (n == 1)
+ {
+ crServerDispatchDrawBuffer( bufs[0] );
+ }
+ else
+ {
+ /** @todo State tracker. */
+ cr_server.head_spu->dispatch_table.DrawBuffers( n, bufs );
+ }
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchReadBuffer( GLenum mode )
+{
+ crStateReadBuffer( mode );
+
+ if (crServerIsRedirectedToFBO()
+ && cr_server.curClient->currentMural->aidFBOs[0]
+ && !crStateGetCurrent()->framebufferobject.readFB)
+ {
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ GLint iBufferNeeded = -1;
+ switch (mode)
+ {
+ case GL_BACK:
+ case GL_BACK_LEFT:
+ case GL_BACK_RIGHT:
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ case GL_FRONT:
+ case GL_FRONT_LEFT:
+ case GL_FRONT_RIGHT:
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_FB_IDX(mural);
+ break;
+ case GL_NONE:
+ crDebug("ReadBuffer: GL_NONE");
+ break;
+ case GL_AUX0:
+ crDebug("ReadBuffer: GL_AUX0");
+ break;
+ case GL_AUX1:
+ crDebug("ReadBuffer: GL_AUX1");
+ break;
+ case GL_AUX2:
+ crDebug("ReadBuffer: GL_AUX2");
+ break;
+ case GL_AUX3:
+ crDebug("ReadBuffer: GL_AUX3");
+ break;
+ case GL_LEFT:
+ crWarning("ReadBuffer: GL_LEFT not supported properly");
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ case GL_RIGHT:
+ crWarning("ReadBuffer: GL_RIGHT not supported properly");
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ case GL_FRONT_AND_BACK:
+ crWarning("ReadBuffer: GL_FRONT_AND_BACK not supported properly");
+ mode = GL_COLOR_ATTACHMENT0;
+ iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural);
+ break;
+ default:
+ crWarning("ReadBuffer: unexpected mode! 0x%x", mode);
+ iBufferNeeded = mural->iCurDrawBuffer;
+ break;
+ }
+
+ Assert(CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ if (iBufferNeeded != mural->iCurReadBuffer)
+ {
+ mural->iCurReadBuffer = iBufferNeeded;
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, iBufferNeeded));
+ }
+ }
+ cr_server.head_spu->dispatch_table.ReadBuffer( mode );
+}
+
+GLenum SERVER_DISPATCH_APIENTRY crServerDispatchGetError( void )
+{
+ GLenum retval, err;
+ CRContext *ctx = crStateGetCurrent();
+ retval = ctx->error;
+
+ err = cr_server.head_spu->dispatch_table.GetError();
+ if (retval == GL_NO_ERROR)
+ retval = err;
+ else
+ ctx->error = GL_NO_ERROR;
+
+ /* our impl has a single error flag, so we just loop here to reset all error flags to no_error */
+ while (err != GL_NO_ERROR)
+ err = cr_server.head_spu->dispatch_table.GetError();
+
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerMakeTmpCtxCurrent( GLint window, GLint nativeWindow, GLint context )
+{
+ CRContext *pCtx = crStateGetCurrent();
+ CRContext *pCurCtx = NULL;
+ GLuint idDrawFBO = 0, idReadFBO = 0;
+ int fDoPrePostProcess = 0;
+
+ if (pCtx)
+ {
+ CRMuralInfo *pCurrentMural = cr_server.currentMural;
+
+ pCurCtx = cr_server.currentCtxInfo ? cr_server.currentCtxInfo->pContext : cr_server.MainContextInfo.pContext;
+ Assert(pCurCtx == pCtx);
+
+ if (!context)
+ {
+ if (pCurrentMural)
+ {
+ Assert(cr_server.currentCtxInfo);
+ context = cr_server.currentCtxInfo->SpuContext > 0 ? cr_server.currentCtxInfo->SpuContext : cr_server.MainContextInfo.SpuContext;
+ window = pCurrentMural->spuWindow;
+ }
+ else
+ {
+ CRMuralInfo * pDummy;
+ Assert(!cr_server.currentCtxInfo);
+ pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ context = cr_server.MainContextInfo.SpuContext;
+ window = pDummy->spuWindow;
+ }
+
+
+ fDoPrePostProcess = -1;
+ }
+ else
+ {
+ fDoPrePostProcess = 1;
+ }
+
+ if (pCurrentMural)
+ {
+ idDrawFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurDrawBuffer);
+ idReadFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurReadBuffer);
+ }
+ else
+ {
+ idDrawFBO = 0;
+ idReadFBO = 0;
+ }
+ }
+ else
+ {
+ /* this is a GUI thread, so no need to do anything here */
+ }
+
+ if (fDoPrePostProcess > 0)
+ crStateSwitchPrepare(NULL, pCurCtx, idDrawFBO, idReadFBO);
+
+ cr_server.head_spu->dispatch_table.MakeCurrent( window, nativeWindow, context);
+
+ if (fDoPrePostProcess < 0)
+ crStateSwitchPostprocess(pCurCtx, NULL, idDrawFBO, idReadFBO);
+}
+
+void crServerInitTmpCtxDispatch()
+{
+ MakeCurrentFunc_t pfnMakeCurrent;
+
+ crSPUInitDispatchTable(&cr_server.TmpCtxDispatch);
+ crSPUCopyDispatchTable(&cr_server.TmpCtxDispatch, &cr_server.head_spu->dispatch_table);
+ cr_server.TmpCtxDispatch.MakeCurrent = crServerMakeTmpCtxCurrent;
+
+ pfnMakeCurrent = crServerMakeTmpCtxCurrent;
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_TMPCTX_MAKE_CURRENT, GL_BYTE, sizeof (void*), &pfnMakeCurrent);
+
+}
+
+/* dump stuff */
+#ifdef VBOX_WITH_CRSERVER_DUMPER
+
+# ifndef VBOX_WITH_CRDUMPER
+# error "VBOX_WITH_CRDUMPER undefined!"
+# endif
+
+/* first four bits are buffer dump config
+ * second four bits are texture dump config
+ * config flags:
+ * 1 - blit on enter
+ * 2 - blit on exit
+ *
+ *
+ * Example:
+ *
+ * 0x03 - dump buffer on enter and exit
+ * 0x22 - dump texture and buffer on exit */
+
+int64_t g_CrDbgDumpPid = 0;
+unsigned long g_CrDbgDumpEnabled = 0;
+unsigned long g_CrDbgDumpDraw = 0
+#if 0
+ | CR_SERVER_DUMP_F_COMPILE_SHADER
+ | CR_SERVER_DUMP_F_LINK_PROGRAM
+#endif
+ ;
+#if 0
+ | CR_SERVER_DUMP_F_DRAW_BUFF_ENTER
+ | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER
+ | CR_SERVER_DUMP_F_DRAW_TEX_ENTER
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER
+ | CR_SERVER_DUMP_F_DRAW_STATE_ENTER
+ | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER
+ | CR_SERVER_DUMP_F_DRAWEL
+ | CR_SERVER_DUMP_F_SHADER_SOURCE
+ ;
+#endif
+unsigned long g_CrDbgDumpDrawFramesSettings = CR_SERVER_DUMP_F_DRAW_BUFF_ENTER
+ | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE
+ | CR_SERVER_DUMP_F_DRAW_TEX_ENTER
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER
+ | CR_SERVER_DUMP_F_COMPILE_SHADER
+ | CR_SERVER_DUMP_F_LINK_PROGRAM
+ | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER;
+unsigned long g_CrDbgDumpDrawFramesAppliedSettings = 0;
+unsigned long g_CrDbgDumpDrawFramesSavedInitSettings = 0;
+unsigned long g_CrDbgDumpDrawFramesCount = 0;
+
+uint32_t g_CrDbgDumpDrawCount = 0;
+uint32_t g_CrDbgDumpDumpOnCount = 10;
+uint32_t g_CrDbgDumpDumpOnCountEnabled = 0;
+uint32_t g_CrDbgDumpDumpOnCountPerform = 0;
+uint32_t g_CrDbgDumpDrawFlags = CR_SERVER_DUMP_F_COMPILE_SHADER
+ | CR_SERVER_DUMP_F_SHADER_SOURCE
+ | CR_SERVER_DUMP_F_COMPILE_SHADER
+ | CR_SERVER_DUMP_F_LINK_PROGRAM
+ | CR_SERVER_DUMP_F_DRAW_BUFF_ENTER
+ | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE
+ | CR_SERVER_DUMP_F_DRAW_TEX_ENTER
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER
+ | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER
+ | CR_SERVER_DUMP_F_DRAW_STATE_ENTER
+ | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER
+ | CR_SERVER_DUMP_F_DRAWEL
+ | CR_SERVER_DUMP_F_TEXPRESENT;
+
+void crServerDumpCheckTerm()
+{
+ if (!CrBltIsInitialized(&cr_server.RecorderBlitter))
+ return;
+
+ CrBltTerm(&cr_server.RecorderBlitter);
+}
+
+int crServerDumpCheckInit()
+{
+ int rc;
+ CR_BLITTER_WINDOW BltWin;
+ CR_BLITTER_CONTEXT BltCtx;
+ CRMuralInfo *pBlitterMural;
+
+ if (!CrBltIsInitialized(&cr_server.RecorderBlitter))
+ {
+ pBlitterMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ if (!pBlitterMural)
+ {
+ crWarning("crServerGetDummyMural failed");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ crServerVBoxBlitterWinInit(&BltWin, pBlitterMural);
+ crServerVBoxBlitterCtxInit(&BltCtx, &cr_server.MainContextInfo);
+
+ rc = CrBltInit(&cr_server.RecorderBlitter, &BltCtx, true, true, NULL, &cr_server.TmpCtxDispatch);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrBltInit failed rc %d", rc);
+ return rc;
+ }
+
+ rc = CrBltMuralSetCurrentInfo(&cr_server.RecorderBlitter, &BltWin);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrBltMuralSetCurrentInfo failed rc %d", rc);
+ return rc;
+ }
+ }
+
+#if 0
+ crDmpDbgPrintInit(&cr_server.DbgPrintDumper);
+ cr_server.pDumper = &cr_server.DbgPrintDumper.Base;
+#else
+ if (!crDmpHtmlIsInited(&cr_server.HtmlDumper))
+ {
+ static int cCounter = 0;
+// crDmpHtmlInit(&cr_server.HtmlDumper, "S:\\projects\\virtualbox\\3d\\dumps\\1", "index.html");
+ crDmpHtmlInitF(&cr_server.HtmlDumper, "/Users/oracle-mac/vbox/dump/1", "index%d.html", cCounter);
+ cr_server.pDumper = &cr_server.HtmlDumper.Base;
+ ++cCounter;
+ }
+#endif
+
+ crRecInit(&cr_server.Recorder, &cr_server.RecorderBlitter, &cr_server.TmpCtxDispatch, cr_server.pDumper);
+ return VINF_SUCCESS;
+}
+
+void crServerDumpShader(GLint id)
+{
+ CRContext *ctx = crStateGetCurrent();
+ crRecDumpShader(&cr_server.Recorder, ctx, id, 0);
+}
+
+void crServerDumpProgram(GLint id)
+{
+ CRContext *ctx = crStateGetCurrent();
+ crRecDumpProgram(&cr_server.Recorder, ctx, id, 0);
+}
+
+void crServerDumpCurrentProgram()
+{
+ CRContext *ctx = crStateGetCurrent();
+ crRecDumpCurrentProgram(&cr_server.Recorder, ctx);
+}
+
+void crServerDumpRecompileDumpCurrentProgram()
+{
+ crDmpStrF(cr_server.Recorder.pDumper, "==Dump(1)==");
+ crServerRecompileCurrentProgram();
+ crServerDumpCurrentProgramUniforms();
+ crServerDumpCurrentProgramAttribs();
+ crDmpStrF(cr_server.Recorder.pDumper, "Done Dump(1)");
+ crServerRecompileCurrentProgram();
+ crDmpStrF(cr_server.Recorder.pDumper, "Dump(2)");
+ crServerRecompileCurrentProgram();
+ crServerDumpCurrentProgramUniforms();
+ crServerDumpCurrentProgramAttribs();
+ crDmpStrF(cr_server.Recorder.pDumper, "Done Dump(2)");
+}
+
+void crServerRecompileCurrentProgram()
+{
+ CRContext *ctx = crStateGetCurrent();
+ crRecRecompileCurrentProgram(&cr_server.Recorder, ctx);
+}
+
+void crServerDumpCurrentProgramUniforms()
+{
+ CRContext *ctx = crStateGetCurrent();
+ crDmpStrF(cr_server.Recorder.pDumper, "==Uniforms==");
+ crRecDumpCurrentProgramUniforms(&cr_server.Recorder, ctx);
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done Uniforms==");
+}
+
+void crServerDumpCurrentProgramAttribs()
+{
+ CRContext *ctx = crStateGetCurrent();
+ crDmpStrF(cr_server.Recorder.pDumper, "==Attribs==");
+ crRecDumpCurrentProgramAttribs(&cr_server.Recorder, ctx);
+ crDmpStrF(cr_server.Recorder.pDumper, "==Done Attribs==");
+}
+
+void crServerDumpState()
+{
+ CRContext *ctx = crStateGetCurrent();
+ crRecDumpGlGetState(&cr_server.Recorder, ctx);
+ crRecDumpGlEnableState(&cr_server.Recorder, ctx);
+}
+
+void crServerDumpDrawel(const char*pszFormat, ...)
+{
+ CRContext *ctx = crStateGetCurrent();
+ va_list pArgList;
+ va_start(pArgList, pszFormat);
+ crRecDumpVertAttrV(&cr_server.Recorder, ctx, pszFormat, pArgList);
+ va_end(pArgList);
+}
+
+void crServerDumpDrawelv(GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal)
+{
+ CRContext *ctx = crStateGetCurrent();
+ crRecDumpVertAttrv(&cr_server.Recorder, ctx, idx, pszElFormat, cbEl, pvVal, cVal);
+}
+
+void crServerDumpBuffer(int idx)
+{
+ CRContextInfo *pCtxInfo = cr_server.currentCtxInfo;
+ CRContext *ctx = crStateGetCurrent();
+ GLint idFBO;
+ GLint idTex;
+ VBOXVR_TEXTURE RedirTex;
+ int rc = crServerDumpCheckInit();
+ idx = idx >= 0 ? idx : crServerMuralFBOIdxFromBufferName(cr_server.currentMural, pCtxInfo->pContext->buffer.drawBuffer);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerDumpCheckInit failed, rc %d", rc);
+ return;
+ }
+
+ if (idx < 0)
+ {
+ crWarning("neg idx, unsupported");
+ return;
+ }
+
+ idFBO = CR_SERVER_FBO_FOR_IDX(cr_server.currentMural, idx);
+ idTex = CR_SERVER_FBO_TEX_FOR_IDX(cr_server.currentMural, idx);
+
+ RedirTex.width = cr_server.currentMural->fboWidth;
+ RedirTex.height = cr_server.currentMural->fboHeight;
+ RedirTex.target = GL_TEXTURE_2D;
+ RedirTex.hwid = idTex;
+
+ crRecDumpBuffer(&cr_server.Recorder, ctx, idFBO, idTex ? &RedirTex : NULL);
+}
+
+void crServerDumpTexture(const VBOXVR_TEXTURE *pTex)
+{
+ CRContextInfo *pCtxInfo = cr_server.currentCtxInfo;
+ CR_BLITTER_WINDOW BltWin;
+ CR_BLITTER_CONTEXT BltCtx;
+ CRContext *ctx = crStateGetCurrent();
+ int rc = crServerDumpCheckInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerDumpCheckInit failed, rc %d", rc);
+ return;
+ }
+
+ crServerVBoxBlitterWinInit(&BltWin, cr_server.currentMural);
+ crServerVBoxBlitterCtxInit(&BltCtx, pCtxInfo);
+
+ crRecDumpTextureF(&cr_server.Recorder, pTex, &BltCtx, &BltWin, "Tex (%d x %d), hwid (%d) target %#x", pTex->width, pTex->height, pTex->hwid, pTex->target);
+}
+
+void crServerDumpTextures()
+{
+ CRContextInfo *pCtxInfo = cr_server.currentCtxInfo;
+ CRContext *ctx = crStateGetCurrent();
+ int rc = crServerDumpCheckInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerDumpCheckInit failed, rc %d", rc);
+ return;
+ }
+
+ crRecDumpTextures(&cr_server.Recorder, ctx);
+}
+
+void crServerDumpFilterOpLeave(unsigned long event, CR_DUMPER *pDumper)
+{
+ if (CR_SERVER_DUMP_F_DRAW_LEAVE_ALL & event)
+ {
+ g_CrDbgDumpDumpOnCountPerform = 0;
+ }
+}
+
+bool crServerDumpFilterOpEnter(unsigned long event, CR_DUMPER *pDumper)
+{
+ if ((CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER & event)
+ || (CR_SERVER_DUMP_F_TEXPRESENT & event))
+ {
+ if (g_CrDbgDumpDumpOnCountEnabled == 1)
+ g_CrDbgDumpDumpOnCountEnabled = 2;
+ else if (g_CrDbgDumpDumpOnCountEnabled)
+ {
+ g_CrDbgDumpDumpOnCountEnabled = 0;
+ if (cr_server.pDumper == &cr_server.HtmlDumper.Base)
+ {
+ crDmpHtmlTerm(&cr_server.HtmlDumper);
+ cr_server.pDumper = NULL;
+ }
+ }
+
+ g_CrDbgDumpDrawCount = 0;
+ }
+ else if (CR_SERVER_DUMP_F_DRAW_ENTER_ALL & event)
+ {
+ if (g_CrDbgDumpDumpOnCountEnabled == 2)
+ {
+ if (g_CrDbgDumpDumpOnCount == g_CrDbgDumpDrawCount)
+ {
+ g_CrDbgDumpDumpOnCountPerform = 1;
+ }
+ ++g_CrDbgDumpDrawCount;
+ }
+ }
+ if (g_CrDbgDumpDumpOnCountPerform)
+ {
+ if (g_CrDbgDumpDrawFlags & event)
+ return true;
+ }
+ return CR_SERVER_DUMP_DEFAULT_FILTER_OP(event);
+}
+
+bool crServerDumpFilterDmp(unsigned long event, CR_DUMPER *pDumper)
+{
+ if (g_CrDbgDumpDumpOnCountPerform)
+ {
+ if (g_CrDbgDumpDrawFlags & event)
+ return true;
+ }
+ return CR_SERVER_DUMP_DEFAULT_FILTER_DMP(event);
+}
+
+void crServerDumpFramesCheck()
+{
+ if (!g_CrDbgDumpDrawFramesCount)
+ return;
+
+ if (!g_CrDbgDumpDrawFramesAppliedSettings)
+ {
+ if (!g_CrDbgDumpDrawFramesSettings)
+ {
+ crWarning("g_CrDbgDumpDrawFramesSettings is NULL, bump will not be started");
+ g_CrDbgDumpDrawFramesCount = 0;
+ return;
+ }
+
+ g_CrDbgDumpDrawFramesSavedInitSettings = g_CrDbgDumpDraw;
+ g_CrDbgDumpDrawFramesAppliedSettings = g_CrDbgDumpDrawFramesSettings;
+ g_CrDbgDumpDraw = g_CrDbgDumpDrawFramesSettings;
+ crDmpStrF(cr_server.Recorder.pDumper, "***Starting draw dump for %d frames, settings(0x%x)", g_CrDbgDumpDrawFramesCount, g_CrDbgDumpDraw);
+ return;
+ }
+
+ --g_CrDbgDumpDrawFramesCount;
+
+ if (!g_CrDbgDumpDrawFramesCount)
+ {
+ crDmpStrF(cr_server.Recorder.pDumper, "***Stop draw dump");
+ g_CrDbgDumpDraw = g_CrDbgDumpDrawFramesSavedInitSettings;
+ g_CrDbgDumpDrawFramesAppliedSettings = 0;
+ }
+}
+#endif
+
+GLvoid crServerSpriteCoordReplEnable(GLboolean fEnable)
+{
+ CRContext *g = crStateGetCurrent();
+ CRTextureState *t = &(g->texture);
+ GLuint curTextureUnit = t->curTextureUnit;
+ GLuint curTextureUnitRestore = curTextureUnit;
+ GLuint i;
+
+ for (i = 0; i < g->limits.maxTextureUnits; ++i)
+ {
+ if (g->point.coordReplacement[i])
+ {
+ if (i != curTextureUnit)
+ {
+ curTextureUnit = i;
+ cr_server.head_spu->dispatch_table.ActiveTextureARB( i + GL_TEXTURE0_ARB );
+ }
+
+ cr_server.head_spu->dispatch_table.TexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, (GLint)fEnable);
+ }
+ }
+
+ if (curTextureUnit != curTextureUnitRestore)
+ {
+ cr_server.head_spu->dispatch_table.ActiveTextureARB( curTextureUnitRestore + GL_TEXTURE0_ARB );
+ }
+}
+
+GLvoid SERVER_DISPATCH_APIENTRY crServerDispatchDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+#ifdef DEBUG
+ GLenum status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
+ Assert(GL_FRAMEBUFFER_COMPLETE == status);
+#endif
+ if (mode == GL_POINTS)
+ crServerSpriteCoordReplEnable(GL_TRUE);
+ CR_SERVER_DUMP_DRAW_ENTER();
+ CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.DrawArrays(mode, first, count););
+ CR_SERVER_DUMP_DRAW_LEAVE();
+ if (mode == GL_POINTS)
+ crServerSpriteCoordReplEnable(GL_FALSE);
+}
+
+GLvoid SERVER_DISPATCH_APIENTRY crServerDispatchDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices)
+{
+#ifdef DEBUG
+ GLenum status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
+ Assert(GL_FRAMEBUFFER_COMPLETE == status);
+#endif
+ if (mode == GL_POINTS)
+ crServerSpriteCoordReplEnable(GL_TRUE);
+ CR_SERVER_DUMP_DRAW_ENTER();
+ CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.DrawElements(mode, count, type, indices););
+ CR_SERVER_DUMP_DRAW_LEAVE();
+ if (mode == GL_POINTS)
+ crServerSpriteCoordReplEnable(GL_FALSE);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchEnd( void )
+{
+ CRContext *g = crStateGetCurrent();
+ GLenum mode = g->current.mode;
+
+ crStateEnd();
+ cr_server.head_spu->dispatch_table.End();
+
+ CR_SERVER_DUMP_DRAW_LEAVE();
+
+ if (mode == GL_POINTS)
+ crServerSpriteCoordReplEnable(GL_FALSE);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBegin(GLenum mode)
+{
+#ifdef DEBUG
+ CRContext *ctx = crStateGetCurrent();
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+
+ if (ctx->program.vpProgramBinding)
+ {
+ AssertRelease(ctx->program.currentVertexProgram);
+
+ if (ctx->program.currentVertexProgram->isARBprogram)
+ {
+ GLint pid=-1;
+ gl->GetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &pid);
+
+ if (pid != ctx->program.currentVertexProgram->id)
+ {
+ crWarning("pid(%d) != ctx->program.currentVertexProgram->id(%d)", pid, ctx->program.currentVertexProgram->id);
+ }
+ AssertRelease(pid == ctx->program.currentVertexProgram->id);
+ }
+ else
+ {
+ GLint pid=-1;
+
+ gl->GetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &pid);
+ if (pid != ctx->program.currentVertexProgram->id)
+ {
+ crWarning("pid(%d) != ctx->program.currentVertexProgram->id(%d)", pid, ctx->program.currentVertexProgram->id);
+ }
+ AssertRelease(pid == ctx->program.currentVertexProgram->id);
+ }
+ }
+ else if (ctx->glsl.activeProgram)
+ {
+ GLint pid=-1;
+
+ gl->GetIntegerv(GL_CURRENT_PROGRAM, &pid);
+ //crDebug("pid %i, state: id %i, hwid %i", pid, ctx->glsl.activeProgram->id, ctx->glsl.activeProgram->hwid);
+ if (pid != ctx->glsl.activeProgram->hwid)
+ {
+ crWarning("pid(%d) != ctx->glsl.activeProgram->hwid(%d)", pid, ctx->glsl.activeProgram->hwid);
+ }
+ AssertRelease(pid == ctx->glsl.activeProgram->hwid);
+ }
+#endif
+
+ if (mode == GL_POINTS)
+ crServerSpriteCoordReplEnable(GL_TRUE);
+
+ CR_SERVER_DUMP_DRAW_ENTER();
+
+ crStateBegin(mode);
+ cr_server.head_spu->dispatch_table.Begin(mode);
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
new file mode 100644
index 00000000..d4617026
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp
@@ -0,0 +1,840 @@
+/* $Id: server_muralfbo.cpp $ */
+
+/** @file
+ * VBox crOpenGL: Window to FBO redirect support.
+ */
+
+/*
+ * Copyright (C) 2010-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "server.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_vreg.h"
+#include "render/renderspu.h"
+
+static void crServerRedirMuralFbSync(CRMuralInfo *mural);
+
+void crServerCheckMuralGeometry(CRMuralInfo *mural)
+{
+ if (!mural->CreateInfo.externalID)
+ return;
+
+ CRASSERT(mural->spuWindow);
+ CRASSERT(mural->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID);
+
+ if (!mural->width || !mural->height
+ || mural->fboWidth != mural->width
+ || mural->fboHeight != mural->height)
+ {
+ crServerRedirMuralFbClear(mural);
+ crServerRedirMuralFBO(mural, false);
+ crServerDeleteMuralFBO(mural);
+ }
+
+ if (!mural->width || !mural->height)
+ return;
+
+ crServerRedirMuralFBO(mural, true);
+ crServerRedirMuralFbSync(mural);
+}
+
+static void crServerCheckMuralGeometryCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+
+ if (!pMI->fRedirected || pMI == data2)
+ return;
+
+ crServerCheckMuralGeometry(pMI);
+}
+
+
+void crServerCheckAllMuralGeometry(CRMuralInfo *pMI)
+{
+ CR_FBMAP Map;
+ int rc = CrPMgrHlpGlblUpdateBegin(&Map);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrPMgrHlpGlblUpdateBegin failed %d", rc));
+ return;
+ }
+
+ crHashtableWalk(cr_server.muralTable, crServerCheckMuralGeometryCB, pMI);
+
+ if (pMI)
+ crServerCheckMuralGeometry(pMI);
+
+ CrPMgrHlpGlblUpdateEnd(&Map);
+}
+
+GLboolean crServerSupportRedirMuralFBO(void)
+{
+ static GLboolean fInited = GL_FALSE;
+ static GLboolean fSupported = GL_FALSE;
+ if (!fInited)
+ {
+ const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS);
+
+ fSupported = ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object")
+ || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object"))
+ && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two");
+ fInited = GL_TRUE;
+ }
+ return fSupported;
+}
+
+static void crServerCreateMuralFBO(CRMuralInfo *mural);
+
+void crServerRedirMuralFbClear(CRMuralInfo *mural)
+{
+ uint32_t i;
+ for (i = 0; i < mural->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = mural->apUsedFBDatas[i];
+ int rc = CrFbUpdateBegin(pData->hFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false);
+ CrFbUpdateEnd(pData->hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ }
+ mural->cUsedFBDatas = 0;
+
+ for (i = 0; i < (uint32_t)cr_server.screenCount; ++i)
+ {
+ GLuint j;
+ CR_FBDATA *pData = &mural->aFBDatas[i];
+ if (!pData->hFb)
+ continue;
+
+ if (pData->hFbEntry != NULL)
+ {
+ CrFbEntryRelease(pData->hFb, pData->hFbEntry);
+ pData->hFbEntry = NULL;
+ }
+
+ /* Release all valid texture data structures in the array.
+ * Do not rely on mural->cBuffers because it might be already
+ * set to zero in crServerDeleteMuralFBO.
+ */
+ for (j = 0; j < RT_ELEMENTS(pData->apTexDatas); ++j)
+ {
+ if (pData->apTexDatas[j] != NULL)
+ {
+ CrTdRelease(pData->apTexDatas[j]);
+ pData->apTexDatas[j] = NULL;
+ }
+ }
+
+ pData->hFb = NULL;
+ }
+}
+
+static int crServerRedirMuralDbSyncFb(CRMuralInfo *mural, HCR_FRAMEBUFFER hFb, CR_FBDATA **ppData)
+{
+ CR_FBDATA *pData;
+ const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(hFb);
+ const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb);
+ RTRECT FbRect = *CrVrScrCompositorRectGet(pCompositor);
+ RTRECT DefaultRegionsRect;
+ const RTRECT * pRegions;
+ uint32_t cRegions;
+ RTPOINT Pos;
+ RTRECT MuralRect;
+ int rc;
+
+ CRASSERT(mural->fRedirected);
+
+ *ppData = NULL;
+
+ if (!mural->bVisible)
+ return VINF_SUCCESS;
+
+ MuralRect.xLeft = mural->gX;
+ MuralRect.yTop = mural->gY;
+ MuralRect.xRight = MuralRect.xLeft + mural->width;
+ MuralRect.yBottom = MuralRect.yTop + mural->height;
+
+ Pos.x = mural->gX - pScreenInfo->i32OriginX;
+ Pos.y = mural->gY - pScreenInfo->i32OriginY;
+
+ VBoxRectTranslate(&FbRect, pScreenInfo->i32OriginX, pScreenInfo->i32OriginY);
+
+ VBoxRectIntersect(&FbRect, &MuralRect);
+
+ if (VBoxRectIsZero(&FbRect))
+ return VINF_SUCCESS;
+
+ if (mural->bReceivedRects)
+ {
+ pRegions = (const RTRECT*)mural->pVisibleRects;
+ cRegions = mural->cVisibleRects;
+ }
+ else
+ {
+ DefaultRegionsRect.xLeft = 0;
+ DefaultRegionsRect.yTop = 0;
+ DefaultRegionsRect.xRight = mural->width;
+ DefaultRegionsRect.yBottom = mural->height;
+ pRegions = &DefaultRegionsRect;
+ cRegions = 1;
+ }
+
+ if (!cRegions)
+ return VINF_SUCCESS;
+
+ pData = &mural->aFBDatas[pScreenInfo->u32ViewIndex];
+
+ if (!pData->hFb)
+ {
+ /* Guard against modulo-by-zero when calling CrFbEntryCreateForTexData
+ below. Observed when failing to load atig6pxx.dll and similar. */
+ if (RT_UNLIKELY(mural->cBuffers == 0))
+ {
+ WARN(("crServerRedirMuralDbSyncFb: cBuffers == 0 (crServerSupportRedirMuralFBO=%d)", crServerSupportRedirMuralFBO()));
+ return VERR_NOT_SUPPORTED;
+ }
+
+ pData->hFb = hFb;
+
+ RT_ZERO(pData->apTexDatas);
+ for (uint32_t i = 0; i < mural->cBuffers; ++i)
+ {
+ VBOXVR_TEXTURE Tex;
+ Tex.width = mural->width;
+ Tex.height = mural->height;
+ Tex.hwid = mural->aidColorTexs[i];
+ Tex.target = GL_TEXTURE_2D;
+
+ pData->apTexDatas[i] = CrFbTexDataCreate(&Tex);
+ }
+
+ rc = CrFbEntryCreateForTexData(hFb, pData->apTexDatas[CR_SERVER_FBO_FB_IDX(mural)], 0, &pData->hFbEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryCreateForTexData failed rc %d", rc));
+ }
+ }
+ else
+ {
+ CRASSERT(pData->hFb == hFb);
+ }
+
+ rc = CrFbUpdateBegin(hFb);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ return rc;
+ }
+
+ rc = CrFbEntryRegionsSet(hFb, pData->hFbEntry, &Pos, cRegions, pRegions, true);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbEntryRegionsSet failed rc %d", rc));
+ }
+
+ CrFbUpdateEnd(hFb);
+
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry = CrFbEntryGetCompositorEntry(pData->hFbEntry);
+ if (CrVrScrCompositorEntryIsUsed(pCEntry))
+ *ppData = pData;
+
+ return rc;
+}
+
+static void crServerRedirMuralFbSync(CRMuralInfo *mural)
+{
+ uint32_t i;
+ uint32_t cUsedFBs = 0;
+ HCR_FRAMEBUFFER ahUsedFbs[CR_MAX_GUEST_MONITORS];
+ HCR_FRAMEBUFFER hFb;
+
+ for (i = 0; i < mural->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = mural->apUsedFBDatas[i];
+ int rc = CrFbUpdateBegin(pData->hFb);
+ if (RT_SUCCESS(rc))
+ {
+ ahUsedFbs[cUsedFBs] = pData->hFb;
+ CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false);
+ ++cUsedFBs;
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ }
+ mural->cUsedFBDatas = 0;
+
+ if (!mural->width
+ || !mural->height
+ || !mural->bVisible
+ )
+ goto end;
+
+ CRASSERT(mural->fRedirected);
+
+ for (hFb = CrPMgrFbGetFirstEnabled();
+ hFb;
+ hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ CR_FBDATA *pData = NULL;
+ int rc = crServerRedirMuralDbSyncFb(mural, hFb, &pData);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crServerRedirMuralDbSyncFb failed %d", rc));
+ continue;
+ }
+
+ if (!pData)
+ continue;
+
+ mural->apUsedFBDatas[mural->cUsedFBDatas] = pData;
+ ++mural->cUsedFBDatas;
+ }
+
+end:
+
+ for (i = 0; i < cUsedFBs; ++i)
+ {
+ CrFbUpdateEnd(ahUsedFbs[i]);
+ }
+}
+
+static void crVBoxServerMuralFbCleanCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+ HCR_FRAMEBUFFER hFb = (HCR_FRAMEBUFFER)data2;
+ uint32_t i;
+ for (i = 0; i < pMI->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = pMI->apUsedFBDatas[i];
+ if (hFb != pData->hFb)
+ continue;
+
+ CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false);
+ break;
+ }
+}
+
+static void crVBoxServerMuralFbSetCB(unsigned long key, void *data1, void *data2)
+{
+ CRMuralInfo *pMI = (CRMuralInfo*) data1;
+ HCR_FRAMEBUFFER hFb = (HCR_FRAMEBUFFER)data2;
+ uint32_t i;
+ CR_FBDATA *pData = NULL;
+ bool fFbWasUsed = false;
+
+ Assert(hFb);
+
+ if (!pMI->fRedirected)
+ {
+ Assert(!pMI->cUsedFBDatas);
+ return;
+ }
+
+ for (i = 0; i < pMI->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = pMI->apUsedFBDatas[i];
+ if (hFb != pData->hFb)
+ continue;
+
+ fFbWasUsed = true;
+ break;
+ }
+
+ if (CrFbIsEnabled(hFb))
+ {
+ int rc = crServerRedirMuralDbSyncFb(pMI, hFb, &pData);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("crServerRedirMuralDbSyncFb failed %d", rc));
+ pData = NULL;
+ }
+ }
+
+ if (pData)
+ {
+ if (!fFbWasUsed)
+ {
+ uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex;
+ for (i = 0; i < pMI->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = pMI->apUsedFBDatas[i];
+ uint32_t idCurScreen = CrFbGetScreenInfo(pData->hFb)->u32ViewIndex;
+ if (idCurScreen > idScreen)
+ break;
+
+ Assert(idCurScreen != idScreen);
+ }
+
+ for (uint32_t j = pMI->cUsedFBDatas; j > i; --j)
+ {
+ pMI->apUsedFBDatas[j] = pMI->apUsedFBDatas[j-1];
+ }
+
+ pMI->apUsedFBDatas[i] = pData;
+ ++pMI->cUsedFBDatas;
+ }
+ /* else - nothing to do */
+ }
+ else
+ {
+ if (fFbWasUsed)
+ {
+ for (uint32_t j = i; j < pMI->cUsedFBDatas - 1; ++j)
+ {
+ pMI->apUsedFBDatas[j] = pMI->apUsedFBDatas[j+1];
+ }
+ --pMI->cUsedFBDatas;
+ }
+ /* else - nothing to do */
+ }
+}
+
+void crVBoxServerMuralFbResizeEnd(HCR_FRAMEBUFFER hFb)
+{
+ crHashtableWalk(cr_server.muralTable, crVBoxServerMuralFbSetCB, hFb);
+}
+
+void crVBoxServerMuralFbResizeBegin(HCR_FRAMEBUFFER hFb)
+{
+ crHashtableWalk(cr_server.muralTable, crVBoxServerMuralFbCleanCB, hFb);
+}
+
+DECLEXPORT(int) crVBoxServerNotifyResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM)
+{
+ if (cr_server.fCrCmdEnabled)
+ {
+ WARN(("crVBoxServerNotifyResize for enabled CrCmd"));
+ return VERR_INVALID_STATE;
+ }
+
+ if (pScreen->u32ViewIndex >= (uint32_t)cr_server.screenCount)
+ {
+ WARN(("invalid view index"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ VBOXCMDVBVA_SCREENMAP_DECL(uint32_t, aTargetMap);
+
+ memset(aTargetMap, 0, sizeof (aTargetMap));
+
+ ASMBitSet(aTargetMap, pScreen->u32ViewIndex);
+
+ int rc = CrPMgrResize(pScreen, pvVRAM, aTargetMap);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("err"));
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+void crServerRedirMuralFBO(CRMuralInfo *mural, bool fEnabled)
+{
+ if (!mural->fRedirected == !fEnabled)
+ {
+ return;
+ }
+
+ if (!mural->CreateInfo.externalID)
+ {
+ WARN(("trying to change redir setting for internal mural %d", mural->spuWindow));
+ return;
+ }
+
+ if (fEnabled)
+ {
+ if (!crServerSupportRedirMuralFBO())
+ {
+ WARN(("FBO not supported, can't redirect window output"));
+ return;
+ }
+
+ if (mural->aidFBOs[0]==0)
+ {
+ crServerCreateMuralFBO(mural);
+ }
+
+ if (cr_server.curClient && cr_server.curClient->currentMural == mural)
+ {
+ if (!crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
+ }
+ if (!crStateGetCurrent()->framebufferobject.readFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ }
+
+ crStateGetCurrent()->buffer.width = 0;
+ crStateGetCurrent()->buffer.height = 0;
+ }
+ }
+ else
+ {
+ if (cr_server.curClient && cr_server.curClient->currentMural == mural)
+ {
+ if (!crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
+ }
+ if (!crStateGetCurrent()->framebufferobject.readFB)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0);
+ }
+
+ crStateGetCurrent()->buffer.width = mural->width;
+ crStateGetCurrent()->buffer.height = mural->height;
+ }
+ }
+
+ mural->fRedirected = !!fEnabled;
+}
+
+static void crServerCreateMuralFBO(CRMuralInfo *mural)
+{
+ CRContext *ctx = crStateGetCurrent();
+ GLuint uid, i;
+ GLenum status;
+ SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table;
+ CRContextInfo *pMuralContextInfo;
+
+ CRASSERT(mural->aidFBOs[0]==0);
+ CRASSERT(mural->aidFBOs[1]==0);
+
+ pMuralContextInfo = cr_server.currentCtxInfo;
+ if (!pMuralContextInfo)
+ {
+ /* happens on saved state load */
+ CRASSERT(cr_server.MainContextInfo.SpuContext);
+ pMuralContextInfo = &cr_server.MainContextInfo;
+ cr_server.head_spu->dispatch_table.MakeCurrent(mural->spuWindow, 0, cr_server.MainContextInfo.SpuContext);
+ }
+
+ if (pMuralContextInfo->CreateInfo.realVisualBits != mural->CreateInfo.realVisualBits)
+ {
+ WARN(("mural visual bits do not match with current context visual bits!"));
+ }
+
+ mural->cBuffers = 2;
+ mural->iBbBuffer = 0;
+ /*Color texture*/
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ }
+
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ gl->GenTextures(1, &mural->aidColorTexs[i]);
+ gl->BindTexture(GL_TEXTURE_2D, mural->aidColorTexs[i]);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height,
+ 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ }
+
+ /* Depth & Stencil. */
+ gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB);
+ gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
+ gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT,
+ mural->width, mural->height);
+
+ /*FBO*/
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ gl->GenFramebuffersEXT(1, &mural->aidFBOs[i]);
+ gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->aidFBOs[i]);
+
+ gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, mural->aidColorTexs[i], 0);
+ gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
+ gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, mural->idDepthStencilRB);
+
+ status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ if (status!=GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ WARN(("FBO status(0x%x) isn't complete", status));
+ }
+ }
+
+ mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
+ mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
+
+ mural->fboWidth = mural->width;
+ mural->fboHeight = mural->height;
+
+ mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer);
+ mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer);
+
+ /*Restore gl state*/
+ uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid;
+ gl->BindTexture(GL_TEXTURE_2D, uid);
+
+ uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0;
+ gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, uid);
+
+ uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0;
+ gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, uid);
+
+ uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0;
+ gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER, uid);
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid);
+ }
+
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid);
+ }
+ else
+ {
+ gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ }
+
+ CRASSERT(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
+}
+
+void crServerDeleteMuralFBO(CRMuralInfo *mural)
+{
+ if (mural->aidFBOs[0]!=0)
+ {
+ GLuint i;
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->aidColorTexs[i]);
+ mural->aidColorTexs[i] = 0;
+ }
+
+ cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB);
+ mural->idDepthStencilRB = 0;
+
+ for (i = 0; i < mural->cBuffers; ++i)
+ {
+ cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->aidFBOs[i]);
+ mural->aidFBOs[i] = 0;
+ }
+ }
+
+ mural->cBuffers = 0;
+}
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect)
+{
+ CRASSERT(a && b && rect);
+
+ rect->x1 = MAX(a->x1, b->x1);
+ rect->x2 = MIN(a->x2, b->x2);
+ rect->y1 = MAX(a->y1, b->y1);
+ rect->y2 = MIN(a->y2, b->y2);
+
+ return (rect->x2>rect->x1) && (rect->y2>rect->y1);
+}
+
+DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable)
+{
+}
+
+DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot)
+{
+ if (pScreenshot->fDataAllocated)
+ {
+ RTMemFree(pScreenshot->Img.pvData);
+ pScreenshot->fDataAllocated = 0;
+ }
+}
+
+DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, uint32_t width, uint32_t height, uint32_t pitch, void *pvBuffer, CR_SCREENSHOT *pScreenshot)
+{
+ HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabledForScreen(u32Screen);
+ if (!hFb)
+ return VERR_INVALID_STATE;
+
+ const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb);
+
+ if (!width)
+ width = pScreen->u32Width;
+ if (!height)
+ height = pScreen->u32Height;
+ if (!pitch)
+ pitch = pScreen->u32LineSize;
+
+ if (CrFbHas3DData(hFb)
+ || pScreen->u32Width != width
+ || pScreen->u32Height != height
+ || pScreen->u32LineSize != pitch
+ || pScreen->u16BitsPerPixel != 32)
+ {
+ RTRECTSIZE SrcRectSize;
+ RTRECT DstRect;
+
+ pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+ if (!pvBuffer)
+ {
+ pScreenshot->Img.pvData = RTMemAlloc(pScreenshot->Img.cbData);
+ if (!pScreenshot->Img.pvData)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+ pScreenshot->fDataAllocated = 1;
+ }
+ else
+ {
+ pScreenshot->Img.pvData = pvBuffer;
+ pScreenshot->fDataAllocated = 0;
+ }
+
+ pScreenshot->Img.enmFormat = GL_BGRA;
+ pScreenshot->Img.width = width;
+ pScreenshot->Img.height = height;
+ pScreenshot->Img.bpp = 32;
+ pScreenshot->Img.pitch = pitch;
+ SrcRectSize.cx = pScreen->u32Width;
+ SrcRectSize.cy = pScreen->u32Height;
+ DstRect.xLeft = 0;
+ DstRect.yTop = 0;
+ DstRect.xRight = width;
+ DstRect.yBottom = height;
+ int rc = CrFbBltGetContentsEx(hFb, &SrcRectSize, &DstRect, 1, &DstRect, &pScreenshot->Img);
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("CrFbBltGetContents failed %d", rc));
+ crServerVBoxScreenshotRelease(pScreenshot);
+ return rc;
+ }
+ }
+ else
+ {
+ pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height;
+ if (!pvBuffer)
+ pScreenshot->Img.pvData = CrFbGetVRAM(hFb);
+ else
+ {
+ pScreenshot->Img.pvData = pvBuffer;
+ memcpy(pvBuffer, CrFbGetVRAM(hFb), pScreenshot->Img.cbData);
+ }
+ pScreenshot->Img.enmFormat = GL_BGRA;
+ pScreenshot->Img.width = pScreen->u32Width;
+ pScreenshot->Img.height = pScreen->u32Height;
+ pScreenshot->Img.bpp = pScreen->u16BitsPerPixel;
+ pScreenshot->Img.pitch = pScreen->u32LineSize;
+
+ pScreenshot->fDataAllocated = 0;
+ }
+
+ pScreenshot->u32Screen = u32Screen;
+
+ return VINF_SUCCESS;
+}
+
+extern DECLEXPORT(int) crServerVBoxWindowsShow(bool fShow)
+{
+ return CrPMgrModeWinVisible(fShow);
+}
+
+void crServerPresentFBO(CRMuralInfo *mural)
+{
+ uint32_t i;
+ for (i = 0; i < mural->cUsedFBDatas; ++i)
+ {
+ CR_FBDATA *pData = mural->apUsedFBDatas[i];
+ int rc = CrFbUpdateBegin(pData->hFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbEntryTexDataUpdate(pData->hFb, pData->hFbEntry, pData->apTexDatas[CR_SERVER_FBO_FB_IDX(mural)]);
+ CrFbUpdateEnd(pData->hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed rc %d", rc));
+ }
+}
+
+GLboolean crServerIsRedirectedToFBO()
+{
+#ifdef DEBUG_misha
+ Assert(cr_server.curClient);
+ if (cr_server.curClient)
+ {
+ Assert(cr_server.curClient->currentMural == cr_server.currentMural);
+ Assert(cr_server.curClient->currentCtxInfo == cr_server.currentCtxInfo);
+ }
+#endif
+ return cr_server.curClient
+ && cr_server.curClient->currentMural
+ && cr_server.curClient->currentMural->fRedirected;
+}
+
+GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer)
+{
+ switch (buffer)
+ {
+ case GL_FRONT:
+ case GL_FRONT_LEFT:
+ case GL_FRONT_RIGHT:
+ return CR_SERVER_FBO_FB_IDX(mural);
+ case GL_BACK:
+ case GL_BACK_LEFT:
+ case GL_BACK_RIGHT:
+ return CR_SERVER_FBO_BB_IDX(mural);
+ case GL_NONE:
+ case GL_AUX0:
+ case GL_AUX1:
+ case GL_AUX2:
+ case GL_AUX3:
+ case GL_LEFT:
+ case GL_RIGHT:
+ case GL_FRONT_AND_BACK:
+ return -1;
+ default:
+ WARN(("crServerMuralFBOIdxFromBufferName: invalid buffer passed 0x%x", buffer));
+ return -2;
+ }
+}
+
+void crServerMuralFBOSwapBuffers(CRMuralInfo *mural)
+{
+ CRContext *ctx = crStateGetCurrent();
+ GLuint iOldCurDrawBuffer = mural->iCurDrawBuffer;
+ GLuint iOldCurReadBuffer = mural->iCurReadBuffer;
+ mural->iBbBuffer = ((mural->iBbBuffer + 1) % (mural->cBuffers));
+ if (mural->iCurDrawBuffer >= 0)
+ mural->iCurDrawBuffer = ((mural->iCurDrawBuffer + 1) % (mural->cBuffers));
+ if (mural->iCurReadBuffer >= 0)
+ mural->iCurReadBuffer = ((mural->iCurReadBuffer + 1) % (mural->cBuffers));
+ Assert(iOldCurDrawBuffer != mural->iCurDrawBuffer || mural->cBuffers == 1 || mural->iCurDrawBuffer < 0);
+ Assert(iOldCurReadBuffer != mural->iCurReadBuffer || mural->cBuffers == 1 || mural->iCurReadBuffer < 0);
+ if (!ctx->framebufferobject.drawFB && iOldCurDrawBuffer != mural->iCurDrawBuffer)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer));
+ }
+ if (!ctx->framebufferobject.readFB && iOldCurReadBuffer != mural->iCurReadBuffer)
+ {
+ cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer));
+ }
+ Assert(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]);
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_occlude.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_occlude.c
new file mode 100644
index 00000000..6d479369
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_occlude.c
@@ -0,0 +1,37 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchGenQueriesARB(GLsizei n, GLuint *queries)
+{
+ GLuint *local_queries;
+ (void) queries;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchGenQueriesARB: parameter 'n' is out of range");
+ return;
+ }
+
+ local_queries = (GLuint *)crCalloc(n * sizeof(*local_queries));
+
+ if (!local_queries)
+ {
+ crError("crServerDispatchGenQueriesARB: out of memory");
+ return;
+ }
+
+ cr_server.head_spu->dispatch_table.GenQueriesARB( n, local_queries );
+
+ crServerReturnValue( local_queries, n * sizeof(*local_queries) );
+ crFree( local_queries );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_papi.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_papi.c
new file mode 100644
index 00000000..84a4e3e6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_papi.c
@@ -0,0 +1,272 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "state/cr_statetypes.h"
+
+#define DEBUG_BARRIERS 1
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBarrierCreateCR( GLuint name, GLuint count )
+{
+ CRServerBarrier *barrier;
+#if DEBUG_BARRIERS
+ char debug_buf[4096];
+#endif
+
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.BarrierCreateCR( name, count );
+ return;
+ }
+
+ barrier = (CRServerBarrier *) crHashtableSearch( cr_server.barriers, name );
+
+#if DEBUG_BARRIERS
+ sprintf( debug_buf, "BarrierCreateCR( %d, %d )", name, count );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+#endif
+ if (count == 0)
+ {
+ count = cr_server.numClients;
+#if DEBUG_BARRIERS
+ sprintf( debug_buf, "changing count to %d", count );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+#endif
+ }
+
+
+ /* we use maxBarrierCount in Clear() and SwapBuffers() and also use it
+ * in __getNextClient() for deadlock detection. The issue is that all
+ * the existing clients may be blocked, but we might soon get another
+ * client connection to break the apparent deadlock.
+ */
+ if (count > cr_server.maxBarrierCount)
+ cr_server.maxBarrierCount = count;
+
+ if ( barrier == NULL )
+ {
+ barrier = (CRServerBarrier *) crAlloc( sizeof(*barrier) );
+ barrier->count = count;
+ barrier->num_waiting = 0;
+ barrier->waiting = (RunQueue **)
+ crAlloc( count * sizeof(*(barrier->waiting)) );
+
+ crHashtableAdd( cr_server.barriers, name, barrier );
+#if DEBUG_BARRIERS
+ sprintf( debug_buf, "This was a new barrier!" );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+#endif
+ }
+ else
+ {
+ /* HACK -- this allows everybody to create a barrier, and all
+ but the first creation are ignored, assuming the count
+ match. */
+#if DEBUG_BARRIERS
+ sprintf( debug_buf, "I already knew about this barrier." );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+#endif
+ if ( barrier->count != count )
+ {
+#if DEBUG_BARRIERS
+ sprintf( debug_buf, "And someone messed up the count!." );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+#endif
+ crError( "Barrier name=%u created with count=%u, but already "
+ "exists with count=%u", name, count, barrier->count );
+ }
+ }
+
+ if (cr_server.debug_barriers)
+ crDebug("crserver: BarrierCreate(id=%d, count=%d)", name, barrier->count);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBarrierDestroyCR( GLuint name )
+{
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.BarrierDestroyCR( name );
+ return;
+ }
+
+ crError( "NO BARRIER DESTROY FOR YOU! (name=%u)", name );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBarrierExecCR( GLuint name )
+{
+ CRServerBarrier *barrier;
+#if DEBUG_BARRIERS
+ char debug_buf[4096];
+#endif
+
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.BarrierExecCR( name );
+ return;
+ }
+
+ barrier = (CRServerBarrier *) crHashtableSearch( cr_server.barriers, name );
+ if ( barrier == NULL )
+ {
+ crError( "crServerDispatchBarrierExec: No such barrier: %d", name );
+ }
+
+#if DEBUG_BARRIERS
+ sprintf( debug_buf, "BarrierExec( %d )", name );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+ sprintf( debug_buf, "num_waiting = %d", barrier->num_waiting );
+ cr_server.head_spu->dispatch_table.ChromiumParametervCR( GL_PRINT_STRING_CR, GL_UNSIGNED_BYTE, sizeof(debug_buf), debug_buf );
+#endif
+
+ barrier->waiting[barrier->num_waiting++] = cr_server.run_queue;
+
+ cr_server.run_queue->blocked = 1;
+
+ if ( barrier->num_waiting == barrier->count )
+ {
+ GLuint i;
+
+ if (cr_server.debug_barriers)
+ crDebug("crserver: BarrierExec(client=%p, id=%d, num_waiting=%d/%d) - release",
+ cr_server.curClient, name, barrier->num_waiting,
+ barrier->count);
+
+ for ( i = 0; i < barrier->count; i++ )
+ {
+ barrier->waiting[i]->blocked = 0;
+ }
+ barrier->num_waiting = 0;
+ }
+ else if (cr_server.debug_barriers)
+ crDebug("crserver: BarrierExec(client=%p, id=%d, num_waiting=%d/%d) - block",
+ cr_server.curClient, name, barrier->num_waiting,
+ barrier->count);
+
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphoreCreateCR( GLuint name, GLuint count )
+{
+ CRServerSemaphore *sema;
+
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.SemaphoreCreateCR( name, count );
+ return;
+ }
+
+ sema = crHashtableSearch(cr_server.semaphores, name);
+ if (sema)
+ return; /* already created */
+
+ sema = (CRServerSemaphore *) crAlloc( sizeof( *sema ) );
+ crHashtableAdd( cr_server.semaphores, name, sema );
+ sema->count = count;
+ sema->waiting = sema->tail = NULL;
+ if (cr_server.debug_barriers)
+ crDebug("crserver: SemaphoreCreate(id=%d, count=%d)", name, count);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphoreDestroyCR( GLuint name )
+{
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.SemaphoreDestroyCR( name );
+ return;
+ }
+
+ crError( "NO DESTROY FOR YOU! (name=%u)", name );
+}
+
+/* Semaphore wait */
+void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphorePCR( GLuint name )
+{
+ CRServerSemaphore *sema;
+
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.SemaphorePCR( name );
+ return;
+ }
+
+ sema = (CRServerSemaphore *) crHashtableSearch( cr_server.semaphores, name );
+ if (!sema)
+ {
+ crError( "No such semaphore: %d", name );
+ }
+ if (sema->count)
+ {
+ /* go */
+ if (cr_server.debug_barriers)
+ crDebug("crserver: SemaphoreP(client=%p, id=%d, count=%d) decrement to %d",
+ cr_server.curClient, name, sema->count, sema->count - 1);
+ sema->count--;
+ }
+ else
+ {
+ /* block */
+ wqnode *node;
+ if (cr_server.debug_barriers)
+ crDebug("crserver: SemaphoreP(client=%p, id=%d, count=%d) - block.",
+ cr_server.curClient, name, sema->count);
+ cr_server.run_queue->blocked = 1;
+ node = (wqnode *) crAlloc( sizeof( *node ) );
+ node->q = cr_server.run_queue;
+ node->next = NULL;
+ if (sema->tail)
+ {
+ sema->tail->next = node;
+ }
+ else
+ {
+ sema->waiting = node;
+ }
+ sema->tail = node;
+ }
+}
+
+/* Semaphore signal */
+void SERVER_DISPATCH_APIENTRY crServerDispatchSemaphoreVCR( GLuint name )
+{
+ CRServerSemaphore *sema;
+
+ if (cr_server.ignore_papi)
+ {
+ cr_server.head_spu->dispatch_table.SemaphoreVCR( name );
+ return;
+ }
+
+ sema = (CRServerSemaphore *) crHashtableSearch( cr_server.semaphores, name );
+ if (!sema)
+ {
+ crError( "No such semaphore: %d", name );
+ }
+ if (sema->waiting)
+ {
+ wqnode *temp = sema->waiting;
+ if (cr_server.debug_barriers)
+ crDebug("crserver: SemaphoreV(client=%p, id=%d, count=%d) - unblock.",
+ cr_server.curClient, name, sema->count);
+ /* unblock one waiter */
+ temp->q->blocked = 0;
+ sema->waiting = temp->next;
+ crFree( temp );
+ if (!sema->waiting)
+ {
+ sema->tail = NULL;
+ }
+ }
+ else
+ {
+ /* nobody's waiting */
+ if (cr_server.debug_barriers)
+ crDebug("crserver: SemaphoreV(client=%p, id=%d, count=%d) - increment to %d",
+ cr_server.curClient, name, sema->count, sema->count + 1);
+ sema->count++;
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_projmatrix.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_projmatrix.c
new file mode 100644
index 00000000..a4598509
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_projmatrix.c
@@ -0,0 +1,402 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_error.h"
+#include "state/cr_statetypes.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+
+/*
+ * This file provides implementations of the basic OpenGL matrix functions.
+ * We often need to twiddle with their operation in order to make tilesorting
+ * and non-planar projections work.
+ */
+
+
+
+/*
+ * Determine which view and projection matrices to use when in stereo mode.
+ * Return 0 = left eye, 1 = right eye.
+ */
+int crServerGetCurrentEye(void)
+{
+ if (cr_server.currentEye != -1) {
+ /* current eye was specified by tilesort SPU */
+ return cr_server.currentEye;
+ }
+ else {
+ /* we have a quad-buffered window and we're watching glDrawBuffer */
+ GLenum drawBuffer = cr_server.curClient->currentCtxInfo->pContext->buffer.drawBuffer;
+ int eye = drawBuffer == GL_BACK_RIGHT || drawBuffer == GL_FRONT_RIGHT
+ || drawBuffer == GL_RIGHT;
+ return eye;
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchLoadMatrixf( const GLfloat *m )
+{
+ const GLenum matMode = cr_server.curClient->currentCtxInfo->pContext->transform.matrixMode;
+ const CRMuralInfo *mural = cr_server.curClient->currentMural;
+
+ crStateLoadMatrixf( m );
+
+ if (matMode == GL_MODELVIEW && cr_server.viewOverride) {
+ int eye = crServerGetCurrentEye();
+ crServerApplyViewMatrix(&cr_server.viewMatrix[eye]);
+ }
+ else {
+ cr_server.head_spu->dispatch_table.LoadMatrixf( m );
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchLoadMatrixd( const GLdouble *m )
+{
+ const GLenum matMode = cr_server.curClient->currentCtxInfo->pContext->transform.matrixMode;
+ const CRMuralInfo *mural = cr_server.curClient->currentMural;
+
+ crStateLoadMatrixd( m );
+
+ if (matMode == GL_MODELVIEW && cr_server.viewOverride) {
+ int eye = crServerGetCurrentEye();
+ crServerApplyViewMatrix(&cr_server.viewMatrix[eye]);
+ }
+ else {
+ cr_server.head_spu->dispatch_table.LoadMatrixd( m );
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchMultMatrixf( const GLfloat *m )
+{
+ const GLenum matMode = cr_server.curClient->currentCtxInfo->pContext->transform.matrixMode;
+
+ if (matMode == GL_PROJECTION && cr_server.projectionOverride) {
+ /* load the overriding projection matrix */
+ int eye = crServerGetCurrentEye();
+ crStateLoadMatrix( &cr_server.projectionMatrix[eye] );
+ }
+ else {
+ /* the usual case */
+ crStateMultMatrixf( m );
+ cr_server.head_spu->dispatch_table.MultMatrixf( m );
+ }
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchMultMatrixd( const GLdouble *m )
+{
+ const GLenum matMode = cr_server.curClient->currentCtxInfo->pContext->transform.matrixMode;
+
+ if (matMode == GL_PROJECTION && cr_server.projectionOverride) {
+ /* load the overriding projection matrix */
+ int eye = crServerGetCurrentEye();
+ crStateLoadMatrix( &cr_server.projectionMatrix[eye] );
+ }
+ else {
+ /* the usual case */
+ crStateMultMatrixd( m );
+ cr_server.head_spu->dispatch_table.MultMatrixd( m );
+ }
+}
+
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchLoadIdentity( void )
+{
+ const GLenum matMode = cr_server.curClient->currentCtxInfo->pContext->transform.matrixMode;
+ const CRMuralInfo *mural = cr_server.curClient->currentMural;
+
+ crStateLoadIdentity();
+
+ if (matMode == GL_MODELVIEW && cr_server.viewOverride) {
+ int eye = crServerGetCurrentEye();
+ crServerApplyViewMatrix(&cr_server.viewMatrix[eye]);
+ }
+ else {
+ cr_server.head_spu->dispatch_table.LoadIdentity( );
+ }
+}
+
+
+
+/*
+ * The following code is used to deal with vertex programs.
+ * Basically, vertex programs might not directly use the usual
+ * OpenGL projection matrix to project vertices from eye coords to
+ * clip coords.
+ *
+ * If you're using Cg then the vertex programs it generates will have
+ * some comments that we can scan to figure out which program parameters
+ * contain the projection matrix.
+ * In this case, look at the Cg program code for a string like
+ * "ModelViewProj". Then set the crserver's 'vertprog_projection_param'
+ * config option to this name.
+ *
+ * If you're not using Cg, you may have to tell Chromium which program
+ * parameters contain the projection matrix.
+ * In this case, look at the OpenGL application's vertex program code to
+ * determine which program parameters contain the projection matrix.
+ * Then set the crserver's 'vertprog_projection_param' config option to
+ * the number of the parameter which holds the first row of the matrix.
+ *
+ * Yup, this is complicated.
+ *
+ */
+
+
+static void matmul(GLfloat r[16], const GLfloat p[16], const GLfloat q[16])
+{
+ GLfloat tmp[16];
+ int i, j, k;
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ GLfloat dot = 0.0;
+ for (k = 0; k < 4; k++) {
+ dot += p[i+4*k] * q[k+4*j];
+ }
+ tmp[i+4*j] = dot;
+ }
+ }
+ for (i = 0; i < 16; i++)
+ r[i] = tmp[i];
+}
+
+
+static CRServerProgram *
+LookupProgram(GLuint id)
+{
+ CRServerProgram *prog = crHashtableSearch(cr_server.programTable, id);
+ if (!prog) {
+ prog = (CRServerProgram *) crAlloc(sizeof(CRServerProgram));
+ if (!prog)
+ return NULL;
+ prog->id = id;
+ prog->projParamStart = cr_server.vpProjectionMatrixParameter;
+ crHashtableAdd(cr_server.programTable, id, prog);
+ }
+ return prog;
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchProgramLocalParameter4fARB(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+#if 0
+ if (target == GL_VERTEX_PROGRAM_ARB) {
+ CRServerProgram *prog = LookupProgram(cr_server.currentProgram);
+
+ if (prog && prog->projParamStart != -1) {
+ if (index >= (GLuint) prog->projParamStart && index <= (GLuint) prog->projParamStart + 3) {
+ /* save the parameters as rows in the matrix */
+ const int i = index - prog->projParamStart;
+ prog->projMat[4*0+i] = x;
+ prog->projMat[4*1+i] = y;
+ prog->projMat[4*2+i] = z;
+ prog->projMat[4*3+i] = w;
+ }
+
+ /* When we get the 4th row (row==3) of the projection matrix we can
+ * then pre-multiply it by the base matrix and update the program
+ * parameters with the new matrix.
+ */
+ if (index == (GLuint) (prog->projParamStart + 3)) {
+ const CRMuralInfo *mural = cr_server.curClient->currentMural;
+ const GLfloat *baseMat = (const GLfloat *) &(mural->extents[mural->curExtent].baseProjection);
+ int i;
+ GLfloat mat[16];
+
+ /* pre-mult the projection matrix by the base projection */
+ matmul(mat, baseMat, prog->projMat);
+ /* update the program parameters with the new matrix */
+ for (i = 0; i < 4; i++) {
+ cr_server.head_spu->dispatch_table.ProgramLocalParameter4fARB(target, index + i - 3, mat[4*0+i], mat[4*1+i], mat[4*2+i], mat[4*3+i]);
+ }
+ return; /* done */
+ }
+ }
+ }
+#endif
+
+ /* if we get here, pass the call through unchanged */
+ cr_server.head_spu->dispatch_table.ProgramLocalParameter4fARB(target, index, x, y, z, w);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchProgramLocalParameter4dARB(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+ crServerDispatchProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchProgramParameter4fNV(GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+#if 0
+ if (target == GL_VERTEX_PROGRAM_NV) {
+ CRServerProgram *prog = LookupProgram(cr_server.currentProgram);
+
+ if (prog && prog->projParamStart != -1) {
+ if (index >= (GLuint) prog->projParamStart && index <= (GLuint) prog->projParamStart + 3) {
+ /* save the parameters as rows in the matrix */
+ const int i = index - prog->projParamStart;
+ prog->projMat[4*0+i] = x;
+ prog->projMat[4*1+i] = y;
+ prog->projMat[4*2+i] = z;
+ prog->projMat[4*3+i] = w;
+ }
+
+ /* When we get the 4th row (row==3) of the projection matrix we can
+ * then pre-multiply it by the base matrix and update the program
+ * parameters with the new matrix.
+ */
+ if (index == (GLuint) (prog->projParamStart + 3)) {
+ const CRMuralInfo *mural = cr_server.curClient->currentMural;
+ const GLfloat *baseMat = (const GLfloat *) &(mural->extents[mural->curExtent].baseProjection);
+ int i;
+ GLfloat mat[16];
+
+ /* pre-mult the projection matrix by the base projection */
+ matmul(mat, baseMat, prog->projMat);
+ /* update the program parameters with the new matrix */
+ for (i = 0; i < 4; i++) {
+ cr_server.head_spu->dispatch_table.ProgramParameter4fNV(target, index + i - 3, mat[4*0+i], mat[4*1+i], mat[4*2+i], mat[4*3+i]);
+ }
+ return; /* done */
+ }
+ }
+ }
+#endif
+
+ /* if we get here, pass the call through unchanged */
+ cr_server.head_spu->dispatch_table.ProgramParameter4fNV(target, index, x, y, z, w);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchProgramParameter4dNV(GLenum target, GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+ crServerDispatchProgramParameter4fNV(target, index, (GLfloat) x, (GLfloat) y, (GLfloat) z, (GLfloat) w);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchProgramStringARB(GLenum target, GLenum format, GLsizei len, const GLvoid *string)
+{
+ if (target == GL_VERTEX_PROGRAM_ARB &&
+ cr_server.vpProjectionMatrixVariable != NULL) {
+ /* scan the program string looking for 'vertprog_projection'
+ * If the program was generated by Cg, the info we want will look
+ * something like this:
+ * #var float4x4 ModelViewProj : : c[0], 4 : 1 : 1
+ */
+ CRServerProgram *prog = LookupProgram(cr_server.currentProgram);
+ CRASSERT(prog);
+ if (prog) {
+ const char *varPos, *paramPos;
+ varPos = crStrstr((const char *) string, cr_server.vpProjectionMatrixVariable);
+ if (varPos) {
+ paramPos = crStrstr(varPos, "c[");
+ if (paramPos) {
+ char number[10];
+ int i = 0;
+ paramPos += 2; /* skip "c[" */
+ while (crIsDigit(paramPos[i])) {
+ number[i] = paramPos[i];
+ i++;
+ }
+ number[i] = 0;
+ prog->projParamStart = crStrToInt(number);
+ }
+ }
+ else {
+ crWarning("Didn't find %s parameter in vertex program string",
+ cr_server.vpProjectionMatrixVariable);
+ }
+ }
+ }
+
+ /* pass through */
+ crStateProgramStringARB(target, format, len, string);
+ cr_server.head_spu->dispatch_table.ProgramStringARB(target, format, len, string);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchLoadProgramNV(GLenum target, GLuint id, GLsizei len, const GLubyte *string)
+{
+ if (target == GL_VERTEX_PROGRAM_NV &&
+ cr_server.vpProjectionMatrixVariable != NULL) {
+ /* scan the program string looking for 'vertprog_projection'
+ * If the program was generated by Cg, the info we want will look
+ * something like this:
+ * #var float4x4 ModelViewProj : : c[0], 4 : 1 : 1
+ */
+ CRServerProgram *prog = LookupProgram(id);
+ CRASSERT(prog);
+ if (prog) {
+ const char *varPos, *paramPos;
+ varPos = crStrstr((const char *) string, cr_server.vpProjectionMatrixVariable);
+ if (varPos) {
+ paramPos = crStrstr(varPos, "c[");
+ if (paramPos) {
+ char number[10];
+ int i = 0;
+ paramPos += 2; /* skip "c[" */
+ while (crIsDigit(paramPos[i])) {
+ number[i] = paramPos[i];
+ i++;
+ }
+ number[i] = 0;
+ prog->projParamStart = crStrToInt(number);
+ }
+ }
+ else {
+ crWarning("Didn't find %s parameter in vertex program string",
+ cr_server.vpProjectionMatrixVariable);
+ }
+ }
+ }
+
+ /* pass through */
+ crStateLoadProgramNV(target, id, len, string);
+ cr_server.head_spu->dispatch_table.LoadProgramNV(target, id, len, string);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchBindProgramARB(GLenum target, GLuint id)
+{
+ id = crServerTranslateProgramID(id);
+
+ if (target == GL_VERTEX_PROGRAM_ARB) {
+ CRServerProgram *prog = LookupProgram(id);
+ (void) prog;
+ cr_server.currentProgram = id;
+ }
+
+ /* pass through */
+ crStateBindProgramARB(target, id);
+ cr_server.head_spu->dispatch_table.BindProgramARB(target, id);
+}
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchBindProgramNV(GLenum target, GLuint id)
+{
+ if (target == GL_VERTEX_PROGRAM_NV) {
+ CRServerProgram *prog = LookupProgram(id);
+ (void) prog;
+ cr_server.currentProgram = id;
+ }
+ /* pass through */
+ crStateBindProgramNV(target, id);
+ cr_server.head_spu->dispatch_table.BindProgramNV(target, id);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_readpixels.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_readpixels.c
new file mode 100644
index 00000000..b53ab02b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_readpixels.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "cr_pixeldata.h"
+#include "cr_unpack.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLvoid *pixels)
+{
+ const GLint stride = READ_DATA( 24, GLint );
+ const GLint alignment = READ_DATA( 28, GLint );
+ const GLint skipRows = READ_DATA( 32, GLint );
+ const GLint skipPixels = READ_DATA( 36, GLint );
+ const GLint bytes_per_row = READ_DATA( 40, GLint );
+ const GLint rowLength = READ_DATA( 44, GLint );
+
+ CRASSERT(bytes_per_row > 0);
+
+#ifdef CR_ARB_pixel_buffer_object
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ GLvoid *pbo_offset;
+
+ /*pixels are actually a pointer to location of 8byte network pointer in hgcm buffer
+ regardless of guest/host bitness we're using only 4lower bytes as there're no
+ pbo>4gb (yet?)
+ */
+ pbo_offset = (GLvoid*) ((uintptr_t) *((GLint*)pixels));
+
+ cr_server.head_spu->dispatch_table.ReadPixels(x, y, width, height,
+ format, type, pbo_offset);
+ }
+ else
+#endif
+ {
+ CRMessageReadPixels *rp;
+ uint32_t msg_len;
+
+ if (bytes_per_row <= 0 || height <= 0 || bytes_per_row > INT32_MAX / height)
+ {
+ crError("crServerDispatchReadPixels: parameters out of range");
+ return;
+ }
+
+ msg_len = sizeof(*rp) + (uint32_t)bytes_per_row * height;
+
+ rp = (CRMessageReadPixels *) crAlloc( msg_len );
+ if (!rp)
+ {
+ crError("crServerDispatchReadPixels: out of memory");
+ return;
+ }
+
+ /* Note: the ReadPixels data gets densely packed into the buffer
+ * (no skip pixels, skip rows, etc. It's up to the receiver (pack spu,
+ * tilesort spu, etc) to apply the real PixelStore packing parameters.
+ */
+ cr_server.head_spu->dispatch_table.ReadPixels(x, y, width, height,
+ format, type, rp + 1);
+
+ rp->header.type = CR_MESSAGE_READ_PIXELS;
+ rp->width = width;
+ rp->height = height;
+ rp->bytes_per_row = bytes_per_row;
+ rp->stride = stride;
+ rp->format = format;
+ rp->type = type;
+ rp->alignment = alignment;
+ rp->skipRows = skipRows;
+ rp->skipPixels = skipPixels;
+ rp->rowLength = rowLength;
+
+ /* <pixels> points to the 8-byte network pointer */
+ crMemcpy( &rp->pixels, pixels, sizeof(rp->pixels) );
+
+ crNetSend( cr_server.curClient->conn, NULL, rp, msg_len );
+ crFree( rp );
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py
new file mode 100755
index 00000000..421f3e8d
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py
@@ -0,0 +1,83 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys
+
+import apiutil
+
+
+apiutil.CopyrightC()
+
+print("""
+/* DO NOT EDIT - THIS FILE AUTOMATICALLY GENERATED BY server_retval.py SCRIPT */
+#include "chromium.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+void crServerReturnValue( const void *payload, unsigned int payload_len )
+{
+ if (!cr_server.fProcessingPendedCommands)
+ {
+ CRMessageReadback *rb;
+ int msg_len;
+
+ /* Don't reply to client if we're loading VM snapshot*/
+ if (cr_server.bIsInLoadingState)
+ return;
+
+ if (cr_server.curClient->conn->type == CR_FILE)
+ {
+ return;
+ }
+
+ if (payload_len >= INT32_MAX - sizeof( *rb ))
+ {
+ return;
+ }
+
+ msg_len = sizeof( *rb ) + payload_len;
+ rb = (CRMessageReadback *) crAlloc( msg_len );
+
+ rb->header.type = CR_MESSAGE_READBACK;
+ CRDBGPTR_PRINTRB(cr_server.curClient->conn->u32ClientID, &cr_server.writeback_ptr);
+ CRDBGPTR_CHECKNZ(&cr_server.writeback_ptr);
+ CRDBGPTR_CHECKNZ(&cr_server.return_ptr);
+ crMemcpy( &(rb->writeback_ptr), &(cr_server.writeback_ptr), sizeof( rb->writeback_ptr ) );
+ crMemcpy( &(rb->readback_ptr), &(cr_server.return_ptr), sizeof( rb->readback_ptr ) );
+ crMemcpy( rb+1, payload, payload_len );
+ crNetSend( cr_server.curClient->conn, NULL, rb, msg_len );
+ CRDBGPTR_SETZ(&cr_server.writeback_ptr);
+ CRDBGPTR_SETZ(&cr_server.return_ptr);
+ crFree( rb );
+ return;
+ }
+#ifdef DEBUG_misha
+ WARN(("Pending command returns value"));
+#endif
+ CRDBGPTR_SETZ(&cr_server.writeback_ptr);
+ CRDBGPTR_SETZ(&cr_server.return_ptr);
+}
+""")
+
+keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt")
+
+for func_name in keys:
+ params = apiutil.Parameters(func_name)
+ return_type = apiutil.ReturnType(func_name)
+ if apiutil.FindSpecial( "server", func_name ):
+ continue
+ if "VBox" == apiutil.Category(func_name):
+ continue
+ if return_type != 'void':
+ print('%s SERVER_DISPATCH_APIENTRY crServerDispatch%s(%s)' % ( return_type, func_name, apiutil.MakeDeclarationString(params)))
+ print('{')
+ print('\t%s retval;' % return_type)
+ print('\tretval = cr_server.head_spu->dispatch_table.%s(%s);' % (func_name, apiutil.MakeCallString(params) ))
+ print('\tcrServerReturnValue( &retval, sizeof(retval) );')
+ print('\treturn retval; /* WILL PROBABLY BE IGNORED */')
+ print('}')
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp
new file mode 100644
index 00000000..5569e497
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp
@@ -0,0 +1,755 @@
+/* $Id: server_rpw.cpp $ */
+
+/** @file
+ * VBox crOpenGL: Read Pixels worker
+ */
+
+/*
+ * Copyright (C) 2010-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+#include "server.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_vreg.h"
+#include "render/renderspu.h"
+
+static void crServerRpwWorkerGpuSubmit(PRTLISTNODE pWorkList)
+{
+ CR_SERVER_RPW_ENTRY *pCurEntry;
+ RTListForEach(pWorkList, pCurEntry, CR_SERVER_RPW_ENTRY, WorkerWorkEntry)
+ {
+ cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, CR_SERVER_RPW_ENTRY_TEX(pCurEntry, Worker));
+
+ if (CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pCurEntry))
+ {
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, CR_SERVER_RPW_ENTRY_PBO_CUR(pCurEntry));
+ /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/
+ cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ CR_SERVER_RPW_ENTRY_PBO_FLIP(pCurEntry);
+ }
+ else
+ {
+ void *pvData = crAlloc(4*pCurEntry->Size.cx*pCurEntry->Size.cy);
+ if (pvData)
+ {
+ cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pvData);
+
+ pCurEntry->pfnData(pCurEntry, pvData);
+
+ crFree(pvData);
+ }
+ else
+ {
+ crWarning("crAlloc failed");
+ }
+ }
+
+ cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, 0);
+ }
+}
+
+static void crServerRpwWorkerGpuComplete(PRTLISTNODE pGpuSubmitedList)
+{
+ CR_SERVER_RPW_ENTRY *pCurEntry;
+ RTListForEach(pGpuSubmitedList, pCurEntry, CR_SERVER_RPW_ENTRY, GpuSubmittedEntry)
+ {
+ Assert(CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pCurEntry));
+
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, CR_SERVER_RPW_ENTRY_PBO_COMPLETED(pCurEntry));
+
+ void *pvData = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
+
+ pCurEntry->pfnData(pCurEntry, pvData);
+
+ cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
+
+ cr_server.head_spu->dispatch_table.BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, pCurEntry->Size.cx*pCurEntry->Size.cy*4, 0, GL_STREAM_READ_ARB);
+
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ }
+}
+
+static void crServerRpwWorkerGpuMarkGpuCompletedSubmitedLocked(PRTLISTNODE pGpuSubmitedList, PRTLISTNODE pWorkList)
+{
+ CR_SERVER_RPW_ENTRY *pCurEntry, *pNextEntry;
+ RTListForEachSafe(pGpuSubmitedList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, GpuSubmittedEntry)
+ {
+ CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pCurEntry, Gpu);
+ RTListNodeRemove(&pCurEntry->GpuSubmittedEntry);
+ }
+
+ Assert(RTListIsEmpty(pGpuSubmitedList));
+
+ RTListForEachSafe(pWorkList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, WorkerWorkEntry)
+ {
+ Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pCurEntry, Worker));
+ RTListNodeRemove(&pCurEntry->WorkerWorkEntry);
+ if (CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pCurEntry))
+ {
+ /* PBO mode, put to the GPU submitted queue*/
+ RTListAppend(pGpuSubmitedList, &pCurEntry->GpuSubmittedEntry);
+ CR_SERVER_RPW_ENTRY_TEX_PROMOTE(pCurEntry, Worker, Gpu);
+ }
+ else
+ {
+ /* no PBO, we are already done entry data processing, free it right away */
+ Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pCurEntry, Gpu));
+ CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pCurEntry, Worker);
+ }
+ }
+}
+
+static void crServerRpwWorkerGetWorkLocked(CR_SERVER_RPW *pWorker, PRTLISTNODE pWorkList)
+{
+ CR_SERVER_RPW_ENTRY *pCurEntry, *pNextEntry;
+ RTListForEachSafe(&pWorker->WorkList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, WorkEntry)
+ {
+ RTListNodeRemove(&pCurEntry->WorkEntry);
+ RTListAppend(pWorkList, &pCurEntry->WorkerWorkEntry);
+ CR_SERVER_RPW_ENTRY_TEX_PROMOTE(pCurEntry, Submitted, Worker);
+ }
+}
+
+static DECLCALLBACK(int) crServerRpwWorkerThread(RTTHREAD ThreadSelf, void *pvUser)
+{
+ CR_SERVER_RPW *pWorker = (CR_SERVER_RPW *)pvUser;
+ RTMSINTERVAL cWaitMillis = RT_INDEFINITE_WAIT;
+ RTLISTNODE WorkList, GpuSubmittedList;
+ CR_SERVER_RPW_CTL_TYPE enmCtlType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED;
+ CR_SERVER_RPW_ENTRY *pCtlEntry = NULL;
+ CRMuralInfo *pDummyMural = crServerGetDummyMural(pWorker->ctxVisBits);
+ bool fExit = false;
+ bool fForceComplete = false;
+ bool fNotifyCmdCompleted = false;
+
+ CRASSERT(pDummyMural);
+
+ int rc = RTSemEventSignal(pWorker->Ctl.hCompleteEvent);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTSemEventSignal failed rc %d", rc);
+ return rc;
+ }
+
+ RTListInit(&WorkList);
+ RTListInit(&GpuSubmittedList);
+
+ cr_server.head_spu->dispatch_table.MakeCurrent(pDummyMural->spuWindow, 0, pWorker->ctxId);
+
+ rc = RTCritSectEnter(&pWorker->CritSect);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTCritSectEnter failed, rc %d", rc);
+ goto end;
+ }
+
+ for (;;)
+ {
+ /* the crit sect is locked here */
+
+ if (pWorker->Ctl.enmType != CR_SERVER_RPW_CTL_TYPE_UNDEFINED)
+ {
+ enmCtlType = pWorker->Ctl.enmType;
+ pCtlEntry = pWorker->Ctl.pEntry;
+ pWorker->Ctl.enmType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED;
+ pWorker->Ctl.pEntry = NULL;
+ }
+
+ crServerRpwWorkerGetWorkLocked(pWorker, &WorkList);
+
+ RTCritSectLeave(&pWorker->CritSect);
+
+ if (enmCtlType != CR_SERVER_RPW_CTL_TYPE_UNDEFINED)
+ {
+ switch (enmCtlType)
+ {
+ case CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE:
+ break;
+ case CR_SERVER_RPW_CTL_TYPE_TERM:
+ fExit = true;
+ break;
+ default:
+ crWarning("unexpected CtlType %d", enmCtlType);
+ break;
+ }
+ enmCtlType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED;
+ pCtlEntry = NULL;
+ fNotifyCmdCompleted = true;
+ }
+
+ bool fNewItems = !RTListIsEmpty(&WorkList);
+ bool fCompleted = false;
+
+ if (fNewItems)
+ {
+ crServerRpwWorkerGpuSubmit(&WorkList);
+ }
+
+ if (!RTListIsEmpty(&GpuSubmittedList))
+ {
+ if (fForceComplete || fNewItems)
+ {
+ crServerRpwWorkerGpuComplete(&GpuSubmittedList);
+ fForceComplete = false;
+ fCompleted = true;
+ }
+ }
+
+ rc = RTCritSectEnter(&pWorker->CritSect);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTCritSectEnter failed, rc %d", rc);
+ break;
+ }
+
+ /* fNewGpuItems means new entries arrived. WorkList contains new GPU submitted data
+ * fCompleted means completion was performed, GpuSubmittedList contains old GPU submitted data,
+ * which is now completed and should be released */
+ if (fNewItems || fCompleted)
+ {
+ crServerRpwWorkerGpuMarkGpuCompletedSubmitedLocked(&GpuSubmittedList, &WorkList);
+ }
+
+ if (fExit || !fNewItems)
+ {
+ RTCritSectLeave(&pWorker->CritSect);
+
+ if (fNotifyCmdCompleted)
+ {
+ rc = RTSemEventSignal(pWorker->Ctl.hCompleteEvent);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTSemEventSignal failed rc %d", rc);
+ break;
+ }
+ fNotifyCmdCompleted = false;
+ }
+
+ if (fExit)
+ break;
+
+ if (!RTListIsEmpty(&GpuSubmittedList))
+ cWaitMillis = 17; /* ~60Hz */
+ else
+ cWaitMillis = RT_INDEFINITE_WAIT;
+
+ rc = RTSemEventWait(pWorker->hSubmitEvent, cWaitMillis);
+ if (!RT_SUCCESS(rc) && rc != VERR_TIMEOUT)
+ {
+ crWarning("RTSemEventWait failed, rc %d", rc);
+ break;
+ }
+
+ if (rc == VERR_TIMEOUT)
+ {
+ Assert(!RTListIsEmpty(&GpuSubmittedList));
+ fForceComplete = true;
+ }
+
+ rc = RTCritSectEnter(&pWorker->CritSect);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTCritSectEnter failed, rc %d", rc);
+ break;
+ }
+ }
+ }
+
+end:
+ cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0);
+
+ return rc;
+}
+
+static int crServerRpwCtlNotify(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry)
+{
+ int rc = RTSemEventSignal(pWorker->hSubmitEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventWait(pWorker->Ctl.hCompleteEvent, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ rc = pWorker->Ctl.rc;
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("WdCtl command failed rc %d", rc);
+ }
+ }
+ else
+ {
+ crWarning("RTSemEventWait failed rc %d", rc);
+ }
+ }
+ else
+ {
+ int tmpRc;
+ crWarning("RTSemEventSignal failed rc %d", rc);
+ tmpRc = RTCritSectEnter(&pWorker->CritSect);
+ if (RT_SUCCESS(tmpRc))
+ {
+ pWorker->Ctl.enmType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED;
+ pWorker->Ctl.pEntry = NULL;
+ RTCritSectLeave(&pWorker->CritSect);
+ }
+ else
+ {
+ crWarning("RTSemEventSignal failed tmpRc %d", tmpRc);
+ }
+ }
+
+ return rc;
+}
+
+static int crServerRpwCtl(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_CTL_TYPE enmType, CR_SERVER_RPW_ENTRY *pEntry)
+{
+ int rc = RTCritSectEnter(&pWorker->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ pWorker->Ctl.enmType = enmType;
+ pWorker->Ctl.pEntry = pEntry;
+ RTCritSectLeave(&pWorker->CritSect);
+ }
+ else
+ {
+ crWarning("RTCritSectEnter failed rc %d", rc);
+ return rc;
+ }
+
+ rc = crServerRpwCtlNotify(pWorker, pEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwCtlNotify failed rc %d", rc);
+ return rc;
+ }
+ return VINF_SUCCESS;
+}
+
+int crServerRpwInit(CR_SERVER_RPW *pWorker)
+{
+ int rc;
+
+ memset(pWorker, 0, sizeof (*pWorker));
+
+ RTListInit(&pWorker->WorkList);
+
+ rc = RTCritSectInit(&pWorker->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pWorker->hSubmitEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventCreate(&pWorker->Ctl.hCompleteEvent);
+ if (RT_SUCCESS(rc))
+ {
+ CRASSERT(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ CRASSERT(cr_server.MainContextInfo.SpuContext);
+
+ pWorker->ctxId = cr_server.head_spu->dispatch_table.CreateContext("", cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext);
+ if (pWorker->ctxId)
+ {
+ CRMuralInfo *pDummyMural;
+ pWorker->ctxVisBits = cr_server.MainContextInfo.CreateInfo.realVisualBits;
+ pDummyMural = crServerGetDummyMural(pWorker->ctxVisBits);
+ if (pDummyMural)
+ {
+ /* since CreateContext does not actually create it on some platforms, e.g. on win,
+ * we need to do MakeCurrent to ensure it is created.
+ * There is some black magic in doing that to work around ogl driver bugs
+ * (i.e. we need to switch offscreen rendering off before doing make current) */
+ CR_SERVER_CTX_SWITCH CtxSwitch;
+
+ crServerCtxSwitchPrepare(&CtxSwitch, NULL);
+
+ cr_server.head_spu->dispatch_table.Flush();
+
+ cr_server.head_spu->dispatch_table.MakeCurrent(pDummyMural->spuWindow, 0, pWorker->ctxId);
+
+ if (cr_server.currentCtxInfo)
+ {
+ CRASSERT(cr_server.currentMural);
+ cr_server.head_spu->dispatch_table.MakeCurrent(cr_server.currentMural->spuWindow, 0,
+ cr_server.currentCtxInfo->SpuContext > 0 ? cr_server.currentCtxInfo->SpuContext : cr_server.MainContextInfo.SpuContext);
+ }
+ else
+ cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+
+ crServerCtxSwitchPostprocess(&CtxSwitch);
+
+ rc = RTThreadCreate(&pWorker->hThread, crServerRpwWorkerThread, pWorker, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "CrServerDw");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventWait(pWorker->Ctl.hCompleteEvent, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crWarning("RTSemEventWait failed rc %d", rc);
+ }
+ }
+ else
+ {
+ crWarning("RTThreadCreate failed rc %d", rc);
+ }
+ }
+ else
+ {
+ crWarning("Failed to get dummy mural");
+ rc = VERR_GENERAL_FAILURE;
+ }
+ cr_server.head_spu->dispatch_table.DestroyContext(pWorker->ctxId);
+ }
+ else
+ {
+ crWarning("CreateContext failed rc %d", rc);
+ }
+
+ RTSemEventDestroy(pWorker->Ctl.hCompleteEvent);
+ }
+ else
+ {
+ crWarning("RTSemEventCreate failed rc %d", rc);
+ }
+ RTSemEventDestroy(pWorker->hSubmitEvent);
+ }
+ else
+ {
+ crWarning("RTSemEventCreate failed rc %d", rc);
+ }
+
+ RTCritSectDelete(&pWorker->CritSect);
+ }
+ else
+ {
+ crWarning("RTCritSectInit failed rc %d", rc);
+ }
+
+ return rc;
+}
+
+int crServerRpwEntryResizeCleaned(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height)
+{
+ CRContext *pContext;
+ if (!width || !height)
+ {
+ return VINF_SUCCESS;
+ }
+
+ if (!cr_server.currentCtxInfo)
+ {
+ CRMuralInfo *pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ if (!pDummy)
+ {
+ crWarning("crServerGetDummyMural failed");
+ return VERR_GENERAL_FAILURE;
+ }
+
+
+ crServerPerformMakeCurrent(pDummy, &cr_server.MainContextInfo);
+ }
+
+ Assert(width);
+ Assert(height);
+
+ pContext = cr_server.currentCtxInfo->pContext;
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
+ }
+
+ for (int i = 0; i < 4; ++i)
+ {
+ cr_server.head_spu->dispatch_table.GenTextures(1, &pEntry->aidWorkerTexs[i]);
+
+ cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, pEntry->aidWorkerTexs[i]);
+ cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ cr_server.head_spu->dispatch_table.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
+ 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
+ }
+
+ pEntry->iTexDraw = -pEntry->iTexDraw;
+
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ {
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pContext->bufferobject.unpackBuffer->hwid);
+ }
+
+ if (cr_server.bUsePBOForReadback)
+ {
+ for (int i = 0; i < 2; ++i)
+ {
+ cr_server.head_spu->dispatch_table.GenBuffersARB(1, &pEntry->aidPBOs[i]);
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pEntry->aidPBOs[i]);
+ cr_server.head_spu->dispatch_table.BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, width*height*4, 0, GL_STREAM_READ_ARB);
+ }
+
+ if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB))
+ {
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pContext->bufferobject.packBuffer->hwid);
+ }
+ else
+ {
+ cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ }
+ pEntry->iCurPBO = 0;
+ }
+
+
+ GLuint uid = pContext->texture.unit[pContext->texture.curTextureUnit].currentTexture2D->hwid;
+ cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid);
+
+
+ pEntry->Size.cx = width;
+ pEntry->Size.cy = height;
+
+ crServerRpwEntryDbgVerify(pEntry);
+
+ return VINF_SUCCESS;
+}
+
+int crServerRpwEntryCleanup(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry)
+{
+ if (!pEntry->Size.cx)
+ return VINF_SUCCESS;
+
+ int rc = crServerRpwEntryCancel(pWorker, pEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwEntryCancel failed rc %d", rc);
+ return rc;
+ }
+
+ if (!cr_server.currentCtxInfo)
+ {
+ CRMuralInfo *pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ if (!pDummy)
+ {
+ crWarning("crServerGetDummyMural failed");
+ return VERR_GENERAL_FAILURE;
+ }
+
+
+ crServerPerformMakeCurrent(pDummy, &cr_server.MainContextInfo);
+ }
+
+ cr_server.head_spu->dispatch_table.DeleteTextures(4, pEntry->aidWorkerTexs);
+
+ if (CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pEntry))
+ {
+ cr_server.head_spu->dispatch_table.DeleteBuffersARB(2, pEntry->aidPBOs);
+ memset(pEntry->aidPBOs, 0, sizeof (pEntry->aidPBOs));
+ pEntry->iCurPBO = -1;
+ }
+
+ memset(pEntry->aidWorkerTexs, 0, sizeof (pEntry->aidWorkerTexs));
+ CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Submitted);
+ CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Worker);
+ CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Gpu);
+ pEntry->iTexDraw = -1;
+ pEntry->iTexSubmitted = -2;
+ pEntry->iTexWorker = -3;
+ pEntry->iTexGpu = -4;
+ pEntry->Size.cx = 0;
+ pEntry->Size.cy = 0;
+ return VINF_SUCCESS;
+}
+
+int crServerRpwEntryResize(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height)
+{
+ if (!width || !height)
+ {
+ width = 0;
+ height = 0;
+ }
+
+ if (width == pEntry->Size.cx && width == pEntry->Size.cy)
+ return VINF_SUCCESS;
+
+ int rc = crServerRpwEntryCleanup(pWorker, pEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwEntryCleanup failed rc %d", rc);
+ return rc;
+ }
+
+ rc = crServerRpwEntryResizeCleaned(pWorker, pEntry, width, height);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwEntryResizeCleaned failed rc %d", rc);
+ }
+ return rc;
+}
+
+int crServerRpwEntryInit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height, PFNCR_SERVER_RPW_DATA pfnData)
+{
+ memset(pEntry, 0, sizeof (*pEntry));
+
+ pEntry->iTexDraw = -1;
+ pEntry->iTexSubmitted = -2;
+ pEntry->iTexWorker = -3;
+ pEntry->iTexGpu = -4;
+ pEntry->iCurPBO = -1;
+ pEntry->pfnData = pfnData;
+ int rc = crServerRpwEntryResizeCleaned(pWorker, pEntry, width, height);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwEntryResizeCleaned failed rc %d", rc);
+ return rc;
+ }
+ return VINF_SUCCESS;
+}
+
+int crServerRpwEntrySubmit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry)
+{
+ if (!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw))
+ {
+ crWarning("submitting empty entry, ignoting");
+ Assert(!pEntry->Size.cx);
+ Assert(!pEntry->Size.cy);
+ return VERR_INVALID_PARAMETER;
+ }
+
+ Assert(pEntry->Size.cx);
+ Assert(pEntry->Size.cy);
+
+ int rc = RTCritSectEnter(&pWorker->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ Assert(pWorker->Ctl.enmType == CR_SERVER_RPW_CTL_TYPE_UNDEFINED);
+ if (!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Submitted))
+ {
+ CR_SERVER_RPW_ENTRY_TEX_PROMOTE_KEEPVALID(pEntry, Draw, Submitted);
+ RTListAppend(&pWorker->WorkList, &pEntry->WorkEntry);
+ }
+ else
+ {
+ CR_SERVER_RPW_ENTRY_TEX_XCHG_VALID(pEntry, Draw, Submitted);
+ }
+ RTCritSectLeave(&pWorker->CritSect);
+
+ RTSemEventSignal(pWorker->hSubmitEvent);
+ }
+ else
+ {
+ crWarning("RTCritSectEnter failed rc %d", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int crServerRpwEntryCancelCtl(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, CR_SERVER_RPW_CTL_TYPE enmType)
+{
+ if (CR_SERVER_RPW_CTL_TYPE_TERM == enmType && pEntry)
+ {
+ crWarning("Entry should be null for term request");
+ pEntry = NULL;
+ }
+
+ int rc = RTCritSectEnter(&pWorker->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ if (pEntry)
+ {
+ if (CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Submitted))
+ {
+ CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pEntry, Submitted);
+ RTListNodeRemove(&pEntry->WorkEntry);
+ }
+
+ if (!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Worker) && !CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Gpu))
+ {
+ /* can cancel it wight away */
+ RTCritSectLeave(&pWorker->CritSect);
+ return VINF_SUCCESS;
+ }
+ }
+ else
+ {
+ CR_SERVER_RPW_ENTRY *pCurEntry, *pNextEntry;
+ RTListForEachSafe(&pWorker->WorkList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, WorkEntry)
+ {
+ CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pCurEntry, Submitted);
+ CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pEntry, Submitted);
+ RTListNodeRemove(&pCurEntry->WorkEntry);
+ }
+ }
+ pWorker->Ctl.enmType = enmType;
+ pWorker->Ctl.pEntry = pEntry;
+ RTCritSectLeave(&pWorker->CritSect);
+ }
+ else
+ {
+ crWarning("RTCritSectEnter failed rc %d", rc);
+ return rc;
+ }
+
+ rc = crServerRpwCtlNotify(pWorker, pEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwCtlNotify failed rc %d", rc);
+ }
+ return VINF_SUCCESS;
+}
+
+int crServerRpwEntryWaitComplete(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry)
+{
+ int rc = crServerRpwCtl(pWorker, CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE, pEntry);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwCtl failed rc %d", rc);
+ }
+ return rc;
+}
+
+int crServerRpwEntryCancel(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry)
+{
+ return crServerRpwEntryCancelCtl(pWorker, pEntry, CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE);
+}
+
+static int crServerRpwCtlTerm(CR_SERVER_RPW *pWorker)
+{
+ int rc = crServerRpwEntryCancelCtl(pWorker, NULL, CR_SERVER_RPW_CTL_TYPE_TERM);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwCtl failed rc %d", rc);
+ }
+ return rc;
+}
+
+int crServerRpwTerm(CR_SERVER_RPW *pWorker)
+{
+ int rc = crServerRpwCtlTerm(pWorker);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("crServerRpwCtlTerm failed rc %d", rc);
+ return rc;
+ }
+
+ rc = RTThreadWait(pWorker->hThread, RT_INDEFINITE_WAIT, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTThreadWait failed rc %d", rc);
+ return rc;
+ }
+
+ RTSemEventDestroy(pWorker->Ctl.hCompleteEvent);
+ RTSemEventDestroy(pWorker->hSubmitEvent);
+ RTCritSectDelete(&pWorker->CritSect);
+
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py
new file mode 100755
index 00000000..3ccda91c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py
@@ -0,0 +1,152 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys
+
+import apiutil
+
+
+apiutil.CopyrightC()
+
+print("""#include "cr_spu.h"
+#include "chromium.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+""")
+
+from get_sizes import *;
+
+
+funcs = [ 'GetIntegerv', 'GetFloatv', 'GetDoublev', 'GetBooleanv' ]
+types = [ 'GLint', 'GLfloat', 'GLdouble', 'GLboolean' ]
+
+for index in range(len(funcs)):
+ func_name = funcs[index]
+ params = apiutil.Parameters(func_name)
+ print('void SERVER_DISPATCH_APIENTRY crServerDispatch%s(%s)' % ( func_name, apiutil.MakeDeclarationString(params)))
+ print('{')
+ print('\t%s *get_values;' % types[index])
+ print('\tint tablesize;')
+ print("""
+ #ifdef CR_ARB_texture_compression
+ if (GL_COMPRESSED_TEXTURE_FORMATS_ARB == pname)
+ {
+ GLint numtexfmts = 0;
+ cr_server.head_spu->dispatch_table.GetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, &numtexfmts);
+ tablesize = numtexfmts * sizeof(%s);
+ }
+ else
+ #endif
+ {
+ tablesize = __numValues( pname ) * sizeof(%s);
+ }
+ """ % (types[index], types[index]))
+ print('\t(void) params;')
+ print('\tget_values = (%s *) crAlloc( tablesize );' % types[index])
+ print('\tif (tablesize>0)')
+ print('\tcr_server.head_spu->dispatch_table.%s( pname, get_values );' % func_name)
+ print("""
+ if (GL_TEXTURE_BINDING_1D==pname
+ || GL_TEXTURE_BINDING_2D==pname
+ || GL_TEXTURE_BINDING_3D==pname
+ || GL_TEXTURE_BINDING_RECTANGLE_ARB==pname
+ || GL_TEXTURE_BINDING_CUBE_MAP_ARB==pname)
+ {
+ GLuint texid;
+ CRASSERT(tablesize/sizeof(%s)==1);
+ texid = (GLuint) *get_values;
+ *get_values = (%s) crStateTextureHWIDtoID(texid);
+ }
+ else if (GL_CURRENT_PROGRAM==pname)
+ {
+ GLuint programid;
+ CRASSERT(tablesize/sizeof(%s)==1);
+ programid = (GLuint) *get_values;
+ *get_values = (%s) crStateGLSLProgramHWIDtoID(programid);
+ }
+ else if (GL_FRAMEBUFFER_BINDING_EXT==pname
+ ||GL_READ_FRAMEBUFFER_BINDING==pname)
+ {
+ GLuint fboid;
+ CRASSERT(tablesize/sizeof(%s)==1);
+ fboid = (GLuint) *get_values;
+ if (crServerIsRedirectedToFBO()
+ && (fboid==cr_server.curClient->currentMural->aidFBOs[0]
+ || fboid==cr_server.curClient->currentMural->aidFBOs[1]))
+ {
+ fboid = 0;
+ }
+ else
+ {
+ fboid = crStateFBOHWIDtoID(fboid);
+ }
+ *get_values = (%s) fboid;
+ }
+ else if (GL_READ_BUFFER==pname)
+ {
+ if (crServerIsRedirectedToFBO()
+ && CR_SERVER_FBO_FOR_IDX(cr_server.curClient->currentMural, cr_server.curClient->currentMural->iCurReadBuffer)
+ && !crStateGetCurrent()->framebufferobject.readFB)
+ {
+ *get_values = (%s) crStateGetCurrent()->buffer.readBuffer;
+ Assert(crStateGetCurrent()->buffer.readBuffer == GL_BACK || crStateGetCurrent()->buffer.readBuffer == GL_FRONT);
+ }
+ }
+ else if (GL_DRAW_BUFFER==pname)
+ {
+ if (crServerIsRedirectedToFBO()
+ && CR_SERVER_FBO_FOR_IDX(cr_server.curClient->currentMural, cr_server.curClient->currentMural->iCurDrawBuffer)
+ && !crStateGetCurrent()->framebufferobject.drawFB)
+ {
+ *get_values = (%s) crStateGetCurrent()->buffer.drawBuffer;
+ Assert(crStateGetCurrent()->buffer.drawBuffer == GL_BACK || crStateGetCurrent()->buffer.drawBuffer == GL_FRONT);
+ }
+ }
+ else if (GL_RENDERBUFFER_BINDING_EXT==pname)
+ {
+ GLuint rbid;
+ CRASSERT(tablesize/sizeof(%s)==1);
+ rbid = (GLuint) *get_values;
+ *get_values = (%s) crStateRBOHWIDtoID(rbid);
+ }
+ else if (GL_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_VERTEX_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_NORMAL_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_COLOR_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_INDEX_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB==pname
+ || GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB==pname)
+ {
+ GLuint bufid;
+ CRASSERT(tablesize/sizeof(%s)==1);
+ bufid = (GLuint) *get_values;
+ *get_values = (%s) crStateBufferHWIDtoID(bufid);
+ }
+ else if (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS==pname)
+ {
+ if (CR_MAX_TEXTURE_UNITS < (GLuint)*get_values)
+ {
+ *get_values = (%s)CR_MAX_TEXTURE_UNITS;
+ }
+ }
+ else if (GL_MAX_VERTEX_ATTRIBS_ARB==pname)
+ {
+ if (CR_MAX_VERTEX_ATTRIBS < (GLuint)*get_values)
+ {
+ *get_values = (%s)CR_MAX_VERTEX_ATTRIBS;
+ }
+ }
+ """ % (types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index]))
+ print('\tcrServerReturnValue( get_values, tablesize );')
+ print('\tcrFree(get_values);')
+ print('}\n')
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special
new file mode 100644
index 00000000..e640a8b6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special
@@ -0,0 +1,268 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+BoundsInfoCR
+Clear
+GetBooleanv
+GetDoublev
+GetFloatv
+GetIntegerv
+GetString
+GenTextures
+GetTexImage
+GetMapdv
+GetMapiv
+GetMapfv
+GetPixelMapfv
+GetPixelMapuiv
+GetPixelMapusv
+GetPointerv
+GenLists
+Writeback
+Viewport
+LoadMatrixf
+LoadMatrixd
+MultMatrixf
+MultMatrixd
+LoadIdentity
+Color3ub
+Color3b
+Color3us
+Color3s
+Color3ui
+Color3i
+Color3f
+Color3d
+Color4ub
+Color4b
+Color4us
+Color4s
+Color4ui
+Color4i
+Color4f
+Color4d
+Normal3b
+Normal3d
+Normal3f
+Normal3i
+Normal3s
+TexCoord1d
+TexCoord1f
+TexCoord1i
+TexCoord1s
+TexCoord2d
+TexCoord2f
+TexCoord2i
+TexCoord2s
+TexCoord3d
+TexCoord3f
+TexCoord3i
+TexCoord3s
+TexCoord4d
+TexCoord4f
+TexCoord4i
+TexCoord4s
+Indexd
+Indexf
+Indexi
+Indexs
+Indexub
+EdgeFlag
+SelectBuffer
+BarrierCreateCR
+BarrierDestroyCR
+SemaphoreCreateCR
+SemaphoreDestroyCR
+SemaphoreVCR
+SemaphorePCR
+BarrierExecCR
+SecondaryColor3ubEXT
+SecondaryColor3bEXT
+SecondaryColor3usEXT
+SecondaryColor3sEXT
+SecondaryColor3uiEXT
+SecondaryColor3iEXT
+SecondaryColor3fEXT
+SecondaryColor3dEXT
+MakeCurrent
+CreateContext
+DestroyContext
+WindowCreate
+WindowDestroy
+WindowSize
+WindowPosition
+WindowVisibleRegion
+WindowShow
+ReadPixels
+GetChromiumParametervCR
+ChromiumParametervCR
+ChromiumParameteriCR
+ChromiumParameterfCR
+SwapBuffers
+GenProgramsNV
+GetProgramStringNV
+GetVertexAttribPointervNV
+GenFencesNV
+MultiTexCoord1dARB
+MultiTexCoord1fARB
+MultiTexCoord1iARB
+MultiTexCoord1sARB
+MultiTexCoord2dARB
+MultiTexCoord2fARB
+MultiTexCoord2iARB
+MultiTexCoord2sARB
+MultiTexCoord3dARB
+MultiTexCoord3fARB
+MultiTexCoord3iARB
+MultiTexCoord3sARB
+MultiTexCoord4dARB
+MultiTexCoord4fARB
+MultiTexCoord4iARB
+MultiTexCoord4sARB
+FogCoordfEXT
+FogCoorddEXT
+NewList
+CallList
+CallLists
+IsList
+DeleteLists
+BindTexture
+DeleteTextures
+IsTexture
+AreTexturesResident
+PrioritizeTextures
+AreProgramsResidentNV
+GenProgramsARB
+IsProgramARB
+GetProgramStringARB
+GetVertexAttribPointervARB
+VertexAttrib1dARB
+VertexAttrib2dARB
+VertexAttrib3dARB
+VertexAttrib4dARB
+VertexAttrib1fARB
+VertexAttrib2fARB
+VertexAttrib3fARB
+VertexAttrib4fARB
+VertexAttrib1sARB
+VertexAttrib2sARB
+VertexAttrib3sARB
+VertexAttrib4sARB
+VertexAttrib4NubARB
+ProgramStringARB
+ProgramLocalParameter4fARB
+ProgramLocalParameter4dARB
+BindProgramARB
+DeleteProgramsARB
+LoadProgramNV
+BindProgramNV
+ProgramParameter4fNV
+ProgramParameter4dNV
+GetCompressedTexImageARB
+GenBuffersARB
+DeleteBuffersARB
+GetBufferSubDataARB
+GetBufferPointervARB
+MapBufferARB
+UnmapBufferARB
+GenQueriesARB
+WindowPos2dARB
+WindowPos2dvARB
+WindowPos2fARB
+WindowPos2fvARB
+WindowPos2iARB
+WindowPos2ivARB
+WindowPos2sARB
+WindowPos2svARB
+WindowPos3dARB
+WindowPos3dvARB
+WindowPos3fARB
+WindowPos3fvARB
+WindowPos3iARB
+WindowPos3ivARB
+WindowPos3sARB
+WindowPos3svARB
+GetActiveAttrib
+GetActiveUniform
+GetAttachedShaders
+GetShaderInfoLog
+GetProgramInfoLog
+GetShaderSource
+GetUniformfv
+GetUniformiv
+GetAttachedObjectsARB
+GetInfoLogARB
+GenFramebuffersEXT
+GenRenderbuffersEXT
+FramebufferTexture1DEXT
+FramebufferTexture2DEXT
+FramebufferTexture3DEXT
+CopyTexImage2D
+BindFramebufferEXT
+BindRenderbufferEXT
+DeleteFramebuffersEXT
+DeleteRenderbuffersEXT
+FramebufferRenderbufferEXT
+GetFramebufferAttachmentParameterivEXT
+CreateShader
+CreateProgram
+ShaderSource
+IsShader
+IsProgram
+CompileShader
+DeleteShader
+AttachShader
+DetachShader
+LinkProgram
+UseProgram
+DeleteProgram
+ValidateProgram
+BindAttribLocation
+DeleteObjectARB
+GetUniformsLocations
+GetAttribsLocations
+GetPolygonStipple
+Flush
+Finish
+CompressedTexSubImage1DARB
+CompressedTexSubImage2DARB
+CompressedTexSubImage3DARB
+TexSubImage1D
+TexSubImage2D
+TexSubImage3D
+CompressedTexImage1DARB
+CompressedTexImage2DARB
+CompressedTexImage3DARB
+TexImage1D
+TexImage2D
+TexImage3D
+BindBufferARB
+IsBufferARB
+IsFramebufferEXT
+IsRenderbufferEXT
+GetAttribLocation
+GetHandleARB
+GetUniformLocation
+CopyTexSubImage2D
+GetObjectParameterivARB
+GetObjectParameterfvARB
+BlitFramebufferEXT
+EndList
+DrawBuffer
+ReadBuffer
+VBoxTexPresent
+GetError
+GetProgramiv
+GetShaderiv
+Begin
+DrawArrays
+DrawElements
+End
+TexEnvf
+TexEnvfv
+TexEnvi
+TexEnviv
+GetTexEnvfv
+GetTexEnviv
+DrawBuffers \ No newline at end of file
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c
new file mode 100644
index 00000000..9cdbe71f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c
@@ -0,0 +1,934 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server.h"
+#include "cr_unpack.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "server_dispatch.h"
+
+
+/**
+ * Accept a new client connection, create a new CRClient and add to run queue.
+ */
+void
+crServerAddNewClient(void)
+{
+ CRClient *newClient = (CRClient *) crCalloc(sizeof(CRClient));
+
+ if (newClient) {
+ newClient->spu_id = cr_server.client_spu_id;
+ newClient->conn = crNetAcceptClient( cr_server.protocol, NULL,
+ cr_server.tcpip_port,
+ cr_server.mtu, 1 );
+
+ newClient->currentCtxInfo = &cr_server.MainContextInfo;
+
+ /* add to array */
+ cr_server.clients[cr_server.numClients++] = newClient;
+
+ crServerAddToRunQueue( newClient );
+ }
+}
+
+
+/**
+ * Check if client is in the run queue.
+ */
+static GLboolean
+FindClientInQueue(CRClient *client)
+{
+ RunQueue *q = cr_server.run_queue;
+ while (q) {
+ if (q->client == client) {
+ return 1;
+ }
+ q = q->next;
+ if (q == cr_server.run_queue)
+ return 0; /* back head */
+ }
+ return 0;
+}
+
+
+#if 0
+static int
+PrintQueue(void)
+{
+ RunQueue *q = cr_server.run_queue;
+ int count = 0;
+ crDebug("Queue entries:");
+ while (q) {
+ count++;
+ crDebug("Entry: %p client: %p", q, q->client);
+ q = q->next;
+ if (q == cr_server.run_queue)
+ return count;
+ }
+ return count;
+}
+#endif
+
+
+void crServerAddToRunQueue( CRClient *client )
+{
+ RunQueue *q = (RunQueue *) crAlloc( sizeof( *q ) );
+
+#ifdef VBOX_WITH_CRHGSMI
+ client->conn->pClient = client;
+ CRVBOXHGSMI_CMDDATA_CLEANUP(&client->conn->CmdData);
+#endif
+
+ /* give this client a unique number if needed */
+ if (!client->number) {
+ client->number = client->conn->u32ClientID;
+ }
+
+ crDebug("Adding client %p to the run queue", client);
+
+ if (FindClientInQueue(client)) {
+ crError("CRServer: client %p already in the queue!", client);
+ }
+
+ q->client = client;
+ q->blocked = 0;
+
+ if (!cr_server.run_queue)
+ {
+ /* adding to empty queue */
+ cr_server.run_queue = q;
+ q->next = q;
+ q->prev = q;
+ }
+ else
+ {
+ /* insert in doubly-linked list */
+ q->next = cr_server.run_queue->next;
+ cr_server.run_queue->next->prev = q;
+
+ q->prev = cr_server.run_queue;
+ cr_server.run_queue->next = q;
+ }
+}
+
+static void crServerCleanupClient(CRClient *client)
+{
+ int32_t pos;
+ CRClient *oldclient = cr_server.curClient;
+
+ cr_server.curClient = client;
+
+ /* Destroy any windows created by the client */
+ for (pos = 0; pos<CR_MAX_WINDOWS; pos++)
+ {
+ if (client->windowList[pos])
+ {
+ cr_server.dispatch.WindowDestroy(client->windowList[pos]);
+ }
+ }
+
+ /* Check if we have context(s) made by this client left, could happen if client side code is lazy */
+ for (pos = 0; pos<CR_MAX_CONTEXTS; pos++)
+ {
+ if (client->contextList[pos])
+ {
+ cr_server.dispatch.DestroyContext(client->contextList[pos]);
+ }
+ }
+
+ cr_server.curClient = oldclient;
+}
+
+static void crServerCleanupByPID(uint64_t pid)
+{
+ CRClientNode *pNode=cr_server.pCleanupClient, *pNext;
+
+ while (pNode)
+ {
+ if (pNode->pClient->pid==pid)
+ {
+ crServerCleanupClient(pNode->pClient);
+ crFree(pNode->pClient);
+ if (pNode->prev)
+ {
+ pNode->prev->next=pNode->next;
+ }
+ else
+ {
+ cr_server.pCleanupClient=pNode->next;
+ }
+ if (pNode->next)
+ {
+ pNode->next->prev = pNode->prev;
+ }
+
+ pNext=pNode->next;
+ crFree(pNode);
+ pNode=pNext;
+ }
+ else
+ {
+ pNode=pNode->next;
+ }
+ }
+}
+
+void
+crServerDeleteClient( CRClient *client )
+{
+ int i, j;
+ int cleanup=1;
+
+ crDebug("Deleting client %p (%d msgs left)", client, crNetNumMessages(client->conn));
+
+#if 0
+ if (crNetNumMessages(client->conn) > 0) {
+ crDebug("Delay destroying client: message still pending");
+ return;
+ }
+#endif
+
+ if (!FindClientInQueue(client)) {
+ /* this should never happen */
+ crError("CRServer: client %p not found in the queue!", client);
+ }
+
+ /* remove from clients[] array */
+ for (i = 0; i < cr_server.numClients; i++) {
+ if (cr_server.clients[i] == client) {
+ /* found it */
+ for (j = i; j < cr_server.numClients - 1; j++)
+ cr_server.clients[j] = cr_server.clients[j + 1];
+ cr_server.numClients--;
+ break;
+ }
+ }
+
+ /* check if there're any other guest threads in same process */
+ for (i=0; i < cr_server.numClients; i++)
+ {
+ if (cr_server.clients[i]->pid==client->pid)
+ {
+ cleanup=0;
+ break;
+ }
+ }
+
+ if (cleanup)
+ {
+ crServerCleanupClient(client);
+ }
+
+ /* remove from the run queue */
+ if (cr_server.run_queue)
+ {
+ RunQueue *q = cr_server.run_queue;
+ RunQueue *qStart = cr_server.run_queue;
+ do {
+ if (q->client == client)
+ {
+ /* this test seems a bit excessive */
+ if ((q->next == q->prev) && (q->next == q) && (cr_server.run_queue == q))
+ {
+ /* We're removing/deleting the only client */
+ CRASSERT(cr_server.numClients == 0);
+ crFree(q);
+ cr_server.run_queue = NULL;
+ cr_server.curClient = NULL;
+ crDebug("Last client deleted - empty run queue.");
+ }
+ else
+ {
+ /* remove from doubly linked list and free the node */
+ if (cr_server.curClient == q->client)
+ cr_server.curClient = NULL;
+ if (cr_server.run_queue == q)
+ cr_server.run_queue = q->next;
+ q->prev->next = q->next;
+ q->next->prev = q->prev;
+ crFree(q);
+ }
+ break;
+ }
+ q = q->next;
+ } while (q != qStart);
+ }
+
+ crNetFreeConnection(client->conn);
+ client->conn = NULL;
+
+ if (cleanup)
+ {
+ crServerCleanupByPID(client->pid);
+ crFree(client);
+ }
+ else
+ {
+ CRClientNode *pNode = (CRClientNode *)crAlloc(sizeof(CRClientNode));
+ if (!pNode)
+ {
+ crWarning("Not enough memory, forcing client cleanup");
+ crServerCleanupClient(client);
+ crServerCleanupByPID(client->pid);
+ crFree(client);
+ return;
+ }
+ pNode->pClient = client;
+ pNode->prev = NULL;
+ pNode->next = cr_server.pCleanupClient;
+ cr_server.pCleanupClient = pNode;
+ }
+
+ if (!cr_server.numClients)
+ {
+ /* if no clients, the guest driver may be unloaded,
+ * and thus the visible regions situation might not be under control anymore,
+ * so cleanup the 3D framebuffer data here
+ * @todo: what really should happen is that guest driver on unload
+ * posts some request to host that would copy the current framebuffer 3D data to the 2D buffer
+ * (i.e. to the memory used by the standard IFramebuffer API) */
+ HCR_FRAMEBUFFER hFb;
+ for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb))
+ {
+ int rc = CrFbUpdateBegin(hFb);
+ if (RT_SUCCESS(rc))
+ {
+ CrFbRegionsClear(hFb);
+ CrFbUpdateEnd(hFb);
+ }
+ else
+ WARN(("CrFbUpdateBegin failed %d", rc));
+ }
+ }
+}
+
+/**
+ * Test if the given client is in the middle of a glBegin/End or
+ * glNewList/EndList pair.
+ * This is used to test if we can advance to the next client.
+ * \return GL_TRUE if so, GL_FALSE otherwise.
+ */
+GLboolean
+crServerClientInBeginEnd(const CRClient *client)
+{
+ if (client->currentCtxInfo
+ && client->currentCtxInfo->pContext
+ && (client->currentCtxInfo->pContext->lists.currentIndex != 0 ||
+ client->currentCtxInfo->pContext->current.inBeginEnd ||
+ client->currentCtxInfo->pContext->occlusion.currentQueryObject)) {
+ return GL_TRUE;
+ }
+ else {
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Find the next client in the run queue that's not blocked and has a
+ * waiting message.
+ * Check if all clients are blocked (on barriers, semaphores), if so we've
+ * deadlocked!
+ * If no clients have a waiting message, call crNetRecv to get something
+ * if 'block' is true, else return NULL if 'block' if false.
+ */
+static RunQueue *
+getNextClient(GLboolean block)
+{
+ while (1)
+ {
+ if (cr_server.run_queue)
+ {
+ GLboolean all_blocked = GL_TRUE;
+ GLboolean done_something = GL_FALSE;
+ RunQueue *start = cr_server.run_queue;
+
+ /* check if this client's connection has gone away */
+ if (!cr_server.run_queue->client->conn
+ || (cr_server.run_queue->client->conn->type == CR_NO_CONNECTION
+ && crNetNumMessages(cr_server.run_queue->client->conn) == 0))
+ {
+ crServerDeleteClient( cr_server.run_queue->client );
+ start = cr_server.run_queue;
+ }
+
+ if (cr_server.run_queue == NULL) {
+ /* empty queue */
+ return NULL;
+ }
+
+ if (crServerClientInBeginEnd(cr_server.run_queue->client)) {
+ /* We _must_ service this client and no other.
+ * If we've got a message waiting on this client's connection we'll
+ * service it. Else, return NULL.
+ */
+ if (crNetNumMessages(cr_server.run_queue->client->conn) > 0)
+ return cr_server.run_queue;
+ else
+ return NULL;
+ }
+
+ /* loop over entries in run queue, looking for next one that's ready */
+ while (!done_something || cr_server.run_queue != start)
+ {
+ done_something = GL_TRUE;
+ if (!cr_server.run_queue->blocked)
+ {
+ all_blocked = GL_FALSE;
+ }
+ if (!cr_server.run_queue->blocked
+ && cr_server.run_queue->client->conn
+ && crNetNumMessages(cr_server.run_queue->client->conn) > 0)
+ {
+ /* OK, this client isn't blocked and has a queued message */
+ return cr_server.run_queue;
+ }
+ cr_server.run_queue = cr_server.run_queue->next;
+ }
+
+ if (all_blocked)
+ {
+ /* XXX crError is fatal? Should this be an info/warning msg? */
+ crError( "crserver: DEADLOCK! (numClients=%d, all blocked)",
+ cr_server.numClients );
+ if (cr_server.numClients < (int) cr_server.maxBarrierCount) {
+ crError("Waiting for more clients!!!");
+ while (cr_server.numClients < (int) cr_server.maxBarrierCount) {
+ crNetRecv();
+ }
+ }
+ }
+ }
+
+ if (!block)
+ return NULL;
+
+ /* no one had any work, get some! */
+ crNetRecv();
+
+ } /* while */
+
+ /* UNREACHED */
+ /* return NULL; */
+}
+
+typedef struct CR_SERVER_PENDING_MSG
+{
+ RTLISTNODE Node;
+ uint32_t cbMsg;
+ CRMessage Msg;
+} CR_SERVER_PENDING_MSG;
+
+static int crServerPendMsg(CRConnection *conn, const CRMessage *msg, int cbMsg)
+{
+ CR_SERVER_PENDING_MSG *pMsg;
+
+ if (!cbMsg)
+ {
+ WARN(("cbMsg is null!"));
+ return VERR_INVALID_PARAMETER;
+ }
+
+ pMsg = (CR_SERVER_PENDING_MSG*)RTMemAlloc(cbMsg + RT_UOFFSETOF(CR_SERVER_PENDING_MSG, Msg));
+ if (!pMsg)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+
+ pMsg->cbMsg = cbMsg;
+
+ memcpy(&pMsg->Msg, msg, cbMsg);
+
+ RTListAppend(&conn->PendingMsgList, &pMsg->Node);
+
+ return VINF_SUCCESS;
+}
+
+int crServerPendSaveState(PSSMHANDLE pSSM)
+{
+ int i, rc;
+
+ for (i = 0; i < cr_server.numClients; i++)
+ {
+ CR_SERVER_PENDING_MSG *pIter;
+ CRClient *pClient = cr_server.clients[i];
+ CRConnection *pConn;
+ if (!pClient || !pClient->conn)
+ {
+ WARN(("invalid client state"));
+ continue;
+ }
+
+ pConn = pClient->conn;
+
+ if (RTListIsEmpty(&pConn->PendingMsgList))
+ continue;
+
+ CRASSERT(pConn->u32ClientID);
+
+ rc = SSMR3PutU32(pSSM, pConn->u32ClientID);
+ AssertRCReturn(rc, rc);
+
+ RTListForEach(&pConn->PendingMsgList, pIter, CR_SERVER_PENDING_MSG, Node)
+ {
+ CRASSERT(pIter->cbMsg);
+
+ rc = SSMR3PutU32(pSSM, pIter->cbMsg);
+ AssertRCReturn(rc, rc);
+
+ rc = SSMR3PutMem(pSSM, &pIter->Msg, pIter->cbMsg);
+ AssertRCReturn(rc, rc);
+ }
+
+ rc = SSMR3PutU32(pSSM, 0);
+ AssertRCReturn(rc, rc);
+ }
+
+ rc = SSMR3PutU32(pSSM, 0);
+ AssertRCReturn(rc, rc);
+
+ return VINF_SUCCESS;
+}
+
+int crServerPendLoadState(PSSMHANDLE pSSM, uint32_t u32Version)
+{
+ int rc;
+ uint32_t u32;
+ CRClient *pClient;
+
+ if (u32Version < SHCROGL_SSM_VERSION_WITH_PEND_CMD_INFO)
+ return VINF_SUCCESS;
+
+ rc = SSMR3GetU32(pSSM, &u32);
+ AssertRCReturn(rc, rc);
+
+ if (!u32)
+ return VINF_SUCCESS;
+
+ do {
+ rc = crVBoxServerClientGet(u32, &pClient);
+ AssertRCReturn(rc, rc);
+
+ for(;;)
+ {
+ CR_SERVER_PENDING_MSG *pMsg;
+
+ rc = SSMR3GetU32(pSSM, &u32);
+ AssertRCReturn(rc, rc);
+
+ if (!u32)
+ break;
+
+ pMsg = (CR_SERVER_PENDING_MSG*)RTMemAlloc(u32 + RT_UOFFSETOF(CR_SERVER_PENDING_MSG, Msg));
+ if (!pMsg)
+ {
+ WARN(("RTMemAlloc failed"));
+ return VERR_NO_MEMORY;
+ }
+
+ pMsg->cbMsg = u32;
+ rc = SSMR3GetMem(pSSM, &pMsg->Msg, u32);
+ AssertRCReturn(rc, rc);
+
+ RTListAppend(&pClient->conn->PendingMsgList, &pMsg->Node);
+ }
+
+ rc = SSMR3GetU32(pSSM, &u32);
+ AssertRCReturn(rc, rc);
+ } while (u32);
+
+ rc = SSMR3GetU32(pSSM, &u32);
+ AssertRCReturn(rc, rc);
+
+ return VINF_SUCCESS;
+}
+
+static void crServerPendProcess(CRConnection *conn)
+{
+ CR_SERVER_PENDING_MSG *pIter, *pNext;
+
+ cr_server.fProcessingPendedCommands = GL_TRUE;
+
+ RTListForEachSafe(&conn->PendingMsgList, pIter, pNext, CR_SERVER_PENDING_MSG, Node)
+ {
+ CRMessage *msg = &pIter->Msg;
+ const CRMessageOpcodes *msg_opcodes;
+ int opcodeBytes;
+ const char *data_ptr, *data_ptr_end;
+
+ RTListNodeRemove(&pIter->Node);
+
+ CRASSERT(msg->header.type == CR_MESSAGE_OPCODES);
+
+ msg_opcodes = (const CRMessageOpcodes *) msg;
+ opcodeBytes = (msg_opcodes->numOpcodes + 3) & ~0x03;
+
+ data_ptr = (const char *) msg_opcodes + sizeof (CRMessageOpcodes) + opcodeBytes;
+ data_ptr_end = (const char *)msg_opcodes + pIter->cbMsg;
+
+ crUnpack(data_ptr, /* first command's operands */
+ data_ptr_end, /* first byte after command's operands*/
+ data_ptr - 1, /* first command's opcode */
+ msg_opcodes->numOpcodes, /* how many opcodes */
+ &(cr_server.dispatch)); /* the CR dispatch table */
+
+ RTMemFree(pIter);
+ }
+
+ cr_server.fProcessingPendedCommands = GL_FALSE;
+}
+
+/**
+ * This function takes the given message (which should be a buffer of
+ * rendering commands) and executes it.
+ */
+static void
+crServerDispatchMessage(CRConnection *conn, CRMessage *msg, int cbMsg)
+{
+ const CRMessageOpcodes *msg_opcodes;
+ int opcodeBytes;
+ const char *data_ptr, *data_ptr_end;
+#ifdef VBOX_WITH_CRHGSMI
+ PCRVBOXHGSMI_CMDDATA pCmdData = NULL;
+#endif
+ CR_UNPACK_BUFFER_TYPE enmType;
+ bool fUnpack = true;
+
+ if (msg->header.type == CR_MESSAGE_REDIR_PTR)
+ {
+#ifdef VBOX_WITH_CRHGSMI
+ pCmdData = &msg->redirptr.CmdData;
+#endif
+ msg = (CRMessage *) msg->redirptr.pMessage;
+ }
+
+ CRASSERT(msg->header.type == CR_MESSAGE_OPCODES);
+
+ msg_opcodes = (const CRMessageOpcodes *) msg;
+ opcodeBytes = (msg_opcodes->numOpcodes + 3) & ~0x03;
+
+#ifdef VBOXCR_LOGFPS
+ CRASSERT(cr_server.curClient && cr_server.curClient->conn && cr_server.curClient->conn->id == msg->header.conn_id);
+ cr_server.curClient->conn->opcodes_count += msg_opcodes->numOpcodes;
+#endif
+
+ data_ptr = (const char *) msg_opcodes + sizeof(CRMessageOpcodes) + opcodeBytes;
+ data_ptr_end = (const char *)msg_opcodes + cbMsg; // Pointer to the first byte after message data
+
+ enmType = crUnpackGetBufferType(data_ptr - 1, /* first command's opcode */
+ msg_opcodes->numOpcodes /* how many opcodes */);
+ switch (enmType)
+ {
+ case CR_UNPACK_BUFFER_TYPE_GENERIC:
+ {
+ if (RTListIsEmpty(&conn->PendingMsgList))
+ break;
+
+ if (RT_SUCCESS(crServerPendMsg(conn, msg, cbMsg)))
+ {
+ fUnpack = false;
+ break;
+ }
+
+ WARN(("crServerPendMsg failed"));
+ crServerPendProcess(conn);
+ break;
+ }
+ case CR_UNPACK_BUFFER_TYPE_CMDBLOCK_BEGIN:
+ {
+ if (RTListIsEmpty(&conn->PendingMsgList))
+ {
+ if (RT_SUCCESS(crServerPendMsg(conn, msg, cbMsg)))
+ {
+ Assert(!RTListIsEmpty(&conn->PendingMsgList));
+ fUnpack = false;
+ break;
+ }
+ else
+ WARN(("crServerPendMsg failed"));
+ }
+ else
+ WARN(("Pend List is NOT empty, drain the current list, and ignore this command"));
+
+ crServerPendProcess(conn);
+ break;
+ }
+ case CR_UNPACK_BUFFER_TYPE_CMDBLOCK_FLUSH: /* just flush for now */
+ {
+ CrPMgrClearRegionsGlobal(); /* clear regions to ensure we don't do MakeCurrent and friends */
+ crServerPendProcess(conn);
+ Assert(RTListIsEmpty(&conn->PendingMsgList));
+ break;
+ }
+ case CR_UNPACK_BUFFER_TYPE_CMDBLOCK_END:
+ {
+// CRASSERT(!RTListIsEmpty(&conn->PendingMsgList));
+ crServerPendProcess(conn);
+ Assert(RTListIsEmpty(&conn->PendingMsgList));
+ break;
+ }
+ default:
+ WARN(("unsupported buffer type"));
+ break;
+ }
+
+ if (fUnpack)
+ {
+ crUnpack(data_ptr, /* first command's operands */
+ data_ptr_end, /* first byte after command's operands*/
+ data_ptr - 1, /* first command's opcode */
+ msg_opcodes->numOpcodes, /* how many opcodes */
+ &(cr_server.dispatch)); /* the CR dispatch table */
+ }
+
+#ifdef VBOX_WITH_CRHGSMI
+ if (pCmdData)
+ {
+ int rc = VINF_SUCCESS;
+ CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(pCmdData);
+ if (CRVBOXHGSMI_CMDDATA_IS_SETWB(pCmdData))
+ {
+ uint32_t cbWriteback = pCmdData->cbWriteback;
+ rc = crVBoxServerInternalClientRead(conn->pClient, (uint8_t*)pCmdData->pWriteback, &cbWriteback);
+ Assert(rc == VINF_SUCCESS || rc == VERR_BUFFER_OVERFLOW);
+ *pCmdData->pcbWriteback = cbWriteback;
+ }
+ VBOXCRHGSMI_CMD_CHECK_COMPLETE(pCmdData, rc);
+ }
+#endif
+}
+
+
+typedef enum
+{
+ CLIENT_GONE = 1, /* the client has disconnected */
+ CLIENT_NEXT = 2, /* we can advance to next client */
+ CLIENT_MORE = 3 /* we need to keep servicing current client */
+} ClientStatus;
+
+
+/**
+ * Process incoming/pending message for the given client (queue entry).
+ * \return CLIENT_GONE if this client has gone away/exited,
+ * CLIENT_NEXT if we can advance to the next client
+ * CLIENT_MORE if we have to process more messages for this client.
+ */
+static ClientStatus
+crServerServiceClient(const RunQueue *qEntry)
+{
+ CRMessage *msg;
+ CRConnection *conn;
+
+ /* set current client pointer */
+ cr_server.curClient = qEntry->client;
+
+ conn = cr_server.run_queue->client->conn;
+
+ /* service current client as long as we can */
+ while (conn && conn->type != CR_NO_CONNECTION &&
+ crNetNumMessages(conn) > 0) {
+ unsigned int len;
+
+ /*
+ crDebug("%d messages on %p",
+ crNetNumMessages(conn), (void *) conn);
+ */
+
+ /* Don't use GetMessage, because we want to do our own crNetRecv() calls
+ * here ourself.
+ * Note that crNetPeekMessage() DOES remove the message from the queue
+ * if there is one.
+ */
+ len = crNetPeekMessage( conn, &msg );
+ CRASSERT(len > 0);
+ if (msg->header.type != CR_MESSAGE_OPCODES
+ && msg->header.type != CR_MESSAGE_REDIR_PTR) {
+ crError( "SPU %d sent me CRAP (type=0x%x)",
+ cr_server.curClient->spu_id, msg->header.type );
+ }
+
+ /* Do the context switch here. No sense in switching before we
+ * really have any work to process. This is a no-op if we're
+ * not really switching contexts.
+ *
+ * XXX This isn't entirely sound. The crStateMakeCurrent() call
+ * will compute the state difference and dispatch it using
+ * the head SPU's dispatch table.
+ *
+ * This is a problem if this is the first buffer coming in,
+ * and the head SPU hasn't had a chance to do a MakeCurrent()
+ * yet (likely because the MakeCurrent() command is in the
+ * buffer itself).
+ *
+ * At best, in this case, the functions are no-ops, and
+ * are essentially ignored by the SPU. In the typical
+ * case, things aren't too bad; if the SPU just calls
+ * crState*() functions to update local state, everything
+ * will work just fine.
+ *
+ * In the worst (but unusual) case where a nontrivial
+ * SPU is at the head of a crserver's SPU chain (say,
+ * in a multiple-tiered "tilesort" arrangement, as
+ * seen in the "multitilesort.conf" configuration), the
+ * SPU may rely on state set during the MakeCurrent() that
+ * may not be present yet, because no MakeCurrent() has
+ * yet been dispatched.
+ *
+ * This headache will have to be revisited in the future;
+ * for now, SPUs that could head a crserver's SPU chain
+ * will have to detect the case that their functions are
+ * being called outside of a MakeCurrent(), and will have
+ * to handle the situation gracefully. (This is currently
+ * the case with the "tilesort" SPU.)
+ */
+
+#if 0
+ crStateMakeCurrent( cr_server.curClient->currentCtx );
+#else
+ /* Check if the current window is the one that the client wants to
+ * draw into. If not, dispatch a MakeCurrent to activate the proper
+ * window.
+ */
+ if (cr_server.curClient) {
+ int clientWindow = cr_server.curClient->currentWindow;
+ int clientContext = cr_server.curClient->currentContextNumber;
+ CRContextInfo *clientCtxInfo = cr_server.curClient->currentCtxInfo;
+ if (clientCtxInfo != cr_server.currentCtxInfo
+ || clientWindow != cr_server.currentWindow
+ || cr_server.bForceMakeCurrentOnClientSwitch) {
+ crServerDispatchMakeCurrent(clientWindow, 0, clientContext);
+ /*
+ CRASSERT(cr_server.currentWindow == clientWindow);
+ */
+ }
+ }
+#endif
+
+ /* Force scissor, viewport and projection matrix update in
+ * crServerSetOutputBounds().
+ */
+ cr_server.currentSerialNo = 0;
+
+ /* Commands get dispatched here */
+ crServerDispatchMessage( conn, msg, len );
+
+ crNetFree( conn, msg );
+
+ if (qEntry->blocked) {
+ /* Note/assert: we should not be inside a glBegin/End or glNewList/
+ * glEndList pair at this time!
+ */
+ CRASSERT(0);
+ return CLIENT_NEXT;
+ }
+
+ } /* while */
+
+ /*
+ * Check if client/connection is gone
+ */
+ if (!conn || conn->type == CR_NO_CONNECTION) {
+ crDebug("Delete client %p at %d", cr_server.run_queue->client, __LINE__);
+ crServerDeleteClient( cr_server.run_queue->client );
+ return CLIENT_GONE;
+ }
+
+ /*
+ * Determine if we can advance to next client.
+ * If we're currently inside a glBegin/End primitive or building a display
+ * list we can't service another client until we're done with the
+ * primitive/list.
+ */
+ if (crServerClientInBeginEnd(cr_server.curClient)) {
+ /* The next message has to come from the current client's connection. */
+ CRASSERT(!qEntry->blocked);
+ return CLIENT_MORE;
+ }
+ else {
+ /* get next client */
+ return CLIENT_NEXT;
+ }
+}
+
+
+
+/**
+ * Check if any of the clients need servicing.
+ * If so, service one client and return.
+ * Else, just return.
+ */
+void
+crServerServiceClients(void)
+{
+ RunQueue *q;
+
+ q = getNextClient(GL_FALSE); /* don't block */
+ while (q)
+ {
+ ClientStatus stat = crServerServiceClient(q);
+ if (stat == CLIENT_NEXT && cr_server.run_queue->next) {
+ /* advance to next client */
+ cr_server.run_queue = cr_server.run_queue->next;
+ }
+ q = getNextClient(GL_FALSE);
+ }
+}
+
+
+
+
+/**
+ * Main crserver loop. Service connections from all connected clients.
+ * XXX add a config option to specify whether the crserver
+ * should exit when there's no more clients.
+ */
+void
+crServerSerializeRemoteStreams(void)
+{
+ /*MSG msg;*/
+
+ while (cr_server.run_queue)
+ {
+ crServerServiceClients();
+ /*if (PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
+ {
+ if (msg.message == WM_QUIT)
+ {
+ PostQuitMessage((int)msg.wParam);
+ break;
+ }
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }*/
+ }
+}
+
+
+/**
+ * This will be called by the network layer when it's received a new message.
+ */
+int
+crServerRecv( CRConnection *conn, CRMessage *msg, unsigned int len )
+{
+ CRMessage *pRealMsg;
+ (void) len;
+
+ pRealMsg = (msg->header.type!=CR_MESSAGE_REDIR_PTR) ? msg : (CRMessage*) msg->redirptr.pMessage;
+
+ switch( pRealMsg->header.type )
+ {
+ /* Called when using multiple threads */
+ case CR_MESSAGE_NEWCLIENT:
+ crServerAddNewClient();
+ return 1; /* msg handled */
+ default:
+ /*crWarning( "Why is the crserver getting a message of type 0x%x?",
+ msg->header.type ); */
+ ;
+ }
+ return 0; /* not handled */
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c
new file mode 100644
index 00000000..7e779cf8
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c
@@ -0,0 +1,323 @@
+/* $Id: server_texture.c $ */
+/** @file
+ * VBox crOpenGL - teximage functions.
+ */
+
+/*
+ * Copyright (C) 2010-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "chromium.h"
+#include "cr_error.h"
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_mem.h"
+
+#define CR_NOTHING()
+
+#define CR_CHECKPTR(name) \
+ if (!realptr) \
+ { \
+ crWarning(#name " with NULL ptr, ignored!"); \
+ return; \
+ }
+
+#if !defined(CR_STATE_NO_TEXTURE_IMAGE_STORE)
+# define CR_FIXPTR() (uintptr_t) realptr += (uintptr_t) cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_ONLY_ARB)
+#else
+# define CR_FIXPTR()
+#endif
+
+#if defined(CR_ARB_pixel_buffer_object)
+# define CR_CHECKBUFFER(name, checkptr) \
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) \
+ { \
+ CR_FIXPTR(); \
+ } \
+ else \
+ { \
+ checkptr \
+ }
+#else
+# define CR_CHECKBUFFER(name, checkptr) checkptr
+#endif
+
+#if defined(CR_ARB_pixel_buffer_object) && !defined(CR_STATE_NO_TEXTURE_IMAGE_STORE)
+# define CR_FINISHBUFFER() \
+ if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) \
+ { \
+ if (!cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB)) \
+ { \
+ crWarning("UnmapBufferARB failed"); \
+ } \
+ }
+#else
+#define CR_FINISHBUFFER()
+#endif
+
+#define CR_FUNC_SUBIMAGE(name, def, call, ptrname) \
+void SERVER_DISPATCH_APIENTRY \
+crServerDispatch##name def \
+{ \
+ const GLvoid *realptr = ptrname; \
+ CR_CHECKBUFFER(name, CR_CHECKPTR(name)) \
+ crState##name call; \
+ CR_FINISHBUFFER() \
+ realptr = ptrname; \
+ cr_server.head_spu->dispatch_table.name call; \
+}
+
+#define CR_FUNC_IMAGE(name, def, call, ptrname) \
+void SERVER_DISPATCH_APIENTRY \
+crServerDispatch##name def \
+{ \
+ const GLvoid *realptr = ptrname; \
+ CR_CHECKBUFFER(name, CR_NOTHING()) \
+ crState##name call; \
+ CR_FINISHBUFFER() \
+ realptr = ptrname; \
+ cr_server.head_spu->dispatch_table.name call; \
+}
+
+#if defined(CR_ARB_texture_compression)
+CR_FUNC_SUBIMAGE(CompressedTexSubImage1DARB,
+ (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imagesize, const GLvoid * data),
+ (target, level, xoffset, width, format, imagesize, realptr), data)
+
+CR_FUNC_SUBIMAGE(CompressedTexSubImage2DARB,
+ (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imagesize, const GLvoid * data),
+ (target, level, xoffset, yoffset, width, height, format, imagesize, realptr), data)
+
+CR_FUNC_SUBIMAGE(CompressedTexSubImage3DARB,
+ (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imagesize, const GLvoid * data),
+ (target, level, xoffset, yoffset, zoffset, width, height, depth, format, imagesize, realptr), data)
+
+CR_FUNC_IMAGE(CompressedTexImage1DARB,
+ (GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imagesize, const GLvoid * data),
+ (target, level, internalFormat, width, border, imagesize, realptr), data)
+
+CR_FUNC_IMAGE(CompressedTexImage2DARB,
+ (GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imagesize, const GLvoid * data),
+ (target, level, internalFormat, width, height, border, imagesize, realptr), data)
+
+CR_FUNC_IMAGE(CompressedTexImage3DARB,
+ (GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imagesize, const GLvoid * data),
+ (target, level, internalFormat, width, height, depth, border, imagesize, realptr), data)
+#endif
+
+CR_FUNC_SUBIMAGE(TexSubImage1D,
+ (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid * pixels),
+ (target, level, xoffset, width, format, type, realptr), pixels)
+
+CR_FUNC_SUBIMAGE(TexSubImage2D,
+ (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid * pixels),
+ (target, level, xoffset, yoffset, width, height, format, type, realptr), pixels)
+
+CR_FUNC_SUBIMAGE(TexSubImage3D,
+ (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid * pixels),
+ (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, realptr), pixels)
+
+CR_FUNC_IMAGE(TexImage1D,
+ (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid * pixels),
+ (target, level, internalFormat, width, border, format, type, realptr), pixels)
+
+CR_FUNC_IMAGE(TexImage2D,
+ (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * pixels),
+ (target, level, internalFormat, width, height, border, format, type, realptr), pixels)
+
+CR_FUNC_IMAGE(TexImage3D,
+ (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * pixels),
+ (target, level, internalFormat, width, height, depth, border, format, type, realptr), pixels)
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnvf( GLenum target, GLenum pname, GLfloat param )
+{
+ crStateTexEnvf( target, pname, param );
+ if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE)
+ CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnvf( target, pname, param ););
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnvfv( GLenum target, GLenum pname, const GLfloat * params )
+{
+ crStateTexEnvfv( target, pname, params );
+ if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE)
+ CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnvfv( target, pname, params ););
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnvi( GLenum target, GLenum pname, GLint param )
+{
+ crStateTexEnvi( target, pname, param );
+ if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE)
+ CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnvi( target, pname, param ););
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnviv( GLenum target, GLenum pname, const GLint * params )
+{
+ crStateTexEnviv( target, pname, params );
+ if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE)
+ CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnviv( target, pname, params ););
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetTexEnvfv( GLenum target, GLenum pname, GLfloat * params )
+{
+ GLfloat local_params[4] = {0};
+ (void) params;
+ if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE)
+ cr_server.head_spu->dispatch_table.GetTexEnvfv( target, pname, local_params );
+ else
+ crStateGetTexEnvfv( target, pname, local_params );
+
+ crServerReturnValue( &(local_params[0]), crStateHlpComponentsCount(pname)*sizeof (GLfloat) );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchGetTexEnviv( GLenum target, GLenum pname, GLint * params )
+{
+ GLint local_params[4] = {0};
+ (void) params;
+ if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE)
+ cr_server.head_spu->dispatch_table.GetTexEnviv( target, pname, local_params );
+ else
+ crStateGetTexEnviv( target, pname, local_params );
+
+ crServerReturnValue( &(local_params[0]), crStateHlpComponentsCount(pname)*sizeof (GLint) );
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchBindTexture( GLenum target, GLuint texture )
+{
+ crStateBindTexture( target, texture );
+ cr_server.head_spu->dispatch_table.BindTexture(target, crStateGetTextureHWID(texture));
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteTextures( GLsizei n, const GLuint *textures)
+{
+ GLuint *newTextures;
+ GLint i;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchDeleteTextures: parameter 'n' is out of range");
+ return;
+ }
+
+ newTextures = (GLuint *)crAlloc(n * sizeof(GLuint));
+
+ if (!newTextures)
+ {
+ crError("crServerDispatchDeleteTextures: out of memory");
+ return;
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ newTextures[i] = crStateGetTextureHWID(textures[i]);
+ }
+
+// for (i = 0; i < n; ++i)
+// {
+// crDebug("DeleteTexture: %d, pid %d, ctx %d", textures[i], (uint32_t)cr_server.curClient->pid, cr_server.currentCtxInfo->pContext->id);
+// }
+
+
+ crStateDeleteTextures(n, textures);
+ cr_server.head_spu->dispatch_table.DeleteTextures(n, newTextures);
+ crFree(newTextures);
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchPrioritizeTextures( GLsizei n, const GLuint * textures, const GLclampf * priorities )
+{
+ GLuint *newTextures;
+ GLint i;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchPrioritizeTextures: parameter 'n' is out of range");
+ return;
+ }
+
+ newTextures = (GLuint *)crAlloc(n * sizeof(GLuint));
+
+ if (!newTextures)
+ {
+ crError("crServerDispatchPrioritizeTextures: out of memory");
+ return;
+ }
+
+ crStatePrioritizeTextures(n, textures, priorities);
+
+ for (i = 0; i < n; i++)
+ {
+ newTextures[i] = crStateGetTextureHWID(textures[i]);
+ }
+
+ cr_server.head_spu->dispatch_table.PrioritizeTextures(n, newTextures, priorities);
+ crFree(newTextures);
+}
+
+
+/** @todo will fail for textures loaded from snapshot */
+GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsTexture( GLuint texture )
+{
+ GLboolean retval;
+ retval = cr_server.head_spu->dispatch_table.IsTexture(crStateGetTextureHWID(texture));
+ crServerReturnValue( &retval, sizeof(retval) );
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
+
+GLboolean SERVER_DISPATCH_APIENTRY
+crServerDispatchAreTexturesResident(GLsizei n, const GLuint *textures,
+ GLboolean *residences)
+{
+ GLboolean retval = GL_FALSE;
+ GLsizei i;
+ GLboolean *res;
+ GLuint *textures2;
+ (void) residences;
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crServerDispatchAreTexturesResident: parameter 'n' is out of range");
+ return GL_FALSE;
+ }
+
+ res = (GLboolean *)crCalloc(n * sizeof(GLboolean));
+ if (!res)
+ {
+ crError("crServerDispatchAreTexturesResident: out of memory");
+ return GL_FALSE;
+ }
+
+ textures2 = (GLuint *)crAlloc(n * sizeof(GLuint));
+
+ if (!textures2)
+ {
+ crError("crServerDispatchAreTexturesResident: out of memory");
+ crFree(res);
+ return GL_FALSE;
+ }
+
+ for (i = 0; i < n; i++)
+ {
+ textures2[i] = crStateGetTextureHWID(textures[i]);
+ }
+ retval = cr_server.head_spu->dispatch_table.AreTexturesResident(n, textures2, res);
+
+ crFree(textures2);
+
+ crServerReturnValue(res, n * sizeof(GLboolean));
+
+ crFree(res);
+
+ return retval; /* WILL PROBABLY BE IGNORED */
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_viewport.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_viewport.c
new file mode 100644
index 00000000..c583faee
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_viewport.c
@@ -0,0 +1,288 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server_dispatch.h"
+#include "server.h"
+#include "cr_error.h"
+#include "state/cr_statetypes.h"
+
+
+static const CRmatrix identity_matrix = {
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0
+};
+
+
+/*
+ * Clip the rectangle q against the given image window.
+ */
+static void
+crServerViewportClipToWindow( const CRrecti *imagewindow, CRrecti *q)
+{
+ if (q->x1 < imagewindow->x1) q->x1 = imagewindow->x1;
+ if (q->x1 > imagewindow->x2) q->x1 = imagewindow->x2;
+
+ if (q->x2 > imagewindow->x2) q->x2 = imagewindow->x2;
+ if (q->x2 < imagewindow->x1) q->x2 = imagewindow->x1;
+
+ if (q->y1 < imagewindow->y1) q->y1 = imagewindow->y1;
+ if (q->y1 > imagewindow->y2) q->y1 = imagewindow->y2;
+
+ if (q->y2 > imagewindow->y2) q->y2 = imagewindow->y2;
+ if (q->y2 < imagewindow->y1) q->y2 = imagewindow->y1;
+}
+
+
+/*
+ * Translate the rectangle q from the image window space to the outputwindow
+ * space.
+ */
+static void
+crServerConvertToOutput( const CRrecti *imagewindow,
+ const CRrecti *outputwindow,
+ CRrecti *q )
+{
+ q->x1 = q->x1 - imagewindow->x1 + outputwindow->x1;
+ q->x2 = q->x2 - imagewindow->x2 + outputwindow->x2;
+ q->y1 = q->y1 - imagewindow->y1 + outputwindow->y1;
+ q->y2 = q->y2 - imagewindow->y2 + outputwindow->y2;
+}
+
+
+/*
+ * Compute clipped image window, scissor, viewport and base projection
+ * info for each tile in the mural.
+ * Need to call this when either the viewport or mural is changed.
+ */
+void
+crServerComputeViewportBounds(const CRViewportState *v, CRMuralInfo *mural)
+{
+#if 0
+ static GLuint serialNo = 1;
+ int i;
+
+ for (i = 0; i < mural->numExtents; i++) {
+ CRExtent *extent = &mural->extents[i];
+ CRrecti q;
+
+ /* If the scissor is disabled set it to the whole output.
+ ** We might as well use the actual scissorTest rather than
+ ** scissorValid - it never gets reset anyway.
+ */
+ if (!v->scissorTest)
+ {
+ extent->scissorBox = extent->outputwindow;
+ }
+ else
+ {
+ q.x1 = v->scissorX;
+ q.x2 = v->scissorX + v->scissorW;
+ q.y1 = v->scissorY;
+ q.y2 = v->scissorY + v->scissorH;
+
+ crServerViewportClipToWindow(&(extent->imagewindow), &q);
+ crServerConvertToOutput(&(extent->imagewindow),
+ &(extent->outputwindow), &q);
+ extent->scissorBox = q;
+ }
+
+ /* if the viewport is not valid,
+ ** set it to the entire output.
+ */
+ if (!v->viewportValid)
+ {
+ extent->clippedImagewindow = extent->imagewindow;
+ extent->viewport = extent->outputwindow;
+ }
+ else
+ {
+ q.x1 = v->viewportX;
+ q.x2 = v->viewportX + v->viewportW;
+ q.y1 = v->viewportY;
+ q.y2 = v->viewportY + v->viewportH;
+
+ /* This is where the viewport gets clamped to the max size. */
+ crServerViewportClipToWindow(&(extent->imagewindow), &q);
+
+ extent->clippedImagewindow = q;
+
+ crServerConvertToOutput(&(extent->imagewindow),
+ &(extent->outputwindow), &q);
+
+ extent->viewport = q;
+ }
+
+ /*
+ ** Now, compute the base projection.
+ */
+ if (extent->clippedImagewindow.x1 == extent->clippedImagewindow.x2 ||
+ extent->clippedImagewindow.y1 == extent->clippedImagewindow.y2) {
+ /* zero-area extent, use identity matrix (doesn't really matter) */
+ extent->baseProjection = identity_matrix;
+ }
+ else
+ {
+ const int vpx = v->viewportX;
+ const int vpy = v->viewportY;
+ const int vpw = v->viewportW;
+ const int vph = v->viewportH;
+ GLfloat xscale, yscale;
+ GLfloat xtrans, ytrans;
+ CRrectf p;
+
+ /*
+ * We need to take account of the current viewport parameters,
+ * and they are passed to this function as x, y, w, h.
+ * In the default case (from main.c) we pass the the
+ * full muralsize of 0, 0, width, height
+ */
+ p.x1 = (GLfloat) (extent->clippedImagewindow.x1 - vpx) / vpw;
+ p.y1 = (GLfloat) (extent->clippedImagewindow.y1 - vpy) / vph;
+ p.x2 = (GLfloat) (extent->clippedImagewindow.x2 - vpx) / vpw;
+ p.y2 = (GLfloat) (extent->clippedImagewindow.y2 - vpy) / vph;
+
+ /* XXX not sure this clamping is really need anymore
+ */
+ if (p.x1 < 0.0) {
+ p.x1 = 0.0;
+ if (p.x2 > 1.0) p.x2 = 1.0;
+ }
+
+ if (p.y1 < 0.0) {
+ p.y1 = 0.0;
+ if (p.y2 > 1.0) p.y2 = 1.0;
+ }
+
+ /* Rescale [0,1] -> [-1,1] */
+ p.x1 = p.x1 * 2.0f - 1.0f;
+ p.x2 = p.x2 * 2.0f - 1.0f;
+ p.y1 = p.y1 * 2.0f - 1.0f;
+ p.y2 = p.y2 * 2.0f - 1.0f;
+
+ xscale = 2.0f / (p.x2 - p.x1);
+ yscale = 2.0f / (p.y2 - p.y1);
+ xtrans = -(p.x2 + p.x1) / 2.0f;
+ ytrans = -(p.y2 + p.y1) / 2.0f;
+
+ CRASSERT(xscale == xscale); /* NaN test */
+ CRASSERT(yscale == yscale);
+
+ extent->baseProjection = identity_matrix;
+ extent->baseProjection.m00 = xscale;
+ extent->baseProjection.m11 = yscale;
+ extent->baseProjection.m30 = xtrans * xscale;
+ extent->baseProjection.m31 = ytrans * yscale;
+ }
+
+ extent->serialNo = serialNo++;
+ }
+ mural->viewportValidated = GL_TRUE;
+#endif
+}
+
+
+/*
+ * Issue the glScissor, glViewport and projection matrix needed for
+ * rendering the tile specified by extNum. We computed the scissor,
+ * viewport and projection parameters above in crServerComputeViewportBounds.
+ */
+void
+crServerSetOutputBounds( const CRMuralInfo *mural, int extNum )
+{
+#if 0
+ const CRExtent *extent = mural->extents + extNum;
+ CRASSERT(mural->viewportValidated);
+
+ /*
+ * Serial Number info:
+ * Everytime we compute new scissor, viewport, projection matrix info for
+ * a tile, we give that tile a new serial number.
+ * When we're about to render into a tile, we only update the scissor,
+ * viewport and projection matrix if the tile's serial number doesn't match
+ * the current serial number. This avoids a _LOT_ of redundant calls to
+ * those three functions.
+ */
+ if (extent->serialNo != cr_server.currentSerialNo) {
+ cr_server.head_spu->dispatch_table.Scissor(extent->scissorBox.x1,
+ extent->scissorBox.y1,
+ extent->scissorBox.x2 - extent->scissorBox.x1,
+ extent->scissorBox.y2 - extent->scissorBox.y1);
+
+ cr_server.head_spu->dispatch_table.Viewport(extent->viewport.x1,
+ extent->viewport.y1,
+ extent->viewport.x2 - extent->viewport.x1,
+ extent->viewport.y2 - extent->viewport.y1);
+
+ crServerApplyBaseProjection(&(extent->baseProjection));
+ cr_server.currentSerialNo = extent->serialNo;
+ }
+#endif
+}
+
+
+/*
+ * Pre-multiply the current projection matrix with the current client's
+ * base projection. I.e. P' = b * P. Note that OpenGL's glMultMatrix
+ * POST-multiplies.
+ */
+void
+crServerApplyBaseProjection(const CRmatrix *baseProj)
+{
+ const CRmatrix *projMatrix;
+ if (cr_server.projectionOverride) {
+ int eye = crServerGetCurrentEye();
+ projMatrix = &cr_server.projectionMatrix[eye];
+ }
+ else
+ projMatrix = cr_server.curClient->currentCtxInfo->pContext->transform.projectionStack.top;
+
+ cr_server.head_spu->dispatch_table.PushAttrib( GL_TRANSFORM_BIT );
+ cr_server.head_spu->dispatch_table.MatrixMode( GL_PROJECTION );
+ cr_server.head_spu->dispatch_table.LoadMatrixf( (const GLfloat *) baseProj );
+ cr_server.head_spu->dispatch_table.MultMatrixf( cr_server.alignment_matrix );
+ cr_server.head_spu->dispatch_table.MultMatrixf( (const GLfloat *) projMatrix );
+ cr_server.head_spu->dispatch_table.PopAttrib();
+}
+
+
+void
+crServerApplyViewMatrix(const CRmatrix *view)
+{
+ const CRmatrix *modelview = cr_server.curClient->currentCtxInfo->pContext->transform.modelViewStack.top;
+
+ cr_server.head_spu->dispatch_table.PushAttrib( GL_TRANSFORM_BIT );
+ cr_server.head_spu->dispatch_table.MatrixMode( GL_MODELVIEW );
+ cr_server.head_spu->dispatch_table.LoadMatrixf( (const GLfloat *) view );
+ cr_server.head_spu->dispatch_table.MultMatrixf( (const GLfloat *) modelview );
+ cr_server.head_spu->dispatch_table.PopAttrib();
+}
+
+
+/*
+ * Called via unpacker module.
+ * Note: when there's a tilesort SPU upstream, the viewport dimensions
+ * will typically match the mural size. That is, the viewport dimensions
+ * probably won't be the same values that the application issues.
+ */
+void SERVER_DISPATCH_APIENTRY crServerDispatchViewport( GLint x, GLint y, GLsizei width, GLsizei height )
+{
+ CRMuralInfo *mural = cr_server.curClient->currentMural;
+ CRContext *ctx = crStateGetCurrent();
+
+ if (ctx->viewport.viewportX != x ||
+ ctx->viewport.viewportY != y ||
+ ctx->viewport.viewportW != width ||
+ ctx->viewport.viewportH != height) {
+ /* Note -- If there are tiles, this will be overridden in the
+ * process of decoding the BoundsInfo packet, so no worries. */
+ crStateViewport( x, y, width, height );
+ }
+
+ /* always dispatch to be safe */
+ cr_server.head_spu->dispatch_table.Viewport( x, y, width, height );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c
new file mode 100644
index 00000000..6558ea50
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c
@@ -0,0 +1,484 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "server.h"
+#include "server_dispatch.h"
+#include "cr_mem.h"
+#include "cr_rand.h"
+#include "cr_string.h"
+
+#include "render/renderspu.h"
+
+GLint SERVER_DISPATCH_APIENTRY
+crServerDispatchWindowCreate(const char *dpyName, GLint visBits)
+{
+ return crServerDispatchWindowCreateEx(dpyName, visBits, -1);
+}
+
+GLint crServerMuralInit(CRMuralInfo *mural, GLboolean fGuestWindow, GLint visBits, GLint preloadWinID)
+{
+ CRMuralInfo *defaultMural;
+ GLint dims[2];
+ GLint windowID = -1;
+ GLint spuWindow = 0;
+ GLint realVisBits = visBits;
+ const char *dpyName = "";
+
+ crMemset(mural, 0, sizeof (*mural));
+
+ if (cr_server.fVisualBitsDefault)
+ realVisBits = cr_server.fVisualBitsDefault;
+
+#ifdef RT_OS_DARWIN
+ if (fGuestWindow)
+ {
+ CRMuralInfo *dummy = crServerGetDummyMural(realVisBits);
+ if (!dummy)
+ {
+ WARN(("crServerGetDummyMural failed"));
+ return -1;
+ }
+ spuWindow = dummy->spuWindow;
+ mural->fIsDummyRefference = GL_TRUE;
+
+ dims[0] = dummy->width;
+ dims[1] = dummy->height;
+ }
+ else
+#endif
+ {
+ /*
+ * Have first SPU make a new window.
+ */
+ spuWindow = cr_server.head_spu->dispatch_table.WindowCreate( dpyName, realVisBits );
+ if (spuWindow < 0) {
+ return spuWindow;
+ }
+ mural->fIsDummyRefference = GL_FALSE;
+
+ /* get initial window size */
+ cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, spuWindow, GL_INT, 2, dims);
+ }
+
+ defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0);
+ CRASSERT(defaultMural);
+ mural->gX = 0;
+ mural->gY = 0;
+ mural->width = dims[0];
+ mural->height = dims[1];
+
+ mural->spuWindow = spuWindow;
+ mural->screenId = 0;
+ mural->fHasParentWindow = !!cr_server.screen[0].winID;
+ mural->bVisible = !cr_server.bWindowsInitiallyHidden;
+
+ mural->cVisibleRects = 0;
+ mural->pVisibleRects = NULL;
+ mural->bReceivedRects = GL_FALSE;
+
+ /* generate ID for this new window/mural (special-case for file conns) */
+ if (cr_server.curClient && cr_server.curClient->conn->type == CR_FILE)
+ windowID = spuWindow;
+ else
+ windowID = preloadWinID<0 ? (GLint)crHashtableAllocKeys( cr_server.muralTable, 1 ) : preloadWinID;
+
+ mural->CreateInfo.realVisualBits = realVisBits;
+ mural->CreateInfo.requestedVisualBits = visBits;
+ mural->CreateInfo.externalID = windowID;
+ mural->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL;
+
+ CR_STATE_SHAREDOBJ_USAGE_INIT(mural);
+
+ return windowID;
+}
+
+GLint crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID)
+{
+ CRMuralInfo *mural;
+ GLint windowID = -1;
+
+ NOREF(dpyName);
+
+ if (cr_server.sharedWindows) {
+ int pos, j;
+
+ /* find empty position in my (curclient) windowList */
+ for (pos = 0; pos < CR_MAX_WINDOWS; pos++) {
+ if (cr_server.curClient->windowList[pos] == 0) {
+ break;
+ }
+ }
+ if (pos == CR_MAX_WINDOWS) {
+ crWarning("Too many windows in crserver!");
+ return -1;
+ }
+
+ /* Look if any other client has a window for this slot */
+ for (j = 0; j < cr_server.numClients; j++) {
+ if (cr_server.clients[j]->windowList[pos] != 0) {
+ /* use that client's window */
+ windowID = cr_server.clients[j]->windowList[pos];
+ cr_server.curClient->windowList[pos] = windowID;
+ crServerReturnValue( &windowID, sizeof(windowID) ); /* real return value */
+ crDebug("CRServer: client %p sharing window %d",
+ cr_server.curClient, windowID);
+ return windowID;
+ }
+ }
+ }
+
+
+ /*
+ * Create a new mural for the new window.
+ */
+ mural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo));
+ if (!mural)
+ {
+ crWarning("crCalloc failed!");
+ return -1;
+ }
+
+ windowID = crServerMuralInit(mural, GL_TRUE, visBits, preloadWinID);
+ if (windowID < 0)
+ {
+ crWarning("crServerMuralInit failed!");
+ crServerReturnValue( &windowID, sizeof(windowID) );
+ crFree(mural);
+ return windowID;
+ }
+
+ crHashtableAdd(cr_server.muralTable, windowID, mural);
+
+ crDebug("CRServer: client %p created new window %d (SPU window %d)",
+ cr_server.curClient, windowID, mural->spuWindow);
+
+ if (windowID != -1 && !cr_server.bIsInLoadingState) {
+ int pos;
+ for (pos = 0; pos < CR_MAX_WINDOWS; pos++) {
+ if (cr_server.curClient->windowList[pos] == 0) {
+ cr_server.curClient->windowList[pos] = windowID;
+ break;
+ }
+ }
+ }
+
+ /* ensure we have a dummy mural created right away to avoid potential deadlocks on VM shutdown */
+ crServerGetDummyMural(mural->CreateInfo.realVisualBits);
+
+ crServerReturnValue( &windowID, sizeof(windowID) );
+ return windowID;
+}
+
+static int crServerRemoveClientWindow(CRClient *pClient, GLint window)
+{
+ int pos;
+
+ for (pos = 0; pos < CR_MAX_WINDOWS; ++pos)
+ {
+ if (pClient->windowList[pos] == window)
+ {
+ pClient->windowList[pos] = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void crServerMuralTerm(CRMuralInfo *mural)
+{
+ PCR_BLITTER pBlitter;
+ crServerRedirMuralFBO(mural, false);
+ crServerDeleteMuralFBO(mural);
+
+ if (cr_server.currentMural == mural)
+ {
+ CRMuralInfo *dummyMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits);
+ /* reset the current context to some dummy values to ensure render spu does not switch to a default "0" context,
+ * which might lead to muralFBO (offscreen rendering) gl entities being created in a scope of that context */
+ cr_server.head_spu->dispatch_table.MakeCurrent(dummyMural->spuWindow, 0, cr_server.MainContextInfo.SpuContext);
+ cr_server.currentWindow = -1;
+ cr_server.currentMural = dummyMural;
+ }
+ else
+ {
+ CRASSERT(cr_server.currentMural != mural);
+ }
+
+ pBlitter = crServerVBoxBlitterGetInitialized();
+ if (pBlitter)
+ {
+ const CR_BLITTER_WINDOW * pWindow = CrBltMuralGetCurrentInfo(pBlitter);
+ if (pWindow && pWindow->Base.id == mural->spuWindow)
+ {
+ CRMuralInfo *dummy = crServerGetDummyMural(mural->CreateInfo.realVisualBits);
+ CR_BLITTER_WINDOW DummyInfo;
+ CRASSERT(dummy);
+ crServerVBoxBlitterWinInit(&DummyInfo, dummy);
+ CrBltMuralSetCurrentInfo(pBlitter, &DummyInfo);
+ }
+ }
+
+ if (!mural->fIsDummyRefference)
+ cr_server.head_spu->dispatch_table.WindowDestroy( mural->spuWindow );
+
+ mural->spuWindow = 0;
+
+ if (mural->pVisibleRects)
+ {
+ crFree(mural->pVisibleRects);
+ }
+
+ if (mural->CreateInfo.pszDpyName)
+ crFree(mural->CreateInfo.pszDpyName);
+
+ crServerRedirMuralFbClear(mural);
+}
+
+static void crServerCleanupCtxMuralRefsCB(unsigned long key, void *data1, void *data2)
+{
+ CRContextInfo *ctxInfo = (CRContextInfo *) data1;
+ CRMuralInfo *mural = (CRMuralInfo *) data2;
+
+ if (ctxInfo->currentMural == mural)
+ ctxInfo->currentMural = NULL;
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchWindowDestroy( GLint window )
+{
+ CRMuralInfo *mural;
+ int32_t client;
+ CRClientNode *pNode;
+ int found=false;
+
+ if (!window)
+ {
+ crWarning("Unexpected attempt to delete default mural, ignored!");
+ return;
+ }
+
+ mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural) {
+ crWarning("CRServer: invalid window %d passed to WindowDestroy()", window);
+ return;
+ }
+
+ crDebug("CRServer: Destroying window %d (spu window %d)", window, mural->spuWindow);
+
+ crHashtableWalk(cr_server.contextTable, crServerCleanupCtxMuralRefsCB, mural);
+
+ crServerMuralTerm(mural);
+
+ CRASSERT(cr_server.currentWindow != window);
+
+ if (cr_server.curClient)
+ {
+ if (cr_server.curClient->currentMural == mural)
+ {
+ cr_server.curClient->currentMural = NULL;
+ cr_server.curClient->currentWindow = -1;
+ }
+
+ found = crServerRemoveClientWindow(cr_server.curClient, window);
+
+ /*Same as with contexts, some apps destroy it not in a thread where it was created*/
+ if (!found)
+ {
+ for (client=0; client<cr_server.numClients; ++client)
+ {
+ if (cr_server.clients[client]==cr_server.curClient)
+ continue;
+
+ found = crServerRemoveClientWindow(cr_server.clients[client], window);
+
+ if (found) break;
+ }
+ }
+
+ if (!found)
+ {
+ pNode=cr_server.pCleanupClient;
+
+ while (pNode && !found)
+ {
+ found = crServerRemoveClientWindow(pNode->pClient, window);
+ pNode = pNode->next;
+ }
+ }
+
+ CRASSERT(found);
+ }
+
+ /*Make sure this window isn't active in other clients*/
+ for (client=0; client<cr_server.numClients; ++client)
+ {
+ if (cr_server.clients[client]->currentMural == mural)
+ {
+ cr_server.clients[client]->currentMural = NULL;
+ cr_server.clients[client]->currentWindow = -1;
+ }
+ }
+
+ pNode=cr_server.pCleanupClient;
+ while (pNode)
+ {
+ if (pNode->pClient->currentMural == mural)
+ {
+ pNode->pClient->currentMural = NULL;
+ pNode->pClient->currentWindow = -1;
+ }
+ pNode = pNode->next;
+ }
+
+ crHashtableDelete(cr_server.muralTable, window, crFree);
+
+ crServerCheckAllMuralGeometry(NULL);
+}
+
+GLboolean crServerMuralSize(CRMuralInfo *mural, GLint width, GLint height)
+{
+ if (mural->width == width && mural->height == height)
+ return GL_FALSE;
+
+ mural->width = width;
+ mural->height = height;
+
+ if (cr_server.curClient && cr_server.curClient->currentMural == mural
+ && !mural->fRedirected)
+ {
+ crStateGetCurrent()->buffer.width = mural->width;
+ crStateGetCurrent()->buffer.height = mural->height;
+ }
+
+ crServerCheckAllMuralGeometry(mural);
+
+ return GL_TRUE;
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchWindowSize( GLint window, GLint width, GLint height )
+{
+ CRMuralInfo *mural;
+
+ /* crDebug("CRServer: Window %d size %d x %d", window, width, height);*/
+ mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural) {
+#if EXTRA_WARN
+ crWarning("CRServer: invalid window %d passed to WindowSize()", window);
+#endif
+ return;
+ }
+
+ crServerMuralSize(mural, width, height);
+
+ if (cr_server.currentMural == mural)
+ {
+ crServerPerformMakeCurrent( mural, cr_server.currentCtxInfo );
+ }
+}
+
+void crServerMuralPosition(CRMuralInfo *mural, GLint x, GLint y)
+{
+ if (mural->gX == x && mural->gY == y)
+ return;
+
+ mural->gX = x;
+ mural->gY = y;
+
+ crServerCheckAllMuralGeometry(mural);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchWindowPosition( GLint window, GLint x, GLint y )
+{
+ CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural) {
+#if EXTRA_WARN
+ crWarning("CRServer: invalid window %d passed to WindowPosition()", window);
+#endif
+ return;
+ }
+ crServerMuralPosition(mural, x, y);
+}
+
+void crServerMuralVisibleRegion( CRMuralInfo *mural, GLint cRects, const GLint *pRects )
+{
+ if (mural->pVisibleRects)
+ {
+ crFree(mural->pVisibleRects);
+ mural->pVisibleRects = NULL;
+ }
+
+ mural->cVisibleRects = cRects;
+ mural->bReceivedRects = GL_TRUE;
+ if (cRects)
+ {
+ mural->pVisibleRects = (GLint*) crAlloc(4*sizeof(GLint)*cRects);
+ if (!mural->pVisibleRects)
+ {
+ crError("Out of memory in crServerDispatchWindowVisibleRegion");
+ }
+ crMemcpy(mural->pVisibleRects, pRects, 4*sizeof(GLint)*cRects);
+ }
+
+ crServerCheckAllMuralGeometry(mural);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchWindowVisibleRegion( GLint window, GLint cRects, const GLint *pRects )
+{
+ CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural) {
+#if EXTRA_WARN
+ crWarning("CRServer: invalid window %d passed to WindowVisibleRegion()", window);
+#endif
+ return;
+ }
+
+ crServerMuralVisibleRegion( mural, cRects, pRects );
+}
+
+void crServerMuralShow( CRMuralInfo *mural, GLint state )
+{
+ if (!mural->bVisible == !state)
+ return;
+
+ mural->bVisible = !!state;
+
+ if (mural->bVisible)
+ crServerCheckMuralGeometry(mural);
+ else
+ crServerCheckAllMuralGeometry(mural);
+}
+
+void SERVER_DISPATCH_APIENTRY
+crServerDispatchWindowShow( GLint window, GLint state )
+{
+ CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window);
+ if (!mural) {
+#if EXTRA_WARN
+ crWarning("CRServer: invalid window %d passed to WindowShow()", window);
+#endif
+ return;
+ }
+
+ crServerMuralShow( mural, state );
+}
+
+GLint
+crServerSPUWindowID(GLint serverWindow)
+{
+ CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, serverWindow);
+ if (!mural) {
+#if EXTRA_WARN
+ crWarning("CRServer: invalid window %d passed to crServerSPUWindowID()",
+ serverWindow);
+#endif
+ return -1;
+ }
+ return mural->spuWindow;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_winpos.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_winpos.c
new file mode 100644
index 00000000..8026b962
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_winpos.c
@@ -0,0 +1,95 @@
+
+#include "server_dispatch.h"
+#include "server.h"
+
+
+/**
+ * All glWindowPos commands go through here.
+ */
+static void crServerWindowPos( GLfloat x, GLfloat y, GLfloat z )
+{
+ crStateWindowPos3fARB(x, y, z);
+ cr_server.head_spu->dispatch_table.WindowPos3fARB(x, y, z);
+}
+
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2dARB( GLdouble x, GLdouble y )
+{
+ crServerWindowPos((GLfloat) x, (GLfloat) y, 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2dvARB( const GLdouble * v )
+{
+ crServerWindowPos((GLfloat) v[0], (GLfloat) v[1], 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2fARB( GLfloat x, GLfloat y )
+{
+ crServerWindowPos(x, y, 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2fvARB( const GLfloat * v )
+{
+ crServerWindowPos(v[0], v[1], 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2iARB( GLint x, GLint y )
+{
+ crServerWindowPos((GLfloat)x, (GLfloat)y, 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2ivARB( const GLint * v )
+{
+ crServerWindowPos((GLfloat)v[0], (GLfloat)v[1], 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2sARB( GLshort x, GLshort y )
+{
+ crServerWindowPos(x, y, 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos2svARB( const GLshort * v )
+{
+ crServerWindowPos(v[0], v[1], 0.0F);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3dARB( GLdouble x, GLdouble y, GLdouble z )
+{
+ crServerWindowPos((GLfloat) x, (GLfloat) y, (GLfloat) z);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3dvARB( const GLdouble * v )
+{
+ crServerWindowPos((GLfloat) v[0], (GLfloat) v[1], (GLfloat) v[2]);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3fARB( GLfloat x, GLfloat y, GLfloat z )
+{
+ crServerWindowPos(x, y, z);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3fvARB( const GLfloat * v )
+{
+ crServerWindowPos(v[0], v[1], v[2]);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3iARB( GLint x, GLint y, GLint z )
+{
+ crServerWindowPos((GLfloat)x,(GLfloat)y, (GLfloat)z);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3ivARB( const GLint * v )
+{
+ crServerWindowPos((GLfloat)v[0], (GLfloat)v[1], (GLfloat)v[2]);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3sARB( GLshort x, GLshort y, GLshort z )
+{
+ crServerWindowPos(x, y, z);
+}
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPos3svARB( const GLshort * v )
+{
+ crServerWindowPos(v[0], v[1], v[2]);
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_writeback.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_writeback.c
new file mode 100644
index 00000000..8af28cd5
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_writeback.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_mem.h"
+#include "cr_net.h"
+#include "server_dispatch.h"
+#include "server.h"
+
+void SERVER_DISPATCH_APIENTRY crServerDispatchWriteback( GLint *writeback )
+{
+ (void) writeback;
+ crServerWriteback( );
+}
+
+void crServerWriteback(void)
+{
+ CRMessageWriteback *wb = (CRMessageWriteback *) crAlloc( sizeof( *wb ) );
+ wb->header.type = CR_MESSAGE_WRITEBACK;
+ CRDBGPTR_PRINTWB(cr_server.curClient->conn->u32ClientID, &cr_server.writeback_ptr);
+ CRDBGPTR_CHECKNZ(&cr_server.writeback_ptr);
+ crMemcpy( &(wb->writeback_ptr), &(cr_server.writeback_ptr), sizeof( wb->writeback_ptr ) );
+ crNetSend( cr_server.curClient->conn, NULL, wb, sizeof( *wb ) );
+ CRDBGPTR_SETZ(&cr_server.writeback_ptr);
+ crFree( wb );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/dlm/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm.c
new file mode 100644
index 00000000..8ea6c69c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm.c
@@ -0,0 +1,575 @@
+/* $Id: dlm.c $ */
+
+#include <float.h>
+#include "cr_dlm.h"
+#include "cr_mem.h"
+#include "dlm.h"
+
+/**
+ * \mainpage Dlm
+ *
+ * \section DlmIntroduction Introduction
+ *
+ * Chromium consists of all the top-level files in the cr
+ * directory. The dlm module basically takes care of API dispatch,
+ * and OpenGL state management.
+ *
+ */
+
+/**
+ * Module globals: the current DLM state, bound either to each thread, or
+ * to a global.
+ */
+#ifdef CHROMIUM_THREADSAFE
+CRtsd CRDLMTSDKey;
+#else
+CRDLMContextState *CRDLMCurrentState = NULL;
+#endif
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+
+/*************************************************************************/
+
+#ifdef CHROMIUM_THREADSAFE
+/**
+ * This is the thread-specific destructor function for the
+ * data used in the DLM. It's very simple: if a thread exits
+ * that has DLM-specific data, the data represents the listState
+ * for the thread. All data and buffers associated with the list
+ * can be deleted, and the structure itself can be freed.
+ *
+ * Most Chromium threads don't have such things; but then,
+ * if a thread dies elsewhere in Chromium, huge buffers
+ * of information won't still be floating around in
+ * unrecoverable allocated areas, either.
+ */
+static void threadDestructor(void *tsd)
+{
+ CRDLMContextState *listState = (CRDLMContextState *)tsd;
+
+ if (listState)
+ {
+ //if (listState->currentListInfo)
+ // crdlm_free_list(listState->currentListInfo);
+
+ crFree(listState);
+ }
+}
+#endif
+
+/**
+ * This function creates and initializes a new display list
+ * manager. It returns a pointer to the manager, or NULL in
+ * the case of insufficient memory. The dispatch table pointer
+ * is passed in to allow the utilities to muck with the table
+ * to gain functional control when GL calls are made.
+ */
+CRDLM DLM_APIENTRY *crDLMNewDLM(unsigned int userConfigSize, const CRDLMConfig *userConfig)
+{
+ CRDLM *dlm;
+
+ /* This is the default configuration. We'll overwrite it later
+ * with user-supplied configuration information.
+ */
+ CRDLMConfig config = {
+ CRDLM_DEFAULT_BUFFERSIZE,
+ };
+
+ dlm = crAlloc(sizeof(*dlm));
+ if (!dlm) {
+ return NULL;
+ }
+
+ /* Start off by initializing all entries that require further
+ * memory allocation, so we can free up all the memory if there's
+ * a problem.
+ */
+ if (!(dlm->displayLists = crAllocHashtable())) {
+ crFree(dlm);
+ return NULL;
+ }
+
+ /* The creator counts as the first user. */
+ dlm->userCount = 1;
+
+#ifdef CHROMIUM_THREADSAFE
+ /* This mutex ensures that only one thread is changing the displayLists
+ * hash at a time. Note that we may also need a mutex to guarantee that
+ * the hash is not changed by one thread while another thread is
+ * traversing it; this issue has not yet been resolved.
+ */
+ crInitMutex(&(dlm->dlMutex));
+
+ /* Although the thread-specific data (TSD) functions will initialize
+ * the thread key themselves when needed, those functions do not allow
+ * us to specify a thread destructor. Since a thread could potentially
+ * exit with considerable memory allocated (e.g. if a thread exits
+ * after it has issued NewList but before EndList, and while there
+ * are considerable content buffers allocated), I do the initialization
+ * myself, in order to be able to reclaim those resources if a thread
+ * exits.
+ */
+ crInitTSDF(&(dlm->tsdKey), threadDestructor);
+ crInitTSD(&CRDLMTSDKey);
+#endif
+
+ /* Copy over any appropriate configuration values */
+ if (userConfig != NULL) {
+ /* Copy over as much configuration information as is provided.
+ * Note that if the CRDLMConfig structure strictly grows, this
+ * allows forward compatability - routines compiled with
+ * older versions of the structure will only initialize that
+ * section of the structure that they know about.
+ */
+ crMemcpy((void *)&config, (void *) userConfig,
+ MIN(userConfigSize, sizeof(config)));
+ }
+ dlm->bufferSize = config.bufferSize;
+
+ /* Return the pointer to the newly-allocated display list manager */
+ return dlm;
+}
+
+void DLM_APIENTRY crDLMUseDLM(CRDLM *dlm)
+{
+ DLM_LOCK(dlm);
+ dlm->userCount++;
+ DLM_UNLOCK(dlm);
+}
+
+/**
+ * This routine is called when a context or thread is done with a DLM.
+ * It maintains an internal count of users, and will only actually destroy
+ * itself when no one is still using the DLM.
+ */
+void DLM_APIENTRY crDLMFreeDLM(CRDLM *dlm, SPUDispatchTable *dispatchTable)
+{
+ /* We're about to change the displayLists hash; lock it first */
+ DLM_LOCK(dlm)
+
+ /* Decrement the user count. If the user count has gone to
+ * 0, then free the rest of the DLM. Otherwise, other
+ * contexts or threads are still using this DLM; keep
+ * it around.
+ */
+ dlm->userCount--;
+ if (dlm->userCount == 0) {
+
+ crFreeHashtableEx(dlm->displayLists, crdlmFreeDisplayListResourcesCb, dispatchTable);
+ dlm->displayLists = NULL;
+
+ /* Must unlock before freeing the mutex */
+ DLM_UNLOCK(dlm)
+
+#ifdef CHROMIUM_THREADSAFE
+ /* We release the mutex here; we really should delete the
+ * thread data key, but there's no utility in Chromium to
+ * do this.
+ *
+ * Note that, should one thread release the entire DLM
+ * while other threads still believe they are using it,
+ * any other threads that have current display lists (i.e.
+ * have issued glNewList more recently than glEndList)
+ * will be unable to reclaim their (likely very large)
+ * content buffers, as there will be no way to reclaim
+ * the thread-specific data.
+ *
+ * On the other hand, if one thread really does release
+ * the DLM while other threads still believe they are
+ * using it, unreclaimed memory is the least of the
+ * application's problems...
+ */
+ crFreeMutex(&(dlm->dlMutex));
+
+ /* We free the TSD key here as well. Note that this will
+ * strand any threads that still have thread-specific data
+ * tied to this key; but as stated above, if any threads
+ * still do have thread-specific data attached to this DLM,
+ * they're in big trouble anyway.
+ */
+ crFreeTSD(&(dlm->tsdKey));
+ crFreeTSD(&CRDLMTSDKey);
+#endif
+
+ /* Free the master record, and we're all done. */
+ crFree(dlm);
+ }
+ else {
+ /* We're keeping the DLM around for other users. Unlock it,
+ * but retain its memory and display lists.
+ */
+ DLM_UNLOCK(dlm)
+ }
+}
+
+/**
+ * The actual run-time state of a DLM is bound to a context
+ * (because each context can be used by at most one thread at
+ * a time, and a thread can only use one context at a time,
+ * while multiple contexts can use the same DLM).
+ * This creates the structure required to hold the state, and
+ * returns it to the caller, who should store it with any other
+ * context-specific information.
+ */
+
+CRDLMContextState DLM_APIENTRY *crDLMNewContext(CRDLM *dlm)
+{
+ CRDLMContextState *state;
+
+ /* Get a record for our own internal state structure */
+ state = (CRDLMContextState *)crAlloc(sizeof(CRDLMContextState));
+ if (!state) {
+ return NULL;
+ }
+
+ state->dlm = dlm;
+ state->currentListIdentifier = 0;
+ state->currentListInfo = NULL;
+ state->currentListMode = GL_FALSE;
+ state->listBase = 0;
+
+ /* Increment the use count of the DLM provided. This guarantees that
+ * the DLM won't be released until all the contexts have released it.
+ */
+ crDLMUseDLM(dlm);
+
+ return state;
+}
+
+
+/**
+ * This routine should be called when a MakeCurrent changes the current
+ * context. It sets the thread data (or global data, in an unthreaded
+ * environment) appropriately; this in turn changes the behavior of
+ * the installed DLM API functions.
+ */
+void DLM_APIENTRY crDLMSetCurrentState(CRDLMContextState *state)
+{
+ CRDLMContextState *currentState = CURRENT_STATE();
+ if (currentState != state) {
+ SET_CURRENT_STATE(state);
+ }
+}
+
+CRDLMContextState DLM_APIENTRY *crDLMGetCurrentState(void)
+{
+ return CURRENT_STATE();
+}
+
+/**
+ * This routine, of course, is used to release a DLM context when it
+ * is no longer going to be used.
+ */
+
+void DLM_APIENTRY crDLMFreeContext(CRDLMContextState *state, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+
+ /* If we're currently using this context, release it first */
+ if (listState == state)
+ crDLMSetCurrentState(NULL);
+
+ /* Try to free the DLM. This will either decrement the use count,
+ * or will actually free the DLM, if we were the last user.
+ */
+ crDLMFreeDLM(state->dlm, dispatchTable);
+ state->dlm = NULL;
+
+ /* If any buffers still remain (e.g. because there was an open
+ * display list), remove those as well.
+ */
+ if (state->currentListInfo)
+ {
+ crdlmFreeDisplayListResourcesCb((void *)state->currentListInfo, (void *)dispatchTable);
+ state->currentListInfo = NULL;
+ }
+ state->currentListIdentifier = 0;
+
+ /* Free the state record itself */
+ crFree(state);
+}
+
+
+/**
+ * This function can be used if the caller wishes to free up the
+ * potentially considerable resources used to store the display list
+ * content, without losing the rest of the display list management.
+ * For one example, consider an SPU that conditionally sends its
+ * input stream to multiple servers. It could broadcast all display
+ * lists to all servers, or it could only send display lists to servers
+ * that need them. After all servers have the display list, the SPU
+ * may wish to release the resources used to manage the content.
+ */
+CRDLMError DLM_APIENTRY crDLMDeleteListContent(CRDLM *dlm, unsigned long listIdentifier)
+{
+ DLMListInfo *listInfo;
+ DLMInstanceList *instance;
+
+ listInfo = (DLMListInfo *) crHashtableSearch(dlm->displayLists, listIdentifier);
+ if (listInfo && (instance = listInfo->first)) {
+ while (instance) {
+ DLMInstanceList *nextInstance;
+ nextInstance = instance->next;
+ crFree(instance);
+ instance = nextInstance;
+ }
+ listInfo->first = listInfo->last = NULL;
+ }
+ return GL_NO_ERROR;
+}
+
+/**
+ *
+ * Playback/execute a list.
+ * dlm - the display list manager context
+ * listIdentifier - the display list ID (as specified by app) to playback
+ * dispatchTable - the GL dispatch table to jump through as we execute commands
+ */
+void DLM_APIENTRY crDLMReplayDLMList(CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
+{
+ DLMListInfo *listInfo;
+
+ listInfo = (DLMListInfo *)crHashtableSearch(dlm->displayLists, listIdentifier);
+ if (listInfo) {
+ DLMInstanceList *instance = listInfo->first;
+ while (instance) {
+ /* mutex, to make sure another thread doesn't change the list? */
+ /* For now, leave it alone. */
+ (*instance->execute)(instance, dispatchTable);
+ instance = instance->next;
+ }
+ }
+}
+
+/* Playback/execute a list in the current DLM */
+void DLM_APIENTRY crDLMReplayList(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ if (listState)
+ crDLMReplayDLMList(listState->dlm, listIdentifier, dispatchTable);
+}
+
+/*
+ * Playback/execute the state changing portions of a list.
+ * dlm - the display list manager context
+ * listIdentifier - the display list ID (as specified by app) to playback
+ * dispatchTable - the GL dispatch table to jump through as we execute commands
+ */
+void DLM_APIENTRY crDLMReplayDLMListState(CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
+{
+ DLMListInfo *listInfo;
+
+ listInfo = (DLMListInfo *)crHashtableSearch(dlm->displayLists, listIdentifier);
+ if (listInfo) {
+ DLMInstanceList *instance = listInfo->stateFirst;
+ while (instance) {
+ /* mutex, to make sure another thread doesn't change the list? */
+ /* For now, leave it alone. */
+ (*instance->execute)(instance, dispatchTable);
+ instance = instance->stateNext;
+ }
+ }
+}
+
+void DLM_APIENTRY crDLMReplayListState(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ if (listState)
+ crDLMReplayDLMListState(listState->dlm, listIdentifier, dispatchTable);
+}
+
+/* This is a switch statement that lists every "type" value valid for a
+ * glCallLists() function call, with code for decoding the subsequent
+ * values correctly. It uses the current value of the EXPAND() macro,
+ * which must expand into an appropriate action to be taken.
+ * Its codification here allows for multiple uses.
+ */
+#define CALL_LISTS_SWITCH(type, defaultAction) \
+ switch (type) {\
+ EXPAND(GL_BYTE, GLbyte *, *p, p++)\
+ EXPAND(GL_UNSIGNED_BYTE, GLubyte *, *p, p++)\
+ EXPAND(GL_SHORT, GLshort *, *p, p++)\
+ EXPAND(GL_UNSIGNED_SHORT, GLushort *, *p, p++)\
+ EXPAND(GL_INT, GLint *, *p, p++)\
+ EXPAND(GL_FLOAT, GLfloat *, *p, p++)\
+ EXPAND(GL_2_BYTES, unsigned char *, 256*p[0] + p[1], p += 2)\
+ EXPAND(GL_3_BYTES, unsigned char *, 65536*p[0] + 256*p[1] + p[2], p += 3)\
+ EXPAND(GL_4_BYTES, unsigned char *, 16777216*p[0] + 65536*p[1] + 256*p[2] + p[3], p += 4)\
+ default:\
+ defaultAction;\
+ }
+
+void DLM_APIENTRY crDLMReplayDLMLists(CRDLM *dlm, GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
+{
+ unsigned long listId;
+ CRDLMContextState *listState = CURRENT_STATE();
+
+#define EXPAND(TYPENAME, TYPE, REFERENCE, INCREMENT) \
+ case TYPENAME: {\
+ TYPE p = (TYPE)lists;\
+ while (n--) {\
+ listId = listState->listBase + (unsigned long) (REFERENCE);\
+ crDLMReplayDLMList(dlm, listId, dispatchTable);\
+ INCREMENT;\
+ }\
+ break;\
+ }
+
+ CALL_LISTS_SWITCH(type, break)
+#undef EXPAND
+
+}
+
+void DLM_APIENTRY crDLMReplayLists(GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ if (listState) {
+ crDLMReplayDLMLists(listState->dlm, n, type, lists, dispatchTable);
+ }
+}
+
+void DLM_APIENTRY crDLMReplayDLMListsState(CRDLM *dlm, GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
+{
+ unsigned long listId;
+ CRDLMContextState *listState = CURRENT_STATE();
+
+#define EXPAND(TYPENAME, TYPE, REFERENCE, INCREMENT) \
+ case TYPENAME: {\
+ TYPE p = (TYPE)lists;\
+ while (n--) {\
+ listId = listState->listBase + (unsigned long) (REFERENCE);\
+ crDLMReplayDLMListState(dlm, listId, dispatchTable);\
+ INCREMENT;\
+ }\
+ break;\
+ }
+
+ CALL_LISTS_SWITCH(type, break)
+#undef EXPAND
+
+}
+
+void DLM_APIENTRY crDLMReplayListsState(GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ if (listState) {
+ crDLMReplayDLMListsState(listState->dlm, n, type, lists, dispatchTable);
+ }
+}
+
+/* When we compiled the display list, we packed all pixel data
+ * tightly. When we execute the display list, we have to make
+ * sure that the client state reflects that the pixel data is
+ * tightly packed, or it will be interpreted incorrectly.
+ */
+void DLM_APIENTRY crDLMSetupClientState(SPUDispatchTable *dispatchTable)
+{
+ dispatchTable->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ dispatchTable->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ dispatchTable->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ dispatchTable->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+}
+
+void DLM_APIENTRY crDLMRestoreClientState(CRClientState *clientState, SPUDispatchTable *dispatchTable)
+{
+ if (clientState) {
+ dispatchTable->PixelStorei(GL_UNPACK_ROW_LENGTH, clientState->unpack.rowLength);
+ dispatchTable->PixelStorei(GL_UNPACK_SKIP_PIXELS, clientState->unpack.skipPixels);
+ dispatchTable->PixelStorei(GL_UNPACK_SKIP_ROWS, clientState->unpack.skipRows);
+ dispatchTable->PixelStorei(GL_UNPACK_ALIGNMENT, clientState->unpack.alignment);
+ }
+}
+
+void DLM_APIENTRY crDLMSendDLMList(CRDLM *dlm, unsigned long listIdentifier,
+ SPUDispatchTable *dispatchTable)
+{
+ dispatchTable->NewList(listIdentifier, GL_COMPILE);
+ crDLMReplayDLMList(dlm, listIdentifier, dispatchTable);
+ dispatchTable->EndList();
+}
+
+void DLM_APIENTRY crDLMSendList(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ if (listState) {
+ crDLMSendDLMList(listState->dlm, listIdentifier, dispatchTable);
+ }
+}
+
+struct sendListsCallbackParms {
+ CRDLM *dlm;
+ SPUDispatchTable *dispatchTable;
+};
+
+static void sendListsCallback(unsigned long key, void *data, void *dataPtr2)
+{
+ struct sendListsCallbackParms *parms = (struct sendListsCallbackParms *)dataPtr2;
+
+ crDLMSendDLMList(parms->dlm, key, parms->dispatchTable);
+}
+
+void DLM_APIENTRY crDLMSendAllDLMLists(CRDLM *dlm, SPUDispatchTable *dispatchTable)
+{
+ struct sendListsCallbackParms parms;
+
+ /* This is how we pass our parameter information to the callback routine -
+ * through a pointer to this local structure.
+ */
+ parms.dlm = dlm;
+ parms.dispatchTable = dispatchTable;
+
+ crHashtableWalk(dlm->displayLists, sendListsCallback, (void *)&parms);
+}
+
+void DLM_APIENTRY crDLMSendAllLists(SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ if (listState) {
+ crDLMSendAllDLMLists(listState->dlm, dispatchTable);
+ }
+}
+
+/** Another clever callback arrangement to get the desired data. */
+struct getRefsCallbackParms {
+ int remainingOffset;
+ int remainingCount;
+ unsigned int *buffer;
+ int totalCount;
+};
+
+/*
+ * Return id of list currently being compiled. Returns 0 of there's no
+ * current DLM state, or if no list is being compiled.
+ */
+GLuint DLM_APIENTRY crDLMGetCurrentList(void)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ return listState ? listState->currentListIdentifier : 0;
+}
+
+/*
+ * Return mode of list currently being compiled. Should be
+ * GL_FALSE if no list is being compiled, or GL_COMPILE if a
+ * list is being compiled but not executed, or GL_COMPILE_AND_EXECUTE
+ * if a list is being compiled and executed.
+ */
+GLenum DLM_APIENTRY crDLMGetCurrentMode(void)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ return listState ? listState->currentListMode : 0;
+}
+
+
+static CRDLMErrorCallback ErrorCallback = NULL;
+
+void DLM_APIENTRY crDLMErrorFunction(CRDLMErrorCallback callback)
+{
+ ErrorCallback = callback;
+}
+
+void crdlm_error(int line, const char *file, GLenum error, const char *info)
+{
+ if (ErrorCallback)
+ (*ErrorCallback)(line, file, error, info);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm.h b/src/VBox/HostServices/SharedOpenGL/dlm/dlm.h
new file mode 100644
index 00000000..2e6db46e
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm.h
@@ -0,0 +1,31 @@
+/* $Id: dlm.h $ */
+
+#ifndef _DLM_H
+#define _DLM_H
+
+#include "cr_dlm.h"
+#include "cr_spu.h"
+
+#ifdef CHROMIUM_THREADSAFE
+#define DLM_LOCK(dlm) crLockMutex(&(dlm->dlMutex));
+#define DLM_UNLOCK(dlm) crUnlockMutex(&(dlm->dlMutex));
+extern CRtsd CRDLMTSDKey;
+#define SET_CURRENT_STATE(state) crSetTSD(&CRDLMTSDKey, (void *)state);
+#define CURRENT_STATE() ((CRDLMContextState *)crGetTSD(&CRDLMTSDKey))
+#else
+#define DLM_LOCK(dlm)
+#define DLM_UNLOCK(dlm)
+extern CRDLMContextState *CRDLMCurrentState;
+#define SET_CURRENT_STATE(state) CRDLMCurrentState = (state);
+#define CURRENT_STATE() (CRDLMCurrentState)
+#endif
+
+/* These routines are intended to be used within the DLM library, across
+ * the modules therein, but not as an API into the DLM library from
+ * outside.
+ */
+extern void crdlmWarning( int line, char *file, GLenum error, char *format, ... );
+extern void crdlmFreeDisplayListResourcesCb(void *pParm1, void *pParam2);
+extern void crdlm_error(int line, const char *file, GLenum error, const char *info);
+
+#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_arrays.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_arrays.c
new file mode 100644
index 00000000..d14d7198
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_arrays.c
@@ -0,0 +1,387 @@
+/* $Id: dlm_arrays.c $ */
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "chromium.h"
+#include "cr_dlm.h"
+#include "dlm.h"
+
+/*
+ * XXX this code is awfully similar to the code in arrayspu.c
+ * We should try to write something reusable.
+ */
+
+void DLM_APIENTRY crDLMCompileArrayElement (GLint index, CRClientState *c)
+{
+ unsigned char *p;
+ int unit;
+
+ if (c->array.e.enabled)
+ {
+ crDLMCompileEdgeFlagv(c->array.e.p + index*c->array.e.stride);
+ }
+ for (unit = 0; unit < CR_MAX_TEXTURE_UNITS; unit++)
+ {
+ if (c->array.t[unit].enabled)
+ {
+ p = c->array.t[unit].p + index*c->array.t[unit].stride;
+ switch (c->array.t[unit].type)
+ {
+ case GL_SHORT:
+ switch (c->array.t[c->curClientTextureUnit].size)
+ {
+ case 1: crDLMCompileMultiTexCoord1svARB(GL_TEXTURE0_ARB + unit, (GLshort *)p); break;
+ case 2: crDLMCompileMultiTexCoord2svARB(GL_TEXTURE0_ARB + unit, (GLshort *)p); break;
+ case 3: crDLMCompileMultiTexCoord3svARB(GL_TEXTURE0_ARB + unit, (GLshort *)p); break;
+ case 4: crDLMCompileMultiTexCoord4svARB(GL_TEXTURE0_ARB + unit, (GLshort *)p); break;
+ }
+ break;
+ case GL_INT:
+ switch (c->array.t[c->curClientTextureUnit].size)
+ {
+ case 1: crDLMCompileMultiTexCoord1ivARB(GL_TEXTURE0_ARB + unit, (GLint *)p); break;
+ case 2: crDLMCompileMultiTexCoord2ivARB(GL_TEXTURE0_ARB + unit, (GLint *)p); break;
+ case 3: crDLMCompileMultiTexCoord3ivARB(GL_TEXTURE0_ARB + unit, (GLint *)p); break;
+ case 4: crDLMCompileMultiTexCoord4ivARB(GL_TEXTURE0_ARB + unit, (GLint *)p); break;
+ }
+ break;
+ case GL_FLOAT:
+ switch (c->array.t[c->curClientTextureUnit].size)
+ {
+ case 1: crDLMCompileMultiTexCoord1fvARB(GL_TEXTURE0_ARB + unit, (GLfloat *)p); break;
+ case 2: crDLMCompileMultiTexCoord2fvARB(GL_TEXTURE0_ARB + unit, (GLfloat *)p); break;
+ case 3: crDLMCompileMultiTexCoord3fvARB(GL_TEXTURE0_ARB + unit, (GLfloat *)p); break;
+ case 4: crDLMCompileMultiTexCoord4fvARB(GL_TEXTURE0_ARB + unit, (GLfloat *)p); break;
+ }
+ break;
+ case GL_DOUBLE:
+ switch (c->array.t[c->curClientTextureUnit].size)
+ {
+ case 1: crDLMCompileMultiTexCoord1dvARB(GL_TEXTURE0_ARB + unit, (GLdouble *)p); break;
+ case 2: crDLMCompileMultiTexCoord2dvARB(GL_TEXTURE0_ARB + unit, (GLdouble *)p); break;
+ case 3: crDLMCompileMultiTexCoord3dvARB(GL_TEXTURE0_ARB + unit, (GLdouble *)p); break;
+ case 4: crDLMCompileMultiTexCoord4dvARB(GL_TEXTURE0_ARB + unit, (GLdouble *)p); break;
+ }
+ break;
+ }
+ }
+ } /* loop over texture units */
+
+ if (c->array.i.enabled)
+ {
+ p = c->array.i.p + index*c->array.i.stride;
+ switch (c->array.i.type)
+ {
+ case GL_SHORT: crDLMCompileIndexsv((GLshort *)p); break;
+ case GL_INT: crDLMCompileIndexiv((GLint *)p); break;
+ case GL_FLOAT: crDLMCompileIndexfv((GLfloat *)p); break;
+ case GL_DOUBLE: crDLMCompileIndexdv((GLdouble *)p); break;
+ }
+ }
+ if (c->array.c.enabled)
+ {
+ p = c->array.c.p + index*c->array.c.stride;
+ switch (c->array.c.type)
+ {
+ case GL_BYTE:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3bv((GLbyte *)p); break;
+ case 4: crDLMCompileColor4bv((GLbyte *)p); break;
+ }
+ break;
+ case GL_UNSIGNED_BYTE:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3ubv((GLubyte *)p); break;
+ case 4: crDLMCompileColor4ubv((GLubyte *)p); break;
+ }
+ break;
+ case GL_SHORT:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3sv((GLshort *)p); break;
+ case 4: crDLMCompileColor4sv((GLshort *)p); break;
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3usv((GLushort *)p); break;
+ case 4: crDLMCompileColor4usv((GLushort *)p); break;
+ }
+ break;
+ case GL_INT:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3iv((GLint *)p); break;
+ case 4: crDLMCompileColor4iv((GLint *)p); break;
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3uiv((GLuint *)p); break;
+ case 4: crDLMCompileColor4uiv((GLuint *)p); break;
+ }
+ break;
+ case GL_FLOAT:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3fv((GLfloat *)p); break;
+ case 4: crDLMCompileColor4fv((GLfloat *)p); break;
+ }
+ break;
+ case GL_DOUBLE:
+ switch (c->array.c.size)
+ {
+ case 3: crDLMCompileColor3dv((GLdouble *)p); break;
+ case 4: crDLMCompileColor4dv((GLdouble *)p); break;
+ }
+ break;
+ }
+ }
+ if (c->array.n.enabled)
+ {
+ p = c->array.n.p + index*c->array.n.stride;
+ switch (c->array.n.type)
+ {
+ case GL_BYTE: crDLMCompileNormal3bv((GLbyte *)p); break;
+ case GL_SHORT: crDLMCompileNormal3sv((GLshort *)p); break;
+ case GL_INT: crDLMCompileNormal3iv((GLint *)p); break;
+ case GL_FLOAT: crDLMCompileNormal3fv((GLfloat *)p); break;
+ case GL_DOUBLE: crDLMCompileNormal3dv((GLdouble *)p); break;
+ }
+ }
+#ifdef CR_EXT_secondary_color
+ if (c->array.s.enabled)
+ {
+ p = c->array.s.p + index*c->array.s.stride;
+ switch (c->array.s.type)
+ {
+ case GL_BYTE:
+ crDLMCompileSecondaryColor3bvEXT((GLbyte *)p); break;
+ case GL_UNSIGNED_BYTE:
+ crDLMCompileSecondaryColor3ubvEXT((GLubyte *)p); break;
+ case GL_SHORT:
+ crDLMCompileSecondaryColor3svEXT((GLshort *)p); break;
+ case GL_UNSIGNED_SHORT:
+ crDLMCompileSecondaryColor3usvEXT((GLushort *)p); break;
+ case GL_INT:
+ crDLMCompileSecondaryColor3ivEXT((GLint *)p); break;
+ case GL_UNSIGNED_INT:
+ crDLMCompileSecondaryColor3uivEXT((GLuint *)p); break;
+ case GL_FLOAT:
+ crDLMCompileSecondaryColor3fvEXT((GLfloat *)p); break;
+ case GL_DOUBLE:
+ crDLMCompileSecondaryColor3dvEXT((GLdouble *)p); break;
+ }
+ }
+#endif
+ if (c->array.v.enabled)
+ {
+ p = c->array.v.p + (index*c->array.v.stride);
+
+ switch (c->array.v.type)
+ {
+ case GL_SHORT:
+ switch (c->array.v.size)
+ {
+ case 2: crDLMCompileVertex2sv((GLshort *)p); break;
+ case 3: crDLMCompileVertex3sv((GLshort *)p); break;
+ case 4: crDLMCompileVertex4sv((GLshort *)p); break;
+ }
+ break;
+ case GL_INT:
+ switch (c->array.v.size)
+ {
+ case 2: crDLMCompileVertex2iv((GLint *)p); break;
+ case 3: crDLMCompileVertex3iv((GLint *)p); break;
+ case 4: crDLMCompileVertex4iv((GLint *)p); break;
+ }
+ break;
+ case GL_FLOAT:
+ switch (c->array.v.size)
+ {
+ case 2: crDLMCompileVertex2fv((GLfloat *)p); break;
+ case 3: crDLMCompileVertex3fv((GLfloat *)p); break;
+ case 4: crDLMCompileVertex4fv((GLfloat *)p); break;
+ }
+ break;
+ case GL_DOUBLE:
+ switch (c->array.v.size)
+ {
+ case 2: crDLMCompileVertex2dv((GLdouble *)p); break;
+ case 3: crDLMCompileVertex3dv((GLdouble *)p); break;
+ case 4: crDLMCompileVertex4dv((GLdouble *)p); break;
+ }
+ break;
+ }
+ }
+}
+
+void DLM_APIENTRY crDLMCompileDrawArrays(GLenum mode, GLint first, GLsizei count, CRClientState *c)
+{
+ int i;
+
+ if (count < 0)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_VALUE, "DLM DrawArrays(negative count)");
+ return;
+ }
+
+ if (mode > GL_POLYGON)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_ENUM, "DLM DrawArrays(bad mode)");
+ return;
+ }
+
+ crDLMCompileBegin(mode);
+ for (i=0; i<count; i++)
+ {
+ crDLMCompileArrayElement(first + i, c);
+ }
+ crDLMCompileEnd();
+}
+
+void DLM_APIENTRY crDLMCompileDrawElements(GLenum mode, GLsizei count,
+ GLenum type, const GLvoid *indices, CRClientState *c)
+{
+ int i;
+ GLubyte *p = (GLubyte *)indices;
+
+ if (count < 0)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_VALUE, "DLM DrawElements(negative count)");
+ return;
+ }
+
+ if (mode > GL_POLYGON)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_ENUM, "DLM DrawElements(bad mode)");
+ return;
+ }
+
+ if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_ENUM, "DLM DrawElements(bad type)");
+ return;
+ }
+
+ crDLMCompileBegin(mode);
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ for (i=0; i<count; i++)
+ {
+ crDLMCompileArrayElement((GLint) *p++, c);
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (i=0; i<count; i++)
+ {
+ crDLMCompileArrayElement((GLint) * (GLushort *) p, c);
+ p+=sizeof (GLushort);
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ for (i=0; i<count; i++)
+ {
+ crDLMCompileArrayElement((GLint) * (GLuint *) p, c);
+ p+=sizeof (GLuint);
+ }
+ break;
+ default:
+ crError( "this can't happen: DLM DrawElements" );
+ break;
+ }
+ crDLMCompileEnd();
+}
+
+void DLM_APIENTRY crDLMCompileDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
+ GLenum type, const GLvoid *indices, CRClientState *c)
+{
+ int i;
+ GLubyte *p = (GLubyte *)indices;
+
+ (void) end;
+
+ if (count < 0)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_VALUE, "DLM DrawRangeElements(negative count)");
+ return;
+ }
+
+ if (mode > GL_POLYGON)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_ENUM, "DLM DrawRangeElements(bad mode)");
+ return;
+ }
+
+ if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT)
+ {
+ crdlmWarning(__LINE__, __FILE__, GL_INVALID_ENUM, "DLM DrawRangeElements(bad type)");
+ return;
+ }
+
+ crDLMCompileBegin(mode);
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ for (i=start; i<count; i++)
+ {
+ crDLMCompileArrayElement((GLint) *p++, c);
+ }
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (i=start; i<count; i++)
+ {
+ crDLMCompileArrayElement((GLint) * (GLushort *) p, c);
+ p+=sizeof (GLushort);
+ }
+ break;
+ case GL_UNSIGNED_INT:
+ for (i=start; i<count; i++)
+ {
+ crDLMCompileArrayElement((GLint) * (GLuint *) p, c);
+ p+=sizeof (GLuint);
+ }
+ break;
+ default:
+ crError( "this can't happen: DLM DrawRangeElements" );
+ break;
+ }
+ crDLMCompileEnd();
+}
+
+#ifdef CR_EXT_multi_draw_arrays
+void DLM_APIENTRY crDLMCompileMultiDrawArraysEXT( GLenum mode, GLint *first,
+ GLsizei *count, GLsizei primcount, CRClientState *c)
+{
+ GLint i;
+
+ for (i = 0; i < primcount; i++) {
+ if (count[i] > 0) {
+ crDLMCompileDrawArrays(mode, first[i], count[i], c);
+ }
+ }
+}
+
+
+void DLM_APIENTRY crDLMCompileMultiDrawElementsEXT( GLenum mode, const GLsizei *count, GLenum type,
+ const GLvoid **indices, GLsizei primcount, CRClientState *c)
+{
+ GLint i;
+
+ for (i = 0; i < primcount; i++) {
+ if (count[i] > 0) {
+ crDLMCompileDrawElements(mode, count[i], type, indices[i], c);
+ }
+ }
+}
+#endif /* CR_EXT_multi_draw_arrays */
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_checklist.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_checklist.c
new file mode 100644
index 00000000..e631c02e
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_checklist.c
@@ -0,0 +1,51 @@
+/* $Id: dlm_checklist.c $ */
+#include "cr_dlm.h"
+#include "cr_mem.h"
+#include "cr_pixeldata.h"
+#include "cr_string.h"
+#include "dlm.h"
+
+/*****************************************************************************
+ * These helper functions are used for GL functions that are listed in
+ * the APIspec.txt file as "checklist", meaning that sometimes they
+ * represent functions that can be stored in a display list, and sometimes
+ * they represent control functions that must be executed immediately.
+ *
+ * The calling SPU must use these check functions (or their equivalents)
+ * before asking the DLM to compile any elements of these types.
+ * They return nonzero (TRUE) if the element goes into a display list.
+ */
+
+int DLM_APIENTRY crDLMCheckListTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+ return (target != GL_PROXY_TEXTURE_1D);
+}
+
+int DLM_APIENTRY crDLMCheckListCompressedTexImage1DARB(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imagesize, const GLvoid *data)
+{
+ return (target != GL_PROXY_TEXTURE_1D);
+}
+int DLM_APIENTRY crDLMCheckListTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+ return (target != GL_PROXY_TEXTURE_2D);
+}
+
+int DLM_APIENTRY crDLMCheckListCompressedTexImage2DARB(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imagesize, const GLvoid *data)
+{
+ return (target != GL_PROXY_TEXTURE_2D);
+}
+
+int DLM_APIENTRY crDLMCheckListTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+ return (target != GL_PROXY_TEXTURE_3D);
+}
+
+int DLM_APIENTRY crDLMCheckListTexImage3DEXT(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+ return (target != GL_PROXY_TEXTURE_3D);
+}
+
+int DLM_APIENTRY crDLMCheckListCompressedTexImage3DARB(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imagesize, const GLvoid *data)
+{
+ return (target != GL_PROXY_TEXTURE_3D);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_error.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_error.c
new file mode 100644
index 00000000..90590e76
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_error.c
@@ -0,0 +1,56 @@
+/* $Id: dlm_error.c $ */
+#include <stdio.h>
+#include <stdarg.h>
+#include "chromium.h"
+#include "cr_mem.h"
+#include "dlm.h"
+#include "cr_environment.h"
+#include "cr_error.h"
+
+#define GLCLIENT_LIST_ALLOC 1024
+
+void crdlmWarning( int line, char *file, GLenum error, char *format, ... )
+{
+ char errstr[8096];
+ va_list args;
+
+ if (crGetenv("CR_DEBUG")) {
+ char *glerr;
+ va_start( args, format );
+ vsprintf( errstr, format, args );
+ va_end( args );
+
+ switch (error) {
+ case GL_NO_ERROR:
+ glerr = "GL_NO_ERROR";
+ break;
+ case GL_INVALID_VALUE:
+ glerr = "GL_INVALID_VALUE";
+ break;
+ case GL_INVALID_ENUM:
+ glerr = "GL_INVALID_ENUM";
+ break;
+ case GL_INVALID_OPERATION:
+ glerr = "GL_INVALID_OPERATION";
+ break;
+ case GL_STACK_OVERFLOW:
+ glerr = "GL_STACK_OVERFLOW";
+ break;
+ case GL_STACK_UNDERFLOW:
+ glerr = "GL_STACK_UNDERFLOW";
+ break;
+ case GL_OUT_OF_MEMORY:
+ glerr = "GL_OUT_OF_MEMORY";
+ break;
+ case GL_TABLE_TOO_LARGE:
+ glerr = "GL_TABLE_TOO_LARGE";
+ break;
+ default:
+ glerr = "unknown";
+ break;
+ }
+
+ crWarning( "DLM error in %s, line %d: %s: %s\n",
+ file, line, glerr, errstr );
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_generated.py b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_generated.py
new file mode 100755
index 00000000..e5468e2b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_generated.py
@@ -0,0 +1,355 @@
+# $Id: dlm_generated.py $
+import sys, cPickle, re
+
+sys.path.append( "../glapi_parser" )
+import apiutil
+
+# A routine that can create call strings from instance names
+def InstanceCallString( params ):
+ output = ''
+ for index in range(0,len(params)):
+ if index > 0:
+ output += ", "
+ if params[index][0] != '':
+ output += 'instance->' + params[index][0]
+ return output
+
+def GetPointerType(basetype):
+ words = basetype.split()
+ if words[0] == 'const':
+ words = words[1:]
+ if words[-1].endswith('*'):
+ words[-1] = words[-1][:-1].strip()
+ if words[-1] == '':
+ words = words[:-1]
+ if words[0] == 'void' or words[0] == 'GLvoid':
+ words[0] = 'int'
+ return ' '.join(words)
+
+
+def GetPointerInfo(functionName):
+ # We'll keep track of all the parameters that require pointers.
+ # They'll require special handling later.
+ params = apiutil.Parameters(functionName)
+ pointers = []
+ pointername=''
+ pointerarg=''
+ pointertype=''
+ pointersize=0
+ pointercomment=''
+
+ index = 0
+ for (name, type, vecSize) in params:
+ # Watch out for the word "const" (which should be ignored)
+ # and for types that end in "*" (which are pointers and need
+ # special treatment)
+ words = type.split()
+ if words[-1].endswith('*'):
+ pointers.append(index)
+ index += 1
+
+ # If any argument was a pointer, we need a special pointer data
+ # array. The pointer data will be stored into this array, and
+ # references to the array will be generated as parameters.
+ if len(pointers) == 1:
+ index = pointers[0]
+ pointername = params[index][0]
+ pointerarg = pointername + 'Data'
+ pointertype = GetPointerType(params[index][1])
+ pointersize = params[index][2]
+ if pointersize == 0:
+ pointersize = "special"
+ elif len(pointers) > 1:
+ pointerarg = 'data';
+ pointertype = GetPointerType(params[pointers[0]][1])
+ for index in range(1,len(pointers)):
+ if GetPointerType(params[pointers[index]][1]) != pointertype:
+ pointertype = 'GLvoid *'
+
+ return (pointers,pointername,pointerarg,pointertype,pointersize,pointercomment)
+
+def wrap_struct(functionName):
+ params = apiutil.Parameters(functionName)
+ argstring = apiutil.MakeDeclarationString(params)
+ extendedArgstring = argstring
+ props = apiutil.Properties(functionName)
+ if "useclient" in props or "pixelstore" in props:
+ extendedArgstring += ", CRClientState *c"
+
+ # We'll keep track of all the parameters that require pointers.
+ # They'll require special handling later.
+ (pointers, pointername, pointerarg, pointertype, pointersize, pointercomment) = GetPointerInfo(functionName)
+
+ # Start writing the header
+ print 'struct instance%s {' % (functionName)
+ print ' DLMInstanceList *next;'
+ print ' DLMInstanceList *stateNext;'
+ print ' int cbInstance;'
+ print ' VBoxDLOpCode iVBoxOpCode;'
+ print ' void (DLM_APIENTRY *execute)(DLMInstanceList *instance, SPUDispatchTable *dispatchTable);'
+ for (name, type, vecSize) in params:
+ # Watch out for the word "const" (which should be ignored)
+ # and for types that end in "*" (which are pointers and need
+ # special treatment)
+ words = type.split()
+ if words[0] == 'const':
+ words = words[1:]
+ if words[0] != "void":
+ print ' %s %s;' % (' '.join(words), name)
+
+ # If any argument was a pointer, we need a special pointer data
+ # array. The pointer data will be stored into this array, and
+ # references to the array will be generated as parameters.
+ if len(pointers) == 1:
+ if pointersize == None:
+ print " /* Oh no - pointer parameter %s found, but no pointer class specified and can't guess */" % pointername
+ else:
+ if pointersize == 'special':
+ print ' %s %s[1];%s' % (pointertype, pointerarg, pointercomment)
+ else:
+ print ' %s %s[%s];%s' % (pointertype, pointerarg, pointersize,pointercomment)
+ elif len(pointers) > 1:
+ print ' %s %s[1];%s' % (pointertype, pointerarg,pointercomment)
+
+ print '};'
+
+ # Pointers only happen with instances
+ if len(pointers) > 1 or (len(pointers) == 1 and pointersize == 'special'):
+ print 'int crdlm_pointers_%s(struct instance%s *instance, %s);' % (functionName, functionName, extendedArgstring)
+
+ # See if the GL function must sometimes allow passthrough even
+ # if the display list is open
+ if "checklist" in apiutil.ChromiumProps(functionName):
+ print 'int crdlm_checklist_%s(%s);' % (functionName, argstring)
+
+ return
+
+def wrap_execute(functionName):
+
+ params = apiutil.Parameters(functionName)
+ (pointers, _, pointerarg, _, _, _) = GetPointerInfo(functionName)
+
+ print 'static void execute%s(DLMInstanceList *x, SPUDispatchTable *dispatchTable)' % functionName
+ print '{'
+ if len(params) > 0:
+ print ' struct instance%s *instance = (struct instance%s *)x;' % (functionName, functionName)
+
+ if len(pointers) == 1:
+ print ' instance->%s = instance->%s;' % (params[pointers[0]][0], pointerarg)
+
+ print ' if (dispatchTable->%s != NULL)' % (functionName)
+ print ' dispatchTable->%s(%s);' % (functionName, InstanceCallString(params))
+ print ' else'
+ print ' crWarning("DLM warning: execute%s called with NULL dispatch entry");' % (functionName)
+ print '}'
+
+# These code snippets isolate the code required to add a given instance
+# to the display list correctly. They are used during generation, to
+# generate correct code, and also to create useful utilities.
+def AddInstanceToList(pad):
+ print '%s/* Add this instance to the current display list. */' % pad
+ print '%sinstance->next = NULL;' % pad
+ print '%sinstance->stateNext = NULL;' % pad
+ print '%sif (!state->currentListInfo->first) {' % pad
+ print '%s state->currentListInfo->first = (DLMInstanceList *)instance;' % pad
+ print '%s}' % pad
+ print '%selse {' % pad
+ print '%s state->currentListInfo->last->next = (DLMInstanceList *)instance;' % pad
+ print '%s}' % pad
+ print '%sstate->currentListInfo->last = (DLMInstanceList *)instance;' % pad
+ print '%sstate->currentListInfo->numInstances++;' % pad
+
+def AddInstanceToStateList(pad):
+ print '%s/* Instances that change state have to be added to the state list as well. */' % pad
+ print '%sif (!state->currentListInfo->stateFirst) {' % pad
+ print '%s state->currentListInfo->stateFirst = (DLMInstanceList *)instance;' % pad
+ print '%s}' % pad
+ print '%selse {' % pad
+ print '%s state->currentListInfo->stateLast->stateNext = (DLMInstanceList *)instance;' % pad
+ print '%s}' % pad
+ print '%sstate->currentListInfo->stateLast = (DLMInstanceList *)instance;' % pad
+
+
+# The compile wrapper collects the parameters into a DLMInstanceList
+# element, and adds that element to the end of the display list currently
+# being compiled.
+def wrap_compile(functionName):
+ params = apiutil.Parameters(functionName)
+ return_type = apiutil.ReturnType(functionName)
+ # Make sure the return type is void. It's nonsensical to compile
+ # an element with any other return type.
+ if return_type != 'void':
+ print '/* Nonsense: DL function %s has a %s return type?!? */' % (functionName, return_type)
+
+ # Define a structure to hold all the parameters. Note that the
+ # top parameters must exactly match the DLMInstanceList structure
+ # in include/cr_dlm.h, or everything will break horribly.
+ # Start off by getting all the pointer info we could ever use
+ # from the parameters
+ (pointers, pointername, pointerarg, pointertype, pointersize, pointercomment) = GetPointerInfo(functionName)
+
+ # Finally, the compile wrapper. This one will diverge strongly
+ # depending on whether or not there are pointer parameters.
+ callstring = apiutil.MakeCallString(params)
+ argstring = apiutil.MakeDeclarationString(params)
+ props = apiutil.Properties(functionName)
+ if "useclient" in props or "pixelstore" in props:
+ callstring += ", c"
+ argstring += ", CRClientState *c"
+ print 'void DLM_APIENTRY crDLMCompile%s(%s)' % (functionName, argstring)
+ print '{'
+ print ' CRDLMContextState *state = CURRENT_STATE();'
+ print ' struct instance%s *instance;' % (functionName)
+
+ # The calling SPU is supposed to verify that the element is supposed to be
+ # compiled before it is actually compiled; typically, this is done based
+ # on whether a glNewList has been executed more recently than a glEndList.
+ # But some functions are dual-natured, sometimes being compiled, and sometimes
+ # being executed immediately. We can check for this here.
+ if "checklist" in apiutil.ChromiumProps(functionName):
+ print ' if (crDLMCheckList%s(%s))' % (functionName, apiutil.MakeCallString(params))
+ print ' {'
+ print ' crdlm_error(__LINE__, __FILE__, GL_INVALID_OPERATION,'
+ print ' "this instance of function %s should not be compiled");' % functionName;
+ print ' return;'
+ print ' }'
+
+ if len(pointers) > 1 or pointersize == 'special':
+ # Pass NULL, to just allocate space
+ print ' instance = crCalloc(sizeof(struct instance%s) + crdlm_pointers_%s(NULL, %s));' % (functionName, functionName, callstring)
+ else:
+ print ' instance = crCalloc(sizeof(struct instance%s));' % (functionName)
+ print ' if (!instance)'
+ print ' {'
+ print ' crdlm_error(__LINE__, __FILE__, GL_OUT_OF_MEMORY,'
+ print ' "out of memory adding %s to display list");' % (functionName)
+ print ' return;'
+ print ' }'
+
+ # Put in the fields that must always exist
+ print ' instance->execute = execute%s;' % functionName
+
+ # Apply all the simple (i.e. non-pointer) parameters
+ for index in range(len(params)):
+ if index not in pointers:
+ name = params[index][0]
+ print ' instance->%s = %s;' % (name, name)
+
+ # We need to know instance size in bytes in order to save its state later.
+ print ' instance->cbInstance = sizeof(struct instance%s);' % functionName
+
+ # Set OPCODE.
+ print ' instance->iVBoxOpCode = VBOX_DL_OPCODE_%s;' % functionName
+
+ # If there's a pointer parameter, apply it.
+ if len(pointers) == 1:
+
+ print ' if (%s == NULL)' % (params[pointers[0]][0])
+ print ' instance->%s = NULL;' % (params[pointers[0]][0])
+ print ' else'
+ print ' instance->%s = instance->%s;' % (params[pointers[0]][0], pointerarg)
+
+ if pointersize == 'special':
+ print ' instance->cbInstance += crdlm_pointers_%s(instance, %s);' % (functionName, callstring)
+ else:
+ print ' crMemcpy((void *)instance->%s, (void *) %s, %s*sizeof(%s));' % (params[pointers[0]][0], params[pointers[0]][0], pointersize, pointertype)
+ elif len(pointers) == 2:
+ # this seems to work
+ print ' instance->cbInstance += crdlm_pointers_%s(instance, %s);' % (functionName, callstring)
+ elif len(pointers) > 2:
+ print "#error don't know how to handle pointer parameters for %s" % (functionName)
+
+ # Add the element to the current display list
+ AddInstanceToList(' ')
+ # If the element is a state-changing element, add it to the current state list
+ if apiutil.SetsTrackedState(functionName):
+ AddInstanceToStateList(' ')
+ print '}'
+
+whichfile=sys.argv[1]
+if whichfile == 'headers':
+ print """#ifndef _DLM_GENERATED_H
+#define _DLM_GENERATED_H
+
+#include <VBoxUhgsmi.h>
+
+/* DO NOT EDIT. This file is auto-generated by dlm_generated.py. */
+"""
+else:
+ print """#include <stdio.h>
+#include "cr_spu.h"
+#include "cr_dlm.h"
+#include "cr_mem.h"
+#include "cr_error.h"
+#include "state/cr_statefuncs.h"
+#include "dlm.h"
+#include "dlm_pointers.h"
+#include "dlm_generated.h"
+
+/* DO NOT EDIT. This file is auto-generated by dlm_generated.py. */
+"""
+
+# Add in the "add_to_dl" utility function, which will be used by
+# external (i.e. non-generated) functions. The utility ensures that
+# any external functions that are written for compiling elements
+# don't have to be rewritten if the conventions for adding to display
+# lists are changed.
+print """
+void crdlm_add_to_list(
+ DLMInstanceList *instance,
+ void (*executeFunc)(DLMInstanceList *x, SPUDispatchTable *dispatchTable)"""
+
+if (whichfile == 'headers'):
+ print ");"
+else:
+ print """) {
+ CRDLMContextState *state = CURRENT_STATE();
+ instance->execute = executeFunc;"""
+
+ # Add in the common code for adding the instance to the display list
+ AddInstanceToList(" ")
+
+ print '}'
+ print ''
+
+# Now generate the functions that won't use the crdlm_add_to_list utility.
+# These all directly add their own instances to the current display list
+# themselves, without using the crdlm_add_to_list() function.
+keys = apiutil.GetDispatchedFunctions(sys.argv[3]+"/APIspec.txt")
+for func_name in keys:
+ if apiutil.CanCompile(func_name):
+ print "\n/*** %s ***/" % func_name
+ # Auto-generate an appropriate DL function. First, functions
+ # that go into the display list but that rely on state will
+ # have to have their argument strings expanded, to take pointers
+ # to that appropriate state.
+ if whichfile == "headers":
+ wrap_struct(func_name)
+ elif not apiutil.FindSpecial("dlm", func_name):
+ wrap_execute(func_name)
+ wrap_compile(func_name)
+
+
+# Generate mapping between OPCODE and routines to be executed.
+
+if whichfile == "headers":
+ # Execute routine prototype needed to add static array of routines.
+ print ''
+ print 'struct DLMInstanceList;'
+ print 'typedef void (*VBoxDLMExecuteFn)(struct DLMInstanceList *instance, SPUDispatchTable *dispatchTable);'
+ print ''
+ print 'extern VBoxDLMExecuteFn g_VBoxDLMExecuteFns[VBOX_DL_OPCODE_MAX];'
+ print ''
+else:
+ print ''
+ print 'VBoxDLMExecuteFn g_VBoxDLMExecuteFns[] = {'
+
+ for func_name in keys:
+ if apiutil.CanCompile(func_name) and not apiutil.FindSpecial("dlm", func_name):
+ print ' execute%s,' % func_name
+
+ print '};'
+ print ''
+
+if whichfile == 'headers':
+ print "#endif /* _DLM_GENERATED_H */"
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_header.py b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_header.py
new file mode 100644
index 00000000..f68ccaa0
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_header.py
@@ -0,0 +1,274 @@
+# $Id: dlm_header.py $
+import sys, cPickle, re, os
+
+sys.path.append( "../glapi_parser" )
+import apiutil
+
+# mode is "header" or "defs"
+mode = sys.argv[1]
+
+keys = apiutil.GetDispatchedFunctions(sys.argv[3]+"/APIspec.txt")
+
+# Any new function implemented in the DLM has to have an entry added here.
+# Each function has its return type, function name, and parameters provided.
+# We'll use these to generate both a header file, and a definition file.
+additionalFunctions = [
+ ('CRDLM DLM_APIENTRY *', 'crDLMNewDLM', 'unsigned int configSize, const CRDLMConfig *config'),
+ ('CRDLMContextState DLM_APIENTRY *', 'crDLMNewContext', 'CRDLM *dlm'),
+ ('void DLM_APIENTRY', 'crDLMFreeContext', 'CRDLMContextState *state, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMUseDLM', 'CRDLM *dlm'),
+ ('void DLM_APIENTRY','crDLMFreeDLM', 'CRDLM *dlm, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMSetCurrentState', 'CRDLMContextState *state'),
+ ('CRDLMContextState DLM_APIENTRY *', 'crDLMGetCurrentState', 'void'),
+ ('void DLM_APIENTRY', 'crDLMSetupClientState', 'SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMRestoreClientState', 'CRClientState *clientState, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMSendAllDLMLists', 'CRDLM *dlm, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMSendAllLists', 'SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMSendDLMList', 'CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMSendList', 'unsigned long listIdentifier, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayDLMList', 'CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayList', 'unsigned long listIdentifier, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayDLMListState', 'CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayListState', 'unsigned long listIdentifier, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayDLMLists', 'CRDLM *dlm, GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayLists', 'GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayDLMListsState', 'CRDLM *dlm, GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMReplayListsState', 'GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable'),
+ ('CRDLMError DLM_APIENTRY', 'crDLMDeleteListContent', 'CRDLM *dlm, unsigned long listIdentifier'),
+ ('void DLM_APIENTRY', 'crDLMComputeBoundingBox', 'unsigned long listId'),
+ ('GLuint DLM_APIENTRY', 'crDLMGetCurrentList', 'void'),
+ ('GLenum DLM_APIENTRY', 'crDLMGetCurrentMode', 'void'),
+ ('void DLM_APIENTRY', 'crDLMErrorFunction', 'CRDLMErrorCallback callback'),
+ ('void DLM_APIENTRY', 'crDLMNewList', 'GLuint list, GLenum mode, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMEndList', 'SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMCallList', 'GLuint list, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMCallLists', 'GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMDeleteLists', 'GLuint list, GLsizei range, SPUDispatchTable *dispatchTable'),
+ ('void DLM_APIENTRY', 'crDLMListBase', 'GLuint base, SPUDispatchTable *dispatchTable'),
+ ('GLboolean DLM_APIENTRY', 'crDLMIsList', 'GLuint list, SPUDispatchTable *dispatchTable'),
+ ('GLuint DLM_APIENTRY', 'crDLMGenLists', 'GLsizei range, SPUDispatchTable *dispatchTable'),
+ ('int32_t DLM_APIENTRY', 'crDLMSaveState', 'CRDLM *dlm, PSSMHANDLE pSSM'),
+ ('bool DLM_APIENTRY', 'crDLMLoadState', 'CRDLM *dlm, PSSMHANDLE pSSM, SPUDispatchTable *dispatchTable'),
+ #('void DLM_APIENTRY', 'crDLMListSent', 'CRDLM *dlm, unsigned long listIdentifier'),
+ #('GLboolean DLM_APIENTRY', 'crDLMIsListSent', 'CRDLM *dlm, unsigned long listIdentifier'),
+ #('GLint DLM_APIENTRY', 'crDLMListSize', 'CRDLM *dlm, unsigned long listIdentifier'),
+]
+
+if mode == 'header':
+ print """#ifndef CR_DLM_H
+
+/* DO NOT EDIT. This file is auto-generated by %s. */
+#define CR_DLM_H
+
+#if defined(WINDOWS)
+#define DLM_APIENTRY
+#else
+#define DLM_APIENTRY
+#endif
+
+#include "chromium.h"
+#include "state/cr_client.h"
+#include "cr_spu.h"
+#include "cr_hash.h"
+#include "cr_threads.h"
+#include "cr_pack.h"
+#ifdef CHROMIUM_THREADSAFE
+#include "cr_threads.h"
+#endif
+#include <VBox/types.h>
+""" % os.path.basename(sys.argv[0])
+
+ # Generate operation codes enum to be used for saving and restoring lists.
+ print "/* OpCodes codes enum to be used for saving and restoring lists. */"
+ print "typedef enum {"
+
+ for func_name in keys:
+ if apiutil.CanCompile(func_name) and not apiutil.FindSpecial("dlm", func_name):
+ print " VBOX_DL_OPCODE_%s," % func_name
+
+ print " VBOX_DL_OPCODE_MAX,"
+ print "} VBoxDLOpCode;"
+
+ print """
+/* 3D bounding box */
+typedef struct {
+ double xmin, xmax, ymin, ymax, zmin, zmax;
+} CRDLMBounds;
+
+/* Indicates whether we're currently involved in playback or not */
+typedef enum {
+ CRDLM_IMMEDIATE = 0,
+ CRDLM_REPLAY_STATE_FUNCTIONS = 1,
+ CRDLM_REPLAY_ALL_FUNCTIONS = 2
+} CRDLMReplayState;
+
+/* This is enough information to hold an instance of a single function call. */
+typedef struct DLMInstanceList {
+ struct DLMInstanceList *next;
+ struct DLMInstanceList *stateNext;
+ int cbInstance;
+ VBoxDLOpCode iVBoxOpCode; /* This field name should not interfere w/ OpenGL function parameters names (for example w/ param 'opcode' for glLogicOp()). */
+ void (*execute)(struct DLMInstanceList *instance, SPUDispatchTable *dispatchTable);
+} DLMInstanceList;
+
+typedef struct {
+ DLMInstanceList *first, *last;
+ uint32_t numInstances;
+ DLMInstanceList *stateFirst, *stateLast;
+ GLuint hwid;
+} DLMListInfo;
+
+typedef struct {
+ /* This holds all the display list information, hashed by list identifier. */
+ CRHashTable *displayLists;
+
+ /* This is a count of the number of contexts/users that are using
+ * this DLM.
+ */
+ unsigned int userCount;
+
+#ifdef CHROMIUM_THREADSAFE
+ /* This mutex protects the displayLists hash table from simultaneous
+ * updates by multiple contexts.
+ */
+ CRmutex dlMutex;
+ CRtsd tsdKey;
+#endif
+
+ /* Configuration information - see the CRDLMConfig structure below
+ * for details.
+ */
+ unsigned int bufferSize;
+} CRDLM;
+
+/* This structure holds thread-specific state. Each thread can be
+ * associated with one (and only one) context; and each context can
+ * be associated with one (and only one) DLM. Making things interesting,
+ * though, is that each DLM can be associated with multiple contexts.
+ *
+ * So the thread-specific data key is associated with each context, not
+ * with each DLM. Two different threads can, through two different
+ * contexts that share a single DLM, each have independent state and
+ * conditions.
+ */
+
+typedef struct {
+ CRDLM *dlm; /* the DLM associated with this state */
+ unsigned long currentListIdentifier; /* open display list */
+ DLMListInfo *currentListInfo; /* open display list data */
+ GLenum currentListMode; /* GL_COMPILE or GL_COMPILE_AND_EXECUTE */
+ GLuint listBase;
+
+} CRDLMContextState;
+
+/* These additional structures are for passing information to and from the
+ * CRDLM interface routines.
+ */
+typedef struct {
+ /* The size, in bytes, that the packer will initially allocate for
+ * each new buffer.
+ */
+#define CRDLM_DEFAULT_BUFFERSIZE (1024*1024)
+ unsigned int bufferSize; /* this will be allocated for each buffer */
+} CRDLMConfig;
+
+/* Positive values match GL error values.
+ * 0 (GL_NO_ERROR) is returned for success
+ * Negative values are internal errors.
+ * Possible positive values (from GL/gl.h) are:
+ * GL_NO_ERROR (0x0)
+ * GL_INVALID_ENUM (0x0500)
+ * GL_INVALID_VALUE (0x0501)
+ * GL_INVALID_OPERATION (0x0502)
+ * GL_STACK_OVERFLOW (0x0503)
+ * GL_STACK_UNDERFLOW (0x0504)
+ * GL_OUT_OF_MEMORY (0x0505)
+ */
+typedef int CRDLMError;
+
+/* This error reported if there's no current state. The caller is responsible
+ * for appropriately allocating context state with crDLMNewContext(), and
+ * for making it current with crDLMMakeCurrent().
+ */
+#define CRDLM_ERROR_STATE (-1)
+
+
+typedef void (*CRDLMErrorCallback)(int line, const char *file, GLenum error, const char *info);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+"""
+elif mode == 'defs':
+ apiutil.CopyrightDef()
+ print '''\t; DO NOT EDIT. This code is generated by %s.
+
+EXPORTS''' % os.path.basename(sys.argv[0])
+else:
+ raise "unknown generation mode '%s'" % mode
+
+# Generate the list of functions, starting with those coded into
+# the module
+for (returnValue, name, parameters) in additionalFunctions:
+ if mode == 'header':
+ print "extern %s %s(%s);" % (returnValue, name, parameters)
+ elif mode == 'defs':
+ print "%s" % name
+
+# Continue with functions that are auto-generated.
+
+if mode == 'header':
+ print
+ print "/* auto-generated compilation functions begin here */"
+
+
+
+for func_name in keys:
+ props = apiutil.Properties(func_name)
+ # We're interested in intercepting all calls that:
+ # - can be put into a display list (i.e. "not ("nolist" in props)")
+ # - change client-side state that affects saving DL elements (i.e. "setclient" in props)
+
+ if apiutil.CanCompile(func_name):
+ params = apiutil.Parameters(func_name)
+ argstring = apiutil.MakeDeclarationString(params)
+ if "useclient" in props or "pixelstore" in props:
+ argstring = argstring + ", CRClientState *c"
+
+ if mode == 'header':
+ print 'extern void DLM_APIENTRY crDLMCompile%s(%s);' % (func_name, argstring)
+ elif mode == 'defs':
+ print "crDLMCompile%s" % func_name
+
+# Next make declarations for all the checklist functions.
+if mode == 'header':
+ print """
+/* auto-generated CheckList functions begin here. There is one for each
+ * function that has a dual nature: even when there's an active glNewList,
+ * sometimes they are compiled into the display list, and sometimes they
+ * are treated like a control function. The CheckList function will
+ * return TRUE if the function should really be compiled into a display
+ * list. The calling SPU is responsible for checking this; but the
+ * DLM will also print an error if it detects an invalid use.
+ */
+"""
+elif mode == 'defs':
+ pass
+
+for func_name in keys:
+ if "checklist" in apiutil.ChromiumProps(func_name):
+ params = apiutil.Parameters(func_name)
+ argstring = apiutil.MakeDeclarationString(params)
+ if mode == 'header':
+ print 'int DLM_APIENTRY crDLMCheckList%s(%s);' % (func_name, argstring)
+ elif mode == 'defs':
+ print "crDLMCheckList%s" % func_name
+
+if mode == 'header':
+ print """
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CR_DLM_H */"""
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_lists.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_lists.c
new file mode 100644
index 00000000..495819a1
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_lists.c
@@ -0,0 +1,452 @@
+/* $Id: dlm_lists.c $ */
+/** @file
+ * Implementation of all the Display Lists related routines:
+ *
+ * glGenLists, glDeleteLists, glNewList, glEndList, glCallList, glCallLists,
+ * glListBase and glIsList.
+ *
+ * Provide OpenGL IDs mapping between host and guest.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <float.h>
+#include "cr_dlm.h"
+#include "cr_mem.h"
+#include "dlm.h"
+
+
+/**
+ * Destroy each list entry.
+ */
+static void crdlmFreeDisplayListElements(DLMInstanceList *instance)
+{
+ while (instance)
+ {
+ DLMInstanceList *nextInstance = instance->next;
+ crFree(instance);
+ instance = nextInstance;
+ }
+}
+
+
+/**
+ * A callback routine used when iterating over all
+ * available lists in order to remove them.
+ *
+ * NOTE: @param pParam2 might be NULL.
+ */
+void crdlmFreeDisplayListResourcesCb(void *pParm1, void *pParam2)
+{
+ DLMListInfo *pListInfo = (DLMListInfo *)pParm1;
+ SPUDispatchTable *dispatchTable = (SPUDispatchTable *)pParam2;
+
+ if (pListInfo)
+ {
+ crdlmFreeDisplayListElements(pListInfo->first);
+ pListInfo->first = pListInfo->last = NULL;
+
+ /* Free host OpenGL resources. */
+ if (dispatchTable)
+ dispatchTable->DeleteLists(pListInfo->hwid, 1);
+
+ crFree(pListInfo);
+ }
+}
+
+
+/**
+ * Generate host and guest IDs, setup IDs mapping between host and guest.
+ */
+GLuint DLM_APIENTRY crDLMGenLists(GLsizei range, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+ GLuint idHostRangeStart = 0;
+ GLuint idGuestRangeStart = 0;
+
+ crDebug("DLM: GenLists(%d) (DLM=%p).", range, listState ? listState->dlm : 0);
+
+ if (listState)
+ {
+ idHostRangeStart = dispatchTable->GenLists(range);
+ if (idHostRangeStart > 0)
+ {
+ idGuestRangeStart = crHashtableAllocKeys(listState->dlm->displayLists, range);
+ if (idGuestRangeStart > 0)
+ {
+ GLuint i;
+ bool fSuccess = true;
+
+ /* Now have successfully generated IDs range for host and guest. Let's make IDs association. */
+ for (i = 0; i < (GLuint)range; i++)
+ {
+ DLMListInfo *pListInfo;
+
+ pListInfo = (DLMListInfo *)crCalloc(sizeof(DLMListInfo));
+ if (pListInfo)
+ {
+ crMemset(pListInfo, 0, sizeof(DLMListInfo));
+ pListInfo->hwid = idHostRangeStart + i;
+
+ /* Insert pre-initialized list data which contains IDs mapping into the hash. */
+ crHashtableReplace(listState->dlm->displayLists, idGuestRangeStart + i, pListInfo, NULL);
+ }
+ else
+ {
+ fSuccess = false;
+ break;
+ }
+ }
+
+ /* All structures allocated and initialized successfully. */
+ if (fSuccess)
+ return idGuestRangeStart;
+
+ /* Rollback some data was not allocated. */
+ crDLMDeleteLists(idGuestRangeStart, range, NULL /* we do DeleteLists() later in this routine */ );
+ }
+ else
+ crDebug("DLM: Can't allocate Display List IDs range for the guest.");
+
+ dispatchTable->DeleteLists(idHostRangeStart, range);
+ }
+ else
+ crDebug("DLM: Can't allocate Display List IDs range on the host side.");
+ }
+ else
+ crDebug("DLM: GenLists(%u) called with no current state.", range);
+
+ /* Can't reserve IDs range. */
+ return 0;
+}
+
+
+/**
+ * Release host and guest IDs, free memory resources.
+ */
+void DLM_APIENTRY crDLMDeleteLists(GLuint list, GLsizei range, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+
+ crDebug("DLM: DeleteLists(%u, %d) (DLM=%p).", list, range, listState ? listState->dlm : 0);
+
+ if (listState)
+ {
+ if (range >= 0)
+ {
+ int i;
+
+ /* Free resources: host memory, host IDs and guest IDs. */
+ DLM_LOCK(listState->dlm)
+ for (i = 0; i < range; i++)
+ crHashtableDeleteEx(listState->dlm->displayLists, list + i, crdlmFreeDisplayListResourcesCb, dispatchTable);
+ DLM_UNLOCK(listState->dlm)
+ }
+ else
+ crDebug("DLM: DeleteLists(%u, %d) not allowed.", list, range);
+ }
+ else
+ crDebug("DLM: DeleteLists(%u, %d) called with no current state.", list, range);
+}
+
+
+/**
+ * Start recording a list.
+ */
+void DLM_APIENTRY
+crDLMNewList(GLuint list, GLenum mode, SPUDispatchTable *dispatchTable)
+{
+ DLMListInfo *listInfo;
+ CRDLMContextState *listState = CURRENT_STATE();
+
+ crDebug("DLM: NewList(%u, %u) (DLM=%p).", list, mode, listState ? listState->dlm : 0);
+
+ if (listState)
+ {
+ /* Valid list ID should be > 0. */
+ if (list > 0)
+ {
+ if (listState->currentListInfo == NULL)
+ {
+ listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
+ if (listInfo)
+ {
+ listInfo->first = listInfo->last = NULL;
+ listInfo->stateFirst = listInfo->stateLast = NULL;
+
+ listInfo->numInstances = 0;
+
+ listState->currentListInfo = listInfo;
+ listState->currentListIdentifier = list;
+ listState->currentListMode = mode;
+
+ dispatchTable->NewList(listInfo->hwid, mode);
+
+ crDebug("DLM: create new list with [guest, host] ID pair [%u, %u].", list, listInfo->hwid);
+
+ return;
+ }
+ else
+ crDebug("DLM: Requested Display List %u was not previously reserved with glGenLists().", list);
+ }
+ else
+ crDebug("DLM: NewList called with display list %u while display list %u was already open.", list, listState->currentListIdentifier);
+ }
+ else
+ crDebug("DLM: NewList called with a list identifier of 0.");
+ }
+ else
+ crDebug("DLM: NewList(%u, %u) called with no current state.\n", list, mode);
+}
+
+
+/**
+ * Stop recording a list.
+ */
+void DLM_APIENTRY crDLMEndList(SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+
+ crDebug("DLM: EndList() (DLM=%p).", listState ? listState->dlm : 0);
+
+ if (listState)
+ {
+ /* Check if list was ever started. */
+ if (listState->currentListInfo)
+ {
+ /* reset the current state to show the list had been ended */
+ listState->currentListIdentifier = 0;
+ listState->currentListInfo = NULL;
+ listState->currentListMode = GL_FALSE;
+
+ dispatchTable->EndList();
+ }
+ else
+ crDebug("DLM: glEndList() is assuming glNewList() was issued previously.");
+ }
+ else
+ crDebug("DLM: EndList called with no current state.");
+}
+
+
+/**
+ * Execute list on hardware and cach ethis call if we currently recording a list.
+ */
+void DLM_APIENTRY crDLMCallList(GLuint list, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+
+ //crDebug("DLM: CallList(%u).", list);
+
+ if (listState)
+ {
+ DLMListInfo *listInfo;
+
+ /* Add to calls cache if we recording a list. */
+ if (listState->currentListInfo)
+ crDLMCompileCallList(list);
+
+ /* Find hwid for list.
+ * We need to take into account listBase:
+ * - displayLists hash table contains absolute IDs, so we need to add offset in order to resolve guest ID;
+ * - we also need to substract from hwid in order to execute correct list. */
+ listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list + listState->listBase);
+ if (listInfo)
+ dispatchTable->CallList(listInfo->hwid - listState->listBase);
+ else
+ crDebug("DLM: CallList(%u) issued for non-existent list.", list);
+ }
+ else
+ crDebug("DLM: CallList(%u) called with no current state.", list);
+}
+
+
+/* This routine translates guest Display List IDs in given format to host IDs
+ * and return resulting IDs as an array of elements of type GL_UNSIGNED_INT.
+ * It is based on TranslateListIDs() function from crserverlib/server_lists.c. */
+static bool
+crDLMConvertListIDs(CRDLMContextState *pListState, GLsizei n, GLenum type, const GLvoid *aGuest, GLuint *aHost)
+{
+#define CRDLM_HANDLE_CONVERSION_CASE(_type, _item) \
+ { \
+ const _type *src = (const _type *)aGuest; \
+ for (i = 0; i < n; i++) \
+ { \
+ GLuint idGuest = (GLuint)(_item) + pListState->listBase; \
+ pListInfo = (DLMListInfo *)crHashtableSearch(pListState->dlm->displayLists, idGuest); \
+ if (pListInfo) \
+ { \
+ aHost[i] = pListInfo->hwid - pListState->listBase; \
+ } \
+ else \
+ { \
+ crDebug("DLM: CallLists() cannot resolve host list ID for guest ID %u.", idGuest); \
+ fSuccess = false; \
+ break; \
+ } \
+ } \
+ }
+
+ GLsizei i;
+ DLMListInfo *pListInfo;
+ bool fSuccess = true;
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i]); break;
+ case GL_BYTE: CRDLM_HANDLE_CONVERSION_CASE(GLbyte, src[i]); break;
+ case GL_UNSIGNED_SHORT: CRDLM_HANDLE_CONVERSION_CASE(GLushort, src[i]); break;
+ case GL_SHORT: CRDLM_HANDLE_CONVERSION_CASE(GLshort, src[i]); break;
+ case GL_UNSIGNED_INT: CRDLM_HANDLE_CONVERSION_CASE(GLuint, src[i]); break;
+ case GL_INT: CRDLM_HANDLE_CONVERSION_CASE(GLint, src[i]); break;
+ case GL_FLOAT: CRDLM_HANDLE_CONVERSION_CASE(GLfloat, src[i]); break;
+
+ case GL_2_BYTES:
+ {
+ CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 2 + 0] * 256 +
+ src[i * 2 + 1]);
+ break;
+ }
+
+ case GL_3_BYTES:
+ {
+ CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 3 + 0] * 256 * 256 +
+ src[i * 3 + 1] * 256 +
+ src[i * 3 + 2]);
+ break;
+ }
+
+ case GL_4_BYTES:
+ {
+ CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 4 + 0] * 256 * 256 * 256 +
+ src[i * 4 + 1] * 256 * 256 +
+ src[i * 4 + 2] * 256 +
+ src[i * 4 + 3]);
+ break;
+ }
+
+ default:
+ crWarning("DLM: attempt to pass to crDLMCallLists() an unknown type: 0x%x.", type);
+ }
+
+ return fSuccess;
+#undef CRDLM_HANDLE_CONVERSION_CASE
+}
+
+
+/**
+ * Execute lists on hardware and cache this call if we currently recording a list.
+ */
+void DLM_APIENTRY crDLMCallLists(GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *pListState = CURRENT_STATE();
+
+ crDebug("DLM: CallLists(%d, %u, %p).", n, type, lists);
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint))
+ {
+ crError("crDLMCallLists: parameter 'n' is out of range");
+ return;
+ }
+
+ if (pListState)
+ {
+ GLsizei i;
+ GLuint *aHostIDs;
+
+ /* Add to calls cache if we recording a list. */
+ if (pListState->currentListInfo)
+ crDLMCompileCallLists(n, type, lists);
+
+ aHostIDs = (GLuint *)crAlloc(n * sizeof(GLuint));
+ if (aHostIDs)
+ {
+ /* Convert IDs. Resulting array contains elements of type of GL_UNSIGNED_INT. */
+ if (crDLMConvertListIDs(pListState, n, type, lists, aHostIDs))
+ dispatchTable->CallLists(n, GL_UNSIGNED_INT, aHostIDs);
+ else
+ crDebug("DLM: CallLists() failed.");
+
+ crFree(aHostIDs);
+ }
+ else
+ crDebug("DLM: no memory on CallLists().");
+ }
+ else
+ crDebug("DLM: CallLists(%d, %u, %p) called with no current state.", n, type, lists);
+}
+
+
+/**
+ * Set list base, remember its value and add call to the cache.
+ */
+void DLM_APIENTRY crDLMListBase(GLuint base, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *pListState = CURRENT_STATE();
+
+ crDebug("DLM: ListBase(%u).", base);
+
+ if (pListState)
+ {
+ pListState->listBase = base;
+
+ /* Only add to cache if we are currently recording a list. */
+ /** @todo Do we really need to chache it? */
+ if (pListState->currentListInfo)
+ crDLMCompileListBase(base);
+
+ dispatchTable->ListBase(base);
+ }
+ else
+ crDebug("DLM: ListBase(%u) called with no current state.", base);
+}
+
+
+/**
+ * Check if specified list ID belongs to valid Display List.
+ * Positive result is only returned in case both conditions below are satisfied:
+ *
+ * - given list found in DLM hash table (i.e., it was previously allocated
+ * with crDLMGenLists and still not released with crDLMDeleteLists);
+ *
+ * - list is valid on the host side.
+ */
+GLboolean DLM_APIENTRY crDLMIsList(GLuint list, SPUDispatchTable *dispatchTable)
+{
+ CRDLMContextState *listState = CURRENT_STATE();
+
+ crDebug("DLM: IsList(%u).", list);
+
+ if (listState)
+ {
+ if (list > 0)
+ {
+ DLMListInfo *listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
+ if (listInfo)
+ {
+ if (dispatchTable->IsList(listInfo->hwid))
+ return true;
+ else
+ crDebug("DLM: list [%u, %u] not found on the host side.", list, listInfo->hwid);
+ }
+ else
+ crDebug("DLM: list %u not found in guest cache.", list);
+ }
+ else
+ crDebug("DLM: IsList(%u) is not allowed.", list);
+ }
+ else
+ crDebug("DLM: IsList(%u) called with no current state.", list);
+
+ return false;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.c
new file mode 100644
index 00000000..718ebdec
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.c
@@ -0,0 +1,1125 @@
+/* $Id: dlm_pointers.c $ */
+#include "cr_dlm.h"
+#include "cr_mem.h"
+#include "cr_pixeldata.h"
+#include "cr_string.h"
+#include "dlm.h"
+#include "dlm_pointers.h"
+
+/**
+ * These helper functions are used for GL functions that take a pointers,
+ * if the size of the arrays that the pointers refer to is not constant.
+ * These helper functions will determine, on a case-by-case basis,
+ * how much space is needed to store the array. If the buffer
+ * parameter is not NULL, they will also pack the data into the given
+ * array.
+ *
+ * Many of the functions included deal with pixel state (Bitmap, DrawPixels,
+ * etc.). In all these cases, when the function instance is stored in a
+ * display list, its data is read from memory (as per the parameters
+ * to PixelStore) and is stored in a tightly packed format (with no
+ * excess row length, no pixels skipped, no rows, skipped, and a byte
+ * alignment).
+ *
+ * When the instances are executed again, care must be taken to ensure
+ * that the PixelStore client state that unpacks them is set to reflect
+ * the tight packing actually used, instead of whatever the current
+ * client state indicates.
+ *
+ * So to do this, client PixelStore state is forced to known values
+ * before any instances in the display list are executed. The client
+ * state is then restored to known values afterwards. (The difficulty
+ * of this is somewhat mollified by the observation that PixelStore
+ * instances affect client state, and cannot be stored in a display list.)
+ *
+ */
+
+int crdlm_pointers_Bitmap( struct instanceBitmap *instance, GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap, CRClientState *c)
+{
+ unsigned int size = ((int)((width + 7) / 8)) * height;
+ /* glBitmap can be called with a NULL size 0 bitmap, say for
+ * an empty glyph that only moves the current raster position.
+ * crMemcpy will raise an exception with a NULL source pointer, even if
+ * the size to copy is 0. So make sure we don't ram into this.
+ * Also, the bitmap isn't necessarily just sitting in memory; the PixelStore
+ * client-side state affects how it is read from memory. It's easiest to just
+ * use the utility.
+ */
+ if (instance && size > 0) {
+ crBitmapCopy(width, height, instance->bitmap, bitmap,
+ &c->unpack);
+ }
+
+ return size;
+}
+
+int crdlm_pointers_DrawPixels( struct instanceDrawPixels *instance, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size = crImageSize(format, type, width, height);
+
+ if (instance && size > 0) {
+ crPixelCopy2D(width, height,
+ instance->pixels, format, type, NULL,
+ pixels, format, type, &c->unpack);
+ }
+
+ return size;
+}
+int crdlm_pointers_Fogfv( struct instanceFogfv *instance, GLenum pname, const GLfloat *params )
+{
+ unsigned int size = (pname == GL_FOG_COLOR?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_Fogiv( struct instanceFogiv *instance, GLenum pname, const GLint *params )
+{
+ unsigned int size = (pname == GL_FOG_COLOR?4:1)*sizeof(GLint);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_LightModelfv( struct instanceLightModelfv *instance, GLenum pname, const GLfloat *params )
+{
+ unsigned int size = (pname == GL_LIGHT_MODEL_AMBIENT?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_LightModeliv( struct instanceLightModeliv *instance, GLenum pname, const GLint *params )
+{
+ unsigned int size = (pname == GL_LIGHT_MODEL_AMBIENT?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_Lightfv( struct instanceLightfv *instance, GLenum light, GLenum pname, const GLfloat *params )
+{
+ unsigned int size;
+ switch(pname) {
+ case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: case GL_POSITION:
+ size = 4 * sizeof(GLfloat);
+ break;
+ case GL_SPOT_DIRECTION:
+ size = 3 * sizeof(GLfloat);
+ break;
+ default:
+ size = 1 * sizeof(GLfloat);
+ break;
+ }
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_Lightiv( struct instanceLightiv *instance, GLenum light, GLenum pname, const GLint *params )
+{
+ unsigned int size;
+ switch(pname) {
+ case GL_AMBIENT: case GL_DIFFUSE: case GL_SPECULAR: case GL_POSITION:
+ size = 4 * sizeof(GLint);
+ break;
+ case GL_SPOT_DIRECTION:
+ size = 3 * sizeof(GLint);
+ break;
+ default:
+ size = 1 * sizeof(GLint);
+ break;
+ }
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+
+/* This utility routine returns the number of components per
+ * mapping point for all the glMap* functions.
+ */
+static int map_num_components(GLenum target)
+{
+ switch(target) {
+ case GL_MAP1_INDEX: case GL_MAP1_TEXTURE_COORD_1:
+ return 1;
+ case GL_MAP1_TEXTURE_COORD_2:
+ return 2;
+ case GL_MAP1_VERTEX_3: case GL_MAP1_NORMAL:
+ case GL_MAP1_TEXTURE_COORD_3:
+ return 3;
+ case GL_MAP1_VERTEX_4: case GL_MAP1_COLOR_4:
+ case GL_MAP1_TEXTURE_COORD_4:
+ return 4;
+
+ case GL_MAP2_INDEX: case GL_MAP2_TEXTURE_COORD_1:
+ return 1;
+ case GL_MAP2_TEXTURE_COORD_2:
+ return 2;
+ case GL_MAP2_VERTEX_3: case GL_MAP2_NORMAL:
+ case GL_MAP2_TEXTURE_COORD_3:
+ return 3;
+ case GL_MAP2_VERTEX_4: case GL_MAP2_COLOR_4:
+ case GL_MAP2_TEXTURE_COORD_4:
+ return 4;
+ }
+ return 0;
+}
+
+
+int crdlm_pointers_Map1d( struct instanceMap1d *instance, GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points )
+{
+ unsigned int numValues = map_num_components(target);
+ unsigned int size = order * numValues * sizeof(GLdouble);
+ if (instance) {
+ /* This one's a little different - we rearrange the order to
+ * compress it, and change the instance's stride value to
+ * match.
+ */
+ const GLdouble *src = points;
+ GLdouble *dest = instance->points;
+ register int i;
+ for (i = 0; i < order; i++) {
+ crMemcpy(dest, src, numValues * sizeof(GLdouble));
+ dest += numValues;
+ src += stride;
+ }
+
+ /* We override the stride to show we've compressed the data */
+ instance->stride = numValues;
+ }
+ return size;
+}
+int crdlm_pointers_Map1f( struct instanceMap1f *instance, GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points )
+{
+ unsigned int numValues = map_num_components(target);
+ unsigned int size = order * numValues * sizeof(GLfloat);
+ if (instance) {
+ /* This one's a little different - we rearrange the order to
+ * compress it, and change the instance's stride value to
+ * match.
+ */
+ const GLfloat *src = points;
+ GLfloat *dest = instance->points;
+ register int i;
+ for (i = 0; i < order; i++) {
+ crMemcpy(dest, src, numValues * sizeof(GLfloat));
+ dest += numValues;
+ src += stride;
+ }
+
+ /* We override the stride to show we've compressed the data */
+ instance->stride = numValues;
+ }
+ return size;
+}
+int crdlm_pointers_Map2d( struct instanceMap2d *instance, GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points )
+{
+ unsigned int numValues = map_num_components(target);
+ unsigned int size = uorder * vorder * numValues * sizeof(GLdouble);
+ if (instance) {
+ register int v, u;
+ const GLdouble *src = points;
+ GLdouble *dest = instance->points;
+ for (v = 0; v < vorder; v++) {
+ for (u = 0; u < uorder; u++) {
+ crMemcpy(dest, src, numValues * sizeof(GLdouble));
+ dest += numValues;
+ src += ustride;
+ }
+ src += vstride - ustride*uorder;
+ }
+ /* We override the stride to show we've compressed the data */
+ instance->ustride = numValues;
+ instance->vstride = ustride * uorder;
+ }
+ return size;
+}
+int crdlm_pointers_Map2f( struct instanceMap2f *instance, GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points )
+{
+ unsigned int numValues = map_num_components(target);
+ unsigned int size = uorder * vorder * numValues * sizeof(GLfloat);
+ if (instance) {
+ register int v, u;
+ const GLfloat *src = points;
+ GLfloat *dest = instance->points;
+ for (v = 0; v < vorder; v++) {
+ for (u = 0; u < uorder; u++) {
+ crMemcpy(dest, src, numValues * sizeof(GLfloat));
+ dest += numValues;
+ src += ustride;
+ }
+ src += vstride - ustride*uorder;
+ }
+ /* We override the stride to show we've compressed the data */
+ instance->ustride = numValues;
+ instance->vstride = ustride * uorder;
+ }
+ return size;
+}
+
+int crdlm_pointers_Materialfv(struct instanceMaterialfv *instance, GLenum face, GLenum pname, const GLfloat *params)
+{
+ unsigned int size = 0;
+ switch(pname) {
+ case GL_AMBIENT_AND_DIFFUSE:
+ size = 8 * sizeof(GLfloat);
+ break;
+ case GL_AMBIENT:
+ case GL_DIFFUSE:
+ case GL_SPECULAR:
+ case GL_EMISSION:
+ size = 4 * sizeof(GLfloat);
+ break;
+ case GL_SHININESS:
+ size = 1 * sizeof(GLfloat);
+ break;
+ case GL_COLOR_INDEXES:
+ size = 3 * sizeof(GLfloat);
+ break;
+ default:
+ break;
+ }
+ if (instance && size > 0) crMemcpy(instance->params, params, size);
+ return size;
+}
+
+int crdlm_pointers_Materialiv(struct instanceMaterialiv *instance, GLenum face, GLenum pname, const GLint *params)
+{
+ unsigned int size = 0;
+ switch(pname) {
+ case GL_AMBIENT_AND_DIFFUSE:
+ size = 8 * sizeof(GLint);
+ break;
+ case GL_AMBIENT:
+ case GL_DIFFUSE:
+ case GL_SPECULAR:
+ case GL_EMISSION:
+ size = 4 * sizeof(GLint);
+ break;
+ case GL_SHININESS:
+ size = 1 * sizeof(GLint);
+ break;
+ case GL_COLOR_INDEXES:
+ size = 3 * sizeof(GLint);
+ break;
+ default:
+ break;
+ }
+ if (instance && size > 0) crMemcpy(instance->params, params, size);
+ return size;
+}
+
+int crdlm_pointers_PixelMapfv( struct instancePixelMapfv *instance, GLenum map, GLsizei mapsize, const GLfloat *values )
+{
+ unsigned int size = mapsize * sizeof(GLfloat);
+ if (instance && size > 0) crMemcpy(instance->values, values, size);
+ return size;
+}
+int crdlm_pointers_PixelMapuiv( struct instancePixelMapuiv *instance, GLenum map, GLsizei mapsize, const GLuint *values )
+{
+ unsigned int size = mapsize * sizeof(GLuint);
+ if (instance && size > 0) crMemcpy(instance->values, values, size);
+ return size;
+}
+int crdlm_pointers_PixelMapusv( struct instancePixelMapusv *instance, GLenum map, GLsizei mapsize, const GLushort *values )
+{
+ unsigned int size = mapsize * sizeof(GLushort);
+ if (instance && size > 0) crMemcpy(instance->values, values, size);
+ return size;
+}
+
+int crdlm_pointers_PointParameterfvARB( struct instancePointParameterfvARB *instance, GLenum pname, const GLfloat *params)
+{
+ unsigned int size = 0;
+ switch(pname) {
+ case GL_POINT_DISTANCE_ATTENUATION_ARB:
+ size = 3 * sizeof(GLfloat);
+ break;
+ default:
+ size = 1 * sizeof(GLfloat);
+ break;
+ }
+ return size;
+}
+
+int crdlm_pointers_PointParameteriv( struct instancePointParameteriv *instance, GLenum pname, const GLint *params)
+{
+ unsigned int size = 0;
+ switch(pname) {
+ case GL_POINT_DISTANCE_ATTENUATION_ARB:
+ size = 3 * sizeof(GLint);
+ break;
+ default:
+ size = 1 * sizeof(GLint);
+ break;
+ }
+ return size;
+}
+
+int crdlm_pointers_TexEnvfv( struct instanceTexEnvfv *instance, GLenum target, GLenum pname, const GLfloat *params )
+{
+ unsigned int size = (pname == GL_TEXTURE_ENV_COLOR?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexEnviv( struct instanceTexEnviv *instance, GLenum target, GLenum pname, const GLint *params )
+{
+ unsigned int size = (pname == GL_TEXTURE_ENV_COLOR?4:1)*sizeof(GLint);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexGendv( struct instanceTexGendv *instance, GLenum coord, GLenum pname, const GLdouble *params )
+{
+ unsigned int size = (pname == GL_OBJECT_PLANE||pname==GL_EYE_PLANE?4:1)*sizeof(GLdouble);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexGenfv( struct instanceTexGenfv *instance, GLenum coord, GLenum pname, const GLfloat *params )
+{
+ unsigned int size = (pname == GL_OBJECT_PLANE||pname==GL_EYE_PLANE?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexGeniv( struct instanceTexGeniv *instance, GLenum coord, GLenum pname, const GLint *params )
+{
+ unsigned int size = (pname == GL_OBJECT_PLANE||pname==GL_EYE_PLANE?4:1)*sizeof(GLint);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexImage1D( struct instanceTexImage1D *instance, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size = crImageSize(format, type, width, 1);
+
+ if (instance && size > 0) {
+ crPixelCopy1D(instance->pixels, format, type,
+ pixels, format, type, width, &c->unpack);
+ }
+
+ return size;
+}
+int crdlm_pointers_CompressedTexImage1DARB(struct instanceCompressedTexImage1DARB *instance, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imagesize, const GLvoid *data)
+{
+ unsigned int size = imagesize;
+
+ if (instance && size > 0) {
+ crMemcpy(instance->data, data, size);
+ }
+
+ return size;
+}
+
+int crdlm_pointers_TexImage2D( struct instanceTexImage2D *instance, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size = crImageSize(format, type, width, height);
+
+ if (instance && size > 0) {
+ crPixelCopy2D(width, height,
+ instance->pixels, format, type, NULL,
+ pixels, format, type, &c->unpack);
+ }
+
+ return size;
+}
+int crdlm_pointers_CompressedTexImage2DARB(struct instanceCompressedTexImage2DARB *instance, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imagesize, const GLvoid *data)
+{
+ unsigned int size = imagesize;
+
+ if (instance && size > 0) {
+ crMemcpy(instance->data, data, size);
+ }
+
+ return size;
+}
+
+int crdlm_pointers_TexImage3D( struct instanceTexImage3D *instance, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size;
+ int is_distrib = ((type == GL_TRUE) || (type == GL_FALSE));
+
+ if (pixels == NULL) {
+ size = 0;
+ }
+ else if (is_distrib) {
+ size = crStrlen(pixels) + 1 + (type==GL_TRUE?width*height*3:0);
+ }
+ else {
+ size = crTextureSize(format, type, width, height, depth);
+ }
+
+ if (instance && size > 0) {
+ if (is_distrib) {
+ crMemcpy(instance->pixels, pixels, size);
+ }
+ else {
+ crPixelCopy3D(width, height, depth,
+ instance->pixels, format, type, NULL,
+ pixels, format, type, &c->unpack);
+ }
+ }
+
+ return size;
+}
+int crdlm_pointers_TexImage3DEXT( struct instanceTexImage3DEXT *instance, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size;
+ int is_distrib = ((type == GL_TRUE) || (type == GL_FALSE));
+
+ if (pixels == NULL) {
+ size = 0;
+ }
+ else if (is_distrib) {
+ size = crStrlen(pixels) + 1 + (type==GL_TRUE?width*height*3:0);
+ }
+ else {
+ size = crTextureSize(format, type, width, height, depth);
+ }
+
+ if (instance && size > 0) {
+ if (is_distrib) {
+ crMemcpy(instance->pixels, pixels, size);
+ }
+ else {
+ crPixelCopy3D(width, height, depth,
+ instance->pixels, format, type, NULL,
+ pixels, format, type, &c->unpack);
+ }
+ }
+
+ return size;
+}
+
+int crdlm_pointers_CompressedTexImage3DARB(struct instanceCompressedTexImage3DARB *instance, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imagesize, const GLvoid *data)
+{
+ unsigned int size = imagesize;
+
+ if (instance && size > 0) {
+ crMemcpy(instance->data, data, size);
+ }
+
+ return size;
+}
+
+int crdlm_pointers_TexParameterfv( struct instanceTexParameterfv *instance, GLenum target, GLenum pname, const GLfloat *params )
+{
+ unsigned int size = (pname == GL_TEXTURE_BORDER_COLOR?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexParameteriv( struct instanceTexParameteriv *instance, GLenum target, GLenum pname, const GLint *params )
+{
+ unsigned int size = (pname == GL_TEXTURE_BORDER_COLOR?4:1)*sizeof(GLfloat);
+ if (instance) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_TexSubImage1D( struct instanceTexSubImage1D *instance, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size = crImageSize(format, type, width, 1);
+
+ if (instance && size > 0) {
+ crPixelCopy1D(instance->pixels, format, type,
+ pixels, format, type, width, &c->unpack);
+ }
+
+ return size;
+}
+int crdlm_pointers_TexSubImage2D( struct instanceTexSubImage2D *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size = crImageSize(format, type, width, height);
+
+ if (instance && size > 0) {
+ crPixelCopy2D(width, height,
+ instance->pixels, format, type, NULL,
+ pixels, format, type, &c->unpack);
+ }
+
+ return size;
+}
+int crdlm_pointers_TexSubImage3D( struct instanceTexSubImage3D *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c )
+{
+ unsigned int size;
+ int is_distrib = ((type == GL_TRUE) || (type == GL_FALSE));
+
+ if (pixels == NULL) {
+ size = 0;
+ }
+ else if (is_distrib) {
+ size = crStrlen(pixels) + 1 + (type==GL_TRUE?width*height*3:0);
+ }
+ else {
+ size = crTextureSize(format, type, width, height, depth);
+ }
+
+ if (instance && size > 0) {
+ if (is_distrib) {
+ crMemcpy(instance->pixels, pixels, size);
+ }
+ else {
+ crPixelCopy3D(width, height, depth,
+ instance->pixels, format, type, NULL,
+ pixels, format, type, &c->unpack);
+ }
+ }
+
+ return size;
+}
+
+int crdlm_pointers_CompressedTexSubImage1DARB(struct instanceCompressedTexSubImage1DARB *instance, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imagesize, const GLvoid *data)
+{
+ unsigned int size = imagesize;
+
+ if (instance && size > 0) {
+ crMemcpy(instance->data, data, size);
+ }
+
+ return size;
+}
+
+int crdlm_pointers_CompressedTexSubImage2DARB(struct instanceCompressedTexSubImage2DARB *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imagesize, const GLvoid *data)
+{
+ unsigned int size = imagesize;
+
+ if (instance && size > 0) {
+ crMemcpy(instance->data, data, size);
+ }
+
+ return size;
+}
+int crdlm_pointers_CompressedTexSubImage3DARB(struct instanceCompressedTexSubImage3DARB *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imagesize, const GLvoid *data)
+{
+ unsigned int size = imagesize;
+
+ if (instance && size > 0) {
+ crMemcpy(instance->data, data, size);
+ }
+
+ return size;
+}
+
+int crdlm_pointers_Rectdv(struct instanceRectdv *instance, const GLdouble *v1, const GLdouble *v2)
+{
+ unsigned int size = 4 * sizeof(GLdouble);
+ if (instance) {
+ instance->data[0] = v1[0];
+ instance->data[1] = v1[1];
+ instance->data[2] = v2[0];
+ instance->data[3] = v2[1];
+ instance->v1 = &instance->data[0];
+ instance->v2 = &instance->data[2];
+ }
+ return size;
+}
+int crdlm_pointers_Rectfv(struct instanceRectfv *instance, const GLfloat *v1, const GLfloat *v2)
+{
+ unsigned int size = 4 * sizeof(GLfloat);
+ if (instance) {
+ instance->data[0] = v1[0];
+ instance->data[1] = v1[1];
+ instance->data[2] = v2[0];
+ instance->data[3] = v2[1];
+ instance->v1 = &instance->data[0];
+ instance->v2 = &instance->data[2];
+ }
+ return size;
+}
+int crdlm_pointers_Rectiv(struct instanceRectiv *instance, const GLint *v1, const GLint *v2)
+{
+ unsigned int size = 4 * sizeof(GLint);
+ if (instance) {
+ instance->data[0] = v1[0];
+ instance->data[1] = v1[1];
+ instance->data[2] = v2[0];
+ instance->data[3] = v2[1];
+ instance->v1 = &instance->data[0];
+ instance->v2 = &instance->data[2];
+ }
+ return size;
+}
+int crdlm_pointers_Rectsv(struct instanceRectsv *instance, const GLshort *v1, const GLshort *v2)
+{
+ unsigned int size = 4 * sizeof(GLshort);
+ if (instance) {
+ instance->data[0] = v1[0];
+ instance->data[1] = v1[1];
+ instance->data[2] = v2[0];
+ instance->data[3] = v2[1];
+ instance->v1 = &instance->data[0];
+ instance->v2 = &instance->data[2];
+ }
+ return size;
+}
+
+int crdlm_pointers_PrioritizeTextures(struct instancePrioritizeTextures *instance, GLsizei n, const GLuint *textures, const GLclampf *priorities)
+{
+ unsigned int size = n * (sizeof(GLuint) + sizeof(GLclampf));
+ if (instance) {
+ instance->textures = (GLuint *)&instance->data[0];
+ instance->priorities = (GLclampf *)(((char *)&instance->data[0]) + n * sizeof(GLuint));
+ if (size > 0) {
+ crMemcpy(instance->textures, textures, n * sizeof(GLuint));
+ crMemcpy(instance->priorities, priorities, n * sizeof(GLclampf));
+ }
+ }
+
+ return size;
+}
+
+static int combiner_num_components(GLenum pname)
+{
+ switch(pname) {
+ case GL_CONSTANT_COLOR0_NV:
+ case GL_CONSTANT_COLOR1_NV:
+ return 4;
+ case GL_NUM_GENERAL_COMBINERS_NV:
+ case GL_COLOR_SUM_CLAMP_NV:
+ return 1;
+ }
+ return 0;
+}
+int crdlm_pointers_CombinerParameterivNV(struct instanceCombinerParameterivNV *instance, GLenum pname, const GLint *params)
+{
+ unsigned int size = combiner_num_components(pname) * sizeof(GLint);
+ if (instance && size > 0) crMemcpy(instance->params, params, size);
+ return size;
+}
+int crdlm_pointers_CombinerParameterfvNV(struct instanceCombinerParameterfvNV *instance, GLenum pname, const GLfloat *params)
+{
+ unsigned int size = combiner_num_components(pname) * sizeof(GLfloat);
+ if (instance && size > 0) crMemcpy(instance->params, params, size);
+ return size;
+}
+
+static int combinerstage_num_components(GLenum pname)
+{
+ switch(pname) {
+ case GL_CONSTANT_COLOR0_NV:
+ case GL_CONSTANT_COLOR1_NV:
+ return 4;
+ }
+ return 0;
+}
+int crdlm_pointers_CombinerStageParameterfvNV(struct instanceCombinerStageParameterfvNV *instance, GLenum stage, GLenum pname, const GLfloat *params)
+{
+ unsigned int size = combinerstage_num_components(pname) * sizeof(GLfloat);
+ if (instance && size > 0) crMemcpy(instance->params, params, size);
+ return size;
+}
+
+static int program_num_components(GLenum target)
+{
+ switch(target) {
+ case GL_VERTEX_STATE_PROGRAM_NV:
+ return 4;
+ }
+ return 0;
+}
+int crdlm_pointers_ExecuteProgramNV(struct instanceExecuteProgramNV *instance, GLenum target, GLuint id, const GLfloat *params)
+{
+ unsigned int size = program_num_components(target) * sizeof(GLfloat);
+ if (instance && size > 0) crMemcpy(instance->params, params, size);
+ return size;
+}
+
+int crdlm_pointers_RequestResidentProgramsNV(struct instanceRequestResidentProgramsNV *instance, GLsizei n, const GLuint *ids)
+{
+ unsigned int size = 4*sizeof(GLuint);
+ if (instance && size > 0) crMemcpy(instance->ids, ids, size);
+ return size;
+}
+
+int crdlm_pointers_LoadProgramNV(struct instanceLoadProgramNV *instance, GLenum target, GLuint id, GLsizei len, const GLubyte *program)
+{
+ unsigned int size = len*sizeof(GLubyte);
+ if (instance && size > 0) crMemcpy(instance->program, program, size);
+ return size;
+}
+
+int crdlm_pointers_ProgramNamedParameter4dNV(struct instanceProgramNamedParameter4dNV *instance, GLuint id, GLsizei len, const GLubyte * name, GLdouble x, GLdouble y, GLdouble z, GLdouble w)
+{
+ unsigned int size = len * sizeof(GLubyte);
+ /* XXX */
+ return size;
+}
+
+int crdlm_pointers_ProgramNamedParameter4dvNV(struct instanceProgramNamedParameter4dvNV *instance, GLuint id, GLsizei len, const GLubyte * name, const GLdouble * v)
+{
+ unsigned int size = len * sizeof(GLubyte);
+ /* XXX */
+ return size;
+}
+
+int crdlm_pointers_ProgramNamedParameter4fNV(struct instanceProgramNamedParameter4fNV *instance, GLuint id, GLsizei len, const GLubyte * name, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ unsigned int size = len * sizeof(GLubyte);
+ /* XXX */
+ return size;
+}
+
+int crdlm_pointers_ProgramNamedParameter4fvNV(struct instanceProgramNamedParameter4fvNV *instance, GLuint id, GLsizei len, const GLubyte * name, const GLfloat * v)
+{
+ unsigned int size = len * sizeof(GLubyte);
+ /* XXX */
+ return size;
+}
+
+int crdlm_pointers_ProgramStringARB(struct instanceProgramStringARB *instance, GLenum target, GLenum format, GLsizei len, const GLvoid * string)
+{
+ unsigned int size = len*sizeof(GLubyte);
+ if (instance && size > 0) crMemcpy(instance->string, string, size);
+ return size;
+}
+
+int crdlm_pointers_CallLists(struct instanceCallLists *instance, GLsizei n, GLenum type, const GLvoid *lists )
+{
+ unsigned int size;
+ switch (type) {
+ case GL_BYTE:
+ size = sizeof(GLbyte);
+ break;
+ case GL_UNSIGNED_BYTE:
+ size = sizeof(GLubyte);
+ break;
+ case GL_SHORT:
+ size = sizeof(GLshort);
+ break;
+ case GL_UNSIGNED_SHORT:
+ size = sizeof(GLushort);
+ break;
+ case GL_INT:
+ size = sizeof(GLint);
+ break;
+ case GL_UNSIGNED_INT:
+ size = sizeof(GLuint);
+ break;
+ case GL_FLOAT:
+ size = sizeof(GLfloat);
+ break;
+ case GL_2_BYTES:
+ size = 2 * sizeof(GLbyte);
+ break;
+ case GL_3_BYTES:
+ size = 3 * sizeof(GLbyte);
+ break;
+ case GL_4_BYTES:
+ size = 4 * sizeof(GLbyte);
+ break;
+ default:
+ size = 0;
+ }
+ size *= n;
+ if (instance && size > 0) crMemcpy(instance->lists, lists, size);
+ return size;
+}
+
+
+int crdlm_pointers_VertexAttribs1dvNV(struct instanceVertexAttribs1dvNV *instance, GLuint index, GLsizei n, const GLdouble *v)
+{
+ return 1 * n * sizeof(GLdouble);
+}
+
+int crdlm_pointers_VertexAttribs1fvNV(struct instanceVertexAttribs1fvNV *instance, GLuint index, GLsizei n, const GLfloat *v)
+{
+ return 1 * n * sizeof(GLfloat);
+}
+
+int crdlm_pointers_VertexAttribs1svNV(struct instanceVertexAttribs1svNV *instance, GLuint index, GLsizei n, const GLshort *v)
+{
+ return 1 * n * sizeof(GLshort);
+}
+
+int crdlm_pointers_VertexAttribs2dvNV(struct instanceVertexAttribs2dvNV *instance, GLuint index, GLsizei n, const GLdouble *v)
+{
+ return 2 * n * sizeof(GLdouble);
+}
+
+int crdlm_pointers_VertexAttribs2fvNV(struct instanceVertexAttribs2fvNV *instance, GLuint index, GLsizei n, const GLfloat *v)
+{
+ return 2 * n * sizeof(GLfloat);
+}
+
+int crdlm_pointers_VertexAttribs2svNV(struct instanceVertexAttribs2svNV *instance, GLuint index, GLsizei n, const GLshort *v)
+{
+ return 2 * n * sizeof(GLshort);
+}
+
+int crdlm_pointers_VertexAttribs3dvNV(struct instanceVertexAttribs3dvNV *instance, GLuint index, GLsizei n, const GLdouble *v)
+{
+ return 3 * n * sizeof(GLdouble);
+}
+
+int crdlm_pointers_VertexAttribs3fvNV(struct instanceVertexAttribs3fvNV *instance, GLuint index, GLsizei n, const GLfloat *v)
+{
+ return 3 * n * sizeof(GLfloat);
+}
+
+int crdlm_pointers_VertexAttribs3svNV(struct instanceVertexAttribs3svNV *instance, GLuint index, GLsizei n, const GLshort *v)
+{
+ return 3 * n * sizeof(GLshort);
+}
+
+int crdlm_pointers_VertexAttribs4dvNV(struct instanceVertexAttribs4dvNV *instance, GLuint index, GLsizei n, const GLdouble *v)
+{
+ return 4 * n * sizeof(GLdouble);
+}
+
+int crdlm_pointers_VertexAttribs4fvNV(struct instanceVertexAttribs4fvNV *instance, GLuint index, GLsizei n, const GLfloat *v)
+{
+ return 4 * n * sizeof(GLfloat);
+}
+
+int crdlm_pointers_VertexAttribs4svNV(struct instanceVertexAttribs4svNV *instance, GLuint index, GLsizei n, const GLshort *v)
+{
+ return 4 * n * sizeof(GLshort);
+}
+
+int crdlm_pointers_VertexAttribs4ubvNV(struct instanceVertexAttribs4ubvNV *instance, GLuint index, GLsizei n, const GLubyte *v)
+{
+ return 4 * n * sizeof(GLubyte);
+}
+
+int crdlm_pointers_ZPixCR( struct instanceZPixCR *instance, GLsizei width,
+ GLsizei height, GLenum format, GLenum type,
+ GLenum ztype, GLint zparm, GLint length,
+ const GLvoid *pixels, CRClientState *c)
+{
+ unsigned int size = length;
+ if (instance && size > 0) {
+ crMemcpy(instance->pixels,pixels,length);
+ }
+
+ return size;
+}
+
+
+/*
+ * Prototypes for functions below are auto-generated and definded at out/<os.arch>/<build type>/obj/VBoxOGLgen/dlm_generated.h.
+ *
+ * All non-pointer structure fields are already assifned to *instance in out/<os.arch>/<build type>/obj/VBoxOGLgen/dlm_generated.c.
+ * Here we need to specify the additional size which is required to store data from pointers.
+ * This size will be added to sizeof(*instance) when dlm_generated.c will dynamically allocate memory for it. Also,
+ * data from pointers shouls be copied to *instance in case if instance != NULL. Each of functions below is called
+ * twice from dlm_generated.c:
+ * - first time with instance = NULL in order to get actual size of data provided by pointer
+ * - the second time with valid instance in order to copy data into it.
+ */
+
+int crdlm_pointers_BindAttribLocation(struct instanceBindAttribLocation *instance, GLuint program, GLuint index, const char * name)
+{
+ int cbExtraSpace = (name ? crStrlen(name) + 1 : 0);
+ if (instance && name && cbExtraSpace)
+ {
+ crMemcpy(instance->name, name, cbExtraSpace);
+ }
+
+ return cbExtraSpace;
+}
+
+int crdlm_pointers_DeleteFramebuffersEXT(struct instanceDeleteFramebuffersEXT *instance, GLsizei n, const GLuint * framebuffers)
+{
+ int cbExtraSpace = n * sizeof(GLuint);
+
+ if (instance && framebuffers && cbExtraSpace)
+ crMemcpy(instance->framebuffers, framebuffers, cbExtraSpace);
+
+ return cbExtraSpace;
+}
+
+int crdlm_pointers_DeleteRenderbuffersEXT(struct instanceDeleteRenderbuffersEXT *instance, GLsizei n, const GLuint * renderbuffers)
+{
+ int cbExtraSpace = n * sizeof(GLuint);
+
+ if (instance && renderbuffers && cbExtraSpace)
+ crMemcpy(instance->renderbuffers, renderbuffers, cbExtraSpace);
+
+ return cbExtraSpace;
+}
+
+int crdlm_pointers_DrawBuffers(struct instanceDrawBuffers *instance, GLsizei n, const GLenum* bufs)
+{
+ int cbExtraSpace = n * sizeof(GLenum);
+
+ if (instance && bufs && cbExtraSpace)
+ crMemcpy(instance->bufs, bufs, cbExtraSpace);
+
+ return cbExtraSpace;
+}
+
+int crdlm_pointers_ShaderSource(struct instanceShaderSource *instance, GLuint shader, GLsizei count, const char ** string, const GLint * length)
+{
+ int cbExtraSpace = 0;
+ int cbStrings = 0;
+ int cbLenghts = 0;
+ int i;
+
+ /* Calculate reported source code size. */
+ if (length && count)
+ for (i = 0; i < count; i++)
+ cbStrings += length[i] + /* termination character */ 1;
+
+ /* Calculate size of the rest of parameters. */
+ cbLenghts = count * sizeof(GLint);
+
+ /* Resulting size is a summ. */
+ cbExtraSpace = cbStrings + cbLenghts;
+
+ /* Copy data if requested. */
+ if (instance)
+ {
+ if (string && *string && cbStrings)
+ crMemcpy(instance->string, *string, cbStrings);
+ if (length && cbLenghts)
+ crMemcpy(instance->length, length, cbLenghts);
+ }
+
+ return cbExtraSpace;
+}
+
+int crdlm_pointers_StringMarkerGREMEDY(struct instanceStringMarkerGREMEDY *instance, GLsizei len, const GLvoid* string)
+{
+ /* @param len assumed to indicate string lenght in bytes. No termination character assumed. */
+ int cbExtraSpace = (string && len) ? len : 0;
+
+ if (instance && string && cbExtraSpace)
+ crMemcpy(instance->string, string, cbExtraSpace);
+
+ return cbExtraSpace;
+}
+
+/* Simplify things a bit. Use this macro instead of copy/paste to similar functions. */
+#define _VBOX_crdlm_pointers_UniformX(_uniformType) \
+ int cbExtraSpace = count * sizeof(_uniformType); \
+ if (instance && cbExtraSpace && value) \
+ crMemcpy(instance->value, value, cbExtraSpace); \
+ return cbExtraSpace;
+
+int crdlm_pointers_Uniform1fv(struct instanceUniform1fv *instance, GLint location, GLsizei count, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLfloat);
+}
+
+int crdlm_pointers_Uniform1iv(struct instanceUniform1iv *instance, GLint location, GLsizei count, const GLint * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLint);
+}
+
+int crdlm_pointers_Uniform2fv(struct instanceUniform2fv *instance, GLint location, GLsizei count, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLfloat);
+}
+
+int crdlm_pointers_Uniform2iv(struct instanceUniform2iv *instance, GLint location, GLsizei count, const GLint * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLint);
+}
+
+int crdlm_pointers_Uniform3fv(struct instanceUniform3fv *instance, GLint location, GLsizei count, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLfloat);
+}
+
+int crdlm_pointers_Uniform3iv(struct instanceUniform3iv *instance, GLint location, GLsizei count, const GLint * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLint);
+}
+
+int crdlm_pointers_Uniform4fv(struct instanceUniform4fv *instance, GLint location, GLsizei count, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLfloat);
+}
+
+int crdlm_pointers_Uniform4iv(struct instanceUniform4iv *instance, GLint location, GLsizei count, const GLint * value)
+{
+ _VBOX_crdlm_pointers_UniformX(GLint);
+}
+
+#undef crdlm_pointers_Uniform4iv
+
+/* Now do the same for UniformMatrix. */
+#define _VBOX_crdlm_pointers_UniformMatrixX(_uniformMatrixType) \
+ int cbExtraSpace = count * sizeof(_uniformMatrixType); \
+ if (instance && value && cbExtraSpace) \
+ crMemcpy(instance->value, value, cbExtraSpace); \
+ return cbExtraSpace;
+
+int crdlm_pointers_UniformMatrix2fv(struct instanceUniformMatrix2fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix2x3fv(struct instanceUniformMatrix2x3fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix2x4fv(struct instanceUniformMatrix2x4fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix3fv(struct instanceUniformMatrix3fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix3x2fv(struct instanceUniformMatrix3x2fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix3x4fv(struct instanceUniformMatrix3x4fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix4fv(struct instanceUniformMatrix4fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix4x2fv(struct instanceUniformMatrix4x2fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+int crdlm_pointers_UniformMatrix4x3fv(struct instanceUniformMatrix4x3fv *instance, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)
+{
+ _VBOX_crdlm_pointers_UniformMatrixX(GLfloat);
+}
+
+#undef _VBOX_crdlm_pointers_UniformMatrixX
+
+#if 0
+VBoxConCreate
+VBoxCreateContext
+VBoxPackSetInjectThread
+VBoxPresentComposition
+VBoxWindowCreate
+#endif
+
+int crdlm_pointers_VBoxConCreate(struct instanceVBoxConCreate *instance, struct VBOXUHGSMI * pHgsmi)
+{
+ CRASSERT(0);
+ return 0;
+}
+
+int crdlm_pointers_VBoxCreateContext(struct instanceVBoxCreateContext *instance, GLint con, const char * dpyName, GLint visual, GLint shareCtx)
+{
+ int cbExtraSpace = (dpyName ? crStrlen(dpyName) + 1 : 0);
+
+ if (instance && dpyName && cbExtraSpace)
+ crMemcpy(instance->dpyName, dpyName, cbExtraSpace);
+
+ return cbExtraSpace;
+}
+
+int crdlm_pointers_VBoxPackSetInjectThread(struct instanceVBoxPackSetInjectThread *instance, struct VBOXUHGSMI * pHgsmi)
+{
+ CRASSERT(0);
+ return 0;
+}
+
+int crdlm_pointers_VBoxPresentComposition(struct instanceVBoxPresentComposition *instance, GLint win,
+ const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY * pChangedEntry)
+{
+ CRASSERT(0);
+ return 0;
+}
+
+int crdlm_pointers_VBoxWindowCreate(struct instanceVBoxWindowCreate *instance, GLint con, const char * dpyName, GLint visBits)
+{
+ int cbExtraSpace = (dpyName ? crStrlen(dpyName) + 1 : 0);
+
+ if (instance && dpyName && cbExtraSpace)
+ crMemcpy(instance->dpyName, dpyName, cbExtraSpace);
+
+ return cbExtraSpace;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.h b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.h
new file mode 100644
index 00000000..51ac2085
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_pointers.h
@@ -0,0 +1,81 @@
+/* $Id: dlm_pointers.h $ */
+#include <VBoxUhgsmi.h>
+
+#include "cr_dlm.h"
+#include "dlm_generated.h"
+
+#ifndef _DLM_POINTERS_H
+#define _DLM_POINTERS_H
+
+extern int crdlm_pointers_Bitmap( struct instanceBitmap *instance, GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap, CRClientState *c);
+extern int crdlm_pointers_DrawPixels( struct instanceDrawPixels *instance, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_Fogfv( struct instanceFogfv *instance, GLenum pname, const GLfloat *params );
+extern int crdlm_pointers_Fogiv( struct instanceFogiv *instance, GLenum pname, const GLint *params );
+extern int crdlm_pointers_LightModelfv( struct instanceLightModelfv *instance, GLenum pname, const GLfloat *params );
+extern int crdlm_pointers_LightModeliv( struct instanceLightModeliv *instance, GLenum pname, const GLint *params );
+extern int crdlm_pointers_Lightfv( struct instanceLightfv *instance, GLenum light, GLenum pname, const GLfloat *params );
+extern int crdlm_pointers_Lightiv( struct instanceLightiv *instance, GLenum light, GLenum pname, const GLint *params );
+extern int crdlm_pointers_Map1d( struct instanceMap1d *instance, GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points );
+extern int crdlm_pointers_Map1f( struct instanceMap1f *instance, GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points );
+extern int crdlm_pointers_Map2d( struct instanceMap2d *instance, GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points );
+extern int crdlm_pointers_Map2f( struct instanceMap2f *instance, GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points );
+extern int crdlm_pointers_Materialfv(struct instanceMaterialfv *instance, GLenum face, GLenum pname, const GLfloat *params);
+extern int crdlm_pointers_Materialiv(struct instanceMaterialiv *instance, GLenum face, GLenum pname, const GLint *params);
+extern int crdlm_pointers_PixelMapfv( struct instancePixelMapfv *instance, GLenum map, GLsizei mapsize, const GLfloat *values );
+extern int crdlm_pointers_PixelMapuiv( struct instancePixelMapuiv *instance, GLenum map, GLsizei mapsize, const GLuint *values );
+extern int crdlm_pointers_PixelMapusv( struct instancePixelMapusv *instance, GLenum map, GLsizei mapsize, const GLushort *values );
+extern int crdlm_pointers_PointParameterfvARB( struct instancePointParameterfvARB *instance, GLenum pname, const GLfloat *params);
+extern int crdlm_pointers_PointParameteriv( struct instancePointParameteriv *instance, GLenum pname, const GLint *params);
+extern int crdlm_pointers_TexEnvfv( struct instanceTexEnvfv *instance, GLenum target, GLenum pname, const GLfloat *params );
+extern int crdlm_pointers_TexEnviv( struct instanceTexEnviv *instance, GLenum target, GLenum pname, const GLint *params );
+extern int crdlm_pointers_TexGendv( struct instanceTexGendv *instance, GLenum coord, GLenum pname, const GLdouble *params );
+extern int crdlm_pointers_TexGenfv( struct instanceTexGenfv *instance, GLenum coord, GLenum pname, const GLfloat *params );
+extern int crdlm_pointers_TexGeniv( struct instanceTexGeniv *instance, GLenum coord, GLenum pname, const GLint *params );
+extern int crdlm_pointers_TexImage1D( struct instanceTexImage1D *instance, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_CompressedTexImage1DARB(struct instanceCompressedTexImage1DARB *instance, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imagesize, const GLvoid *data);
+extern int crdlm_pointers_TexImage2D( struct instanceTexImage2D *instance, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_CompressedTexImage2DARB(struct instanceCompressedTexImage2DARB *instance, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imagesize, const GLvoid *data);
+extern int crdlm_pointers_TexImage3D( struct instanceTexImage3D *instance, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_TexImage3DEXT( struct instanceTexImage3DEXT *instance, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_CompressedTexImage3DARB(struct instanceCompressedTexImage3DARB *instance, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imagesize, const GLvoid *data);
+extern int crdlm_pointers_TexParameterfv( struct instanceTexParameterfv *instance, GLenum target, GLenum pname, const GLfloat *params );
+extern int crdlm_pointers_TexParameteriv( struct instanceTexParameteriv *instance, GLenum target, GLenum pname, const GLint *params );
+extern int crdlm_pointers_TexSubImage1D( struct instanceTexSubImage1D *instance, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_TexSubImage2D( struct instanceTexSubImage2D *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_TexSubImage3D( struct instanceTexSubImage3D *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels, CRClientState *c );
+extern int crdlm_pointers_CompressedTexSubImage1DARB(struct instanceCompressedTexSubImage1DARB *instance, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imagesize, const GLvoid *data);
+extern int crdlm_pointers_CompressedTexSubImage2DARB(struct instanceCompressedTexSubImage2DARB *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imagesize, const GLvoid *data);
+extern int crdlm_pointers_CompressedTexSubImage3DARB(struct instanceCompressedTexSubImage3DARB *instance, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imagesize, const GLvoid *data);
+extern int crdlm_pointers_Rectdv(struct instanceRectdv *instance, const GLdouble *v1, const GLdouble *v2);
+extern int crdlm_pointers_Rectfv(struct instanceRectfv *instance, const GLfloat *v1, const GLfloat *v2);
+extern int crdlm_pointers_Rectiv(struct instanceRectiv *instance, const GLint *v1, const GLint *v2);
+extern int crdlm_pointers_Rectsv(struct instanceRectsv *instance, const GLshort *v1, const GLshort *v2);
+extern int crdlm_pointers_PrioritizeTextures(struct instancePrioritizeTextures *instance, GLsizei n, const GLuint *textures, const GLclampf *priorities);
+extern int crdlm_pointers_CombinerParameterivNV(struct instanceCombinerParameterivNV *instance, GLenum pname, const GLint *params);
+extern int crdlm_pointers_CombinerParameterfvNV(struct instanceCombinerParameterfvNV *instance, GLenum pname, const GLfloat *params);
+extern int crdlm_pointers_CombinerStageParameterfvNV(struct instanceCombinerStageParameterfvNV *instance, GLenum stage, GLenum pname, const GLfloat *params);
+extern int crdlm_pointers_ExecuteProgramNV(struct instanceExecuteProgramNV *instance, GLenum target, GLuint id, const GLfloat *params);
+extern int crdlm_pointers_RequestResidentProgramsNV(struct instanceRequestResidentProgramsNV *instance, GLsizei n, const GLuint *ids);
+extern int crdlm_pointers_LoadProgramNV(struct instanceLoadProgramNV *instance, GLenum target, GLuint id, GLsizei len, const GLubyte *program);
+extern int crdlm_pointers_ProgramNamedParameter4dNV(struct instanceProgramNamedParameter4dNV *instance, GLuint id, GLsizei len, const GLubyte * name, GLdouble x, GLdouble y, GLdouble z, GLdouble w);
+extern int crdlm_pointers_ProgramNamedParameter4dvNV(struct instanceProgramNamedParameter4dvNV *instance, GLuint id, GLsizei len, const GLubyte * name, const GLdouble * v);
+extern int crdlm_pointers_ProgramNamedParameter4fNV(struct instanceProgramNamedParameter4fNV *instance, GLuint id, GLsizei len, const GLubyte * name, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+extern int crdlm_pointers_ProgramNamedParameter4fvNV(struct instanceProgramNamedParameter4fvNV *instance, GLuint id, GLsizei len, const GLubyte * name, const GLfloat * v);
+extern int crdlm_pointers_ProgramStringARB(struct instanceProgramStringARB *instance, GLenum target, GLenum format, GLsizei len, const GLvoid * string);
+extern int crdlm_pointers_CallLists(struct instanceCallLists *instance, GLsizei n, GLenum type, const GLvoid *lists );
+extern int crdlm_pointers_VertexAttribs1dvNV(struct instanceVertexAttribs1dvNV *instance, GLuint index, GLsizei n, const GLdouble *v);
+extern int crdlm_pointers_VertexAttribs1fvNV(struct instanceVertexAttribs1fvNV *instance, GLuint index, GLsizei n, const GLfloat *v);
+extern int crdlm_pointers_VertexAttribs1svNV(struct instanceVertexAttribs1svNV *instance, GLuint index, GLsizei n, const GLshort *v);
+extern int crdlm_pointers_VertexAttribs2dvNV(struct instanceVertexAttribs2dvNV *instance, GLuint index, GLsizei n, const GLdouble *v);
+extern int crdlm_pointers_VertexAttribs2fvNV(struct instanceVertexAttribs2fvNV *instance, GLuint index, GLsizei n, const GLfloat *v);
+extern int crdlm_pointers_VertexAttribs2svNV(struct instanceVertexAttribs2svNV *instance, GLuint index, GLsizei n, const GLshort *v);
+extern int crdlm_pointers_VertexAttribs3dvNV(struct instanceVertexAttribs3dvNV *instance, GLuint index, GLsizei n, const GLdouble *v);
+extern int crdlm_pointers_VertexAttribs3fvNV(struct instanceVertexAttribs3fvNV *instance, GLuint index, GLsizei n, const GLfloat *v);
+extern int crdlm_pointers_VertexAttribs3svNV(struct instanceVertexAttribs3svNV *instance, GLuint index, GLsizei n, const GLshort *v);
+extern int crdlm_pointers_VertexAttribs4dvNV(struct instanceVertexAttribs4dvNV *instance, GLuint index, GLsizei n, const GLdouble *v);
+extern int crdlm_pointers_VertexAttribs4fvNV(struct instanceVertexAttribs4fvNV *instance, GLuint index, GLsizei n, const GLfloat *v);
+extern int crdlm_pointers_VertexAttribs4svNV(struct instanceVertexAttribs4svNV *instance, GLuint index, GLsizei n, const GLshort *v);
+extern int crdlm_pointers_VertexAttribs4ubvNV(struct instanceVertexAttribs4ubvNV *instance, GLuint index, GLsizei n, const GLubyte *v);
+extern int crdlm_pointers_ZPixCR( struct instanceZPixCR *instance, GLsizei width, GLsizei height, GLenum format, GLenum type, GLenum ztype, GLint zparm, GLint length, const GLvoid *pixels, CRClientState *c );
+
+#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_special b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_special
new file mode 100644
index 00000000..bcbd643e
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_special
@@ -0,0 +1,21 @@
+# dlm_arrays.c: these have to be expanded out into
+# their components before being stored in a display list
+ArrayElement
+DrawArrays
+DrawElements
+DrawRangeElements
+MultiDrawArraysEXT
+MultiDrawElementsEXT
+
+# dlm_calllist.c: since the DLM can manage state stored
+# inside display lists, we can manage state updates for
+# these sorts of elements.
+#CallList
+#CallLists
+
+# Calls to be ignored.
+#VBoxConCreate
+#VBoxCreateContext
+#VBoxPackSetInjectThread
+#VBoxPresentComposition
+#VBoxWindowCreate
diff --git a/src/VBox/HostServices/SharedOpenGL/dlm/dlm_state.c b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_state.c
new file mode 100644
index 00000000..341d62e6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/dlm/dlm_state.c
@@ -0,0 +1,280 @@
+/* $Id: dlm_state.c $ */
+/** @file
+ * Implementation of saving and restoring Display Lists.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "cr_mem.h"
+#include "cr_dlm.h"
+#include "dlm.h"
+#include "dlm_generated.h"
+
+#include "VBox/vmm/ssm.h"
+#include <iprt/errcore.h>
+
+
+typedef struct {
+
+ PSSMHANDLE pSSM;
+ uint32_t err;
+
+} CRDLMSaveListsCbArg;
+
+static void crDLMSaveListsCb(unsigned long key, void *pData1, void *pData2)
+{
+ DLMListInfo *pListInfo = (DLMListInfo*)pData1;
+ CRDLMSaveListsCbArg *pArg = (CRDLMSaveListsCbArg *)pData2;
+ PSSMHANDLE pSSM = pArg->pSSM;
+ DLMInstanceList *pInstance = pListInfo->first;
+ uint32_t cInstanceCheck = 0;
+ int32_t rc;
+
+ crDebug("Saving Display Lists: found ID=%u, numInstances=%d.", key, pListInfo->numInstances);
+
+ /* Store Display List length. */
+ rc = SSMR3PutU32(pSSM, pListInfo->numInstances);
+ if (RT_SUCCESS(rc))
+ {
+ /* Store Display List (guest) ID. */
+ rc = SSMR3PutU32(pSSM, (uint32_t)key);
+ if (RT_SUCCESS(rc))
+ {
+ /* Store each Display List item one by one. */
+ while (pInstance)
+ {
+ /* Let's count each list item and compare total number with pListInfo->numInstances.
+ * This is simple consistency check. */
+ cInstanceCheck++;
+
+ /* Store instance data size. */
+ rc = SSMR3PutU32(pSSM, (uint32_t)pInstance->cbInstance);
+ if (RT_SUCCESS(rc))
+ {
+ rc = SSMR3PutMem(pSSM, pInstance, pInstance->cbInstance);
+ if (RT_SUCCESS(rc))
+ {
+ /* We just stored all we need. Let's move on to the next list element. */
+ pInstance = pInstance->next;
+ continue;
+ }
+ }
+
+ crError("Saving Display Lists: can't store data.");
+
+ pArg->err = 1;
+ return;
+ }
+
+ if (cInstanceCheck == pListInfo->numInstances)
+ return;
+
+ crError("Saving Display Lists: list currupted.");
+ }
+ }
+
+ pArg->err = 1;
+}
+
+int32_t DLM_APIENTRY crDLMSaveState(CRDLM *dlm, PSSMHANDLE pSSM)
+{
+ uint32_t ui32;
+ int32_t rc;
+
+ CRDLMSaveListsCbArg arg;
+
+ arg.pSSM = pSSM;
+ arg.err = 0;
+
+ /* Save number of Display Lists assigned to current DLM context. */
+ ui32 = (uint32_t)crHashtableNumElements(dlm->displayLists);
+ rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc);
+
+ crHashtableWalk(dlm->displayLists, crDLMSaveListsCb, (void *)&arg);
+
+ return arg.err == 0;
+}
+
+static VBoxDLMExecuteFn crDLMGetExecuteRoutine(VBoxDLOpCode opcode)
+{
+ if (opcode < VBOX_DL_OPCODE_MAX)
+ return g_VBoxDLMExecuteFns[opcode];
+
+ crError("Restoring Display Lists: Invalid opcode %u.", opcode);
+
+ return NULL;
+}
+
+static bool
+crDLMLoadListInstance(PSSMHANDLE pSSM, DLMListInfo *pListInfo, SPUDispatchTable *dispatchTable)
+{
+ uint32_t cbInstance = 0;
+ DLMInstanceList *pInstance;
+ int32_t rc;
+
+ /* Get Display List item size. */
+ rc = SSMR3GetU32(pSSM, &cbInstance);
+ if (RT_SUCCESS(rc))
+ {
+ /* Allocate memory for the item, initialize it and put into the list. */
+ pInstance = crCalloc(cbInstance);
+ if (pInstance)
+ {
+ crMemset(pInstance, 0, cbInstance);
+
+ rc = SSMR3GetMem(pSSM, pInstance, cbInstance); AssertRCReturn(rc, rc);
+ if (RT_SUCCESS(rc))
+ {
+ pInstance->execute = crDLMGetExecuteRoutine(pInstance->iVBoxOpCode);
+ if (pInstance->execute)
+ {
+ pInstance->execute(pInstance, dispatchTable);
+
+ pInstance->next = NULL;
+ pInstance->stateNext = NULL;
+ pInstance->cbInstance = cbInstance;
+
+ pListInfo->numInstances++;
+
+ if (!pListInfo->first)
+ pListInfo->first = pInstance;
+
+ if (pListInfo->last)
+ pListInfo->last->next = pInstance;
+
+ pListInfo->last = pInstance;
+
+ return true;
+ }
+ else
+ crError("Restoring Display Lists: unknown list item (opcode=%u).", pInstance->iVBoxOpCode);
+ }
+ else
+ crError("Restoring Display Lists: can't read list element size.");
+ }
+ else
+ crError("Restoring Display Lists: not enough memory, aborting.");
+ }
+ else
+ crError("Restoring Display Lists: saved state file might be corrupted.");
+
+ return false;
+}
+
+static bool
+crDLMLoadList(CRDLM *dlm, PSSMHANDLE pSSM, SPUDispatchTable *dispatchTable)
+{
+ uint32_t cElements = 0;
+ uint32_t idList = 0;
+ uint32_t i;
+ int32_t rc;
+
+ /* Restore Display List length. */
+ rc = SSMR3GetU32(pSSM, &cElements);
+ if (RT_SUCCESS(rc))
+ {
+ /* Restore Display List ID. */
+ rc = SSMR3GetU32(pSSM, &idList);
+ if (RT_SUCCESS(rc))
+ {
+ /* Initialize new list data and start recording it. */
+ DLMListInfo *pListInfo;
+
+ pListInfo = (DLMListInfo *)crCalloc(sizeof(DLMListInfo));
+ if (pListInfo)
+ {
+ GLuint hwid;
+
+ crMemset(pListInfo, 0, sizeof(DLMListInfo));
+
+ hwid = dispatchTable->GenLists(1);
+ if (hwid > 0)
+ {
+ bool fSuccess = true;
+ CRDLMContextState *pDLMContextState;
+
+ pListInfo->numInstances = 0;
+ pListInfo->stateFirst = pListInfo->stateLast = NULL;
+ pListInfo->hwid = hwid;
+
+ dispatchTable->NewList(hwid, GL_COMPILE);
+
+ /* Fake list state in order to prevent expando SPU from double caching. */
+ pDLMContextState = crDLMGetCurrentState();
+ pDLMContextState->currentListMode = GL_FALSE;
+
+ crDebug("Restoring Display Lists:\t%u elements to restore.", cElements);
+
+ /* Iterate over list instances. */
+ for (i = 0; i < cElements; i++)
+ {
+ fSuccess = crDLMLoadListInstance(pSSM, pListInfo, dispatchTable);
+ if (!fSuccess)
+ break;
+ }
+
+ dispatchTable->EndList();
+
+ if (fSuccess)
+ {
+ /* Add list to cache. */
+ crHashtableReplace(dlm->displayLists, idList, pListInfo, NULL);
+ return true;
+ }
+ else
+ crError("Restoring Display Lists: some elements could not be restored.");
+ }
+ else
+ crError("Restoring Display Lists: can't allocate hwid for list %u.", idList);
+
+ crFree(pListInfo);
+ }
+ else
+ crError("Restoring Display Lists: can't allocate memory.");
+ }
+ else
+ crError("Restoring Display Lists: can't get list ID.");
+ }
+ else
+ crError("Restoring Display Lists: can't get number of elements in list.");
+
+ return false;
+}
+
+
+bool DLM_APIENTRY
+crDLMLoadState(CRDLM *dlm, PSSMHANDLE pSSM, SPUDispatchTable *dispatchTable)
+{
+ uint32_t cLists = 0;
+ uint32_t i;
+ int32_t rc;
+ bool fSuccess = true;
+
+ /* Get number of Display Lists assigned to current DLM context. */
+ rc = SSMR3GetU32(pSSM, &cLists);
+ if (RT_SUCCESS(rc))
+ {
+ crDebug("Restoring Display Lists: %u lists to restore.", cLists);
+
+ for (i = 0; i < cLists; i++)
+ {
+ fSuccess = crDLMLoadList(dlm, pSSM, dispatchTable);
+ if (!fSuccess)
+ break;
+ }
+ }
+ else
+ crError("Restoring Display Lists: can't get number of lists.");
+
+ return fSuccess;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expando.py b/src/VBox/HostServices/SharedOpenGL/expando/expando.py
new file mode 100644
index 00000000..86c45950
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expando.py
@@ -0,0 +1,91 @@
+# $Id: expando.py $
+# This script generates calls for display list compilation
+# and state management.
+import sys
+
+sys.path.append( "../../glapi_parser" )
+import apiutil
+
+apiutil.CopyrightC()
+
+print """
+/* DO NOT EDIT - THIS FILE AUTOMATICALLY GENERATED BY expando.py SCRIPT */
+#include <stdio.h>
+#include "cr_error.h"
+#include "cr_spu.h"
+#include "cr_dlm.h"
+#include "expandospu.h"
+"""
+
+allFunctions = []
+generatedFunctions = []
+
+for func_name in apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt"):
+ if apiutil.FindSpecial("expando", func_name):
+ allFunctions.append(func_name)
+ elif apiutil.CanCompile(func_name) or apiutil.SetsClientState(func_name):
+ generatedFunctions.append(func_name)
+ allFunctions.append(func_name)
+
+for func_name in generatedFunctions:
+ params = apiutil.Parameters(func_name)
+ return_type = apiutil.ReturnType(func_name)
+ basicCallString = apiutil.MakeCallString(params)
+ declarationString = apiutil.MakeDeclarationString(params)
+ dlmCallString = basicCallString
+ chromiumProps = apiutil.ChromiumProps(func_name)
+
+ needClientState = 0
+ if apiutil.UsesClientState(func_name):
+ dlmCallString = basicCallString + ", clientState"
+ needClientState = 1
+
+ needDL = 0
+ if apiutil.CanCompile(func_name):
+ needDL = 1
+
+ print 'static %s EXPANDOSPU_APIENTRY expando%s(%s)' % ( return_type, func_name, declarationString)
+ print '{'
+ if needDL:
+ print '\tGLenum dlMode = crDLMGetCurrentMode();'
+ if needClientState:
+ print '\tCRContext *stateContext = crStateGetCurrent();'
+ print '\tCRClientState *clientState = NULL;'
+ print '\tif (stateContext != NULL) {'
+ print '\t\tclientState = &(stateContext->client);'
+ print '\t}'
+
+ if needDL:
+ if "checklist" in chromiumProps:
+ print '\tif (dlMode != GL_FALSE && crDLMCheckList%s(%s)) {' % (func_name, basicCallString)
+ else:
+ print '\tif (dlMode != GL_FALSE) {'
+ print '\t\tcrDLMCompile%s(%s);' % (func_name, dlmCallString)
+ # If we're only compiling, return now.
+ print '\t\tif (dlMode == GL_COMPILE) return %s;' % '0' if return_type != "void" else ""
+ print '\t}'
+
+ # If it gets this far, we're either just executing, or executing
+ # and compiling. Either way, pass the call to the super SPU,
+ # and to the state tracker (if appropriate; note that we only
+ # track client-side state, not all state).
+ if return_type != "void":
+ print '\t%s rc = expando_spu.super.%s(%s);' % (return_type, func_name, basicCallString)
+ else:
+ print '\texpando_spu.super.%s(%s);' % (func_name, basicCallString)
+ if apiutil.SetsClientState(func_name):
+ print '\tcrState%s(%s);' % (func_name, basicCallString)
+
+ if return_type != "void":
+ print "\treturn rc;"
+
+ print '}'
+ print ''
+
+# Generate the table of named functions. including all the static generated
+# functions as well as the special functions.
+print 'SPUNamedFunctionTable _cr_expando_table[] = {'
+for func_name in allFunctions:
+ print '\t{ "%s", (SPUGenericFunction) expando%s },' % (func_name, func_name )
+print '\t{ NULL, NULL }'
+print '};'
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expando_special b/src/VBox/HostServices/SharedOpenGL/expando/expando_special
new file mode 100644
index 00000000..9a8cd569
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expando_special
@@ -0,0 +1,18 @@
+CreateContext
+DestroyContext
+MakeCurrent
+NewList
+EndList
+DeleteLists
+GenLists
+ListBase
+IsList
+CallList
+CallLists
+
+# Calls to be ignored.
+#VBoxConCreate
+#VBoxCreateContext
+#VBoxPackSetInjectThread
+#VBoxPresentComposition
+#VBoxWindowCreate
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu.c b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.c
new file mode 100644
index 00000000..8db885a5
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.c
@@ -0,0 +1,182 @@
+/* $Id: expandospu.c $ */
+/** @file
+ * Implementation of routines which Expando SPU explicitly overrides.
+ */
+
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <stdio.h>
+#include "cr_spu.h"
+#include "cr_dlm.h"
+#include "cr_mem.h"
+#include "expandospu.h"
+
+extern GLint EXPANDOSPU_APIENTRY
+expandoCreateContext(const char *displayName, GLint visBits, GLint shareCtx)
+{
+ ExpandoContextState *contextState;
+
+ /* Allocate our own per-context record */
+ contextState = crCalloc(sizeof(ExpandoContextState));
+ if (contextState)
+ {
+ GLint contextId;
+
+ /* Get an official context ID from our super */
+ contextId = expando_spu.super.CreateContext(displayName, visBits, shareCtx);
+
+ /* Supplement that with our DLM. In a more correct situation, we should
+ * see if we've been called through glXCreateContext, which has a parameter
+ * for sharing DLMs. We don't currently get that information, so for now
+ * give each context its own DLM.
+ */
+ contextState->dlm = crDLMNewDLM(0, NULL);
+ if (contextState->dlm)
+ {
+ contextState->dlmContext = crDLMNewContext(contextState->dlm);
+ if (contextState->dlmContext)
+ {
+ /* The DLM needs us to use the state tracker to track client
+ * state, so we can compile client-state-using functions correctly.
+ */
+ contextState->State = crStateCreateContext(NULL, visBits, NULL);
+
+ /* Associate the Expando context with the user context. */
+ crHashtableAdd(expando_spu.contextTable, contextId, (void *)contextState);
+
+ crDebug("Expando SPU: created context %d (contextState=%p, contextState->dlm=%p, "
+ "contextState->dlmContext=%p, contextState->State=%p).",
+ contextId, contextState, contextState->dlm, contextState->dlmContext, contextState->State);
+
+ return contextId;
+ }
+ else
+ crError("Expando SPU: can't allocate new DLM context.");
+
+ crDLMFreeDLM(contextState->dlm, &expando_spu.super);
+ }
+ else
+ crError("Expando SPU: can't allocate new DLM.");
+
+ crFree(contextState);
+ }
+ else
+ crError("Expando SPU: couldn't allocate per-context state");
+
+ return 0;
+}
+
+void expando_free_context_state(void *data)
+{
+ ExpandoContextState *contextState = (ExpandoContextState *)data;
+
+ crDebug("Expando SPU: destroying context internals: "
+ "contextState=%p, contextState->dlm=%p, contextState->dlmContext=%p, contextState->State=%p",
+ contextState, contextState->dlm, contextState->dlmContext, contextState->State);
+
+ crDLMFreeContext(contextState->dlmContext, &expando_spu.super);
+ crDLMFreeDLM(contextState->dlm, &expando_spu.super);
+ crStateDestroyContext(contextState->State);
+ crFree(contextState);
+}
+
+void EXPANDOSPU_APIENTRY
+expandoDestroyContext(GLint contextId)
+{
+ crDebug("Expando SPU: destroy context %d.", contextId);
+
+ /* Destroy our context information */
+ crHashtableDelete(expando_spu.contextTable, contextId, expando_free_context_state);
+
+ /* Pass along the destruction to our super. */
+ expando_spu.super.DestroyContext(contextId);
+}
+
+void EXPANDOSPU_APIENTRY
+expandoMakeCurrent(GLint crWindow, GLint nativeWindow, GLint contextId)
+{
+ ExpandoContextState *expandoContextState;
+
+ expando_spu.super.MakeCurrent(crWindow, nativeWindow, contextId);
+
+ expandoContextState = crHashtableSearch(expando_spu.contextTable, contextId);
+ if (expandoContextState)
+ {
+ crDebug("Expando SPU: switch to context %d.", contextId);
+
+ crDLMSetCurrentState(expandoContextState->dlmContext);
+ crStateMakeCurrent(expandoContextState->State);
+ }
+ else
+ {
+ crDebug("Expando SPU: can't switch to context %d: not found.", contextId);
+
+ crDLMSetCurrentState(NULL);
+ crStateMakeCurrent(NULL);
+ }
+}
+
+extern void EXPANDOSPU_APIENTRY
+expandoNewList(GLuint list, GLenum mode)
+{
+ crDLMNewList(list, mode, &expando_spu.super);
+}
+
+extern void EXPANDOSPU_APIENTRY
+expandoEndList(void)
+{
+ crDLMEndList(&expando_spu.super);
+}
+
+extern void EXPANDOSPU_APIENTRY
+expandoDeleteLists(GLuint first, GLsizei range)
+{
+ crDLMDeleteLists(first, range, &expando_spu.super);
+}
+
+extern GLuint EXPANDOSPU_APIENTRY
+expandoGenLists(GLsizei range)
+{
+ return crDLMGenLists(range, &expando_spu.super);
+}
+
+void EXPANDOSPU_APIENTRY
+expandoListBase(GLuint base)
+{
+ crDLMListBase(base, &expando_spu.super);
+}
+
+extern GLboolean EXPANDOSPU_APIENTRY
+expandoIsList(GLuint list)
+{
+ return crDLMIsList(list, &expando_spu.super);
+}
+
+extern void EXPANDOSPU_APIENTRY
+expandoCallList(GLuint list)
+{
+ crDLMCallList(list, &expando_spu.super);
+}
+
+extern void EXPANDOSPU_APIENTRY
+expandoCallLists(GLsizei n, GLenum type, const GLvoid *lists)
+{
+ crDLMCallLists(n, type, lists, &expando_spu.super);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu.def b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.def
new file mode 100644
index 00000000..9edc7163
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.def
@@ -0,0 +1,6 @@
+; Copyright (c) 2001, Stanford University
+; All rights reserved.
+;
+; See the file LICENSE.txt for information on redistributing this software.
+EXPORTS
+SPULoad
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu.h b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.h
new file mode 100644
index 00000000..dad5e120
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu.h
@@ -0,0 +1,69 @@
+/* $Id: expandospu.h $ */
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved.
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#ifndef EXPANDO_SPU_H
+#define EXPANDO_SPU_H
+
+#ifdef WINDOWS
+#define EXPANDOSPU_APIENTRY __stdcall
+#else
+#define EXPANDOSPU_APIENTRY
+#endif
+
+#include "cr_glstate.h"
+#include "cr_spu.h"
+#include "cr_server.h"
+#include "cr_dlm.h"
+
+typedef struct {
+ int id;
+ int has_child;
+ SPUDispatchTable self, child, super;
+ CRServer *server;
+
+ /* Expando-specific variables */
+ CRHashTable *contextTable;
+} ExpandoSPU;
+
+typedef struct {
+ /* Local copy of state, needed by DLM to compile client-side stuff.
+ * We only collect client-side state; we ignore all server-side
+ * state (we just don't need it).
+ */
+ CRContext *State;
+
+ /* The DLM, and the per-context state for a DLM. Right now, every
+ * context will have its own DLM; it's possible in OpenGL to share
+ * DLMs, but the Chromium interface doesn't allow it yet.
+ */
+ CRDLM *dlm;
+ CRDLMContextState *dlmContext;
+} ExpandoContextState;
+
+extern ExpandoSPU expando_spu;
+
+extern SPUNamedFunctionTable _cr_expando_table[];
+
+extern SPUOptions expandoSPUOptions[];
+
+extern void expandospuGatherConfiguration( void );
+
+extern void expando_free_context_state(void *data);
+
+extern GLint EXPANDOSPU_APIENTRY expandoCreateContext(const char *displayName, GLint visBits, GLint shareCtx);
+extern void EXPANDOSPU_APIENTRY expandoDestroyContext(GLint contextId);
+extern void EXPANDOSPU_APIENTRY expandoMakeCurrent(GLint crWindow, GLint nativeWindow, GLint contextId);
+extern void EXPANDOSPU_APIENTRY expandoNewList(GLuint list, GLenum mode);
+extern void EXPANDOSPU_APIENTRY expandoEndList(void);
+extern void EXPANDOSPU_APIENTRY expandoDeleteLists(GLuint first, GLsizei range);
+extern GLuint EXPANDOSPU_APIENTRY expandoGenLists(GLsizei range);
+extern void EXPANDOSPU_APIENTRY expandoListBase(GLuint base);
+extern GLboolean EXPANDOSPU_APIENTRY expandoIsList(GLuint list);
+extern void EXPANDOSPU_APIENTRY expandoCallList(GLuint list);
+extern void EXPANDOSPU_APIENTRY expandoCallLists(GLsizei n, GLenum type, const GLvoid *lists);
+
+#endif /* EXPANDO_SPU_H */
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c
new file mode 100644
index 00000000..9843f486
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_config.c
@@ -0,0 +1,48 @@
+/* $Id: expandospu_config.c $ */
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "expandospu.h"
+
+//#include "cr_mothership.h"
+#include "cr_string.h"
+
+#include <stdio.h>
+
+static void __setDefaults( void )
+{
+}
+
+/* option, type, nr, default, min, max, title, callback
+ */
+SPUOptions expandoSPUOptions[] = {
+ { NULL, CR_BOOL, 0, NULL, NULL, NULL, NULL, NULL },
+};
+
+
+void expandospuGatherConfiguration( void )
+{
+ CRConnection *conn;
+
+ __setDefaults();
+#if 0
+ /* Connect to the mothership and identify ourselves. */
+
+ conn = crMothershipConnect( );
+ if (!conn)
+ {
+ /* The mothership isn't running. Some SPU's can recover gracefully, some
+ * should issue an error here. */
+ crSPUSetDefaultParams( &expando_spu, expandoSPUOptions );
+ return;
+ }
+ crMothershipIdentifySPU( conn, expando_spu.id );
+
+ crSPUGetMothershipParams( conn, &expando_spu, expandoSPUOptions );
+
+ crMothershipDisconnect( conn );
+#endif
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c
new file mode 100644
index 00000000..f49dffbb
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/expando/expandospu_init.c
@@ -0,0 +1,289 @@
+/* $Id: expandospu_init.c $ */
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include <stdio.h>
+#include "cr_spu.h"
+#include "cr_dlm.h"
+#include "cr_hash.h"
+#include "cr_mem.h"
+#include "expandospu.h"
+
+/* This magic number is used for SSM data consistency check. */
+#define VBOX_EXPANDOSPU_SSM_MAGIC 0x3d3d3d3d
+/* Modify VBox Expando SPU SSM version if SSM data structure changed. */
+#define VBOX_EXPANDOSPU_SSM_VERSION_ONE 1
+#define VBOX_EXPANDOSPU_SSM_VERSION VBOX_EXPANDOSPU_SSM_VERSION_ONE
+
+ExpandoSPU expando_spu;
+
+static SPUFunctions expando_functions = {
+ NULL, /* CHILD COPY */
+ NULL, /* DATA */
+ _cr_expando_table /* THE ACTUAL FUNCTIONS */
+};
+
+/*
+ * Structure of SSM data:
+ *
+ * <VBOX_EXPANDOSPU_SSM_MAGIC>
+ * <VBOX_EXPANDOSPU_SSM_VERSION>
+ * <Number of Expando SPU contexts>
+ *
+ * <Context ID>
+ * <CRDLMContextState structure>
+ * <DLM module data>
+ *
+ * <Next context...>
+ *
+ * <VBOX_EXPANDOSPU_SSM_MAGIC>
+ */
+
+static void
+expandoSPUSaveContextCb(unsigned long id, void *pData1, void *pData2)
+{
+ uint32_t ui32 = (uint32_t)id;
+ PSSMHANDLE pSSM = (PSSMHANDLE)pData2;
+ int32_t rc;
+
+ ExpandoContextState *pExpandoContextState = (ExpandoContextState *)pData1;
+ CRDLMContextState dlmContextState;
+
+ /* Save context ID. */
+ rc = SSMR3PutU32(pSSM, ui32); AssertRCReturnVoid(rc);
+
+ /* Save DLM context state. Clean fields which will not be valid on restore (->dlm and ->currentListInfo).
+ * We interested only in fields: currentListIdentifier, currentListMode and listBase. */
+ crMemcpy(&dlmContextState, pExpandoContextState->dlmContext, sizeof(CRDLMContextState));
+ dlmContextState.dlm = NULL;
+ dlmContextState.currentListInfo = NULL;
+ rc = SSMR3PutMem(pSSM, &dlmContextState, sizeof(CRDLMContextState)); AssertRCReturnVoid(rc);
+
+ /* Delegate the rest of work to DLM module. */
+ crDLMSaveState(pExpandoContextState->dlmContext->dlm, pSSM);
+}
+
+static int
+expandoSPUSaveState(void *pData)
+{
+ uint32_t magic = VBOX_EXPANDOSPU_SSM_MAGIC;
+ uint32_t version = VBOX_EXPANDOSPU_SSM_VERSION;
+ PSSMHANDLE pSSM = (PSSMHANDLE)pData;
+ int32_t rc;
+ uint32_t cStates;
+
+ crDebug("Saving state of Expando SPU.");
+
+ AssertReturn(pSSM, 1);
+
+ /* Magic & version first. */
+ rc = SSMR3PutU32(pSSM, magic); AssertRCReturn(rc, rc);
+ rc = SSMR3PutU32(pSSM, version); AssertRCReturn(rc, rc);
+
+ /* Store number of Expando SPU contexts. */
+ cStates = (uint32_t)crHashtableNumElements(expando_spu.contextTable);
+ rc = SSMR3PutU32(pSSM, cStates); AssertRCReturn(rc, rc);
+
+ /* Walk over context table and store required data. */
+ crHashtableWalk(expando_spu.contextTable, expandoSPUSaveContextCb, pSSM);
+
+ /* Expando SPU and DLM data should end with magic (consistency check). */
+ rc = SSMR3PutU32(pSSM, magic); AssertRCReturn(rc, rc);
+
+ return 0;
+}
+
+static int
+expandoSPULoadState(void *pData)
+{
+ uint32_t magic = 0;
+ uint32_t version = 0;
+ PSSMHANDLE pSSM = (PSSMHANDLE)pData;
+ int32_t rc;
+
+ crDebug("Loading state of Expando SPU.");
+
+ AssertReturn(pSSM, 1);
+
+ /* Check magic and version. */
+ rc = SSMR3GetU32(pSSM, &magic);
+ AssertRCReturn(rc, rc);
+
+ if (magic == VBOX_EXPANDOSPU_SSM_MAGIC)
+ {
+ rc = SSMR3GetU32(pSSM, &version);
+ AssertRCReturn(rc, rc);
+
+ if (version >= VBOX_EXPANDOSPU_SSM_VERSION_ONE)
+ {
+ uint32_t cStates = 0;
+ uint32_t i;
+ bool fSuccess = false;
+
+ CRDLMContextState *pCurrentDLMState;
+ CRContext *pCurrentCRState;
+
+ /* Remember current state. */
+ pCurrentDLMState = crDLMGetCurrentState();
+ pCurrentCRState = crStateGetCurrent();
+
+ /* Restore number of Expando SPU contexts. */
+ rc = SSMR3GetU32(pSSM, &cStates);
+ AssertRCReturn(rc, rc);
+
+ /* Restore and update Expando SPU contexts one by one. */
+ for (i = 0; i < cStates; i++)
+ {
+ uint32_t idContext = 0;
+ ExpandoContextState *pExpandoContextState;
+
+ rc = SSMR3GetU32(pSSM, &idContext);
+ AssertRCReturn(rc, rc);
+
+ /* Find context which was previously created by CR Server. */
+ pExpandoContextState = crHashtableSearch(expando_spu.contextTable, idContext);
+ if (pExpandoContextState)
+ {
+ CRDLMContextState dlmContextState;
+
+ /* Restore and update DLM context state. */
+ rc = SSMR3GetMem(pSSM, &dlmContextState, sizeof(CRDLMContextState));
+ if (RT_SUCCESS(rc))
+ {
+ pExpandoContextState->dlmContext->currentListIdentifier = dlmContextState.currentListIdentifier;
+ pExpandoContextState->dlmContext->currentListMode = dlmContextState.currentListMode;
+ pExpandoContextState->dlmContext->listBase = dlmContextState.listBase;
+
+ crDLMSetCurrentState(pExpandoContextState->dlmContext);
+ crStateMakeCurrent(pExpandoContextState->State);
+
+ /* Delegate the rest of work to DLM module. */
+ fSuccess = crDLMLoadState(pExpandoContextState->dlmContext->dlm, pSSM, &expando_spu.server->dispatch);
+ if (fSuccess)
+ {
+ continue;
+ }
+ else
+ {
+ crError("Expando SPU: stop restoring Display Lists.");
+ break;
+ }
+ }
+ else
+ {
+ crError("Expando SPU: unable to load state: state file structure error (1).");
+ break;
+ }
+ }
+ else
+ {
+ crError("Expando SPU: unable to load state: no context ID %u found.", idContext);
+ break;
+ }
+ }
+
+ /* Restore original state. */
+ crDLMSetCurrentState(pCurrentDLMState);
+ crStateMakeCurrent(pCurrentCRState);
+
+ if (fSuccess)
+ {
+ /* Expando SPU and DLM data should end with magic (consistency check). */
+ magic = 0;
+ rc = SSMR3GetU32(pSSM, &magic);
+ if (RT_SUCCESS(rc))
+ {
+ if (magic == VBOX_EXPANDOSPU_SSM_MAGIC)
+ {
+ crInfo("Expando SPU state loaded.");
+ return 0;
+ }
+ else
+ crError("Expando SPU: unable to load state: SSM data corrupted.");
+ }
+ else
+ crError("Expando SPU: unable to load state: state file structure error (2): no magic.");
+ }
+ else
+ crError("Expando SPU: unable to load state: some list(s) could not be restored.");
+ }
+ else
+ crError("Expando SPU: unable to load state: unexpected SSM version (0x%x).", version);
+ }
+ else
+ crError("Expando SPU: unable to load state: SSM data possibly corrupted.");
+
+ return VERR_SSM_UNEXPECTED_DATA;
+}
+
+static SPUFunctions *
+expandoSPUInit(int id, SPU *child, SPU *self, unsigned int context_id, unsigned int num_contexts)
+{
+
+ (void)self;
+ (void)context_id;
+ (void)num_contexts;
+
+ expando_spu.id = id;
+ expando_spu.has_child = 0;
+ expando_spu.server = NULL;
+
+ if (child)
+ {
+ crSPUInitDispatchTable(&(expando_spu.child));
+ crSPUCopyDispatchTable(&(expando_spu.child), &(child->dispatch_table));
+ expando_spu.has_child = 1;
+ }
+
+ crSPUInitDispatchTable(&(expando_spu.super));
+ crSPUCopyDispatchTable(&(expando_spu.super), &(self->superSPU->dispatch_table));
+ expandospuGatherConfiguration();
+
+ /* Expando-specific initialization */
+ expando_spu.contextTable = crAllocHashtable();
+
+ /* We'll be using the state tracker for each context */
+ crStateInit();
+
+ /* Export optional interfaces for SPU save/restore. */
+ self->dispatch_table.spu_save_state = expandoSPUSaveState;
+ self->dispatch_table.spu_load_state = expandoSPULoadState;
+
+ return &expando_functions;
+}
+
+static void
+expandoSPUSelfDispatch(SPUDispatchTable *self)
+{
+ crSPUInitDispatchTable(&(expando_spu.self));
+ crSPUCopyDispatchTable(&(expando_spu.self), self);
+
+ expando_spu.server = (CRServer *)(self->server);
+}
+
+
+static int
+expandoSPUCleanup(void)
+{
+ crFreeHashtable(expando_spu.contextTable, expando_free_context_state);
+ crStateDestroy();
+ return 1;
+}
+
+int
+SPULoad(char **name, char **super, SPUInitFuncPtr *init, SPUSelfDispatchFuncPtr *self,
+ SPUCleanupFuncPtr *cleanup, SPUOptionsPtr *options, int *flags)
+{
+ *name = "expando";
+ *super = "render";
+ *init = expandoSPUInit;
+ *self = expandoSPUSelfDispatch;
+ *cleanup = expandoSPUCleanup;
+ *options = expandoSPUOptions;
+ *flags = (SPU_NO_PACKER|SPU_NOT_TERMINAL|SPU_MAX_SERVERS_ZERO);
+
+ return 1;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/render/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc b/src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc
new file mode 100644
index 00000000..2cfbc4d9
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/VBoxOGLrenderspu.rc
@@ -0,0 +1,51 @@
+/* $Id: VBoxOGLrenderspu.rc $ */
+/** @file
+ * VBoxOGLrenderspu - Resource file containing version info and icon.
+ */
+
+/*
+ * Copyright (C) 2015-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "FileDescription", "VirtualBox crOpenGL ICD\0"
+ VALUE "InternalName", "VBoxOGLrenderspu\0"
+ VALUE "OriginalFilename", "VBoxOGLrenderspu.dll\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostServices/SharedOpenGL/render/render.def b/src/VBox/HostServices/SharedOpenGL/render/render.def
new file mode 100644
index 00000000..870d7494
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/render.def
@@ -0,0 +1,7 @@
+; Copyright (c) 2001, Stanford University
+; All rights reserved.
+;
+; See the file LICENSE.txt for information on redistributing this software.
+EXPORTS
+SPULoad
+renderspuSetWindowId
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c
new file mode 100644
index 00000000..52a1dfca
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.c
@@ -0,0 +1,1960 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_environment.h"
+#include "cr_string.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_spu.h"
+#include "cr_environment.h"
+#include "renderspu.h"
+#include "cr_extstring.h"
+
+#include <iprt/asm.h>
+
+uint32_t renderspuContextRelease(ContextInfo *context);
+uint32_t renderspuContextRetain(ContextInfo *context);
+
+static void
+DoSync(void)
+{
+ CRMessage *in, out;
+
+ out.header.type = CR_MESSAGE_OOB;
+
+ if (render_spu.is_swap_master)
+ {
+ int a;
+
+ for (a = 0; a < render_spu.num_swap_clients; a++)
+ {
+ crNetGetMessage( render_spu.swap_conns[a], &in );
+ crNetFree( render_spu.swap_conns[a], in);
+ }
+
+ for (a = 0; a < render_spu.num_swap_clients; a++)
+ crNetSend( render_spu.swap_conns[a], NULL, &out, sizeof(CRMessage));
+ }
+ else
+ {
+ crNetSend( render_spu.swap_conns[0], NULL, &out, sizeof(CRMessage));
+
+ crNetGetMessage( render_spu.swap_conns[0], &in );
+ crNetFree( render_spu.swap_conns[0], in);
+ }
+}
+
+
+
+/*
+ * Visual functions
+ */
+
+/**
+ * used for debugging and giving info to the user.
+ */
+void
+renderspuMakeVisString( GLbitfield visAttribs, char *s )
+{
+ s[0] = 0;
+
+ if (visAttribs & CR_RGB_BIT)
+ crStrcat(s, "RGB");
+ if (visAttribs & CR_ALPHA_BIT)
+ crStrcat(s, "A");
+ if (visAttribs & CR_DOUBLE_BIT)
+ crStrcat(s, ", Doublebuffer");
+ if (visAttribs & CR_STEREO_BIT)
+ crStrcat(s, ", Stereo");
+ if (visAttribs & CR_DEPTH_BIT)
+ crStrcat(s, ", Z");
+ if (visAttribs & CR_STENCIL_BIT)
+ crStrcat(s, ", Stencil");
+ if (visAttribs & CR_ACCUM_BIT)
+ crStrcat(s, ", Accum");
+ if (visAttribs & CR_MULTISAMPLE_BIT)
+ crStrcat(s, ", Multisample");
+ if (visAttribs & CR_OVERLAY_BIT)
+ crStrcat(s, ", Overlay");
+ if (visAttribs & CR_PBUFFER_BIT)
+ crStrcat(s, ", PBuffer");
+}
+
+GLboolean renderspuInitVisual(VisualInfo *pVisInfo, const char *displayName, GLbitfield visAttribs)
+{
+ pVisInfo->displayName = crStrdup(displayName);
+ pVisInfo->visAttribs = visAttribs;
+ return renderspu_SystemInitVisual(pVisInfo);
+}
+
+/*
+ * Find a VisualInfo which matches the given display name and attribute
+ * bitmask, or return a pointer to a new visual.
+ */
+VisualInfo *
+renderspuFindVisual(const char *displayName, GLbitfield visAttribs)
+{
+ int i;
+
+ if (!displayName)
+ displayName = "";
+
+ /* first, try to find a match */
+#if defined(WINDOWS) || defined(DARWIN)
+ for (i = 0; i < render_spu.numVisuals; i++) {
+ if (visAttribs == render_spu.visuals[i].visAttribs) {
+ return &(render_spu.visuals[i]);
+ }
+ }
+#elif defined(GLX)
+ for (i = 0; i < render_spu.numVisuals; i++) {
+ if (crStrcmp(displayName, render_spu.visuals[i].displayName) == 0
+ && visAttribs == render_spu.visuals[i].visAttribs) {
+ return &(render_spu.visuals[i]);
+ }
+ }
+#endif
+
+ if (render_spu.numVisuals >= MAX_VISUALS)
+ {
+ crWarning("Render SPU: Couldn't create a visual, too many visuals already");
+ return NULL;
+ }
+
+ /* create a new visual */
+ i = render_spu.numVisuals;
+ if (renderspuInitVisual(&(render_spu.visuals[i]), displayName, visAttribs)) {
+ render_spu.numVisuals++;
+ return &(render_spu.visuals[i]);
+ }
+ else {
+ crWarning("Render SPU: Couldn't get a visual, renderspu_SystemInitVisual failed");
+ return NULL;
+ }
+}
+
+static ContextInfo * renderspuCreateContextInternal(const char *dpyName, GLint visBits, GLint idCtx, ContextInfo * sharedContext)
+{
+ ContextInfo *context;
+ VisualInfo *visual;
+
+ if (idCtx <= 0)
+ {
+ idCtx = (GLint)crHashtableAllocKeys(render_spu.contextTable, 1);
+ if (idCtx <= 0)
+ {
+ crWarning("failed to allocate context id");
+ return NULL;
+ }
+ }
+ else
+ {
+ if (crHashtableIsKeyUsed(render_spu.contextTable, idCtx))
+ {
+ crWarning("the specified ctx key %d is in use", idCtx);
+ return NULL;
+ }
+ }
+
+
+ if (!dpyName || crStrlen(render_spu.display_string)>0)
+ dpyName = render_spu.display_string;
+
+ visual = renderspuFindVisual(dpyName, visBits);
+ if (!visual)
+ return NULL;
+
+ context = (ContextInfo *) crCalloc(sizeof(ContextInfo));
+ if (!context)
+ return NULL;
+ context->BltInfo.Base.id = idCtx;
+ context->shared = sharedContext;
+ if (!renderspu_SystemCreateContext(visual, context, sharedContext))
+ return NULL;
+
+ crHashtableAdd(render_spu.contextTable, idCtx, context);
+
+ context->BltInfo.Base.visualBits = visual->visAttribs;
+ /*
+ crDebug("Render SPU: CreateContext(%s, 0x%x) returning %d",
+ dpyName, visBits, context->BltInfo.Base.id);
+ */
+
+ if (sharedContext)
+ renderspuContextRetain(sharedContext);
+
+ context->cRefs = 1;
+
+ return context;
+}
+
+GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx)
+{
+ ContextInfo *context, *sharedContext = NULL;
+
+ if (shareCtx) {
+ sharedContext
+ = (ContextInfo *) crHashtableSearch(render_spu.contextTable, shareCtx);
+ CRASSERT(sharedContext);
+ }
+
+ context = renderspuCreateContextInternal(dpyName, visBits, id, sharedContext);
+ if (context)
+ return context->BltInfo.Base.id;
+ return -1;
+}
+
+/*
+ * Context functions
+ */
+
+GLint RENDER_APIENTRY
+renderspuCreateContext(const char *dpyName, GLint visBits, GLint shareCtx)
+{
+ return renderspuCreateContextEx(dpyName, visBits, 0, shareCtx);
+}
+
+static void renderspuDestroyContextTerminate( ContextInfo *context )
+{
+ CRASSERT(context->BltInfo.Base.id == -1);
+ renderspu_SystemDestroyContext( context );
+ if (context->extensionString) {
+ crFree(context->extensionString);
+ context->extensionString = NULL;
+ }
+
+ if (context->shared)
+ renderspuContextRelease( context->shared );
+
+ crFree(context);
+}
+
+uint32_t renderspuContextRetain( ContextInfo *context )
+{
+ Assert(context->cRefs);
+ return ASMAtomicIncU32(&context->cRefs);
+}
+
+uint32_t renderspuContextRelease( ContextInfo *context )
+{
+ uint32_t cRefs = ASMAtomicDecU32(&context->cRefs);
+ if (!cRefs)
+ renderspuDestroyContextTerminate( context );
+ else
+ CRASSERT(cRefs < UINT32_MAX/2);
+ return cRefs;
+}
+
+uint32_t renderspuContextMarkDeletedAndRelease( ContextInfo *context )
+{
+ /* invalidate the context id to mark it as deleted */
+ context->BltInfo.Base.id = -1;
+
+ /* some drivers do not like when the base (shared) context is deleted before its referals,
+ * this is why we keep a context refference counting the base (shared) context will be destroyed as soon as*/
+ return renderspuContextRelease( context );
+}
+
+ContextInfo * renderspuDefaultSharedContextAcquire()
+{
+ ContextInfo * pCtx = render_spu.defaultSharedContext;
+ if (!pCtx)
+ return NULL;
+
+ renderspuContextRetain(pCtx);
+ return pCtx;
+}
+
+void renderspuDefaultSharedContextRelease(ContextInfo * pCtx)
+{
+ renderspuContextRelease(pCtx);
+}
+
+
+static void RENDER_APIENTRY
+renderspuDestroyContext( GLint ctx )
+{
+ ContextInfo *context, *curCtx;
+
+ CRASSERT(ctx);
+
+ if (ctx == CR_RENDER_DEFAULT_CONTEXT_ID)
+ {
+ crWarning("request to destroy a default context, ignoring");
+ return;
+ }
+
+ context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx);
+
+ if (!context)
+ {
+ crWarning("request to delete inexistent context");
+ return;
+ }
+
+ if (render_spu.defaultSharedContext == context)
+ {
+ renderspuSetDefaultSharedContext(NULL);
+ }
+
+ curCtx = GET_CONTEXT_VAL();
+// CRASSERT(curCtx);
+ if (curCtx == context)
+ {
+ renderspuMakeCurrent( CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID );
+ curCtx = GET_CONTEXT_VAL();
+ Assert(curCtx);
+ Assert(curCtx != context);
+ }
+
+ crHashtableDelete(render_spu.contextTable, ctx, NULL);
+
+ renderspuContextMarkDeletedAndRelease(context);
+}
+
+WindowInfo* renderspuWinCreate(GLint visBits, GLint id)
+{
+ WindowInfo* window = (WindowInfo *)crAlloc(sizeof (*window));
+ if (!window)
+ {
+ crWarning("crAlloc failed");
+ return NULL;
+ }
+
+ if (!renderspuWinInit(window, NULL, visBits, id))
+ {
+ crWarning("renderspuWinInit failed");
+ crFree(window);
+ return NULL;
+ }
+
+ return window;
+}
+
+void renderspuWinTermOnShutdown(WindowInfo *window)
+{
+ renderspuVBoxCompositorSet(window, NULL);
+ renderspuVBoxPresentBlitterCleanup(window);
+ window->BltInfo.Base.id = -1;
+ renderspu_SystemDestroyWindow( window );
+}
+
+static void renderspuCheckCurrentCtxWindowCB(unsigned long key, void *data1, void *data2)
+{
+ ContextInfo *pCtx = (ContextInfo *) data1;
+ WindowInfo *pWindow = data2;
+ (void) key;
+
+ if (pCtx->currentWindow==pWindow)
+ {
+ WindowInfo* pDummy = renderspuGetDummyWindow(pCtx->BltInfo.Base.visualBits);
+ if (pDummy)
+ {
+ renderspuPerformMakeCurrent(pDummy, 0, pCtx);
+ }
+ else
+ {
+ crWarning("failed to get dummy window");
+ renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, pCtx->BltInfo.Base.id);
+ }
+ }
+}
+
+void renderspuWinTerm( WindowInfo *window )
+{
+ if (!renderspuWinIsTermed(window))
+ {
+
+ GET_CONTEXT(pOldCtx);
+ WindowInfo * pOldWindow = pOldCtx ? pOldCtx->currentWindow : NULL;
+ CRASSERT(!pOldCtx == !pOldWindow);
+ /* ensure no concurrent draws can take place */
+ renderspuWinTermOnShutdown(window);
+ /* check if this window is bound to some ctx. Note: window pointer is already freed here */
+ crHashtableWalk(render_spu.contextTable, renderspuCheckCurrentCtxWindowCB, window);
+ /* restore current context */
+ {
+ GET_CONTEXT(pNewCtx);
+ WindowInfo * pNewWindow = pNewCtx ? pNewCtx->currentWindow : NULL;
+ CRASSERT(!pNewCtx == !pNewWindow);
+
+ if (pOldWindow == window)
+ renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+ else if (pNewCtx != pOldCtx || pOldWindow != pNewWindow)
+ {
+ if (pOldCtx)
+ renderspuPerformMakeCurrent(pOldWindow, 0, pOldCtx);
+ else
+ renderspuMakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID);
+ }
+ }
+
+ }
+}
+
+void renderspuWinCleanup(WindowInfo *window)
+{
+ renderspuWinTerm( window );
+ RTCritSectDelete(&window->CompositorLock);
+}
+
+void renderspuWinDestroy(WindowInfo *window)
+{
+ renderspuWinCleanup(window);
+ crFree(window);
+}
+
+WindowInfo* renderspuGetDummyWindow(GLint visBits)
+{
+ WindowInfo *window = (WindowInfo *) crHashtableSearch(render_spu.dummyWindowTable, visBits);
+ if (!window)
+ {
+ window = renderspuWinCreate(visBits, -1);
+ if (!window)
+ {
+ WARN(("renderspuWinCreate failed"));
+ return NULL;
+ }
+
+ crHashtableAdd(render_spu.dummyWindowTable, visBits, window);
+ }
+
+ return window;
+}
+
+/* Check that OpenGL extensions listed in pszRequiredExts string also exist in the pszAvailableExts string. */
+static void renderCompareGLExtensions(const char *pszAvailableExts, const char *pszRequiredExts)
+{
+ unsigned char fPrintHeader = 1;
+ const char *pszExt = pszRequiredExts;
+
+ for (;;)
+ {
+ const char *pszSrc = pszAvailableExts;
+ size_t offExtEnd;
+
+ while (*pszExt == ' ')
+ ++pszExt;
+
+ if (!*pszExt)
+ break;
+
+ offExtEnd = RTStrOffCharOrTerm(pszExt, ' ');
+
+ for (;;)
+ {
+ size_t offSrcEnd;
+
+ while (*pszSrc == ' ')
+ ++pszSrc;
+
+ if (!*pszSrc)
+ break;
+
+ offSrcEnd = RTStrOffCharOrTerm(pszSrc, ' ');
+
+ if ( offSrcEnd == offExtEnd
+ && memcmp(pszSrc, pszExt, offSrcEnd) == 0)
+ break;
+
+ pszSrc += offSrcEnd;
+ }
+
+ if (!*pszSrc)
+ {
+ if (fPrintHeader)
+ {
+ fPrintHeader = 0;
+ crInfo("Host does not support OpenGL extension(s):");
+ }
+ crInfo(" %.*s", offExtEnd, pszExt);
+ }
+
+ pszExt += offExtEnd;
+ }
+}
+
+void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context)
+{
+ if (window && context)
+ {
+#ifdef CHROMIUM_THREADSAFE
+ crSetTSD(&_RenderTSD, context);
+#else
+ render_spu.currentContext = context;
+#endif
+ context->currentWindow = window;
+
+ renderspu_SystemMakeCurrent( window, nativeWindow, context );
+ if (!context->everCurrent) {
+ static volatile uint32_t u32ExtCompared = 0;
+ /* print OpenGL info */
+ const char *extString = (const char *) render_spu.ws.glGetString( GL_EXTENSIONS );
+ /*
+ crDebug( "Render SPU: GL_EXTENSIONS: %s", render_spu.ws.glGetString( GL_EXTENSIONS ) );
+ */
+ crInfo( "Render SPU: GL_VENDOR: %s", render_spu.ws.glGetString( GL_VENDOR ) );
+ crInfo( "Render SPU: GL_RENDERER: %s", render_spu.ws.glGetString( GL_RENDERER ) );
+ crInfo( "Render SPU: GL_VERSION: %s", render_spu.ws.glGetString( GL_VERSION ) );
+ crInfo( "Render SPU: GL_EXTENSIONS: %s", render_spu.ws.glGetString( GL_EXTENSIONS ) );
+
+ if (ASMAtomicCmpXchgU32(&u32ExtCompared, 1, 0))
+ renderCompareGLExtensions(extString, crExtensions);
+
+ if (crStrstr(extString, "GL_ARB_window_pos"))
+ context->haveWindowPosARB = GL_TRUE;
+ else
+ context->haveWindowPosARB = GL_FALSE;
+ context->everCurrent = GL_TRUE;
+ }
+ if (window->BltInfo.Base.id == CR_RENDER_DEFAULT_WINDOW_ID && window->mapPending &&
+ !render_spu.render_to_app_window && !render_spu.render_to_crut_window) {
+ /* Window[CR_RENDER_DEFAULT_CONTEXT_ID] is special, it's the default window and normally hidden.
+ * If the mapPending flag is set, then we should now make the window
+ * visible.
+ */
+ /*renderspu_SystemShowWindow( window, GL_TRUE );*/
+ window->mapPending = GL_FALSE;
+ }
+ window->everCurrent = GL_TRUE;
+ }
+ else if (!window && !context)
+ {
+ renderspu_SystemMakeCurrent( NULL, 0, NULL );
+#ifdef CHROMIUM_THREADSAFE
+ crSetTSD(&_RenderTSD, NULL);
+#else
+ render_spu.currentContext = NULL;
+#endif
+ }
+ else
+ {
+ crError("renderspuMakeCurrent invalid ids: crWindow(%d), ctx(%d)",
+ window ? window->BltInfo.Base.id : 0,
+ context ? context->BltInfo.Base.id : 0);
+ }
+}
+
+void RENDER_APIENTRY
+renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx)
+{
+ WindowInfo *window = NULL;
+ ContextInfo *context = NULL;
+
+ /*
+ crDebug("%s win=%d native=0x%x ctx=%d", __FUNCTION__, crWindow, (int) nativeWindow, ctx);
+ */
+
+ if (crWindow)
+ {
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, crWindow);
+ if (!window)
+ {
+ crWarning("invalid window %d specified", crWindow);
+ return;
+ }
+ }
+
+ if (ctx)
+ {
+ context = (ContextInfo *) crHashtableSearch(render_spu.contextTable, ctx);
+ if (!context)
+ {
+ crWarning("invalid context %d specified", ctx);
+ return;
+ }
+ }
+
+ if (!context != !window)
+ {
+ crWarning("either window %d or context %d are zero", crWindow, ctx);
+ return;
+ }
+
+ renderspuPerformMakeCurrent(window, nativeWindow, context);
+}
+
+GLboolean renderspuWinInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id )
+{
+ crMemset(window, 0, sizeof (*window));
+ RTCritSectInit(&window->CompositorLock);
+ window->pCompositor = NULL;
+
+ window->BltInfo.Base.id = id;
+
+ window->x = render_spu.defaultX;
+ window->y = render_spu.defaultY;
+ window->BltInfo.width = render_spu.defaultWidth;
+ window->BltInfo.height = render_spu.defaultHeight;
+
+ /* Set window->title, replacing %i with the window ID number */
+ {
+ const char *s = crStrstr(render_spu.window_title, "%i");
+ if (s) {
+ int i, j, k;
+ window->title = crAlloc(crStrlen(render_spu.window_title) + 10);
+ for (i = 0; render_spu.window_title[i] != '%'; i++)
+ window->title[i] = render_spu.window_title[i];
+ k = sprintf(window->title + i, "%d", window->BltInfo.Base.id);
+ CRASSERT(k < 10);
+ i++; /* skip the 'i' after the '%' */
+ j = i + k;
+ for (; (window->title[j] = s[i]) != 0; i++, j++)
+ ;
+ }
+ else {
+ window->title = crStrdup(render_spu.window_title);
+ }
+ }
+
+ window->BltInfo.Base.visualBits = visual->visAttribs;
+
+ window->cRefs = 1;
+
+ /*
+ crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->BltInfo.Base.id);
+ */
+ /* Have GLX/WGL/AGL create the window */
+ if (!renderspu_SystemVBoxCreateWindow( visual, showIt, window ))
+ {
+ crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" );
+ return GL_FALSE;
+ }
+
+ window->visible = !!showIt;
+
+ CRASSERT(window->visual == visual);
+ return GL_TRUE;
+}
+
+/*
+ * Window functions
+ */
+GLboolean renderspuWinInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id)
+{
+ VisualInfo *visual;
+
+ crMemset(pWindow, 0, sizeof (*pWindow));
+
+ if (!dpyName || crStrlen(render_spu.display_string) > 0)
+ dpyName = render_spu.display_string;
+
+ visual = renderspuFindVisual( dpyName, visBits );
+ if (!visual)
+ {
+ crWarning( "Render SPU: Couldn't create a window, renderspuFindVisual returned NULL" );
+ return GL_FALSE;
+ }
+
+ /*
+ crDebug("Render SPU: Creating window (visBits=0x%x, id=%d)", visBits, window->BltInfo.Base.id);
+ */
+ /* Have GLX/WGL/AGL create the window */
+ if (!renderspuWinInitWithVisual( pWindow, visual, 0, id ))
+ {
+ crWarning( "Render SPU: Couldn't create a window, renderspu_SystemCreateWindow failed" );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+GLint renderspuWindowCreateEx( const char *dpyName, GLint visBits, GLint id )
+{
+ WindowInfo *window;
+
+ if (id <= 0)
+ {
+ id = (GLint)crHashtableAllocKeys(render_spu.windowTable, 1);
+ if (id <= 0)
+ {
+ crWarning("failed to allocate window id");
+ return -1;
+ }
+ }
+ else
+ {
+ if (crHashtableIsKeyUsed(render_spu.windowTable, id))
+ {
+ crWarning("the specified window key %d is in use", id);
+ return -1;
+ }
+ }
+
+ /* Allocate WindowInfo */
+ window = renderspuWinCreate(visBits, id);
+
+ if (!window)
+ {
+ crWarning("renderspuWinCreate failed");
+ crFree(window);
+ return -1;
+ }
+
+ crHashtableAdd(render_spu.windowTable, id, window);
+ return window->BltInfo.Base.id;
+}
+
+GLint RENDER_APIENTRY
+renderspuWindowCreate( const char *dpyName, GLint visBits )
+{
+ return renderspuWindowCreateEx( dpyName, visBits, 0 );
+}
+
+void renderspuWinReleaseCb(void*pvWindow)
+{
+ renderspuWinRelease((WindowInfo*)pvWindow);
+}
+
+void
+RENDER_APIENTRY renderspuWindowDestroy( GLint win )
+{
+ WindowInfo *window;
+
+ CRASSERT(win >= 0);
+ if (win == CR_RENDER_DEFAULT_WINDOW_ID)
+ {
+ crWarning("request to destroy a default mural, ignoring");
+ return;
+ }
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ crDebug("Render SPU: Destroy window (%d)", win);
+ /* since os-specific backend can hold its own reference to the window object (e.g. on OSX),
+ * we need to explicitly issue a window destroy command
+ * this ensures the backend will eventually release the reference,
+ * the window object itself will remain valid until its ref count reaches zero */
+ renderspuWinTerm( window );
+
+ /* remove window info from hash table, and free it */
+ crHashtableDelete(render_spu.windowTable, win, renderspuWinReleaseCb);
+
+ }
+ else {
+ crDebug("Render SPU: Attempt to destroy invalid window (%d)", win);
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuWindowSize( GLint win, GLint w, GLint h )
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ if (w != window->BltInfo.width
+ || h != window->BltInfo.height)
+ {
+ /* window is resized, compositor data is no longer valid
+ * this set also ensures all redraw operations are done in the redraw thread
+ * and that no redraw is started until new Present request comes containing a valid presentation data */
+ renderspuVBoxCompositorSet( window, NULL);
+ renderspu_SystemWindowSize( window, w, h );
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ }
+ }
+ else {
+ WARN(("Render SPU: Attempt to resize invalid window (%d)", win));
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuWindowPosition( GLint win, GLint x, GLint y )
+{
+ if (!render_spu.ignore_window_moves) {
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ renderspu_SystemWindowPosition( window, x, y );
+ window->x = x;
+ window->y = y;
+ }
+ else {
+ crDebug("Render SPU: Attempt to move invalid window (%d)", win);
+ }
+ }
+}
+
+#ifdef DEBUG_misha
+# define CR_DBG_DUMP_VISIBLE_REGIONS
+#endif
+
+#ifdef CR_DBG_DUMP_VISIBLE_REGIONS
+static void renderspuDbgDumpVisibleRegion(GLint win, GLint cRects, const GLint *pRects)
+{
+ GLint i;
+ const RTRECT *pRtRects = (const RTRECT *)((const void*)pRects);
+
+ crInfo("Window %d, Vidible Regions%d", win, cRects);
+ for (i = 0; i < cRects; ++i)
+ {
+ crInfo("%d: (%d,%d), (%d,%d)", i, pRtRects[i].xLeft, pRtRects[i].yTop, pRtRects[i].xRight, pRtRects[i].yBottom);
+ }
+ crInfo("======");
+}
+#endif
+
+static void RENDER_APIENTRY
+renderspuWindowVisibleRegion(GLint win, GLint cRects, const GLint *pRects)
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+
+#ifdef CR_DBG_DUMP_VISIBLE_REGIONS
+ renderspuDbgDumpVisibleRegion(win, cRects, pRects);
+#endif
+
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ renderspu_SystemWindowVisibleRegion( window, cRects, pRects );
+ }
+ else {
+ crWarning("Render SPU: Attempt to set VisibleRegion for invalid window (%d)", win);
+ }
+}
+
+static void RENDER_APIENTRY
+renderspuWindowShow( GLint win, GLint flag )
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ GLboolean visible;
+ if (window->nativeWindow) {
+ /* We're rendering back to the native app window instead of the
+ * new window which we (the Render SPU) created earlier.
+ * So, we never want to show the Render SPU's window.
+ */
+ flag = 0;
+ }
+
+ visible = !!flag;
+
+// if (window->visible != visible)
+ {
+ renderspu_SystemShowWindow( window, visible );
+ window->visible = visible;
+ }
+ }
+ else {
+ crDebug("Render SPU: Attempt to hide/show invalid window (%d)", win);
+ }
+}
+
+static void RENDER_APIENTRY
+renderspuVBoxPresentComposition( GLint win, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ WindowInfo *window;
+ CRASSERT(win >= 0);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, win);
+ if (window) {
+ if (renderspuVBoxCompositorSet(window, pCompositor))
+ {
+ renderspu_SystemVBoxPresentComposition(window, pChangedEntry);
+ }
+ }
+ else {
+ crDebug("Render SPU: Attempt to PresentComposition for invalid window (%d)", win);
+ }
+}
+
+void renderspuVBoxCompositorBlitStretched ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter, GLfloat scaleX, GLfloat scaleY)
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ const RTRECT *paSrcRegions, *paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = 0; i < cRegions; ++i)
+ {
+ RTRECT DstRect;
+ const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ DstRect.xLeft = paDstRegions[i].xLeft * scaleX;
+ DstRect.yTop = paDstRegions[i].yTop * scaleY;
+ DstRect.xRight = paDstRegions[i].xRight * scaleX;
+ DstRect.yBottom = paDstRegions[i].yBottom * scaleY;
+ CrBltBlitTexMural(pBlitter, true, CrTdTexGet(pTexData), &paSrcRegions[i], &DstRect, 1, fFlags);
+ }
+ }
+ else
+ {
+ crWarning("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d", rc);
+ }
+ }
+}
+
+void renderspuVBoxCompositorBlit ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter)
+{
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ const RTRECT *paSrcRegions, *paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ const CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+ CrBltBlitTexMural(pBlitter, true, CrTdTexGet(pTexData), paSrcRegions, paDstRegions, cRegions, fFlags);
+ }
+ else
+ {
+ crWarning("Blit: CrVrScrCompositorEntryRegionsGet failed rc %d", rc);
+ }
+ }
+}
+
+void renderspuVBoxPresentBlitterCleanup( WindowInfo *window )
+{
+ if (!window->pBlitter)
+ return;
+
+ if (render_spu.blitterTable)
+ {
+ const CR_BLITTER_WINDOW * pBltInfo = CrBltMuralGetCurrentInfo(window->pBlitter);
+ if (pBltInfo && pBltInfo->Base.id == window->BltInfo.Base.id)
+ {
+ CrBltMuralSetCurrentInfo(window->pBlitter, NULL);
+ }
+ }
+ else
+ {
+ CRASSERT(CrBltMuralGetCurrentInfo(window->pBlitter)->Base.id == window->BltInfo.Base.id);
+ CrBltMuralSetCurrentInfo(window->pBlitter, NULL);
+ CrBltTerm(window->pBlitter);
+ }
+ window->pBlitter = NULL;
+}
+
+PCR_BLITTER renderspuVBoxPresentBlitterGet( WindowInfo *window )
+{
+ PCR_BLITTER pBlitter = window->pBlitter;
+ if (!pBlitter)
+ {
+ if (render_spu.blitterTable)
+ {
+ crHashtableLock(render_spu.blitterTable);
+ pBlitter = (PCR_BLITTER)crHashtableSearch(render_spu.blitterTable, window->visual->visAttribs);
+ }
+
+ if (!pBlitter)
+ {
+ int rc;
+ ContextInfo * pDefaultCtxInfo;
+
+ pBlitter = (PCR_BLITTER)crCalloc(sizeof (*pBlitter));
+ if (!pBlitter)
+ {
+ crWarning("failed to allocate blitter");
+ return NULL;
+ }
+
+ pDefaultCtxInfo = renderspuDefaultSharedContextAcquire();
+ if (!pDefaultCtxInfo)
+ {
+ crWarning("no default ctx info!");
+ crFree(pBlitter);
+ return NULL;
+ }
+
+ rc = CrBltInit(pBlitter, &pDefaultCtxInfo->BltInfo, true, true, NULL, &render_spu.blitterDispatch);
+
+ /* we can release it either way, since it will be retained when used as a shared context */
+ renderspuDefaultSharedContextRelease(pDefaultCtxInfo);
+
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrBltInit failed, rc %d", rc);
+ crFree(pBlitter);
+ return NULL;
+ }
+
+ if (render_spu.blitterTable)
+ {
+ crHashtableAdd( render_spu.blitterTable, window->visual->visAttribs, pBlitter );
+ }
+ }
+
+ if (render_spu.blitterTable)
+ crHashtableUnlock(render_spu.blitterTable);
+
+ Assert(pBlitter);
+ window->pBlitter = pBlitter;
+ }
+
+ CrBltMuralSetCurrentInfo(pBlitter, &window->BltInfo);
+ return pBlitter;
+}
+
+int renderspuVBoxPresentBlitterEnter( PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData)
+{
+ int rc;
+
+ CrBltSetMakeCurrentUserData(pBlitter, i32MakeCurrentUserData);
+
+ rc = CrBltEnter(pBlitter);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("CrBltEnter failed, rc %d", rc);
+ return rc;
+ }
+ return VINF_SUCCESS;
+}
+
+PCR_BLITTER renderspuVBoxPresentBlitterGetAndEnter( WindowInfo *window, int32_t i32MakeCurrentUserData, bool fRedraw )
+{
+ PCR_BLITTER pBlitter = fRedraw ? window->pBlitter : renderspuVBoxPresentBlitterGet(window);
+ if (pBlitter)
+ {
+ int rc = renderspuVBoxPresentBlitterEnter(pBlitter, i32MakeCurrentUserData);
+ if (RT_SUCCESS(rc))
+ {
+ return pBlitter;
+ }
+ }
+ return NULL;
+}
+
+PCR_BLITTER renderspuVBoxPresentBlitterEnsureCreated( WindowInfo *window, int32_t i32MakeCurrentUserData )
+{
+ if (!window->pBlitter)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR * pTmpCompositor;
+ /* just use compositor lock to synchronize */
+ pTmpCompositor = renderspuVBoxCompositorAcquire(window);
+ CRASSERT(pTmpCompositor);
+ if (pTmpCompositor)
+ {
+ PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGet( window );
+ if (pBlitter)
+ {
+ if (!CrBltIsEverEntered(pBlitter))
+ {
+ int rc = renderspuVBoxPresentBlitterEnter(pBlitter, i32MakeCurrentUserData);
+ if (RT_SUCCESS(rc))
+ {
+ CrBltLeave(pBlitter);
+ }
+ else
+ {
+ crWarning("renderspuVBoxPresentBlitterEnter failed rc %d", rc);
+ }
+ }
+ }
+ else
+ {
+ crWarning("renderspuVBoxPresentBlitterGet failed");
+ }
+
+ renderspuVBoxCompositorRelease(window);
+ }
+ else
+ {
+ crWarning("renderspuVBoxCompositorAcquire failed");
+ }
+ }
+ return window->pBlitter;
+}
+
+void renderspuVBoxPresentCompositionGeneric( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor,
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry, int32_t i32MakeCurrentUserData,
+ bool fRedraw )
+{
+ PCR_BLITTER pBlitter = renderspuVBoxPresentBlitterGetAndEnter(window, i32MakeCurrentUserData, fRedraw);
+ if (!pBlitter)
+ return;
+
+ renderspuVBoxCompositorBlit(pCompositor, pBlitter);
+
+ renderspu_SystemSwapBuffers(window, 0);
+
+ CrBltLeave(pBlitter);
+}
+
+GLboolean renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor)
+{
+ int rc;
+ GLboolean fEmpty = pCompositor && CrVrScrCompositorIsEmpty(pCompositor);
+ GLboolean fNeedPresent;
+
+ /* renderspuVBoxCompositorSet can be invoked from the chromium thread only and is not reentrant,
+ * no need to synch here
+ * the lock is actually needed to ensure we're in synch with the redraw thread */
+ if (window->pCompositor == pCompositor && !fEmpty)
+ return !!pCompositor;
+
+ rc = RTCritSectEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ if (!fEmpty)
+ fNeedPresent = !!pCompositor;
+ else
+ {
+ fNeedPresent = renderspu_SystemWindowNeedEmptyPresent(window);
+ pCompositor = NULL;
+ }
+
+ window->pCompositor = !fEmpty ? pCompositor : NULL;
+ RTCritSectLeave(&window->CompositorLock);
+ return fNeedPresent;
+ }
+ else
+ {
+ WARN(("RTCritSectEnter failed rc %d", rc));
+ }
+
+ return GL_FALSE;
+}
+
+static void renderspuVBoxCompositorClearAllCB(unsigned long key, void *data1, void *data2)
+{
+ WindowInfo *window = (WindowInfo *) data1;
+ renderspuVBoxCompositorSet(window, NULL);
+}
+
+void renderspuVBoxCompositorClearAll()
+{
+ /* we need to clear window compositor, which is not that trivial though,
+ * since the lock order used in presentation thread is compositor lock() -> hash table lock (aquired for id->window resolution)
+ * this is why, to prevent potential deadlocks, we use crHashtableWalkUnlocked that does not hold the table lock
+ * we are can be sure noone will modify the table here since renderspuVBoxCompositorClearAll can be called in the command (hgcm) thread only,
+ * and the table can be modified from that thread only as well */
+ crHashtableWalkUnlocked(render_spu.windowTable, renderspuVBoxCompositorClearAllCB, NULL);
+}
+
+const struct VBOXVR_SCR_COMPOSITOR * renderspuVBoxCompositorAcquire( WindowInfo *window)
+{
+ int rc = RTCritSectEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ const VBOXVR_SCR_COMPOSITOR * pCompositor = window->pCompositor;
+ if (pCompositor)
+ {
+ Assert(!CrVrScrCompositorIsEmpty(window->pCompositor));
+ return pCompositor;
+ }
+
+ /* if no compositor is set, release the lock and return */
+ RTCritSectLeave(&window->CompositorLock);
+ }
+ else
+ {
+ crWarning("RTCritSectEnter failed rc %d", rc);
+ }
+ return NULL;
+}
+
+int renderspuVBoxCompositorLock(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor)
+{
+ int rc = RTCritSectEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ if (ppCompositor)
+ *ppCompositor = window->pCompositor;
+ }
+ else
+ WARN(("RTCritSectEnter failed %d", rc));
+ return rc;
+}
+
+int renderspuVBoxCompositorUnlock(WindowInfo *window)
+{
+ int rc = RTCritSectLeave(&window->CompositorLock);
+ AssertRC(rc);
+ return rc;
+}
+
+int renderspuVBoxCompositorTryAcquire(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor)
+{
+ int rc = RTCritSectTryEnter(&window->CompositorLock);
+ if (RT_SUCCESS(rc))
+ {
+ *ppCompositor = window->pCompositor;
+ if (*ppCompositor)
+ {
+ Assert(!CrVrScrCompositorIsEmpty(window->pCompositor));
+ return VINF_SUCCESS;
+ }
+
+ /* if no compositor is set, release the lock and return */
+ RTCritSectLeave(&window->CompositorLock);
+ rc = VERR_INVALID_STATE;
+ }
+ else
+ {
+ *ppCompositor = NULL;
+ }
+ return rc;
+}
+
+void renderspuVBoxCompositorRelease( WindowInfo *window)
+{
+ int rc;
+ Assert(window->pCompositor);
+ Assert(!CrVrScrCompositorIsEmpty(window->pCompositor));
+ rc = RTCritSectLeave(&window->CompositorLock);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTCritSectLeave failed rc %d", rc);
+ }
+}
+
+
+/*
+ * Set the current raster position to the given window coordinate.
+ */
+static void
+SetRasterPos( GLint winX, GLint winY )
+{
+ GLfloat fx, fy;
+
+ /* Push current matrix mode and viewport attributes */
+ render_spu.self.PushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT );
+
+ /* Setup projection parameters */
+ render_spu.self.MatrixMode( GL_PROJECTION );
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+ render_spu.self.MatrixMode( GL_MODELVIEW );
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+
+ render_spu.self.Viewport( winX - 1, winY - 1, 2, 2 );
+
+ /* set the raster (window) position */
+ /* huh ? */
+ fx = (GLfloat) (winX - (int) winX);
+ fy = (GLfloat) (winY - (int) winY);
+ render_spu.self.RasterPos4f( fx, fy, 0.0, 1.0 );
+
+ /* restore matrices, viewport and matrix mode */
+ render_spu.self.PopMatrix();
+ render_spu.self.MatrixMode( GL_PROJECTION );
+ render_spu.self.PopMatrix();
+
+ render_spu.self.PopAttrib();
+}
+
+
+/*
+ * Draw the mouse pointer bitmap at (x,y) in window coords.
+ */
+static void DrawCursor( GLint x, GLint y )
+{
+#define POINTER_WIDTH 32
+#define POINTER_HEIGHT 32
+ /* Somebody artistic could probably do better here */
+ static const char *pointerImage[POINTER_HEIGHT] =
+ {
+ "XX..............................",
+ "XXXX............................",
+ ".XXXXX..........................",
+ ".XXXXXXX........................",
+ "..XXXXXXXX......................",
+ "..XXXXXXXXXX....................",
+ "...XXXXXXXXXXX..................",
+ "...XXXXXXXXXXXXX................",
+ "....XXXXXXXXXXXXXX..............",
+ "....XXXXXXXXXXXXXXXX............",
+ ".....XXXXXXXXXXXXXXXXX..........",
+ ".....XXXXXXXXXXXXXXXXXXX........",
+ "......XXXXXXXXXXXXXXXXXXXX......",
+ "......XXXXXXXXXXXXXXXXXXXXXX....",
+ ".......XXXXXXXXXXXXXXXXXXXXXXX..",
+ ".......XXXXXXXXXXXXXXXXXXXXXXXX.",
+ "........XXXXXXXXXXXXX...........",
+ "........XXXXXXXX.XXXXX..........",
+ ".........XXXXXX...XXXXX.........",
+ ".........XXXXX.....XXXXX........",
+ "..........XXX.......XXXXX.......",
+ "..........XX.........XXXXX......",
+ "......................XXXXX.....",
+ ".......................XXXXX....",
+ "........................XXX.....",
+ ".........................X......",
+ "................................",
+ "................................",
+ "................................",
+ "................................",
+ "................................",
+ "................................"
+
+ };
+ static GLubyte pointerBitmap[POINTER_HEIGHT][POINTER_WIDTH / 8];
+ static GLboolean firstCall = GL_TRUE;
+ GLboolean lighting, depthTest, scissorTest;
+
+ if (firstCall) {
+ /* Convert pointerImage into pointerBitmap */
+ GLint i, j;
+ for (i = 0; i < POINTER_HEIGHT; i++) {
+ for (j = 0; j < POINTER_WIDTH; j++) {
+ if (pointerImage[POINTER_HEIGHT - i - 1][j] == 'X') {
+ GLubyte bit = 128 >> (j & 0x7);
+ pointerBitmap[i][j / 8] |= bit;
+ }
+ }
+ }
+ firstCall = GL_FALSE;
+ }
+
+ render_spu.self.GetBooleanv(GL_LIGHTING, &lighting);
+ render_spu.self.GetBooleanv(GL_DEPTH_TEST, &depthTest);
+ render_spu.self.GetBooleanv(GL_SCISSOR_TEST, &scissorTest);
+ render_spu.self.Disable(GL_LIGHTING);
+ render_spu.self.Disable(GL_DEPTH_TEST);
+ render_spu.self.Disable(GL_SCISSOR_TEST);
+ render_spu.self.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ render_spu.self.Color3f(1, 1, 1);
+
+ /* save current raster pos */
+ render_spu.self.PushAttrib(GL_CURRENT_BIT);
+ SetRasterPos(x, y);
+ render_spu.self.Bitmap(POINTER_WIDTH, POINTER_HEIGHT, 1.0, 31.0, 0, 0,
+ (const GLubyte *) pointerBitmap);
+ /* restore current raster pos */
+ render_spu.self.PopAttrib();
+
+ if (lighting)
+ render_spu.self.Enable(GL_LIGHTING);
+ if (depthTest)
+ render_spu.self.Enable(GL_DEPTH_TEST);
+ if (scissorTest)
+ render_spu.self.Enable(GL_SCISSOR_TEST);
+}
+
+void RENDER_APIENTRY renderspuSwapBuffers( GLint window, GLint flags )
+{
+ WindowInfo *w = (WindowInfo *) crHashtableSearch(render_spu.windowTable, window);
+
+ if (!w)
+ {
+ crDebug("Render SPU: SwapBuffers invalid window id: %d", window);
+ return;
+ }
+
+ if (flags & CR_SUPPRESS_SWAP_BIT)
+ {
+ render_spu.self.Finish();
+ return;
+ }
+
+ if (render_spu.drawCursor)
+ DrawCursor( render_spu.cursorX, render_spu.cursorY );
+
+ if (render_spu.swap_master_url)
+ DoSync();
+
+ renderspu_SystemSwapBuffers( w, flags );
+}
+
+
+/*
+ * Barrier functions
+ * Normally, we'll have a crserver somewhere that handles the barrier calls.
+ * However, if we're running the render SPU on the client node, then we
+ * should handle barriers here. The threadtest demo illustrates this.
+ * If we have N threads calling using this SPU we need these barrier
+ * functions to synchronize them.
+ */
+
+static void RENDER_APIENTRY renderspuBarrierCreateCR( GLuint name, GLuint count )
+{
+ Barrier *b;
+
+ if (render_spu.ignore_papi)
+ return;
+
+ b = (Barrier *) crHashtableSearch( render_spu.barrierHash, name );
+ if (b) {
+ /* HACK -- this allows everybody to create a barrier, and all
+ but the first creation are ignored, assuming the count
+ match. */
+ if ( b->count != count ) {
+ crError( "Render SPU: Barrier name=%u created with count=%u, but already "
+ "exists with count=%u", name, count, b->count );
+ }
+ }
+ else {
+ b = (Barrier *) crAlloc( sizeof(Barrier) );
+ b->count = count;
+ crInitBarrier( &b->barrier, count );
+ crHashtableAdd( render_spu.barrierHash, name, b );
+ }
+}
+
+static void RENDER_APIENTRY renderspuBarrierDestroyCR( GLuint name )
+{
+ if (render_spu.ignore_papi)
+ return;
+ crHashtableDelete( render_spu.barrierHash, name, crFree );
+}
+
+static void RENDER_APIENTRY renderspuBarrierExecCR( GLuint name )
+{
+ Barrier *b;
+
+ if (render_spu.ignore_papi)
+ return;
+
+ b = (Barrier *) crHashtableSearch( render_spu.barrierHash, name );
+ if (b) {
+ crWaitBarrier( &(b->barrier) );
+ }
+ else {
+ crWarning("Render SPU: Bad barrier name %d in BarrierExec()", name);
+ }
+}
+
+
+/*
+ * Semaphore functions
+ * XXX we should probably implement these too, for the same reason as
+ * barriers (see above).
+ */
+
+static void RENDER_APIENTRY renderspuSemaphoreCreateCR( GLuint name, GLuint count )
+{
+ (void) name;
+ (void) count;
+}
+
+static void RENDER_APIENTRY renderspuSemaphoreDestroyCR( GLuint name )
+{
+ (void) name;
+}
+
+static void RENDER_APIENTRY renderspuSemaphorePCR( GLuint name )
+{
+ (void) name;
+}
+
+static void RENDER_APIENTRY renderspuSemaphoreVCR( GLuint name )
+{
+ (void) name;
+}
+
+
+/*
+ * Misc functions
+ */
+void renderspuSetDefaultSharedContext(ContextInfo *pCtx)
+{
+ if (pCtx == render_spu.defaultSharedContext)
+ return;
+
+ renderspu_SystemDefaultSharedContextChanged(render_spu.defaultSharedContext, pCtx);
+
+ if (render_spu.defaultSharedContext)
+ renderspuContextRelease(render_spu.defaultSharedContext);
+
+ if (pCtx)
+ renderspuContextRetain(pCtx);
+ render_spu.defaultSharedContext = pCtx;
+}
+
+static void RENDER_APIENTRY renderspuChromiumParameteriCR(GLenum target, GLint value)
+{
+ switch (target)
+ {
+ case GL_HH_SET_DEFAULT_SHARED_CTX:
+ {
+ ContextInfo * pCtx = NULL;
+ if (value)
+ pCtx = (ContextInfo *)crHashtableSearch(render_spu.contextTable, value);
+ else
+ crWarning("invalid default shared context id %d", value);
+
+ renderspuSetDefaultSharedContext(pCtx);
+ break;
+ }
+ case GL_HH_RENDERTHREAD_INFORM:
+ {
+ if (value)
+ {
+ int rc = renderspuDefaultCtxInit();
+ if (RT_FAILURE(rc))
+ {
+ WARN(("renderspuDefaultCtxInit failed"));
+ break;
+ }
+ }
+ else
+ {
+ renderspuCleanupBase(false);
+ }
+ break;
+ }
+ default:
+// crWarning("Unhandled target in renderspuChromiumParameteriCR()");
+ break;
+ }
+}
+
+static void RENDER_APIENTRY
+renderspuChromiumParameterfCR(GLenum target, GLfloat value)
+{
+ (void) target;
+ (void) value;
+
+#if 0
+ switch (target) {
+ default:
+ crWarning("Unhandled target in renderspuChromiumParameterfCR()");
+ break;
+ }
+#endif
+}
+
+bool renderspuCalloutAvailable()
+{
+ return render_spu.pfnClientCallout != NULL;
+}
+
+bool renderspuCalloutClient(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void *pvCb)
+{
+ if (render_spu.pfnClientCallout)
+ {
+ render_spu.pfnClientCallout(pfnCb, pvCb);
+ return true;
+ }
+ return false;
+}
+
+static void RENDER_APIENTRY
+renderspuChromiumParametervCR(GLenum target, GLenum type, GLsizei count,
+ const GLvoid *values)
+{
+ int client_num;
+ unsigned short port;
+ CRMessage *msg, pingback;
+ unsigned char *privbuf = NULL;
+
+ switch (target) {
+ case GL_HH_SET_CLIENT_CALLOUT:
+ render_spu.pfnClientCallout = (PFNVCRSERVER_CLIENT_CALLOUT)values;
+ break;
+ case GL_GATHER_CONNECT_CR:
+ if (render_spu.gather_userbuf_size)
+ privbuf = (unsigned char *)crAlloc(1024*768*4);
+
+ port = ((GLint *) values)[0];
+
+ if (render_spu.gather_conns == NULL)
+ render_spu.gather_conns = crAlloc(render_spu.server->numClients*sizeof(CRConnection *));
+ else
+ {
+ crError("Oh bother! duplicate GL_GATHER_CONNECT_CR getting through");
+ }
+
+ for (client_num=0; client_num< render_spu.server->numClients; client_num++)
+ {
+ switch (render_spu.server->clients[client_num]->conn->type)
+ {
+ case CR_TCPIP:
+ crDebug("Render SPU: AcceptClient from %s on %d",
+ render_spu.server->clients[client_num]->conn->hostname, render_spu.gather_port);
+ render_spu.gather_conns[client_num] =
+ crNetAcceptClient("tcpip", NULL, port, 1024*1024, 1);
+ break;
+
+ case CR_GM:
+ render_spu.gather_conns[client_num] =
+ crNetAcceptClient("gm", NULL, port, 1024*1024, 1);
+ break;
+
+ default:
+ crError("Render SPU: Unknown Network Type to Open Gather Connection");
+ }
+
+
+ if (render_spu.gather_userbuf_size)
+ {
+ render_spu.gather_conns[client_num]->userbuf = privbuf;
+ render_spu.gather_conns[client_num]->userbuf_len = render_spu.gather_userbuf_size;
+ }
+ else
+ {
+ render_spu.gather_conns[client_num]->userbuf = NULL;
+ render_spu.gather_conns[client_num]->userbuf_len = 0;
+ }
+
+ if (render_spu.gather_conns[client_num])
+ {
+ crDebug("Render SPU: success! from %s", render_spu.gather_conns[client_num]->hostname);
+ }
+ }
+
+ break;
+
+ case GL_GATHER_DRAWPIXELS_CR:
+ pingback.header.type = CR_MESSAGE_OOB;
+
+ for (client_num=0; client_num< render_spu.server->numClients; client_num++)
+ {
+ crNetGetMessage(render_spu.gather_conns[client_num], &msg);
+ if (msg->header.type == CR_MESSAGE_GATHER)
+ {
+ crNetFree(render_spu.gather_conns[client_num], msg);
+ }
+ else
+ {
+ crError("Render SPU: expecting MESSAGE_GATHER. got crap! (%d of %d)",
+ client_num, render_spu.server->numClients-1);
+ }
+ }
+
+ /*
+ * We're only hitting the case if we're not actually calling
+ * child.SwapBuffers from readback, so a switch about which
+ * call to DoSync() we really want [this one, or the one
+ * in SwapBuffers above] is not necessary -- karl
+ */
+
+ if (render_spu.swap_master_url)
+ DoSync();
+
+ for (client_num=0; client_num< render_spu.server->numClients; client_num++)
+ crNetSend(render_spu.gather_conns[client_num], NULL, &pingback,
+ sizeof(CRMessageHeader));
+
+ render_spu.self.RasterPos2i(((GLint *)values)[0], ((GLint *)values)[1]);
+ render_spu.self.DrawPixels( ((GLint *)values)[2], ((GLint *)values)[3],
+ ((GLint *)values)[4], ((GLint *)values)[5],
+ render_spu.gather_conns[0]->userbuf);
+
+
+ render_spu.self.SwapBuffers(((GLint *)values)[6], 0);
+ break;
+
+ case GL_CURSOR_POSITION_CR:
+ if (type == GL_INT && count == 2) {
+ render_spu.cursorX = ((GLint *) values)[0];
+ render_spu.cursorY = ((GLint *) values)[1];
+ crDebug("Render SPU: GL_CURSOR_POSITION_CR (%d, %d)", render_spu.cursorX, render_spu.cursorY);
+ }
+ else {
+ crWarning("Render SPU: Bad type or count for ChromiumParametervCR(GL_CURSOR_POSITION_CR)");
+ }
+ break;
+
+ case GL_WINDOW_SIZE_CR:
+ /* XXX this is old code that should be removed.
+ * NOTE: we can only resize the default (id=CR_RENDER_DEFAULT_WINDOW_ID) window!!!
+ */
+ {
+ GLint w, h;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ w = ((GLint*)values)[0];
+ h = ((GLint*)values)[1];
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID);
+ if (window)
+ {
+ renderspu_SystemWindowSize(window, w, h);
+ }
+ }
+ break;
+
+ case GL_HH_SET_TMPCTX_MAKE_CURRENT:
+ if (type == GL_BYTE && count == sizeof (void*))
+ memcpy(&render_spu.blitterDispatch.MakeCurrent, values, count);
+ else
+ WARN(("unexpected type(%#x) - count(%d) pair", type, count));
+ break;
+
+ default:
+#if 0
+ WARN(("Unhandled target in renderspuChromiumParametervCR(0x%x)", (int) target));
+#endif
+ break;
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuGetChromiumParametervCR(GLenum target, GLuint index, GLenum type,
+ GLsizei count, GLvoid *values)
+{
+ switch (target) {
+ case GL_WINDOW_SIZE_CR:
+ {
+ GLint x, y, w, h, *size = (GLint *) values;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ size[0] = size[1] = 0; /* default */
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h);
+ size[0] = w;
+ size[1] = h;
+ }
+ }
+ break;
+ case GL_WINDOW_POSITION_CR:
+ /* return window position, as a screen coordinate */
+ {
+ GLint *pos = (GLint *) values;
+ GLint x, y, w, h;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ pos[0] = pos[1] = 0; /* default */
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h);
+ pos[0] = x;/*window->x;*/
+ pos[1] = y;/*window->y;*/
+ }
+ }
+ break;
+ case GL_MAX_WINDOW_SIZE_CR:
+ {
+ GLint *maxSize = (GLint *) values;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 2);
+ CRASSERT(values);
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ renderspu_SystemGetMaxWindowSize(window, maxSize + 0, maxSize + 1);
+ }
+ }
+ break;
+ case GL_WINDOW_VISIBILITY_CR:
+ {
+ GLint *vis = (GLint *) values;
+ WindowInfo *window;
+ CRASSERT(type == GL_INT);
+ CRASSERT(count == 1);
+ CRASSERT(values);
+ vis[0] = 0; /* default */
+ window = (WindowInfo *) crHashtableSearch(render_spu.windowTable, index);
+ if (window)
+ {
+ vis[0] = window->visible;
+ }
+ }
+ break;
+ default:
+ ; /* nothing - silence compiler */
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuBoundsInfoCR( CRrecti *bounds, GLbyte *payload, GLint len,
+ GLint num_opcodes )
+{
+ (void) bounds;
+ (void) payload;
+ (void) len;
+ (void) num_opcodes;
+ /* draw the bounding box */
+ if (render_spu.draw_bbox) {
+ GET_CONTEXT(context);
+ WindowInfo *window = context->currentWindow;
+ GLint x, y, w, h;
+
+ renderspu_SystemGetWindowGeometry(window, &x, &y, &w, &h);
+
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+ render_spu.self.MatrixMode(GL_PROJECTION);
+ render_spu.self.PushMatrix();
+ render_spu.self.LoadIdentity();
+ render_spu.self.Ortho(0, w, 0, h, -1, 1);
+ render_spu.self.Color3f(1, 1, 1);
+ render_spu.self.Begin(GL_LINE_LOOP);
+ render_spu.self.Vertex2i(bounds->x1, bounds->y1);
+ render_spu.self.Vertex2i(bounds->x2, bounds->y1);
+ render_spu.self.Vertex2i(bounds->x2, bounds->y2);
+ render_spu.self.Vertex2i(bounds->x1, bounds->y2);
+ render_spu.self.End();
+ render_spu.self.PopMatrix();
+ render_spu.self.MatrixMode(GL_MODELVIEW);
+ render_spu.self.PopMatrix();
+ }
+}
+
+
+static void RENDER_APIENTRY
+renderspuWriteback( GLint *writeback )
+{
+ (void) writeback;
+}
+
+
+static void
+remove_trailing_space(char *s)
+{
+ int k = crStrlen(s);
+ while (k > 0 && s[k-1] == ' ')
+ k--;
+ s[k] = 0;
+}
+
+static const GLubyte * RENDER_APIENTRY
+renderspuGetString(GLenum pname)
+{
+ static char tempStr[1000];
+ GET_CONTEXT(context);
+
+ if (pname == GL_EXTENSIONS)
+ {
+ const char *nativeExt;
+ char *crExt, *s1, *s2;
+
+ if (!render_spu.ws.glGetString)
+ return NULL;
+
+ nativeExt = (const char *) render_spu.ws.glGetString(GL_EXTENSIONS);
+ if (!nativeExt) {
+ /* maybe called w/out current context. */
+ return NULL;
+ }
+
+ if (!context)
+ return (const GLubyte *)nativeExt;
+
+ crExt = crStrjoin3(crExtensions, " ", crAppOnlyExtensions);
+ s1 = crStrIntersect(nativeExt, crExt);
+ remove_trailing_space(s1);
+ s2 = crStrjoin3(s1, " ", crChromiumExtensions);
+ remove_trailing_space(s2);
+ crFree(crExt);
+ crFree(s1);
+ if (context->extensionString)
+ crFree(context->extensionString);
+ context->extensionString = s2;
+ return (const GLubyte *) s2;
+ }
+ else if (pname == GL_VENDOR)
+ return (const GLubyte *) CR_VENDOR;
+ else if (pname == GL_VERSION)
+ return render_spu.ws.glGetString(GL_VERSION);
+ else if (pname == GL_RENDERER) {
+#ifdef VBOX
+ snprintf(tempStr, sizeof(tempStr), "Chromium (%s)", (char *) render_spu.ws.glGetString(GL_RENDERER));
+#else
+ sprintf(tempStr, "Chromium (%s)", (char *) render_spu.ws.glGetString(GL_RENDERER));
+#endif
+ return (const GLubyte *) tempStr;
+ }
+#ifdef CR_OPENGL_VERSION_2_0
+ else if (pname == GL_SHADING_LANGUAGE_VERSION)
+ return render_spu.ws.glGetString(GL_SHADING_LANGUAGE_VERSION);
+#endif
+#ifdef GL_CR_real_vendor_strings
+ else if (pname == GL_REAL_VENDOR)
+ return render_spu.ws.glGetString(GL_VENDOR);
+ else if (pname == GL_REAL_VERSION)
+ return render_spu.ws.glGetString(GL_VERSION);
+ else if (pname == GL_REAL_RENDERER)
+ return render_spu.ws.glGetString(GL_RENDERER);
+ else if (pname == GL_REAL_EXTENSIONS)
+ return render_spu.ws.glGetString(GL_EXTENSIONS);
+#endif
+ else
+ return NULL;
+}
+
+static void renderspuReparentWindowCB(unsigned long key, void *data1, void *data2)
+{
+ WindowInfo *pWindow = (WindowInfo *)data1;
+
+ renderspu_SystemReparentWindow(pWindow);
+}
+
+DECLEXPORT(void) renderspuReparentWindow(GLint window)
+{
+ WindowInfo *pWindow;
+ CRASSERT(window >= 0);
+
+ pWindow = (WindowInfo *) crHashtableSearch(render_spu.windowTable, window);
+
+ if (!pWindow)
+ {
+ crDebug("Render SPU: Attempt to reparent invalid window (%d)", window);
+ return;
+ }
+
+ renderspu_SystemReparentWindow(pWindow);
+
+ /* special case: reparent all internal windows as well */
+ if (window == CR_RENDER_DEFAULT_WINDOW_ID)
+ {
+ crHashtableWalk(render_spu.dummyWindowTable, renderspuReparentWindowCB, NULL);
+ }
+}
+
+DECLEXPORT(void) renderspuSetUnscaledHiDPI(bool fEnable)
+{
+ render_spu.fUnscaledHiDPI = fEnable;
+}
+
+#define FILLIN( NAME, FUNC ) \
+ table[i].name = crStrdup(NAME); \
+ table[i].fn = (SPUGenericFunction) FUNC; \
+ i++;
+
+
+/* These are the functions which the render SPU implements, not OpenGL.
+ */
+int
+renderspuCreateFunctions(SPUNamedFunctionTable table[])
+{
+ int i = 0;
+ FILLIN( "SwapBuffers", renderspuSwapBuffers );
+ FILLIN( "CreateContext", renderspuCreateContext );
+ FILLIN( "DestroyContext", renderspuDestroyContext );
+ FILLIN( "MakeCurrent", renderspuMakeCurrent );
+ FILLIN( "WindowCreate", renderspuWindowCreate );
+ FILLIN( "WindowDestroy", renderspuWindowDestroy );
+ FILLIN( "WindowSize", renderspuWindowSize );
+ FILLIN( "WindowPosition", renderspuWindowPosition );
+ FILLIN( "WindowVisibleRegion", renderspuWindowVisibleRegion );
+ FILLIN( "WindowShow", renderspuWindowShow );
+ FILLIN( "BarrierCreateCR", renderspuBarrierCreateCR );
+ FILLIN( "BarrierDestroyCR", renderspuBarrierDestroyCR );
+ FILLIN( "BarrierExecCR", renderspuBarrierExecCR );
+ FILLIN( "BoundsInfoCR", renderspuBoundsInfoCR );
+ FILLIN( "SemaphoreCreateCR", renderspuSemaphoreCreateCR );
+ FILLIN( "SemaphoreDestroyCR", renderspuSemaphoreDestroyCR );
+ FILLIN( "SemaphorePCR", renderspuSemaphorePCR );
+ FILLIN( "SemaphoreVCR", renderspuSemaphoreVCR );
+ FILLIN( "Writeback", renderspuWriteback );
+ FILLIN( "ChromiumParameteriCR", renderspuChromiumParameteriCR );
+ FILLIN( "ChromiumParameterfCR", renderspuChromiumParameterfCR );
+ FILLIN( "ChromiumParametervCR", renderspuChromiumParametervCR );
+ FILLIN( "GetChromiumParametervCR", renderspuGetChromiumParametervCR );
+ FILLIN( "GetString", renderspuGetString );
+ FILLIN( "VBoxPresentComposition", renderspuVBoxPresentComposition );
+ return i;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
new file mode 100644
index 00000000..dfd591e8
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu.h
@@ -0,0 +1,506 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved.
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#ifndef CR_RENDERSPU_H
+#define CR_RENDERSPU_H
+
+#ifdef WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <iprt/win/windows.h>
+#define RENDER_APIENTRY __stdcall
+#define snprintf _snprintf
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+# include <AGL/AGL.h>
+# else
+# include "renderspu_cocoa_helper.h"
+# endif
+#define RENDER_APIENTRY
+#else
+#include <GL/glx.h>
+#define RENDER_APIENTRY
+#endif
+#include "cr_threads.h"
+#include "cr_spu.h"
+#include "cr_hash.h"
+#include "cr_server.h"
+#include "cr_blitter.h"
+#include "cr_compositor.h"
+
+#include <iprt/cdefs.h>
+#include <iprt/critsect.h>
+#if defined(GLX) /* @todo: unify windows and glx thread creation code */
+#include <iprt/thread.h>
+#include <iprt/semaphore.h>
+
+/* special window id used for representing the command window CRWindowInfo */
+#define CR_RENDER_WINCMD_ID (INT32_MAX-2)
+AssertCompile(CR_RENDER_WINCMD_ID != CR_RENDER_DEFAULT_WINDOW_ID);
+/* CRHashTable is using unsigned long keys, we use it to trore X Window -> CRWindowInfo association */
+AssertCompile(sizeof (Window) == sizeof (unsigned long));
+#endif
+
+
+#define MAX_VISUALS 32
+
+#ifdef RT_OS_DARWIN
+# ifndef VBOX_WITH_COCOA_QT
+enum
+{
+ /* Event classes */
+ kEventClassVBox = 'vbox',
+ /* Event kinds */
+ kEventVBoxShowWindow = 'swin',
+ kEventVBoxHideWindow = 'hwin',
+ kEventVBoxMoveWindow = 'mwin',
+ kEventVBoxResizeWindow = 'rwin',
+ kEventVBoxDisposeWindow = 'dwin',
+ kEventVBoxUpdateDock = 'udck',
+ kEventVBoxUpdateContext = 'uctx',
+ kEventVBoxBoundsChanged = 'bchg'
+};
+pascal OSStatus windowEvtHndlr(EventHandlerCallRef myHandler, EventRef event, void* userData);
+# endif
+#endif /* RT_OS_DARWIN */
+
+/**
+ * Visual info
+ */
+typedef struct {
+ GLbitfield visAttribs;
+ const char *displayName;
+#if defined(WINDOWS)
+// HDC device_context;
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+ WindowRef window;
+# endif
+#elif defined(GLX)
+ Display *dpy;
+ XVisualInfo *visual;
+#ifdef GLX_VERSION_1_3
+ GLXFBConfig fbconfig;
+#endif /* GLX_VERSION_1_3 */
+#endif
+} VisualInfo;
+
+/**
+ * Window info
+ */
+typedef struct WindowInfo {
+ int x, y;
+// int width, height;
+// int id; /**< integer window ID */
+ CR_BLITTER_WINDOW BltInfo;
+
+ VisualInfo *visual;
+
+ volatile uint32_t cRefs;
+
+ GLboolean mapPending;
+ GLboolean visible;
+ GLboolean everCurrent; /**< has this window ever been bound? */
+ char *title;
+
+ const VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* the composotor lock is used to synchronize the current compositor access,
+ * i.e. the compositor can be accessed by a gui refraw thread,
+ * while chromium thread might try to set a new compositor
+ * note that the compositor internally has its own lock to be used for accessing its data
+ * see CrVrScrCompositorLock/Unlock; renderspu and crserverlib would use it for compositor data access */
+ RTCRITSECT CompositorLock;
+ PCR_BLITTER pBlitter;
+#if defined(WINDOWS)
+ HDC nativeWindow; /**< for render_to_app_window */
+ HWND hWnd;
+ HDC device_context;
+ HDC redraw_device_context;
+ HRGN hRgn;
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+ WindowRef window;
+ WindowRef nativeWindow; /**< for render_to_app_window */
+ WindowRef appWindow;
+ EventHandlerUPP event_handler;
+ GLint bufferName;
+ AGLContext dummyContext;
+ RgnHandle hVisibleRegion;
+ /* unsigned long context_ptr; */
+# else
+ NativeNSViewRef window;
+ NativeNSViewRef nativeWindow; /**< for render_to_app_window */
+ NativeNSOpenGLContextRef *currentCtx;
+# endif
+#elif defined(GLX)
+ Window window;
+ Window nativeWindow; /**< for render_to_app_window */
+ Window appWindow; /**< Same as nativeWindow but for garbage collections purposes */
+#endif
+ int nvSwapGroup;
+
+#ifdef USE_OSMESA
+ GLubyte *buffer; /**< for rendering to off screen buffer. */
+ int in_buffer_width;
+ int in_buffer_height;
+#endif
+
+} WindowInfo;
+
+/**
+ * Context Info
+ */
+typedef struct _ContextInfo {
+// int id; /**< integer context ID */
+ CR_BLITTER_CONTEXT BltInfo;
+ VisualInfo *visual;
+ GLboolean everCurrent;
+ GLboolean haveWindowPosARB;
+ WindowInfo *currentWindow;
+#if defined(WINDOWS)
+ HGLRC hRC;
+#elif defined(DARWIN)
+# ifndef VBOX_WITH_COCOA_QT
+ AGLContext context;
+# else
+ NativeNSOpenGLContextRef context;
+# endif
+#elif defined(GLX)
+ GLXContext context;
+#endif
+ struct _ContextInfo *shared;
+ char *extensionString;
+ volatile uint32_t cRefs;
+} ContextInfo;
+
+/**
+ * Barrier info
+ */
+typedef struct {
+ CRbarrier barrier;
+ GLuint count;
+} Barrier;
+
+#ifdef GLX
+typedef enum
+{
+ CR_RENDER_WINCMD_TYPE_UNDEFINED = 0,
+ /* create the window (not used for now) */
+ CR_RENDER_WINCMD_TYPE_WIN_CREATE,
+ /* destroy the window (not used for now) */
+ CR_RENDER_WINCMD_TYPE_WIN_DESTROY,
+ /* notify the WinCmd thread about window creation */
+ CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE,
+ /* notify the WinCmd thread about window destroy */
+ CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY,
+ /* nop used to synchronize with the WinCmd thread */
+ CR_RENDER_WINCMD_TYPE_NOP,
+ /* exit Win Cmd thread */
+ CR_RENDER_WINCMD_TYPE_EXIT,
+} CR_RENDER_WINCMD_TYPE;
+
+typedef struct CR_RENDER_WINCMD
+{
+ /* command type */
+ CR_RENDER_WINCMD_TYPE enmCmd;
+ /* command result */
+ int rc;
+ /* valid for WIN_CREATE & WIN_DESTROY only */
+ WindowInfo *pWindow;
+} CR_RENDER_WINCMD, *PCR_RENDER_WINCMD;
+#endif
+
+#ifdef RT_OS_DARWIN
+typedef void (*PFNDELETE_OBJECT)(GLhandleARB obj);
+typedef void (*PFNGET_ATTACHED_OBJECTS)( GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj );
+typedef GLhandleARB (*PFNGET_HANDLE)(GLenum pname);
+typedef void (*PFNGET_INFO_LOG)( GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog );
+typedef void (*PFNGET_OBJECT_PARAMETERFV)( GLhandleARB obj, GLenum pname, GLfloat * params );
+typedef void (*PFNGET_OBJECT_PARAMETERIV)( GLhandleARB obj, GLenum pname, GLint * params );
+#endif
+
+typedef DECLCALLBACKPTR(void, PFNVCRSERVER_CLIENT_CALLOUT_CB)(void *pvCb);
+typedef DECLCALLBACKPTR(void, PFNVCRSERVER_CLIENT_CALLOUT)(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void*pvCb);
+
+
+/**
+ * Renderspu state info
+ */
+typedef struct {
+ SPUDispatchTable self;
+ int id;
+
+ /** config options */
+ /*@{*/
+ char *window_title;
+ int defaultX, defaultY;
+ unsigned int defaultWidth, defaultHeight;
+ int default_visual;
+ int use_L2;
+ int fullscreen, ontop;
+ char display_string[100];
+#if defined(GLX)
+ int try_direct;
+ int force_direct;
+ int sync;
+#endif
+ int force_present_main_thread;
+ int render_to_app_window;
+ int render_to_crut_window;
+ int crut_drawable;
+ int resizable;
+ int use_lut8, lut8[3][256];
+ int borderless;
+ int nvSwapGroup;
+ int ignore_papi;
+ int ignore_window_moves;
+ int pbufferWidth, pbufferHeight;
+ int use_glxchoosevisual;
+ int draw_bbox;
+ /*@}*/
+
+ CRServer *server;
+ int gather_port;
+ int gather_userbuf_size;
+ CRConnection **gather_conns;
+
+ GLint drawCursor;
+ GLint cursorX, cursorY;
+
+ int numVisuals;
+ VisualInfo visuals[MAX_VISUALS];
+
+ CRHashTable *windowTable;
+ CRHashTable *contextTable;
+
+ CRHashTable *dummyWindowTable;
+
+ ContextInfo *defaultSharedContext;
+
+#ifndef CHROMIUM_THREADSAFE
+ ContextInfo *currentContext;
+#endif
+
+ crOpenGLInterface ws; /**< Window System interface */
+
+ CRHashTable *barrierHash;
+
+ int is_swap_master, num_swap_clients;
+ int swap_mtu;
+ char *swap_master_url;
+ CRConnection **swap_conns;
+
+ SPUDispatchTable blitterDispatch;
+ CRHashTable *blitterTable;
+
+ PFNVCRSERVER_CLIENT_CALLOUT pfnClientCallout;
+
+#ifdef USE_OSMESA
+ /** Off screen rendering hooks. */
+ int use_osmesa;
+
+ OSMesaContext (*OSMesaCreateContext)( GLenum format, OSMesaContext sharelist );
+ GLboolean (* OSMesaMakeCurrent)( OSMesaContext ctx,
+ GLubyte *buffer,
+ GLenum type,
+ GLsizei width,
+ GLsizei height );
+ void (*OSMesaDestroyContext)( OSMesaContext ctx );
+#endif
+
+#if defined(GLX)
+ RTTHREAD hWinCmdThread;
+ VisualInfo WinCmdVisual;
+ WindowInfo WinCmdWindow;
+ RTSEMEVENT hWinCmdCompleteEvent;
+ /* display connection used to send data to the WinCmd thread */
+ Display *pCommunicationDisplay;
+ Atom WinCmdAtom;
+ /* X Window -> CRWindowInfo table */
+ CRHashTable *pWinToInfoTable;
+#endif
+
+#ifdef RT_OS_WINDOWS
+ DWORD dwWinThreadId;
+ HANDLE hWinThreadReadyEvent;
+#endif
+
+#ifdef RT_OS_DARWIN
+# ifdef VBOX_WITH_COCOA_QT
+ PFNDELETE_OBJECT pfnDeleteObject;
+ PFNGET_ATTACHED_OBJECTS pfnGetAttachedObjects;
+ PFNGET_HANDLE pfnGetHandle;
+ PFNGET_INFO_LOG pfnGetInfoLog;
+ PFNGET_OBJECT_PARAMETERFV pfnGetObjectParameterfv;
+ PFNGET_OBJECT_PARAMETERIV pfnGetObjectParameteriv;
+
+ CR_GLSL_CACHE GlobalShaders;
+# else
+ RgnHandle hRootVisibleRegion;
+ RTSEMFASTMUTEX syncMutex;
+ EventHandlerUPP hParentEventHandler;
+ WindowGroupRef pParentGroup;
+ WindowGroupRef pMasterGroup;
+ GLint currentBufferName;
+ uint64_t uiDockUpdateTS;
+ bool fInit;
+# endif
+#endif /* RT_OS_DARWIN */
+ /* If TRUE, render should tell window server to prevent artificial content
+ * up-scaling when displayed on HiDPI monitor. */
+ bool fUnscaledHiDPI;
+} RenderSPU;
+
+#ifdef RT_OS_WINDOWS
+
+/* Asks window thread to create new window.
+ msg.lParam - holds pointer to CREATESTRUCT structure
+ note that lpCreateParams is used to specify address to store handle of created window
+ msg.wParam - unused, should be NULL
+*/
+#define WM_VBOX_RENDERSPU_CREATE_WINDOW (WM_APP+1)
+
+typedef struct _VBOX_RENDERSPU_DESTROY_WINDOW {
+ HWND hWnd; /* handle to window to destroy */
+} VBOX_RENDERSPU_DESTROY_WINDOW;
+
+/* Asks window thread to destroy previously created window.
+ msg.lParam - holds pointer to RENDERSPU_VBOX_WINDOW_DESTROY structure
+ msg.wParam - unused, should be NULL
+*/
+#define WM_VBOX_RENDERSPU_DESTROY_WINDOW (WM_APP+2)
+
+#endif
+
+extern RenderSPU render_spu;
+
+/* @todo remove this hack */
+extern uint64_t render_spu_parent_window_id;
+
+#ifdef CHROMIUM_THREADSAFE
+extern CRtsd _RenderTSD;
+#define GET_CONTEXT_VAL() ((ContextInfo *) crGetTSD(&_RenderTSD))
+#define SET_CONTEXT_VAL(_v) do { \
+ crSetTSD(&_RenderTSD, (_v)); \
+ } while (0)
+#else
+#define GET_CONTEXT_VAL() (render_spu.currentContext)
+#define SET_CONTEXT_VAL(_v) do { \
+ render_spu.currentContext = (_v); \
+ } while (0)
+
+#endif
+
+#define GET_CONTEXT(T) ContextInfo *T = GET_CONTEXT_VAL()
+
+
+extern void renderspuSetDefaultSharedContext(ContextInfo *pCtx);
+extern void renderspuSetVBoxConfiguration( RenderSPU *spu );
+extern void renderspuMakeVisString( GLbitfield visAttribs, char *s );
+extern VisualInfo *renderspuFindVisual(const char *displayName, GLbitfield visAttribs );
+extern GLboolean renderspu_SystemInitVisual( VisualInfo *visual );
+extern GLboolean renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext );
+extern void renderspu_SystemDestroyContext( ContextInfo *context );
+extern GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window );
+extern GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window );
+extern void renderspu_SystemDestroyWindow( WindowInfo *window );
+extern void renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h );
+extern void renderspu_SystemGetWindowGeometry( WindowInfo *window, GLint *x, GLint *y, GLint *w, GLint *h );
+extern void renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h );
+extern void renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y );
+extern void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects);
+extern GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window);
+extern int renderspu_SystemInit();
+extern int renderspu_SystemTerm();
+extern void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext);
+extern void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt );
+extern void renderspu_SystemMakeCurrent( WindowInfo *window, GLint windowInfor, ContextInfo *context );
+extern void renderspu_SystemSwapBuffers( WindowInfo *window, GLint flags );
+extern void renderspu_SystemReparentWindow(WindowInfo *window);
+extern void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry );
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable);
+extern void renderspu_GCWindow(void);
+extern int renderspuCreateFunctions( SPUNamedFunctionTable table[] );
+extern GLboolean renderspuVBoxCompositorSet( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor);
+extern void renderspuVBoxCompositorClearAll();
+extern int renderspuVBoxCompositorLock(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor);
+extern int renderspuVBoxCompositorUnlock(WindowInfo *window);
+extern const struct VBOXVR_SCR_COMPOSITOR * renderspuVBoxCompositorAcquire( WindowInfo *window);
+extern int renderspuVBoxCompositorTryAcquire(WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR **ppCompositor);
+extern void renderspuVBoxCompositorRelease( WindowInfo *window);
+extern void renderspuVBoxPresentCompositionGeneric( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor,
+ const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry, int32_t i32MakeCurrentUserData,
+ bool fRedraw);
+extern PCR_BLITTER renderspuVBoxPresentBlitterGet( WindowInfo *window );
+void renderspuVBoxPresentBlitterCleanup( WindowInfo *window );
+extern int renderspuVBoxPresentBlitterEnter( PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData );
+extern PCR_BLITTER renderspuVBoxPresentBlitterGetAndEnter( WindowInfo *window, int32_t i32MakeCurrentUserData, bool fRedraw );
+extern PCR_BLITTER renderspuVBoxPresentBlitterEnsureCreated( WindowInfo *window, int32_t i32MakeCurrentUserData );
+WindowInfo* renderspuWinCreate(GLint visBits, GLint id);
+void renderspuWinTermOnShutdown(WindowInfo *window);
+void renderspuWinTerm( WindowInfo *window );
+void renderspuWinCleanup(WindowInfo *window);
+void renderspuWinDestroy(WindowInfo *window);
+GLboolean renderspuWinInitWithVisual( WindowInfo *window, VisualInfo *visual, GLboolean showIt, GLint id );
+GLboolean renderspuWinInit(WindowInfo *pWindow, const char *dpyName, GLint visBits, GLint id);
+
+DECLINLINE(void) renderspuWinRetain(WindowInfo *window)
+{
+ ASMAtomicIncU32(&window->cRefs);
+}
+
+DECLINLINE(bool) renderspuWinIsTermed(WindowInfo *window)
+{
+ return window->BltInfo.Base.id < 0;
+}
+
+DECLINLINE(void) renderspuWinRelease(WindowInfo *window)
+{
+ uint32_t cRefs = ASMAtomicDecU32(&window->cRefs);
+ if (!cRefs)
+ {
+ renderspuWinDestroy(window);
+ }
+}
+
+extern WindowInfo* renderspuGetDummyWindow(GLint visBits);
+extern void renderspuPerformMakeCurrent(WindowInfo *window, GLint nativeWindow, ContextInfo *context);
+extern GLboolean renderspuInitVisual(VisualInfo *pVisInfo, const char *displayName, GLbitfield visAttribs);
+extern void renderspuVBoxCompositorBlit ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter);
+extern void renderspuVBoxCompositorBlitStretched ( const struct VBOXVR_SCR_COMPOSITOR * pCompositor, PCR_BLITTER pBlitter, GLfloat scaleX, GLfloat scaleY);
+extern GLint renderspuCreateContextEx(const char *dpyName, GLint visBits, GLint id, GLint shareCtx);
+extern GLint renderspuWindowCreateEx( const char *dpyName, GLint visBits, GLint id );
+
+extern GLint RENDER_APIENTRY renderspuWindowCreate( const char *dpyName, GLint visBits );
+void RENDER_APIENTRY renderspuWindowDestroy( GLint win );
+extern GLint RENDER_APIENTRY renderspuCreateContext( const char *dpyname, GLint visBits, GLint shareCtx );
+extern void RENDER_APIENTRY renderspuMakeCurrent(GLint crWindow, GLint nativeWindow, GLint ctx);
+extern void RENDER_APIENTRY renderspuSwapBuffers( GLint window, GLint flags );
+
+extern uint32_t renderspuContextMarkDeletedAndRelease( ContextInfo *context );
+
+int renderspuDefaultCtxInit();
+void renderspuCleanupBase(bool fDeleteTables);
+
+ContextInfo * renderspuDefaultSharedContextAcquire();
+void renderspuDefaultSharedContextRelease(ContextInfo * pCtx);
+uint32_t renderspuContextRelease(ContextInfo *context);
+uint32_t renderspuContextRetain(ContextInfo *context);
+
+bool renderspuCalloutAvailable();
+bool renderspuCalloutClient(PFNVCRSERVER_CLIENT_CALLOUT_CB pfnCb, void *pvCb);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+DECLEXPORT(void) renderspuSetWindowId(uint64_t winId);
+DECLEXPORT(void) renderspuReparentWindow(GLint window);
+DECLEXPORT(void) renderspuSetUnscaledHiDPI(bool fEnable);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CR_RENDERSPU_H */
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c
new file mode 100644
index 00000000..de55160e
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_agl.c
@@ -0,0 +1,907 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include <Carbon/Carbon.h>
+#include <AGL/agl.h>
+#include <OpenGL/OpenGL.h>
+
+#include <iprt/time.h>
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+
+#include <stdio.h>
+
+#include "cr_environment.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "renderspu.h"
+
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+# define renderspuSetWindowContext(w, c) \
+ AssertFailed()
+# define renderspuGetWindowContext(w) \
+ ( (ContextInfo *) GetWRefCon( ((w)->nativeWindow ? (w)->nativeWindow : (w)->window) ) )
+#else
+# define renderspuSetWindowContext(w, c) \
+ ( SetWRefCon( (w), (unsigned long) (c) ) )
+# define renderspuGetWindowContext(w) \
+ ( (ContextInfo *) GetWRefCon( ((w)->nativeWindow ? (w)->nativeWindow : (w)->window) ) )
+#endif
+
+/* Debug macros */
+#ifdef DEBUG_poetzsch
+#define DEBUG_MSG_POETZSCH(text) \
+ printf text
+#else
+#define DEBUG_MSG_POETZSCH(text) \
+ do {} while (0)
+#endif
+
+#define DEBUG_MSG_RESULT(result, text) \
+ crDebug(text" (%d; %s:%d)", (int)(result), __FILE__, __LINE__)
+
+#define CHECK_CARBON_RC(result, text) \
+ if((result) != noErr) \
+ DEBUG_MSG_RESULT(result, text);
+
+#define CHECK_CARBON_RC_RETURN(result, text, ret) \
+ if((result) != noErr) \
+ { \
+ DEBUG_MSG_RESULT(result, text); \
+ return ret; \
+ }
+
+#define CHECK_CARBON_RC_RETURN_VOID(result, text) \
+ CHECK_CARBON_RC_RETURN(result, text,)
+
+#define CHECK_AGL_RC(result, text) \
+ if(!(result)) \
+ { \
+ GLenum error = render_spu.ws.aglGetError(); \
+ DEBUG_MSG_RESULT(result, text); \
+ }
+
+static void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window);
+static void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects);
+
+/* In some case (like compiz which doesn't provide us with clipping regions) we
+ * have to make sure that *all* open OpenGL windows are clipped to the main
+ * application window. This is done here when called from the event handler
+ * which monitor bounding changes of the main window. */
+static void crClipRootHelper(unsigned long key, void *data1, void *data2)
+{
+ /* The window with id zero is the base window, which isn't displayed at
+ * all. So ignore it. */
+ if (key > 0)
+ {
+ /* Fetch the actually window info & the user data */
+ WindowInfo *pWin = (WindowInfo *) data1;
+ /* We need to assign the context with this window */
+ ContextInfo *context = renderspuGetWindowContext(pWin);
+ if (context &&
+ context->context)
+ {
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ GLboolean result = render_spu.ws.aglSetCurrentContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (crClipRootHelper): SetCurrentContext Failed");
+ if (result)
+ {
+ result = render_spu.ws.aglUpdateContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (crClipRootHelper): UpdateContext Failed");
+ /* Update the clipping region */
+ renderspu_SystemWindowApplyVisibleRegion(pWin);
+ }
+ RTSemFastMutexRelease(render_spu.syncMutex);
+ /* Make sure that the position is updated relative to the Qt main
+ * view */
+ renderspu_SystemWindowPosition(pWin, pWin->x, pWin->y);
+ }
+ }
+}
+
+/* Window event handler */
+pascal OSStatus
+windowEvtHndlr(EventHandlerCallRef myHandler, EventRef event, void* userData)
+{
+ WindowRef window = NULL;
+ OSStatus eventResult = eventNotHandledErr;
+ UInt32 class = GetEventClass (event);
+ UInt32 kind = GetEventKind (event);
+
+ /* If we aren't initialized or even deinitialized already (as on VM
+ * shutdown) do nothing. */
+ if (!render_spu.fInit)
+ return eventNotHandledErr;
+
+ /* Fetch the sender of the event */
+ GetEventParameter(event, kEventParamDirectObject, typeWindowRef,
+ NULL, sizeof(WindowRef), NULL, &window);
+ switch (class)
+ {
+ case kEventClassVBox:
+ {
+ switch (kind)
+ {
+ case kEventVBoxUpdateContext:
+ {
+#ifndef __LP64__ /** @todo port to 64-bit darwin! Need to check if this event is generated or not (it probably isn't). */
+ WindowInfo *wi1;
+ GetEventParameter(event, kEventParamUserData, typeVoidPtr,
+ NULL, sizeof(wi1), NULL, &wi1);
+ ContextInfo *context = renderspuGetWindowContext(wi1);
+ if (context &&
+ context->context)
+ {
+ AGLContext tmpContext = render_spu.ws.aglGetCurrentContext();
+ DEBUG_MSG_POETZSCH (("kEventVBoxUpdateContext %x %x\n", wi1, context->context));
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ GLboolean result = render_spu.ws.aglSetCurrentContext(context->context);
+ if (result)
+ {
+ result = render_spu.ws.aglUpdateContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): UpdateContext Failed");
+ renderspu_SystemWindowApplyVisibleRegion(wi1);
+ /* Reapply the last active context */
+ if (tmpContext)
+ {
+ result = render_spu.ws.aglSetCurrentContext(tmpContext);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): SetCurrentContext Failed");
+ if (result)
+ {
+ result = render_spu.ws.aglUpdateContext(tmpContext);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): UpdateContext Failed");
+ }
+ }
+ }
+ RTSemFastMutexRelease(render_spu.syncMutex);
+ }
+ eventResult = noErr;
+#endif
+ break;
+ }
+ case kEventVBoxBoundsChanged:
+ {
+#ifndef __LP64__ /** @todo port to 64-bit darwin! Need to check if this event is generated or not (it probably isn't). */
+ HIPoint p;
+ GetEventParameter(event, kEventParamOrigin, typeHIPoint,
+ NULL, sizeof(p), NULL, &p);
+ HISize s;
+ GetEventParameter(event, kEventParamDimensions, typeHISize,
+ NULL, sizeof(s), NULL, &s);
+ HIRect r = CGRectMake (0, 0, s.width, s.height);
+ DEBUG_MSG_POETZSCH (("kEventVBoxBoundsChanged %f %f %f %f\n", p.x, p.y, s.width, s.height));
+ GLint l[4] = { 0,
+ 0,
+ r.size.width,
+ r.size.height };
+ /* Update the root window clip region */
+ renderspu_SystemSetRootVisibleRegion(1, l);
+ /* Temporary save the current active context */
+ AGLContext tmpContext = render_spu.ws.aglGetCurrentContext();
+ crHashtableWalk(render_spu.windowTable, crClipRootHelper, NULL);
+ /* Reapply the last active context */
+ if (tmpContext)
+ {
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ GLboolean result = render_spu.ws.aglSetCurrentContext(tmpContext);
+ CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): SetCurrentContext Failed");
+ /* Doesn't work with DirectX; Anyway doesn't */
+/* if (result)*/
+/* {*/
+/* result = render_spu.ws.aglUpdateContext(tmpContext);*/
+/* CHECK_AGL_RC (result, "Render SPU (windowEvtHndlr): UpdateContext Failed");*/
+/* }*/
+ RTSemFastMutexRelease(render_spu.syncMutex);
+ }
+ eventResult = noErr;
+#endif
+ break;
+ }
+ };
+ break;
+ }
+ break;
+ };
+
+ return eventResult;
+}
+
+GLboolean
+renderspu_SystemInitVisual(VisualInfo *visual)
+{
+ if(visual->visAttribs & CR_PBUFFER_BIT)
+ crWarning("Render SPU (renderspu_SystemInitVisual): PBuffers not support on Darwin/AGL yet.");
+
+ return GL_TRUE;
+}
+
+GLboolean
+renderspuChoosePixelFormat(ContextInfo *context, AGLPixelFormat *pix)
+{
+ GLbitfield visAttribs = context->visual->visAttribs;
+ GLint attribs[32];
+ GLint ind = 0;
+
+#define ATTR_ADD(s) ( attribs[ind++] = (s) )
+#define ATTR_ADDV(s,v) ( ATTR_ADD((s)), ATTR_ADD((v)) )
+
+ CRASSERT(render_spu.ws.aglChoosePixelFormat);
+
+ ATTR_ADD(AGL_RGBA);
+/* ATTR_ADDV(AGL_RED_SIZE, 1);
+ ATTR_ADDV(AGL_GREEN_SIZE, 1);
+ ATTR_ADDV(AGL_BLUE_SIZE, 1); */
+
+/* if( render_spu.fullscreen )*/
+/* ATTR_ADD(AGL_FULLSCREEN);*/
+
+ if( visAttribs & CR_ALPHA_BIT )
+ ATTR_ADDV(AGL_ALPHA_SIZE, 1);
+
+ if( visAttribs & CR_DOUBLE_BIT )
+ ATTR_ADD(AGL_DOUBLEBUFFER);
+
+ if( visAttribs & CR_STEREO_BIT )
+ ATTR_ADD(AGL_STEREO);
+
+ if( visAttribs & CR_DEPTH_BIT )
+ ATTR_ADDV(AGL_DEPTH_SIZE, 1);
+
+ if( visAttribs & CR_STENCIL_BIT )
+ ATTR_ADDV(AGL_STENCIL_SIZE, 1);
+
+ if( visAttribs & CR_ACCUM_BIT ) {
+ ATTR_ADDV(AGL_ACCUM_RED_SIZE, 1);
+ ATTR_ADDV(AGL_ACCUM_GREEN_SIZE, 1);
+ ATTR_ADDV(AGL_ACCUM_BLUE_SIZE, 1);
+ if( visAttribs & CR_ALPHA_BIT )
+ ATTR_ADDV(AGL_ACCUM_ALPHA_SIZE, 1);
+ }
+
+ if( visAttribs & CR_MULTISAMPLE_BIT ) {
+ ATTR_ADDV(AGL_SAMPLE_BUFFERS_ARB, 1);
+ ATTR_ADDV(AGL_SAMPLES_ARB, 4);
+ }
+
+ if( visAttribs & CR_OVERLAY_BIT )
+ ATTR_ADDV(AGL_LEVEL, 1);
+
+ ATTR_ADD(AGL_NONE);
+
+ *pix = render_spu.ws.aglChoosePixelFormat( NULL, 0, attribs );
+
+ return (*pix != NULL);
+}
+
+void
+renderspuDestroyPixelFormat(ContextInfo *context, AGLPixelFormat *pix)
+{
+ render_spu.ws.aglDestroyPixelFormat( *pix );
+ *pix = NULL;
+}
+
+GLboolean
+renderspu_SystemCreateContext(VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext)
+{
+ AGLPixelFormat pix;
+
+ (void) sharedContext;
+ CRASSERT(visual);
+ CRASSERT(context);
+
+ context->visual = visual;
+
+ if( !renderspuChoosePixelFormat(context, &pix) ) {
+ crError( "Render SPU (renderspu_SystemCreateContext): Unable to create pixel format" );
+ return GL_FALSE;
+ }
+
+ context->context = render_spu.ws.aglCreateContext( pix, NULL );
+ renderspuDestroyPixelFormat( context, &pix );
+
+ if( !context->context ) {
+ crError( "Render SPU (renderspu_SystemCreateContext): Could not create rendering context" );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+void
+renderspu_SystemDestroyContext(ContextInfo *context)
+{
+ if(!context)
+ return;
+
+ render_spu.ws.aglSetDrawable(context->context, NULL);
+ render_spu.ws.aglSetCurrentContext(NULL);
+ if(context->context)
+ {
+ render_spu.ws.aglDestroyContext(context->context);
+ context->context = NULL;
+ }
+
+ context->visual = NULL;
+}
+
+void
+renderspuFullscreen(WindowInfo *window, GLboolean fullscreen)
+{
+ /* Real fullscreen isn't supported by VirtualBox */
+}
+
+GLboolean
+renderspuWindowAttachContext(WindowInfo *wi, WindowRef window,
+ ContextInfo *context)
+{
+ GLboolean result;
+
+ if(!context || !wi)
+ return render_spu.ws.aglSetCurrentContext( NULL );
+
+/* DEBUG_MSG_POETZSCH (("WindowAttachContext %d\n", wi->BltInfo.Base.id));*/
+
+ /* Flush old context first */
+ if (context->currentWindow->window != window)
+ render_spu.self.Flush();
+ /* If the window buffer name is uninitialized we have to create a new
+ * dummy context. */
+ if (wi->bufferName == -1)
+ {
+ DEBUG_MSG_POETZSCH (("WindowAttachContext: create context %d\n", wi->BltInfo.Base.id));
+ /* Use the same visual bits as those in the context structure */
+ AGLPixelFormat pix;
+ if( !renderspuChoosePixelFormat(context, &pix) )
+ {
+ crError( "Render SPU (renderspuWindowAttachContext): Unable to create pixel format" );
+ return GL_FALSE;
+ }
+ /* Create the dummy context */
+ wi->dummyContext = render_spu.ws.aglCreateContext( pix, NULL );
+ renderspuDestroyPixelFormat( context, &pix );
+ if( !wi->dummyContext )
+ {
+ crError( "Render SPU (renderspuWindowAttachContext): Could not create rendering context" );
+ return GL_FALSE;
+ }
+ AGLDrawable drawable;
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ drawable = NULL;
+#else
+ drawable = (AGLDrawable) GetWindowPort(window);
+#endif
+ /* New global buffer name */
+ wi->bufferName = render_spu.currentBufferName++;
+ /* Set the new buffer name to the dummy context. This enable the
+ * sharing of the same hardware buffer afterwards. */
+ result = render_spu.ws.aglSetInteger(wi->dummyContext, AGL_BUFFER_NAME, &wi->bufferName);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetInteger Failed");
+ /* Assign the dummy context to the window */
+ result = render_spu.ws.aglSetDrawable(wi->dummyContext, drawable);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetDrawable Failed");
+ }
+
+ AGLDrawable oldDrawable;
+ AGLDrawable newDrawable;
+
+ oldDrawable = render_spu.ws.aglGetDrawable(context->context);
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ newDrawable = oldDrawable;
+#else
+ newDrawable = (AGLDrawable) GetWindowPort(window);
+#endif
+ RTSemFastMutexRequest(render_spu.syncMutex);
+ /* Only switch the context if the drawable has changed */
+ if (oldDrawable != newDrawable)
+ {
+ /* Reset the current context */
+ result = render_spu.ws.aglSetDrawable(context->context, NULL);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetDrawable Failed");
+ /* Set the buffer name of the dummy context to the current context
+ * also. After that both share the same hardware buffer. */
+ render_spu.ws.aglSetInteger (context->context, AGL_BUFFER_NAME, &wi->bufferName);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetInteger Failed");
+ /* Set the new drawable */
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ result = -1;
+#else
+ result = render_spu.ws.aglSetDrawable(context->context, newDrawable);
+#endif
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetDrawable Failed");
+ renderspuSetWindowContext(window, context);
+ }
+ result = render_spu.ws.aglSetCurrentContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): SetCurrentContext Failed");
+ result = render_spu.ws.aglUpdateContext(context->context);
+ CHECK_AGL_RC (result, "Render SPU (renderspuWindowAttachContext): UpdateContext Failed");
+ RTSemFastMutexRelease(render_spu.syncMutex);
+
+ return result;
+}
+
+GLboolean
+renderspu_SystemCreateWindow(VisualInfo *visual, GLboolean showIt,
+ WindowInfo *window)
+{
+ return GL_TRUE;
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *)
+{
+ /* stub only */
+}
+
+void
+renderspu_SystemDestroyWindow(WindowInfo *window)
+{
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+ if(!window->nativeWindow)
+ {
+ EventRef evt;
+ OSStatus status = CreateEvent(NULL, kEventClassVBox, kEventVBoxDisposeWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemDestroyWindow): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemDestroyWindow): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemDestroyWindow): PostEventToQueue Failed");
+ }
+
+ /* Delete the dummy context */
+ if(window->dummyContext)
+ {
+ render_spu.ws.aglSetDrawable(window->dummyContext, NULL);
+ render_spu.ws.aglDestroyContext(window->dummyContext);
+ window->dummyContext = NULL;
+ }
+
+ /* Reset some values */
+ window->bufferName = -1;
+ window->visual = NULL;
+ window->window = NULL;
+
+ if (window->hVisibleRegion)
+ {
+ DisposeRgn(window->hVisibleRegion);
+ window->hVisibleRegion = 0;
+ }
+}
+
+void
+renderspu_SystemWindowPosition(WindowInfo *window,
+ GLint x, GLint y)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon aren't
+ * thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxMoveWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof(window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): SetEventParameter Failed");
+ HIPoint p = CGPointMake (x, y);
+ status = SetEventParameter(evt, kEventParamOrigin, typeHIPoint, sizeof (p), &p);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): SetEventParameter Failed");
+ status = SetEventParameter(evt, kEventParamUserData, typeVoidPtr, sizeof (window), &window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowPosition): PostEventToQueue Failed");
+
+ /* save the new pos */
+ window->x = x;
+ window->y = y;
+}
+
+void
+renderspu_SystemWindowSize(WindowInfo *window, GLint w, GLint h)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon aren't
+ * thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxResizeWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): CreateEvent Failed ");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof(window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SetEventParameter Failed");
+ HISize s = CGSizeMake (w, h);
+ status = SetEventParameter(evt, kEventParamDimensions, typeHISize, sizeof (s), &s);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SetEventParameter Failed");
+ status = SetEventParameter(evt, kEventParamUserData, typeVoidPtr, sizeof (window), &window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowSize): SendEventToEventTarget Failed");
+
+ DEBUG_MSG_POETZSCH (("Size %d visible %d\n", window->BltInfo.Base.id, IsWindowVisible (window->window)));
+ /* save the new size */
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+}
+
+void
+renderspu_SystemGetWindowGeometry(WindowInfo *window,
+ GLint *x, GLint *y,
+ GLint *w, GLint *h)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ Rect r;
+ status = GetWindowBounds(window->window, kWindowStructureRgn, &r);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemGetWindowGeometry): GetWindowBounds Failed");
+
+ *x = (int) r.left;
+ *y = (int) r.top;
+ *w = (int) (r.right - r.left);
+ *h = (int) (r.bottom - r.top);
+}
+
+void
+renderspu_SystemGetMaxWindowSize(WindowInfo *window,
+ GLint *w, GLint *h)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ OSStatus status = noErr;
+ HISize s;
+#ifdef __LP64__ /** @todo port to 64-bit darwin. */
+ status = -1;
+#else
+ status = GetWindowResizeLimits (window->window, NULL, &s);
+#endif
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemGetMaxWindowSize): GetWindowResizeLimits Failed");
+
+ *w = s.width;
+ *h = s.height;
+}
+
+/* Either show or hide the render SPU's window. */
+void
+renderspu_SystemShowWindow(WindowInfo *window, GLboolean showIt)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ if (!IsValidWindowPtr(window->window))
+ return;
+
+ if(showIt)
+ {
+ /* Force moving the win to the right position before we show it */
+ renderspu_SystemWindowPosition (window, window->x, window->y);
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon
+ * aren't thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxShowWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): SetEventParameter Failed");
+ status = SetEventParameter(evt, kEventParamUserData, typeVoidPtr, sizeof (window), &window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemWindowShow): SetEventParameter Failed");
+ //status = SendEventToEventTarget (evt, GetWindowEventTarget (HIViewGetWindow ((HIViewRef)render_spu_parent_window_id)));
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): PostEventToQueue Failed");
+ }
+ else
+ {
+ EventRef evt;
+ OSStatus status = CreateEvent(NULL, kEventClassVBox, kEventVBoxHideWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): CreateEvent Failed");
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): SetEventParameter Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemShowWindow): PostEventToQueue Failed");
+ }
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR * pCompositor, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+}
+
+void
+renderspu_SystemMakeCurrent(WindowInfo *window, GLint nativeWindow,
+ ContextInfo *context)
+{
+ Boolean result;
+/* DEBUG_MSG_POETZSCH (("makecurrent %d: \n", window->BltInfo.Base.id));*/
+
+ CRASSERT(render_spu.ws.aglSetCurrentContext);
+ //crDebug( "renderspu_SystemMakeCurrent( %x, %i, %x )", window, nativeWindow, context );
+
+ nativeWindow = 0;
+
+ if(window && context)
+ {
+ CRASSERT(window->window);
+ CRASSERT(context->context);
+
+ if(window->visual != context->visual)
+ {
+ crDebug("Render SPU (renderspu_SystemMakeCurrent): MakeCurrent visual mismatch (0x%x != 0x%x); remaking window.",
+ (uint)window->visual->visAttribs, (uint)context->visual->visAttribs);
+ /*
+ * XXX have to revisit this issue!!!
+ *
+ * But for now we destroy the current window
+ * and re-create it with the context's visual abilities
+ */
+ renderspu_SystemDestroyWindow(window);
+ renderspu_SystemCreateWindow(context->visual, window->visible,
+ window);
+ }
+
+ /* This is the normal case: rendering to the render SPU's own window */
+ result = renderspuWindowAttachContext(window, window->window,
+ context);
+ /* XXX this is a total hack to work around an NVIDIA driver bug */
+ if(render_spu.self.GetFloatv && context->haveWindowPosARB)
+ {
+ GLfloat f[4];
+ render_spu.self.GetFloatv(GL_CURRENT_RASTER_POSITION, f);
+ if (!window->everCurrent || f[1] < 0.0)
+ {
+ crDebug("Render SPU (renderspu_SystemMakeCurrent): Resetting raster pos");
+ render_spu.self.WindowPos2iARB(0, 0);
+ }
+ }
+ /* Reapply the visible regions */
+ renderspu_SystemWindowApplyVisibleRegion(window);
+ }
+ else
+ renderspuWindowAttachContext (0, 0, 0);
+}
+
+void
+renderspu_SystemSwapBuffers(WindowInfo *window, GLint flags)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ ContextInfo *context = renderspuGetWindowContext(window);
+
+ if(!context)
+ crError("Render SPU (renderspu_SystemSwapBuffers): SwapBuffers got a null context from the window");
+
+ RTSemFastMutexRequest(render_spu.syncMutex);
+// DEBUG_MSG_POETZSCH (("Swapped %d context %x visible: %d\n", window->BltInfo.Base.id, context->context, IsWindowVisible (window->window)));
+ if (context->visual &&
+ context->visual->visAttribs & CR_DOUBLE_BIT)
+ render_spu.ws.aglSwapBuffers(context->context);
+ else
+ glFlush();
+ RTSemFastMutexRelease(render_spu.syncMutex);
+
+ /* This method seems called very often. To prevent the dock using all free
+ * resources we update the dock only two times per second. */
+ uint64_t curTS = RTTimeMilliTS();
+ if ((curTS - render_spu.uiDockUpdateTS) > 500)
+ {
+ OSStatus status = noErr;
+ /* Send a event to the main thread, cause some function of Carbon aren't
+ * thread safe */
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxUpdateDock, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemSwapBuffers): CreateEvent Failed");
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN_VOID (status, "Render SPU (renderspu_SystemSwapBuffers): PostEventToQueue Failed");
+
+ render_spu.uiDockUpdateTS = curTS;
+ }
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects)
+{
+ CRASSERT(window);
+ CRASSERT(window->window);
+
+ /* Remember any additional clipping stuff e.g. seamless regions */
+ if (window->hVisibleRegion)
+ {
+ DisposeRgn(window->hVisibleRegion);
+ window->hVisibleRegion = 0;
+ }
+
+ if (cRects>0)
+ {
+ int i;
+ /* Create some temporary regions */
+ RgnHandle rgn = NewRgn();
+ SetEmptyRgn (rgn);
+ RgnHandle tmpRgn = NewRgn();
+ for (i=0; i<cRects; ++i)
+ {
+ SetRectRgn (tmpRgn,
+ pRects[4*i] , pRects[4*i+1],
+ pRects[4*i+2], pRects[4*i+3]);
+ //DEBUG_MSG_POETZSCH (("visible rect %d %d %d %d\n", pRects[4*i] , pRects[4*i+1],
+ // pRects[4*i+2], pRects[4*i+3]));
+ UnionRgn (rgn, tmpRgn, rgn);
+ }
+ DisposeRgn (tmpRgn);
+ window->hVisibleRegion = rgn;
+ }
+
+ renderspu_SystemWindowApplyVisibleRegion(window);
+}
+
+static void renderspu_SystemSetRootVisibleRegion(GLint cRects, GLint *pRects)
+{
+ /* Remember the visible region of the root window if there is one */
+ if (render_spu.hRootVisibleRegion)
+ {
+ DisposeRgn(render_spu.hRootVisibleRegion);
+ render_spu.hRootVisibleRegion = 0;
+ }
+
+ if (cRects>0)
+ {
+ int i;
+ render_spu.hRootVisibleRegion = NewRgn();
+ SetEmptyRgn (render_spu.hRootVisibleRegion);
+ RgnHandle tmpRgn = NewRgn();
+ for (i=0; i<cRects; ++i)
+ {
+ SetRectRgn (tmpRgn,
+ pRects[4*i] , pRects[4*i+1],
+ pRects[4*i+2], pRects[4*i+3]);
+ UnionRgn (render_spu.hRootVisibleRegion, tmpRgn, render_spu.hRootVisibleRegion);
+ }
+ DisposeRgn (tmpRgn);
+ }
+}
+
+/*Assumes that all regions are in the guest coordinates system*/
+static void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *window)
+{
+ ContextInfo *c = renderspuGetWindowContext(window);
+ RgnHandle rgn;
+ GLboolean result = true;
+
+ DEBUG_MSG_POETZSCH (("ApplyVisibleRegion %x\n", window));
+
+ if (!c || !c->context) return;
+
+ rgn = NewRgn();
+ SetEmptyRgn(rgn);
+
+ if (render_spu.hRootVisibleRegion)
+ {
+ /* The render_spu.hRootVisibleRegion has coordinates from the root
+ * window. We intersect it with the rect of the OpenGL window we
+ * currently process. */
+ SetRectRgn(rgn,
+ window->x, window->y,
+ window->x + window->BltInfo.width,
+ window->y + window->BltInfo.height);
+ SectRgn(render_spu.hRootVisibleRegion, rgn, rgn);
+ /* Because the clipping is done in the coordinate space of the OpenGL
+ * window we have to remove the x/y position from the newly created
+ * region. */
+ OffsetRgn (rgn, -window->x, -window->y);
+ }
+ else
+ {
+ /* If there is not root clipping region is available, create a base
+ * region with the size of the target window. This covers all
+ * needed/possible space. */
+ SetRectRgn(rgn, 0, 0, window->BltInfo.width, window->BltInfo.height);
+ }
+
+ /* Now intersect the window clipping region with a additional region e.g.
+ * for the seamless mode. */
+ if (window->hVisibleRegion)
+ SectRgn(rgn, window->hVisibleRegion, rgn);
+
+ if (rgn && !EmptyRgn(rgn))
+ {
+ /* Set the clip region to the context */
+ result = render_spu.ws.aglSetInteger(c->context, AGL_CLIP_REGION, (const GLint*)rgn);
+ CHECK_AGL_RC (result, "Render SPU (renderspu_SystemWindowVisibleRegion): SetInteger Failed");
+ result = render_spu.ws.aglEnable(c->context, AGL_CLIP_REGION);
+ CHECK_AGL_RC (result, "Render SPU (renderspu_SystemWindowVisibleRegion): Enable Failed");
+ }
+ /* Clear the region structure */
+ DisposeRgn (rgn);
+}
+
+GLboolean
+renderspu_SystemVBoxCreateWindow(VisualInfo *visual, GLboolean showIt,
+ WindowInfo *window)
+{
+ CRASSERT(visual);
+ CRASSERT(window);
+
+ WindowAttributes winAttr = kWindowNoShadowAttribute | kWindowCompositingAttribute | kWindowIgnoreClicksAttribute | kWindowStandardHandlerAttribute | kWindowLiveResizeAttribute;
+ WindowClass winClass = kOverlayWindowClass;
+ Rect windowRect;
+ OSStatus status = noErr;
+
+ window->visual = visual;
+ window->nativeWindow = NULL;
+
+ if(window->window && IsValidWindowPtr(window->window))
+ {
+ EventRef evt;
+ status = CreateEvent(NULL, kEventClassVBox, kEventVBoxDisposeWindow, 0, kEventAttributeNone, &evt);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): CreateEvent Failed", false);
+ status = SetEventParameter(evt, kEventParamWindowRef, typeWindowRef, sizeof (window->window), &window->window);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): SetEventParameter Failed", false);
+ status = PostEventToQueue(GetMainEventQueue(), evt, kEventPriorityStandard);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): PostEventToQueue Failed", false);
+ }
+
+ windowRect.left = window->x;
+ windowRect.top = window->y;
+ windowRect.right = window->x + window->BltInfo.width;
+ windowRect.bottom = window->y + window->BltInfo.height;
+
+ status = CreateNewWindow(winClass, winAttr, &windowRect, &window->window);
+ CHECK_CARBON_RC_RETURN (status, "Render SPU (renderspu_SystemVBoxCreateWindow): CreateNewWindow Failed", GL_FALSE);
+
+ /* We set a title for debugging purposes */
+ CFStringRef title_string;
+ title_string = CFStringCreateWithCStringNoCopy(NULL, window->title,
+ kCFStringEncodingMacRoman, NULL);
+ SetWindowTitleWithCFString(window->BltInfo.window, title_string);
+ CFRelease(title_string);
+
+ /* The parent has to be in its own group */
+ WindowRef parent = NULL;
+ if (render_spu_parent_window_id)
+ {
+ parent = HIViewGetWindow ((HIViewRef)render_spu_parent_window_id);
+ SetWindowGroup (parent, render_spu.pParentGroup);
+
+ }
+
+ /* Add the new window to the master group */
+ SetWindowGroup(window->window, render_spu.pMasterGroup);
+
+ /* This will be initialized on the first attempt to attach the global
+ * context to this new window */
+ window->bufferName = -1;
+ window->dummyContext = NULL;
+ window->hVisibleRegion = 0;
+
+ if(showIt)
+ renderspu_SystemShowWindow(window, GL_TRUE);
+
+ crDebug("Render SPU (renderspu_SystemVBoxCreateWindow): actual window (x, y, width, height): %d, %d, %d, %d",
+ window->x, window->y, window->BltInfo.width, window->BltInfo.height);
+
+ return GL_TRUE;
+}
+
+int renderspu_SystemInit()
+{
+ return VINF_SUCCESS;
+}
+
+int renderspu_SystemTerm()
+{
+ return VINF_SUCCESS;
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c
new file mode 100644
index 00000000..583398a3
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa.c
@@ -0,0 +1,479 @@
+/* $Id: renderspu_cocoa.c $ */
+/** @file
+ * VirtualBox OpenGL Cocoa Window System implementation
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include <OpenGL/OpenGL.h>
+
+#include "renderspu.h"
+#include <iprt/process.h>
+#include <iprt/string.h>
+#include <iprt/path.h>
+
+#include <cr_string.h>
+#include <cr_mem.h>
+
+GLboolean renderspu_SystemInitVisual(VisualInfo *pVisInfo)
+{
+ CRASSERT(pVisInfo);
+
+/* cocoaGLVisualCreate(&pCtxInfo->context);*/
+
+ return GL_TRUE;
+}
+
+GLboolean renderspu_SystemCreateContext(VisualInfo *pVisInfo, ContextInfo *pCtxInfo, ContextInfo *pSharedCtxInfo)
+{
+ CRASSERT(pVisInfo);
+ CRASSERT(pCtxInfo);
+
+ pCtxInfo->currentWindow = NULL;
+
+ cocoaGLCtxCreate(&pCtxInfo->context, pVisInfo->visAttribs, pSharedCtxInfo ? pSharedCtxInfo->context : NULL);
+
+ return GL_TRUE;
+}
+
+void renderspu_SystemDestroyContext(ContextInfo *pCtxInfo)
+{
+ if(!pCtxInfo)
+ return;
+
+ if(pCtxInfo->context)
+ {
+ cocoaGLCtxDestroy(pCtxInfo->context);
+ pCtxInfo->context = NULL;
+ }
+}
+
+void renderspuFullscreen(WindowInfo *pWinInfo, GLboolean fFullscreen)
+{
+ /* Real fullscreen isn't supported by VirtualBox */
+}
+
+GLboolean renderspu_SystemVBoxCreateWindow(VisualInfo *pVisInfo, GLboolean fShowIt, WindowInfo *pWinInfo)
+{
+ CRASSERT(pVisInfo);
+ CRASSERT(pWinInfo);
+
+ /* VirtualBox is the only frontend which support 3D right now. */
+ char pszName[256];
+ if (RTProcGetExecutablePath(pszName, sizeof(pszName)))
+ /* Check for VirtualBox and VirtualBoxVM */
+ if (RTStrNICmp(RTPathFilename(pszName), "VirtualBox", 10) != 0)
+ return GL_FALSE;
+
+ pWinInfo->visual = pVisInfo;
+ pWinInfo->window = NULL;
+ pWinInfo->nativeWindow = NULL;
+ pWinInfo->currentCtx = NULL;
+
+ NativeNSViewRef pParentWin = (NativeNSViewRef)(uintptr_t)render_spu_parent_window_id;
+
+ cocoaViewCreate(&pWinInfo->window, pWinInfo, pParentWin, pVisInfo->visAttribs);
+
+ if (fShowIt)
+ renderspu_SystemShowWindow(pWinInfo, fShowIt);
+
+ return GL_TRUE;
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *pWinInfo)
+{
+ NativeNSViewRef pParentWin = (NativeNSViewRef)(uintptr_t)render_spu_parent_window_id;
+ cocoaViewReparent(pWinInfo->window, pParentWin);
+}
+
+void renderspu_SystemDestroyWindow(WindowInfo *pWinInfo)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewDestroy(pWinInfo->window);
+}
+
+void renderspu_SystemWindowPosition(WindowInfo *pWinInfo, GLint x, GLint y)
+{
+ CRASSERT(pWinInfo);
+ NativeNSViewRef pParentWin = (NativeNSViewRef)(uintptr_t)render_spu_parent_window_id;
+
+ /*pParentWin is unused in the call, otherwise it might hold incorrect value if for ex. last reparent call was for
+ a different screen*/
+ cocoaViewSetPosition(pWinInfo->window, pParentWin, x, y);
+}
+
+void renderspu_SystemWindowSize(WindowInfo *pWinInfo, GLint w, GLint h)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewSetSize(pWinInfo->window, w, h);
+}
+
+void renderspu_SystemGetWindowGeometry(WindowInfo *pWinInfo, GLint *pX, GLint *pY, GLint *pW, GLint *pH)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewGetGeometry(pWinInfo->window, pX, pY, pW, pH);
+}
+
+void renderspu_SystemGetMaxWindowSize(WindowInfo *pWinInfo, GLint *pW, GLint *pH)
+{
+ CRASSERT(pWinInfo);
+
+ *pW = 10000;
+ *pH = 10000;
+}
+
+void renderspu_SystemShowWindow(WindowInfo *pWinInfo, GLboolean fShowIt)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewShow(pWinInfo->window, fShowIt);
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ cocoaViewPresentComposition(window->window, pChangedEntry);
+}
+
+void renderspu_SystemMakeCurrent(WindowInfo *pWinInfo, GLint nativeWindow, ContextInfo *pCtxInfo)
+{
+/* if(pWinInfo->visual != pCtxInfo->visual)*/
+/* printf ("visual mismatch .....................\n");*/
+
+ nativeWindow = 0;
+
+ if (pWinInfo && pCtxInfo)
+ cocoaViewMakeCurrentContext(pWinInfo->window, pCtxInfo->context);
+ else
+ cocoaViewMakeCurrentContext(NULL, NULL);
+}
+
+void renderspu_SystemSwapBuffers(WindowInfo *pWinInfo, GLint flags)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewDisplay(pWinInfo->window);
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *pWinInfo)
+{
+ return cocoaViewNeedsEmptyPresent(pWinInfo->window);
+}
+
+void renderspu_SystemWindowVisibleRegion(WindowInfo *pWinInfo, GLint cRects, const GLint* paRects)
+{
+ CRASSERT(pWinInfo);
+
+ cocoaViewSetVisibleRegion(pWinInfo->window, cRects, paRects);
+}
+
+void renderspu_SystemWindowApplyVisibleRegion(WindowInfo *pWinInfo)
+{
+}
+
+int renderspu_SystemInit()
+{
+ return VINF_SUCCESS;
+}
+
+int renderspu_SystemTerm()
+{
+ CrGlslTerm(&render_spu.GlobalShaders);
+ return VINF_SUCCESS;
+}
+
+static SPUNamedFunctionTable * renderspuFindEntry(SPUNamedFunctionTable *aFunctions, const char *pcszName)
+{
+ SPUNamedFunctionTable *pCur;
+
+ for (pCur = aFunctions ; pCur->name != NULL ; pCur++)
+ {
+ if (!crStrcmp( pcszName, pCur->name ) )
+ {
+ return pCur;
+ }
+ }
+
+ AssertFailed();
+
+ return NULL;
+}
+
+typedef struct CR_RENDER_CTX_INFO
+{
+ ContextInfo * pContext;
+ WindowInfo * pWindow;
+} CR_RENDER_CTX_INFO;
+
+void renderspuCtxInfoInitCurrent(CR_RENDER_CTX_INFO *pInfo)
+{
+ GET_CONTEXT(pCurCtx);
+ pInfo->pContext = pCurCtx;
+ pInfo->pWindow = pCurCtx ? pCurCtx->currentWindow : NULL;
+}
+
+void renderspuCtxInfoRestoreCurrent(CR_RENDER_CTX_INFO *pInfo)
+{
+ GET_CONTEXT(pCurCtx);
+ if (pCurCtx == pInfo->pContext && (!pCurCtx || pCurCtx->currentWindow == pInfo->pWindow))
+ return;
+ renderspuPerformMakeCurrent(pInfo->pWindow, 0, pInfo->pContext);
+}
+
+GLboolean renderspuCtxSetCurrentWithAnyWindow(ContextInfo * pContext, CR_RENDER_CTX_INFO *pInfo)
+{
+ WindowInfo * window;
+ renderspuCtxInfoInitCurrent(pInfo);
+
+ if (pInfo->pContext == pContext)
+ return GL_TRUE;
+
+ window = pContext->currentWindow;
+ if (!window)
+ {
+ window = renderspuGetDummyWindow(pContext->BltInfo.Base.visualBits);
+ if (!window)
+ {
+ WARN(("renderspuGetDummyWindow failed"));
+ return GL_FALSE;
+ }
+ }
+
+ Assert(window);
+
+ renderspuPerformMakeCurrent(window, 0, pContext);
+ return GL_TRUE;
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+ CRASSERT(fromContext != toContext);
+
+ if (!CrGlslIsInited(&render_spu.GlobalShaders))
+ {
+ CrGlslInit(&render_spu.GlobalShaders, &render_spu.blitterDispatch);
+ }
+
+ if (fromContext)
+ {
+ if (CrGlslNeedsCleanup(&render_spu.GlobalShaders))
+ {
+ CR_RENDER_CTX_INFO Info;
+ if (renderspuCtxSetCurrentWithAnyWindow(fromContext, &Info))
+ {
+ CrGlslCleanup(&render_spu.GlobalShaders);
+ renderspuCtxInfoRestoreCurrent(&Info);
+ }
+ else
+ WARN(("renderspuCtxSetCurrentWithAnyWindow failed!"));
+ }
+ }
+ else
+ {
+ CRASSERT(!CrGlslNeedsCleanup(&render_spu.GlobalShaders));
+ }
+
+ CRASSERT(!CrGlslNeedsCleanup(&render_spu.GlobalShaders));
+
+ if (toContext)
+ {
+ CR_RENDER_CTX_INFO Info;
+ if (renderspuCtxSetCurrentWithAnyWindow(toContext, &Info))
+ {
+ int rc = CrGlslProgGenAllNoAlpha(&render_spu.GlobalShaders);
+ if (!RT_SUCCESS(rc))
+ WARN(("CrGlslProgGenAllNoAlpha failed, rc %d", rc));
+
+ renderspuCtxInfoRestoreCurrent(&Info);
+ }
+ else
+ crWarning("renderspuCtxSetCurrentWithAnyWindow failed!");
+ }
+}
+
+AssertCompile(sizeof (GLhandleARB) == sizeof (void*));
+
+static VBoxGLhandleARB crHndlSearchVBox(GLhandleARB hNative)
+{
+ CRASSERT(!(((uintptr_t)hNative) >> 32));
+ return (VBoxGLhandleARB)((uintptr_t)hNative);
+}
+
+static GLhandleARB crHndlSearchNative(VBoxGLhandleARB hVBox)
+{
+ return (GLhandleARB)((uintptr_t)hVBox);
+}
+
+static VBoxGLhandleARB crHndlAcquireVBox(GLhandleARB hNative)
+{
+ CRASSERT(!(((uintptr_t)hNative) >> 32));
+ return (VBoxGLhandleARB)((uintptr_t)hNative);
+}
+
+static GLhandleARB crHndlReleaseVBox(VBoxGLhandleARB hVBox)
+{
+ return (GLhandleARB)((uintptr_t)hVBox);
+}
+
+static void SPU_APIENTRY renderspu_SystemDeleteObjectARB(VBoxGLhandleARB obj)
+{
+ GLhandleARB hNative = crHndlReleaseVBox(obj);
+ if (!hNative)
+ {
+ crWarning("no native for %d", obj);
+ return;
+ }
+
+ render_spu.pfnDeleteObject(hNative);
+}
+
+static void SPU_APIENTRY renderspu_SystemGetAttachedObjectsARB( VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * pCount, VBoxGLhandleARB * obj )
+{
+ GLhandleARB *paAttachments;
+ GLhandleARB hNative = crHndlSearchNative(containerObj);
+ GLsizei count, i;
+
+ if (pCount)
+ *pCount = 0;
+
+ if (!hNative)
+ {
+ crWarning("no native for %d", obj);
+ return;
+ }
+
+ paAttachments = crCalloc(maxCount * sizeof (*paAttachments));
+ if (!paAttachments)
+ {
+ crWarning("crCalloc failed");
+ return;
+ }
+
+ render_spu.pfnGetAttachedObjects(hNative, maxCount, &count, paAttachments);
+ if (pCount)
+ *pCount = count;
+ if (count > maxCount)
+ {
+ crWarning("count too big");
+ count = maxCount;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ obj[i] = crHndlSearchVBox(paAttachments[i]);
+ CRASSERT(obj[i]);
+ }
+
+ crFree(paAttachments);
+}
+
+static VBoxGLhandleARB SPU_APIENTRY renderspu_SystemGetHandleARB(GLenum pname)
+{
+ GLhandleARB hNative = render_spu.pfnGetHandle(pname);
+ VBoxGLhandleARB hVBox;
+ if (!hNative)
+ {
+ crWarning("pfnGetHandle failed");
+ return 0;
+ }
+ hVBox = crHndlAcquireVBox(hNative);
+ CRASSERT(hVBox);
+ return hVBox;
+}
+
+static void SPU_APIENTRY renderspu_SystemGetInfoLogARB( VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog )
+{
+ GLhandleARB hNative = crHndlSearchNative(obj);
+ if (!hNative)
+ {
+ crWarning("invalid handle!");
+ return;
+ }
+
+ render_spu.pfnGetInfoLog(hNative, maxLength, length, infoLog);
+}
+
+static void SPU_APIENTRY renderspu_SystemGetObjectParameterfvARB( VBoxGLhandleARB obj, GLenum pname, GLfloat * params )
+{
+ GLhandleARB hNative = crHndlSearchNative(obj);
+ if (!hNative)
+ {
+ crWarning("invalid handle!");
+ return;
+ }
+
+ render_spu.pfnGetObjectParameterfv(hNative, pname, params);
+}
+
+static void SPU_APIENTRY renderspu_SystemGetObjectParameterivARB( VBoxGLhandleARB obj, GLenum pname, GLint * params )
+{
+ GLhandleARB hNative = crHndlSearchNative(obj);
+ if (!hNative)
+ {
+ crWarning("invalid handle!");
+ return;
+ }
+
+ render_spu.pfnGetObjectParameteriv(hNative, pname, params);
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ SPUNamedFunctionTable * pEntry;
+
+ pEntry = renderspuFindEntry(aFunctions, "DeleteObjectARB");
+ if (pEntry)
+ {
+ render_spu.pfnDeleteObject = (PFNDELETE_OBJECT)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemDeleteObjectARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetAttachedObjectsARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetAttachedObjects = (PFNGET_ATTACHED_OBJECTS)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetAttachedObjectsARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetHandleARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetHandle = (PFNGET_HANDLE)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetHandleARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetInfoLogARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetInfoLog = (PFNGET_INFO_LOG)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetInfoLogARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetObjectParameterfvARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetObjectParameterfv = (PFNGET_OBJECT_PARAMETERFV)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetObjectParameterfvARB;
+ }
+
+ pEntry = renderspuFindEntry(aFunctions, "GetObjectParameterivARB");
+ if (pEntry)
+ {
+ render_spu.pfnGetObjectParameteriv = (PFNGET_OBJECT_PARAMETERIV)pEntry->fn;
+ pEntry->fn = (SPUGenericFunction)renderspu_SystemGetObjectParameterivARB;
+ }
+
+ return cFunctions;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h
new file mode 100644
index 00000000..11333083
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.h
@@ -0,0 +1,65 @@
+/* $Id: renderspu_cocoa_helper.h $ */
+/** @file
+ * VirtualBox OpenGL Cocoa Window System Helper definition
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef ___renderspu_cocoa_helper_h
+#define ___renderspu_cocoa_helper_h
+
+#include <iprt/cdefs.h>
+#include <VBox/VBoxCocoa.h>
+#include <OpenGL/OpenGL.h>
+#ifdef IN_VMSVGA3D
+# include "../../../GuestHost/OpenGL/include/cr_vreg.h"
+# include "../../../GuestHost/OpenGL/include/cr_compositor.h"
+#else
+# include <cr_vreg.h>
+# include <cr_compositor.h>
+#endif
+
+
+RT_C_DECLS_BEGIN
+
+struct WindowInfo;
+
+ADD_COCOA_NATIVE_REF(NSView);
+ADD_COCOA_NATIVE_REF(NSOpenGLContext);
+
+/** @name OpenGL context management
+ * @{ */
+void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx);
+void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx);
+/** @} */
+
+/** @name View management
+ * @{ */
+void cocoaViewCreate(NativeNSViewRef *ppView, struct WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams);
+void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView);
+void cocoaViewDestroy(NativeNSViewRef pView);
+void cocoaViewDisplay(NativeNSViewRef pView);
+void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt);
+void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y);
+void cocoaViewSetSize(NativeNSViewRef pView, int cx, int cy);
+void cocoaViewGetGeometry(NativeNSViewRef pView, int *px, int *py, int *pcx, int *pcy);
+void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx);
+void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint *paRects);
+GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView);
+void cocoaViewPresentComposition(NativeNSViewRef pView, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry);
+/** @} */
+
+RT_C_DECLS_END
+
+#endif /* !___renderspu_cocoa_helper_h */
+
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
new file mode 100644
index 00000000..6c643f9c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_cocoa_helper.m
@@ -0,0 +1,3283 @@
+/* $Id: renderspu_cocoa_helper.m $ */
+/** @file
+ * VirtualBox OpenGL Cocoa Window System Helper Implementation.
+ *
+ * This source file is shared between the SharedOpenGL HGCM service and the
+ * SVGA3d emulation.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/** @page pg_opengl_cocoa OpenGL - Cocoa Window System Helper
+ *
+ * How this works:
+ * In general it is not so easy like on the other platforms, cause Cocoa
+ * doesn't support any clipping of already painted stuff. In Mac OS X there is
+ * the concept of translucent canvas's e.g. windows and there it is just
+ * painted what should be visible to the user. Unfortunately this isn't the
+ * concept of chromium. Therefor I reroute all OpenGL operation from the guest
+ * to a frame buffer object (FBO). This is a OpenGL extension, which is
+ * supported by all OS X versions we support (AFAIC tell). Of course the guest
+ * doesn't know that and we have to make sure that the OpenGL state always is
+ * in the right state to paint into the FBO and not to the front/back buffer.
+ * Several functions below (like cocoaBindFramebufferEXT, cocoaGetIntegerv,
+ * ...) doing this. When a swap or finish is triggered by the guest, the
+ * content (which is already bound to an texture) is painted on the screen
+ * within a separate OpenGL context. This allows the usage of the same
+ * resources (texture ids, buffers ...) but at the same time having an
+ * different internal OpenGL state. Another advantage is that we can paint a
+ * thumbnail of the current output in a much more smaller (GPU accelerated
+ * scale) version on a third context and use glReadPixels to get the actual
+ * data. glReadPixels is a very slow operation, but as we just use a much more
+ * smaller image, we can handle it (anyway this is only done 5 times per
+ * second).
+ *
+ * Other things to know:
+ * - If the guest request double buffering, we have to make sure there are two
+ * buffers. We use the same FBO with 2 color attachments. Also glDrawBuffer
+ * and glReadBuffer is intercepted to make sure it is painted/read to/from
+ * the correct buffers. On swap our buffers are swapped and not the
+ * front/back buffer.
+ * - If the guest request a depth/stencil buffer, a combined render buffer for
+ * this is created.
+ * - If the size of the guest OpenGL window changes, all FBO's, textures, ...
+ * need to be recreated.
+ * - We need to track any changes to the parent window
+ * (create/destroy/move/resize). The various classes like OverlayHelperView,
+ * OverlayWindow, ... are there for.
+ * - The HGCM service runs on a other thread than the Main GUI. Keeps this
+ * always in mind (see e.g. performSelectorOnMainThread in renderFBOToView)
+ * - We make heavy use of late binding. We can not be sure that the GUI (or any
+ * other third party GUI), overwrite our NSOpenGLContext. So we always ask if
+ * this is our own one, before use. Really neat concept of Objective-C/Cocoa
+ * ;)
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#ifdef IN_VMSVGA3D
+# define LOG_GROUP LOG_GROUP_DEV_VMSVGA
+#endif
+#include "renderspu_cocoa_helper.h"
+
+#import <Cocoa/Cocoa.h>
+#undef PVM /* sys/param.h (included via Cocoa.h) pollutes the namespace with this define. */
+
+#ifndef IN_VMSVGA3D
+# include "chromium.h" /* For the visual bits of chromium */
+#endif
+
+#include <iprt/assert.h>
+#include <iprt/critsect.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/time.h>
+#include <iprt/thread.h>
+
+#include <VBox/VBoxOGL.h>
+#include <VBox/log.h>
+
+#ifdef IN_VMSVGA3D
+# include "DevVGA-SVGA3d-cocoa.h"
+# include <OpenGL/OpenGL.h>
+# include <OpenGL/gl3.h>
+# include <OpenGL/gl3ext.h>
+# include <OpenGL/glext.h>
+#else
+# include <cr_vreg.h>
+# include <cr_error.h>
+# include <cr_blitter.h>
+# ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
+# include <cr_pixeldata.h>
+# endif
+# include "renderspu.h"
+#endif
+
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/* Debug macros */
+/** @def FBO
+ * Disable this to see how the output is without the FBO in the middle of the processing chain. */
+#define FBO 1
+/** @def SHOW_WINDOW_BACKGROUND
+ * Define this to see the window background even if the window is clipped. */
+/** @def DEBUG_VERBOSE
+ * Define this to get some debug info about the messages flow. */
+#if 0 || defined(DOXYGEN_RUNNING)
+# define SHOW_WINDOW_BACKGROUND 1
+# define DEBUG_VERBOSE
+#endif
+
+#ifdef DEBUG_VERBOSE
+# error "should be disabled!"
+# ifdef IN_VMSVGA3D
+# define DEBUG_INFO(text) do { LogRel(text); AssertFailed(); } while (0)
+# define DEBUG_WARN(text) do { LogRel(text); AssertFailed(); } while (0)
+# else
+# define DEBUG_INFO(text) do { LogRel(text); AssertFailed(); } while (0)
+# define DEBUG_WARN(text) do { LogRel(text); AssertFailed(); } while (0)
+# endif
+
+# define DEBUG_MSG(text) do { LogRel(text); } while (0)
+# define DEBUG_MSG_1(text) do { LogRel(text); } while (0)
+
+#else
+
+# ifdef IN_VMSVGA3D
+# define DEBUG_INFO(text) do { LogRel(text); } while (0)
+# define DEBUG_WARN(text) do { LogRel(text); } while (0)
+# else
+# define DEBUG_INFO(text) do { crInfo text; } while (0)
+# define DEBUG_WARN(text) do { crWarning text; } while (0)
+#endif
+# define DEBUG_MSG(text) do {} while (0)
+# define DEBUG_MSG_1(text) do {} while (0)
+
+#endif
+#ifdef IN_VMSVGA3D
+# define DEBUG_MSG_NOT_VMSVGA3D(a_TextArgs) do {} while (0)
+# define COCOA_LOG_FLOW(a_TextArgs) LogFlow(a_TextArgs)
+#else
+# define DEBUG_MSG_NOT_VMSVGA3D(a_TextArgs) DEBUG_MSG(a_TextArgs)
+# define COCOA_LOG_FLOW(a_TextArgs) DEBUG_MSG(a_TextArgs)
+#endif
+
+
+#define DEBUG_FUNC_ENTER() DEBUG_MSG(("==>%s\n", __PRETTY_FUNCTION__))
+#define DEBUG_FUNC_LEAVE() DEBUG_MSG(("<==%s\n", __PRETTY_FUNCTION__))
+
+#define DEBUG_GL_SAVE_STATE() \
+ do { \
+ glPushAttrib(GL_ALL_ATTRIB_BITS); \
+ glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); \
+ glMatrixMode(GL_PROJECTION); \
+ glPushMatrix(); \
+ glMatrixMode(GL_TEXTURE); \
+ glPushMatrix(); \
+ glMatrixMode(GL_COLOR); \
+ glPushMatrix(); \
+ glMatrixMode(GL_MODELVIEW); \
+ glPushMatrix(); \
+ } while (0)
+
+#define DEBUG_GL_RESTORE_STATE() \
+ do { \
+ glMatrixMode(GL_MODELVIEW); \
+ glPopMatrix(); \
+ glMatrixMode(GL_COLOR); \
+ glPopMatrix(); \
+ glMatrixMode(GL_TEXTURE); \
+ glPopMatrix(); \
+ glMatrixMode(GL_PROJECTION); \
+ glPopMatrix(); \
+ glPopClientAttrib(); \
+ glPopAttrib(); \
+ } while (0)
+
+#ifdef VBOX_STRICT
+# define DEBUG_CLEAR_GL_ERRORS() \
+ do { \
+ while (glGetError() != GL_NO_ERROR) \
+ { /* nothing */ } \
+ } while (0)
+# define DEBUG_CHECK_GL_ERROR(a_szOp) \
+ do { \
+ GLenum iGlCheckErr = glGetError(); \
+ if (RT_UNLIKELY(iGlCheckErr != GL_NO_ERROR)) \
+ AssertMsgFailed((a_szOp ": iGlCheckErr=%#x\n", iGlCheckErr)); \
+ } while (0)
+#else
+# define DEBUG_CLEAR_GL_ERRORS() do {} while (0)
+# define DEBUG_CHECK_GL_ERROR(a_szOp) do {} while (0)
+#endif
+
+/* Whether we control NSView automatic content zooming on Retina/HiDPI displays. */
+#define VBOX_WITH_CONFIGURABLE_HIDPI_SCALING 1
+
+
+#ifdef IN_VMSVGA3D
+
+/*
+ * VMSVGA3D compatibility glue.
+ */
+typedef struct WindowInfo WindowInfo;
+
+# define CR_RGB_BIT RT_BIT_32(0)
+
+# define CR_ALPHA_BIT RT_BIT_32(1)
+# define CR_DEPTH_BIT RT_BIT_32(2)
+# define CR_STENCIL_BIT RT_BIT_32(3)
+# define CR_ACCUM_BIT RT_BIT_32(4)
+# define CR_DOUBLE_BIT RT_BIT_32(5)
+# define CR_STEREO_BIT RT_BIT_32(6)
+# define CR_MULTISAMPLE_BIT RT_BIT_32(7)
+
+# define CR_OVERLAY_BIT RT_BIT_32(8)
+# define CR_PBUFFER_BIT RT_BIT_32(9)
+# define VMSVGA3D_NON_DEFAULT_PROFILE_BIT RT_BIT_32(31)
+# define CR_ALL_BITS UINT32_C(0x800003ff)
+
+#endif /* IN_VMSVGA3D */
+
+
+/**
+ * Works functions that creates a NSOpenGLPixelFormat instance.
+ *
+ * @returns Instance.
+ * @param fVisParams Context flags.
+ */
+static NSOpenGLPixelFormat *vboxCreatePixelFormat(GLbitfield fVisParams)
+{
+ NSOpenGLPixelFormatAttribute attribs[24] =
+ {
+#ifdef IN_VMSVGA3D
+ NSOpenGLPFAOpenGLProfile, (NSOpenGLPixelFormatAttribute)0,
+#endif
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute)24
+ };
+#ifndef IN_VMSVGA3D
+ int i = 3;
+#else
+ int i = 3+2;
+ if (fVisParams & VMSVGA3D_NON_DEFAULT_PROFILE_BIT)
+ attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersionLegacy : NSOpenGLProfileVersion3_2Core;
+ else
+ attribs[1] = VBOX_VMSVGA3D_DEFAULT_OGL_PROFILE >= 3.2 ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy;
+#endif
+
+ if (fVisParams & CR_ALPHA_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_ALPHA_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAAlphaSize;
+ attribs[i++] = 8;
+ }
+ if (fVisParams & CR_DEPTH_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_DEPTH_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFADepthSize;
+ attribs[i++] = 24;
+ }
+ if (fVisParams & CR_STENCIL_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_STENCIL_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAStencilSize;
+ attribs[i++] = 8;
+ }
+ if (fVisParams & CR_ACCUM_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_ACCUM_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAAccumSize;
+ if (fVisParams & CR_ALPHA_BIT)
+ attribs[i++] = 32;
+ else
+ attribs[i++] = 24;
+ }
+ if (fVisParams & CR_MULTISAMPLE_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_MULTISAMPLE_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFASampleBuffers;
+ attribs[i++] = 1;
+ attribs[i++] = NSOpenGLPFASamples;
+ attribs[i++] = 4;
+ }
+ if (fVisParams & CR_DOUBLE_BIT)
+ {
+ COCOA_LOG_FLOW((" CR_DOUBLE_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFADoubleBuffer;
+ }
+ if (fVisParams & CR_STEREO_BIT)
+ {
+ /* We don't support that.
+ COCOA_LOG_FLOW((" CR_STEREO_BIT requested\n"));
+ attribs[i++] = NSOpenGLPFAStereo;
+ */
+ }
+
+ if (VBoxOglIsOfflineRenderingAppropriate())
+ {
+ COCOA_LOG_FLOW((" Offline rendering is enabled\n"));
+ attribs[i++] = NSOpenGLPFAAllowOfflineRenderers;
+ }
+
+ /* Mark the end */
+ attribs[i++] = 0;
+
+ /* Instantiate the pixel format object. */
+ return [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
+}
+
+
+static NSOpenGLContext *vboxCtxGetCurrent(void)
+{
+#ifdef IN_VMSVGA3D
+ return [NSOpenGLContext currentContext];
+#else
+ GET_CONTEXT(pCtxInfo);
+ if (pCtxInfo)
+ {
+ Assert(pCtxInfo->context);
+ return pCtxInfo->context;
+ }
+ return nil;
+#endif
+}
+
+static bool vboxCtxSyncCurrentInfo(void)
+{
+#ifdef IN_VMSVGA3D
+ return false;
+#else
+ bool fAdjusted = false;
+ GET_CONTEXT(pCtxInfo);
+ NSOpenGLContext *pCtx = [NSOpenGLContext currentContext];
+ NSView *pView = pCtx ? [pCtx view] : nil;
+ if (pCtxInfo)
+ {
+ WindowInfo *pWinInfo = pCtxInfo->currentWindow;
+ Assert(pWinInfo);
+ if ( pCtxInfo->context != pCtx
+ || pWinInfo->window != pView)
+ {
+ renderspu_SystemMakeCurrent(pWinInfo, 0, pCtxInfo);
+ fAdjusted = true;
+ }
+ }
+ else if (pCtx)
+ {
+ [NSOpenGLContext clearCurrentContext];
+ fAdjusted = true;
+ }
+
+ return fAdjusted;
+#endif
+}
+
+
+/**
+ * State carrying structure for use with vboxCtxEnter and vboxCtxLeave
+ */
+typedef struct VBOX_CR_RENDER_CTX_INFO
+{
+ bool fIsValid;
+ NSOpenGLContext *pCtx;
+ NSView *pView;
+} VBOX_CR_RENDER_CTX_INFO;
+/** Pointer to render context info for use with vboxCtxEnter/Leave. */
+typedef VBOX_CR_RENDER_CTX_INFO *PVBOX_CR_RENDER_CTX_INFO;
+
+static void vboxCtxEnter(NSOpenGLContext *pNewCtx, PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
+{
+ NSOpenGLContext *pOldCtx = vboxCtxGetCurrent();
+ NSView *pOldView = pOldCtx ? [pOldCtx view] : nil;
+ NSView *pNewView = [pNewCtx view];
+
+ Assert(pNewCtx);
+
+ if ( pOldCtx != pNewCtx
+ || pOldView != pNewView)
+ {
+ if (pOldCtx != nil)
+ glFlush();
+
+ DEBUG_CLEAR_GL_ERRORS();
+ [pNewCtx makeCurrentContext];
+ DEBUG_CHECK_GL_ERROR("makeCurrentContext");
+
+ pCtxInfo->fIsValid = true;
+ pCtxInfo->pCtx = pOldCtx;
+ /** @todo r=bird: Why do we save the NEW VIEW here? vboxCtxLeave calls it 'pOldView'. Bug? */
+ pCtxInfo->pView = pNewView;
+ }
+ else
+ {
+ /* No context switch necessary. */
+ pCtxInfo->fIsValid = false;
+ }
+}
+
+static void vboxCtxLeave(PVBOX_CR_RENDER_CTX_INFO pCtxInfo)
+{
+ if (pCtxInfo->fIsValid)
+ {
+ NSOpenGLContext *pOldCtx = pCtxInfo->pCtx;
+ NSView *pOldView = pCtxInfo->pView;
+
+ glFlush();
+ if (pOldCtx != nil)
+ {
+ /* vboxCtxEnter saves the new view, not the old. So, what we actually
+ do here is switching the view of the old context to that of the new
+ one (wrt vboxCtxEnter) before making it current. */
+ /** @todo r=bird: Figure out what we really want to do here, and either rename
+ * pOldView or fix the code. */
+ if ([pOldCtx view] != pOldView)
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ [pOldCtx setView: pOldView];
+ DEBUG_CHECK_GL_ERROR("setView");
+ }
+
+ DEBUG_CLEAR_GL_ERRORS();
+ [pOldCtx makeCurrentContext];
+ DEBUG_CHECK_GL_ERROR("makeCurrentContext");
+
+#ifdef VBOX_STRICT
+ {
+ NSOpenGLContext *pTstOldCtx = [NSOpenGLContext currentContext];
+ NSView *pTstOldView = pTstOldCtx ? [pTstOldCtx view] : nil;
+ Assert(pTstOldCtx == pOldCtx);
+ Assert(pTstOldView == pOldView);
+ }
+#endif
+ }
+ else
+ {
+ [NSOpenGLContext clearCurrentContext];
+ }
+ }
+}
+
+
+/**
+ * Custom OpenGL context class.
+ *
+ * This implementation doesn't allow to set a view to the context, but save the
+ * view for later use. Also it saves a copy of the pixel format used to create
+ * that context for later use.
+ */
+@interface OverlayOpenGLContext: NSOpenGLContext
+{
+@private
+ NSOpenGLPixelFormat *m_pPixelFormat;
+ NSView *m_pView;
+}
+- (NSOpenGLPixelFormat *)openGLPixelFormat;
+@end
+
+/**
+ * Abstrack task class.
+ */
+@interface VBoxTask : NSObject
+{
+}
+- (void)run;
+@end
+
+@implementation VBoxTask
+/** Run method that the child classes must reimplement.
+ * This will abort the process. */
+- (void)run
+{
+ AssertReleaseFailed();
+}
+@end
+
+
+/**
+ * Generic task class for executing a given method select.
+ */
+@interface VBoxTaskPerformSelector : VBoxTask
+{
+@private
+ id m_Object;
+ SEL m_Selector;
+ id m_Arg;
+}
+- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
+- (void)run;
+- (void)dealloc;
+@end
+
+@implementation VBoxTaskPerformSelector
+
+/**
+ * Initializes a VBoxTaskPerformSelector.
+ *
+ * @param aObject The object (reference not consumed).
+ * @param aSelector The method selector.
+ * @param aArg The method argument (reference not consumed).
+ */
+- (id)initWithObject:(id)aObject selector:(SEL)aSelector arg:(id)aArg
+{
+ self = [super init];
+ if (self)
+ {
+ [aObject retain];
+ m_Object = aObject;
+ m_Selector = aSelector;
+ if (aArg != nil)
+ [aArg retain];
+ m_Arg = aArg;
+ }
+
+ return self;
+}
+
+- (void)run
+{
+ [m_Object performSelector:m_Selector withObject:m_Arg];
+}
+
+- (void)dealloc
+{
+ [m_Object release];
+ if (m_Arg != nil)
+ [m_Arg release];
+
+ [super dealloc];
+}
+@end
+
+
+/**
+ *
+ */
+@interface VBoxTaskComposite : VBoxTask
+{
+@private
+ NSUInteger m_CurIndex;
+ RTCRITSECT m_Lock;
+ NSMutableArray *m_pArray;
+}
+- (id)init;
+- (void)add:(VBoxTask *)pTask;
+- (void)run;
+- (void)dealloc;
+@end
+
+@implementation VBoxTaskComposite
+- (id)init
+{
+ self = [super init];
+
+ if (self)
+ {
+ int rc = RTCritSectInit(&m_Lock);
+ if (!RT_SUCCESS(rc))
+ {
+ DEBUG_WARN(("RTCritSectInit failed %d\n", rc));
+ return nil;
+ }
+
+ m_CurIndex = 0;
+
+ m_pArray = [[NSMutableArray alloc] init];
+ }
+
+ return self;
+}
+
+/**
+ * Adds a task to the composite task object.
+ *
+ * @param pTask Task to add. Reference is NOT consumed.
+ */
+- (void)add:(VBoxTask *)pTask
+{
+ [pTask retain];
+ int rc = RTCritSectEnter(&m_Lock);
+ if (RT_SUCCESS(rc))
+ {
+ [m_pArray addObject:pTask];
+ RTCritSectLeave(&m_Lock);
+ }
+ else
+ {
+ DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
+ [pTask release];
+ }
+}
+
+- (void)run
+{
+ for (;;)
+ {
+ /*
+ * Dequeue a task.
+ */
+ int rc = RTCritSectEnter(&m_Lock);
+ if (RT_FAILURE(rc))
+ {
+ DEBUG_WARN(("RTCritSectEnter failed %d\n", rc));
+ break;
+ }
+
+ NSUInteger count = [m_pArray count];
+ Assert(m_CurIndex <= count);
+ if (m_CurIndex == count)
+ {
+ [m_pArray removeAllObjects];
+ m_CurIndex = 0;
+ RTCritSectLeave(&m_Lock);
+ break;
+ }
+
+ VBoxTask *pTask = (VBoxTask *)[m_pArray objectAtIndex:m_CurIndex];
+ Assert(pTask != nil);
+
+ ++m_CurIndex;
+
+ /*
+ * Remove the first 1025 empty entires.
+ */
+ if (m_CurIndex > 1024)
+ {
+ NSRange range;
+ range.location = 0;
+ range.length = m_CurIndex;
+ [m_pArray removeObjectsInRange:range];
+ m_CurIndex = 0;
+ }
+ RTCritSectLeave(&m_Lock);
+
+ /*
+ * Run the task and release it.
+ */
+ [pTask run];
+ [pTask release];
+ }
+}
+
+- (void)dealloc
+{
+ NSUInteger count = [m_pArray count];
+ for (;m_CurIndex < count; ++m_CurIndex)
+ {
+ VBoxTask *pTask = (VBoxTask*)[m_pArray objectAtIndex:m_CurIndex];
+ DEBUG_WARN(("dealloc with non-empty tasks! %p\n", pTask));
+ [pTask release];
+ }
+
+ [m_pArray release];
+ RTCritSectDelete(&m_Lock);
+
+ [super dealloc];
+}
+@end
+
+
+/**
+ *
+ *
+ */
+@interface VBoxMainThreadTaskRunner : NSObject
+{
+@private
+ VBoxTaskComposite *m_pTasks;
+}
+- (id)init;
+- (void)add:(VBoxTask *)pTask;
+- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg;
+- (void)runTasks;
+- (bool)runTasksSyncIfPossible;
+- (void)dealloc;
++ (VBoxMainThreadTaskRunner *) globalInstance;
+@end
+
+@implementation VBoxMainThreadTaskRunner
+- (id)init
+{
+ self = [super init];
+ if (self)
+ {
+ m_pTasks = [[VBoxTaskComposite alloc] init];
+ }
+
+ return self;
+}
+
++ (VBoxMainThreadTaskRunner *) globalInstance
+{
+ static dispatch_once_t s_DispatchOnce;
+ static VBoxMainThreadTaskRunner *s_pRunner = nil;
+ dispatch_once(&s_DispatchOnce, ^{
+ s_pRunner = [[VBoxMainThreadTaskRunner alloc] init];
+ });
+ return s_pRunner;
+}
+
+- (void)add:(VBoxTask *)pTask
+{
+ DEBUG_FUNC_ENTER();
+ [m_pTasks add:pTask];
+ /** @todo r=bird: Unbalanced [self retain]. */
+ [self retain];
+
+ if (![self runTasksSyncIfPossible])
+ {
+ DEBUG_MSG(("task will be processed async\n"));
+ [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:NO];
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+/**
+ * Adds a task calling an object method (selector).
+ *
+ * @param aObject The object (reference not consumed)..
+ * @param aSelector The method selector.
+ * @param aArg The method argument (reference not consumed).
+ */
+- (void)addObj:(id)aObject selector:(SEL)aSelector arg:(id)aArg
+{
+ VBoxTaskPerformSelector *pSelTask = [[VBoxTaskPerformSelector alloc] initWithObject:aObject selector:aSelector arg:aArg];
+ [self add:pSelTask];
+ [pSelTask release];
+}
+
+
+/**
+ * Internal method for running the pending tasks.
+ */
+- (void)runTasks
+{
+ if ([NSThread isMainThread])
+ {
+ [m_pTasks run];
+ /** @todo r=bird: This release and the retain in the add method aren't
+ * necessarily balanced if there are more than one call to add().
+ *
+ * This could probably end up deleting the singleton prematurely and leave
+ * globalInstance() returning pointers to a stale object in freed memory,
+ * quite possibly causing crashes or/and heap corruption. */
+ [self release];
+ }
+ else
+ {
+ DEBUG_WARN(("run tasks called not on main thread!\n"));
+#ifndef DEBUG_VERBOSE
+ AssertFailed();
+#endif
+ [self performSelectorOnMainThread:@selector(runTasks) withObject:nil waitUntilDone:YES];
+ }
+}
+
+/**
+ * Callback for calling runTasks via renderspuCalloutClient.
+ * @param pvUser The VBoxMainThreadTaskRunner singleton.
+ */
+static DECLCALLBACK(void) VBoxMainThreadTaskRunner_RcdRunCallback(void *pvUser)
+{
+ DEBUG_FUNC_ENTER();
+ VBoxMainThreadTaskRunner *pRunner = (VBoxMainThreadTaskRunner *)pvUser;
+ Assert(pRunner == [VBoxMainThreadTaskRunner globalInstance]);
+ [pRunner runTasks];
+ DEBUG_FUNC_LEAVE();
+}
+
+/**
+ * Runs pending tasks synchronously, if possible in the current context.
+ *
+ * @returns true if executed tasks, false if not possible.
+ */
+- (bool)runTasksSyncIfPossible
+{
+#ifndef IN_VMSVGA3D
+ /*
+ * Call on main thread (?) via renderspuCalloutClient (whatever that is).
+ */
+ if (renderspuCalloutAvailable())
+ {
+ Assert(![NSThread isMainThread]);
+ renderspuCalloutClient(VBoxMainThreadTaskRunner_RcdRunCallback, self);
+ return true;
+ }
+#endif
+
+ /*
+ * Run directly if on main thread.
+ */
+ if ([NSThread isMainThread])
+ {
+ [self runTasks];
+ return true;
+ }
+
+ /* Not possible. */
+ return false;
+}
+
+- (void)dealloc
+{
+ /** @todo r=bird: WTF is the point of the deallocator. The object is a singelton
+ * stored in an inaccessible static variable! */
+ [m_pTasks release];
+ m_pTasks = nil;
+
+ [super dealloc];
+}
+
+@end
+
+#ifndef IN_VMSVGA3D
+@class DockOverlayView;
+#endif
+
+/**
+ * The custom view class.
+ *
+ * This is the main class of the cocoa OpenGL implementation. It manages a
+ * frame buffer object for the rendering of the guest applications. The guest
+ * applications render in this frame buffer which is bound to an OpenGL texture.
+ * To display the guest content, a secondary shared OpenGL context of the main
+ * OpenGL context is created. The secondary context is marked as non-opaque and
+ * the texture is displayed on an object which is composed out of the several
+ * visible region rectangles.
+ */
+@interface OverlayView : NSView
+{
+@private
+ NSView *m_pParentView;
+ NSWindow *m_pOverlayWin;
+
+ NSOpenGLContext *m_pGLCtx;
+ NSOpenGLContext *m_pSharedGLCtx;
+ RTTHREAD m_Thread;
+
+ GLuint m_FBOId;
+
+#ifndef IN_VMSVGA3D
+ /** The corresponding dock tile view of this OpenGL view & all helper
+ * members. */
+ DockOverlayView *m_DockTileView;
+
+ GLfloat m_FBOThumbScaleX;
+ GLfloat m_FBOThumbScaleY;
+ uint64_t m_msDockUpdateTS;
+#endif
+
+ /** @name For clipping
+ * @remarks appears to be unused and a complete waste of time + heap.
+ * @{ */
+ GLint m_cClipRects;
+ GLint *m_paClipRects;
+ /** @} */
+
+ /** @name Position/Size tracking
+ * @{ */
+ NSPoint m_Pos;
+ NSSize m_Size;
+ /** @} */
+
+ /** This is necessary for clipping on the root window */
+ NSRect m_RootRect;
+ float m_yInvRootOffset;
+
+#ifndef IN_VMSVGA3D
+ CR_BLITTER *m_pBlitter;
+ WindowInfo *m_pWinInfo;
+#endif
+ bool m_fNeedViewportUpdate;
+ bool m_fNeedCtxUpdate;
+ bool m_fDataVisible;
+ bool m_fCleanupNeeded;
+ bool m_fEverSized;
+}
+- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo
+ fVisParams:(GLbitfield) fVisParams;
+- (void)setGLCtx:(NSOpenGLContext*)pCtx;
+- (NSOpenGLContext *)glCtx;
+
+- (void)setParentView: (NSView *)view;
+- (NSView *)parentView;
+- (void)setOverlayWin: (NSWindow *)win;
+- (NSWindow *)overlayWin;
+
+- (void)vboxSetPos:(NSPoint)pos;
+- (void)vboxSetPosUI:(NSPoint)pos;
+- (void)vboxSetPosUIObj:(NSValue *)pPos;
+- (NSPoint)pos;
+- (bool)isEverSized;
+- (void)vboxDestroy;
+- (void)vboxSetSizeUI:(NSSize)size;
+- (void)vboxSetSizeUIObj:(NSValue *)pSize;
+- (void)vboxSetSize:(NSSize)size;
+- (NSSize)size;
+- (void)updateViewportCS;
+#ifdef VBOX_WITH_CONFIGURABLE_HIDPI_SCALING
+- (NSRect)safeConvertRectToBacking:(NSRect *)pRect;
+- (CGFloat)safeGetBackingScaleFactor;
+#endif
+- (NSRect)safeConvertToScreen:(NSRect *)pRect;
+- (void)vboxReshapePerform;
+- (void)vboxReshapeOnResizePerform;
+- (void)vboxReshapeOnReparentPerform;
+
+#ifndef IN_VMSVGA3D
+- (void)createDockTile;
+- (void)deleteDockTile;
+#endif
+
+- (void)makeCurrentFBO;
+- (void)swapFBO;
+- (void)vboxSetVisible:(GLboolean)fVisible;
+- (void)vboxSetVisibleUIObj:(NSNumber *)pVisible;
+- (void)vboxSetVisibleUI:(GLboolean)fVisible;
+- (void)vboxTryDraw;
+- (void)vboxTryDrawUI;
+- (void)vboxReparent:(NSView *)pParentView;
+- (void)vboxReparentUI:(NSView *)pParentView;
+- (void)vboxPresent:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+- (void)vboxPresentCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+#ifndef IN_VMSVGA3D
+- (void)vboxPresentToDockTileCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+#endif
+- (void)vboxPresentToViewCS:(const VBOXVR_SCR_COMPOSITOR *)pCompositor;
+- (void)presentComposition:(const VBOXVR_SCR_COMPOSITOR_ENTRY *)pChangedEntry;
+#ifndef IN_VMSVGA3D
+- (void)vboxBlitterSyncWindow;
+#endif
+
+- (void)clearVisibleRegions;
+- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects;
+- (GLboolean)vboxNeedsEmptyPresent;
+
+#ifndef IN_VMSVGA3D
+- (NSView *)dockTileScreen;
+- (void)reshapeDockTile;
+#endif
+- (void)cleanupData;
+@end
+
+/**
+ * Helper view.
+ *
+ * This view is added as a sub view of the parent view to track
+ * main window changes. Whenever the main window is changed
+ * (which happens on fullscreen/seamless entry/exit) the overlay
+ * window is informed & can add them self as a child window
+ * again.
+ */
+@class OverlayWindow;
+@interface OverlayHelperView: NSView
+{
+@private
+ OverlayWindow *m_pOverlayWindow;
+}
+-(id)initWithOverlayWindow:(NSRect)frame overlayWindow:(OverlayWindow *)pOverlayWindow;
+@end
+
+/**
+ * Custom window class.
+ *
+ * This is the overlay window which contains our custom NSView.
+ * Its a direct child of the Qt Main window. It marks its background
+ * transparent & non opaque to make clipping possible. It also disable mouse
+ * events and handle frame change events of the parent view.
+ */
+@interface OverlayWindow : NSWindow
+{
+@private
+ NSView *m_pParentView;
+ OverlayView *m_pOverlayView;
+ OverlayHelperView *m_pOverlayHelperView;
+ NSThread *m_Thread;
+}
+- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView;
+- (void)parentWindowFrameChanged:(NSNotification *)note;
+- (void)parentWindowChanged:(NSWindow *)pWindow;
+@end
+
+
+#ifndef IN_VMSVGA3D
+/**
+ * Dock overlay view class.
+ */
+@interface DockOverlayView: NSView
+{
+ NSBitmapImageRep *m_ThumbBitmap;
+ NSImage *m_ThumbImage;
+ NSLock *m_Lock;
+}
+- (void)dealloc;
+- (void)cleanup;
+- (void)lock;
+- (void)unlock;
+- (void)setFrame:(NSRect)frame;
+- (void)drawRect:(NSRect)aRect;
+- (NSBitmapImageRep *)thumbBitmap;
+- (NSImage *)thumbImage;
+@end
+
+@implementation DockOverlayView
+- (id)init
+{
+ DEBUG_FUNC_ENTER();
+ self = [super init];
+ if (self)
+ {
+ /*
+ * We need a lock cause the thumb image could be accessed from the main
+ * thread when someone is calling display on the dock tile & from the
+ * OpenGL thread when the thumbnail is updated.
+ */
+ m_Lock = [[NSLock alloc] init];
+ }
+
+ DEBUG_FUNC_LEAVE();
+
+ return self;
+}
+
+- (void)dealloc
+{
+ DEBUG_FUNC_ENTER();
+
+ [self cleanup];
+ [m_Lock release];
+
+ [super dealloc];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)cleanup
+{
+ DEBUG_FUNC_ENTER();
+
+ if (m_ThumbImage != nil)
+ {
+ [m_ThumbImage release];
+ m_ThumbImage = nil;
+ }
+
+ if (m_ThumbBitmap != nil)
+ {
+ [m_ThumbBitmap release];
+ m_ThumbBitmap = nil;
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)lock
+{
+ DEBUG_FUNC_ENTER();
+ [m_Lock lock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)unlock
+{
+ DEBUG_FUNC_ENTER();
+ [m_Lock unlock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)setFrame:(NSRect)frame
+{
+ DEBUG_FUNC_ENTER();
+ [super setFrame:frame];
+
+ [self lock];
+ [self cleanup];
+
+ if ( frame.size.width > 0
+ && frame.size.height > 0)
+ {
+ /* Create a buffer for our thumbnail image. Its in the size of this view. */
+ m_ThumbBitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
+ pixelsWide:frame.size.width
+ pixelsHigh:frame.size.height
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bitmapFormat:NSAlphaFirstBitmapFormat
+ bytesPerRow:frame.size.width * 4
+ bitsPerPixel:8 * 4
+ ];
+ m_ThumbImage = [[NSImage alloc] initWithSize:[m_ThumbBitmap size]];
+ [m_ThumbImage addRepresentation:m_ThumbBitmap];
+ }
+
+ [self unlock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (BOOL)isFlipped
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+ return YES;
+}
+
+- (void)drawRect:(NSRect)aRect
+{
+ NSRect frame;
+ DEBUG_FUNC_ENTER();
+ [self lock];
+
+#ifdef SHOW_WINDOW_BACKGROUND
+ [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7] set];
+ frame = [self frame];
+ [NSBezierPath fillRect:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
+#endif /* SHOW_WINDOW_BACKGROUND */
+ if (m_ThumbImage != nil)
+ [m_ThumbImage drawAtPoint:NSMakePoint(0, 0) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
+
+ [self unlock];
+ DEBUG_FUNC_LEAVE();
+}
+
+- (NSBitmapImageRep *)thumbBitmap
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+ return m_ThumbBitmap;
+}
+
+- (NSImage *)thumbImage
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+ return m_ThumbImage;
+}
+@end
+#endif /* !IN_VMSVGA3D */
+
+
+/********************************************************************************
+*
+* OverlayOpenGLContext class implementation
+*
+********************************************************************************/
+@implementation OverlayOpenGLContext
+
+-(id)initWithFormat:(NSOpenGLPixelFormat *)format shareContext:(NSOpenGLContext *)share
+{
+ DEBUG_FUNC_ENTER();
+
+ m_pPixelFormat = NULL;
+ m_pView = NULL;
+
+ self = [super initWithFormat:format shareContext:share];
+ Assert(self != nil);
+ if (self)
+ m_pPixelFormat = format;
+
+ DEBUG_MSG(("OCTX(%p): init OverlayOpenGLContext\n", (void *)self));
+ DEBUG_FUNC_LEAVE();
+ return self;
+}
+
+- (void)dealloc
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OCTX(%p): dealloc OverlayOpenGLContext\n", (void *)self));
+
+ [m_pPixelFormat release];
+
+ [super dealloc];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+-(bool)isDoubleBuffer
+{
+ DEBUG_FUNC_ENTER();
+
+ GLint val;
+ [m_pPixelFormat getValues:&val forAttribute:NSOpenGLPFADoubleBuffer forVirtualScreen:0];
+
+ DEBUG_FUNC_LEAVE();
+ return val == GL_TRUE ? YES : NO;
+}
+
+-(void)setView:(NSView *)view
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OCTX(%p): setView: new view: %p\n", (void *)self, (void *)view));
+
+#if 1 /* def FBO */
+ m_pView = view;;
+#else
+ [super setView: view];
+#endif
+
+ DEBUG_FUNC_LEAVE();
+}
+
+-(NSView *)view
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+#if 1 /* def FBO */
+ return m_pView;
+#else
+ return [super view];
+#endif
+}
+
+-(void)clearDrawable
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OCTX(%p): clearDrawable\n", (void *)self));
+
+ m_pView = NULL;;
+ [super clearDrawable];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+-(NSOpenGLPixelFormat *)openGLPixelFormat
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_FUNC_LEAVE();
+
+ return m_pPixelFormat;
+}
+
+@end /* @implementation OverlayOpenGLContext */
+
+
+/********************************************************************************
+*
+* OverlayHelperView class implementation
+*
+********************************************************************************/
+@implementation OverlayHelperView
+
+-(id)initWithOverlayWindow:(NSRect)frame overlayWindow:(OverlayWindow *)pOverlayWindow
+{
+ DEBUG_FUNC_ENTER();
+
+ self = [super initWithFrame:frame];
+#ifdef IN_VMSVGA3D
+ self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
+#endif
+
+ m_pOverlayWindow = pOverlayWindow;
+
+ DEBUG_MSG(("OHVW(%p): init OverlayHelperView\n", (void *)self));
+ DEBUG_FUNC_LEAVE();
+ return self;
+}
+
+-(void)viewDidMoveToWindow
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OHVW(%p): viewDidMoveToWindow: new win: %p\n", (void *)self, (void *)[self window]));
+
+ [m_pOverlayWindow parentWindowChanged:[self window]];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+@end
+
+
+/********************************************************************************
+*
+* OverlayWindow class implementation
+*
+********************************************************************************/
+@implementation OverlayWindow
+
+- (id)initWithParentView:(NSView *)pParentView overlayView:(OverlayView *)pOverlayView
+{
+ DEBUG_FUNC_ENTER();
+ NSWindow *pParentWin = nil;
+
+ self = [super initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
+ if (self)
+ {
+ m_pParentView = pParentView;
+ m_pOverlayView = pOverlayView;
+ m_Thread = [NSThread currentThread];
+
+ [m_pOverlayView setOverlayWin: self];
+
+#ifdef IN_VMSVGA3D
+ NSRect frame = [pParentView frame];
+ frame.origin.x = frame.origin.x = 0;
+ m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:frame
+ overlayWindow:self];
+#else
+ m_pOverlayHelperView = [[OverlayHelperView alloc] initWithOverlayWindow:NSZeroRect
+ overlayWindow:self];
+#endif
+
+ /* Add the helper view as a child of the parent view to get notifications */
+ [pParentView addSubview:m_pOverlayHelperView];
+
+ /* Make sure this window is transparent */
+#ifdef SHOW_WINDOW_BACKGROUND
+ /* For debugging */
+ [self setBackgroundColor:[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:0.7]];
+#else
+ [self setBackgroundColor:[NSColor clearColor]];
+#endif
+ [self setOpaque:NO];
+ [self setAlphaValue:.999];
+
+ /* Disable mouse events for this window */
+ [self setIgnoresMouseEvents:YES];
+
+ pParentWin = [m_pParentView window];
+
+ /* Initial set the position to the parents view top/left (Compiz fix). */
+ [self setFrameOrigin:
+ [pParentWin convertBaseToScreen:
+ [m_pParentView convertPoint:NSZeroPoint toView:nil]]];
+
+ /* Set the overlay view as our content view */
+ [self setContentView:m_pOverlayView];
+
+ /* Add ourself as a child to the parent views window. Note: this has to
+ * be done last so that everything else is setup in
+ * parentWindowChanged. */
+ [pParentWin addChildWindow:self ordered:NSWindowAbove];
+ }
+
+ DEBUG_MSG(("OWIN(%p): init OverlayWindow\n", (void *)self));
+ DEBUG_FUNC_LEAVE();
+ return self;
+}
+
+- (void)dealloc
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OWIN(%p): dealloc OverlayWindow\n", (void *)self));
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [m_pOverlayHelperView removeFromSuperview];
+ [m_pOverlayHelperView release];
+
+ [super dealloc];
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)parentWindowFrameChanged:(NSNotification *)pNote
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OWIN(%p): parentWindowFrameChanged\n", (void *)self));
+
+ /*
+ * Reposition this window with the help of the OverlayView. Perform the
+ * call in the OpenGL thread.
+ */
+ /*
+ [m_pOverlayView performSelector:@selector(vboxReshapePerform) onThread:m_Thread withObject:nil waitUntilDone:YES];
+ */
+
+ if ([m_pOverlayView isEverSized])
+ {
+ if ([NSThread isMainThread])
+ [m_pOverlayView vboxReshapePerform];
+ else
+ [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+- (void)parentWindowChanged:(NSWindow *)pWindow
+{
+ DEBUG_FUNC_ENTER();
+ DEBUG_MSG(("OWIN(%p): parentWindowChanged\n", (void *)self));
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ if (pWindow != nil)
+ {
+ /* Ask to get notifications when our parent window frame changes. */
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(parentWindowFrameChanged:)
+ name:NSWindowDidResizeNotification
+ object:pWindow];
+
+ /* Add us self as child window */
+ [pWindow addChildWindow:self ordered:NSWindowAbove];
+
+ /*
+ * Reshape the overlay view after a short waiting time to let the main
+ * window resize itself properly.
+ */
+ /*
+ [m_pOverlayView performSelector:@selector(vboxReshapePerform) withObject:nil afterDelay:0.2];
+ [NSTimer scheduledTimerWithTimeInterval:0.2 target:m_pOverlayView selector:@selector(vboxReshapePerform) userInfo:nil repeats:NO];
+ */
+
+ if ([m_pOverlayView isEverSized])
+ {
+ if ([NSThread isMainThread])
+ [m_pOverlayView vboxReshapePerform];
+ else
+ [self performSelectorOnMainThread:@selector(vboxReshapePerform) withObject:nil waitUntilDone:NO];
+ }
+ }
+
+ DEBUG_FUNC_LEAVE();
+}
+
+@end /* @implementation OverlayWindow */
+
+
+
+/********************************************************************************
+*
+* OverlayView class implementation
+*
+********************************************************************************/
+@implementation OverlayView
+
+- (id)initWithFrame:(NSRect)frame thread:(RTTHREAD)aThread parentView:(NSView *)pParentView winInfo:(WindowInfo *)pWinInfo
+ fVisParams:(GLbitfield) fVisParams
+{
+ COCOA_LOG_FLOW(("%s: self=%p aThread=%p pParentView=%p pWinInfo=%p fVisParams=%#x\n", __PRETTY_FUNCTION__, (void *)self,
+ (void *)aThread, (void *)pParentView, (void *)pWinInfo, fVisParams));
+
+ m_pParentView = pParentView;
+ /* Make some reasonable defaults */
+ m_pGLCtx = nil;
+ m_pSharedGLCtx = nil;
+ m_Thread = aThread;
+ m_FBOId = 0;
+ m_cClipRects = 0;
+ m_paClipRects = NULL;
+ m_Pos = NSZeroPoint;
+ m_Size = NSMakeSize(1, 1);
+ m_RootRect = NSMakeRect(0, 0, m_Size.width, m_Size.height);
+ m_yInvRootOffset = 0;
+#ifndef IN_VMSVGA3D
+ m_pBlitter = nil;
+ m_pWinInfo = pWinInfo;
+#endif
+ m_fNeedViewportUpdate = true;
+ m_fNeedCtxUpdate = true;
+ m_fDataVisible = false;
+ m_fCleanupNeeded = false;
+ m_fEverSized = false;
+
+ self = [super initWithFrame:frame];
+#if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
+ /* Always allocate HiDPI-ready backing store for NSView, so we will be able change HiDPI scaling option in runtime. */
+ crDebug("HiDPI: Allocate big backing store for NSView. Up-scaling is currently %s.", render_spu.fUnscaledHiDPI ? "OFF" : "ON");
+ [self performSelector:@selector(setWantsBestResolutionOpenGLSurface:) withObject: (id)YES];
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ return self;
+}
+
+- (void)cleanupData
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+#ifndef IN_VMSVGA3D
+ [self deleteDockTile];
+#endif
+
+ [self setGLCtx:nil];
+
+ if (m_pSharedGLCtx)
+ {
+ if ([m_pSharedGLCtx view] == self)
+ [m_pSharedGLCtx clearDrawable];
+
+ [m_pSharedGLCtx release];
+ m_pSharedGLCtx = nil;
+
+
+#ifndef IN_VMSVGA3D
+ CrBltTerm(m_pBlitter);
+ RTMemFree(m_pBlitter);
+ m_pBlitter = nil;
+#endif
+ }
+
+ [self clearVisibleRegions];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)dealloc
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ [self cleanupData];
+ [super dealloc];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)drawRect:(NSRect)aRect
+{
+ COCOA_LOG_FLOW(("%s: self=%p aRect=%d,%d %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)aRect.origin.x, (int)aRect.origin.y,
+ (int)aRect.size.width, (int)aRect.size.height));
+
+ [self vboxTryDrawUI];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)setGLCtx:(NSOpenGLContext *)pCtx
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCtx=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCtx, m_pGLCtx));
+
+ /*
+ * Only do something if the context changes.
+ */
+ if (m_pGLCtx != pCtx)
+ {
+ /* Ensure the context drawable is cleared to avoid holding a reference to inexistent view. */
+ if (m_pGLCtx)
+ {
+#ifdef IN_VMSVGA3D
+ Assert(!pCtx);
+#endif
+ [m_pGLCtx clearDrawable];
+ [m_pGLCtx release];
+ /*[m_pGLCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
+ }
+
+ m_pGLCtx = pCtx;
+ if (pCtx)
+ [pCtx retain];
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSOpenGLContext *)glCtx
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
+ return m_pGLCtx;
+}
+
+- (NSView *)parentView
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pParentView));
+ return m_pParentView;
+}
+
+- (void)setParentView:(NSView *)pView
+{
+ COCOA_LOG_FLOW(("%s: self=%p pView=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pView, m_pParentView));
+
+ m_pParentView = pView;
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)setOverlayWin:(NSWindow *)pWin
+{
+ COCOA_LOG_FLOW(("%s: self=%p pWin=%p (old=%p)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pWin, m_pOverlayWin));
+
+ m_pOverlayWin = pWin;
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSWindow *)overlayWin
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pOverlayWin));
+ return m_pOverlayWin;
+}
+
+- (void)vboxSetPosUI:(NSPoint)pos
+{
+ COCOA_LOG_FLOW(("%s: self=%p pos=%d,%d (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (int)pos.x, (int)pos.y,
+ (int)m_Pos.x, (int)m_Pos.y));
+
+ DEBUG_MSG(("vboxSetPosUI: [%d, %d].\n", (int)pos.x, (int)pos.y));
+
+ m_Pos = pos;
+
+ if (m_fEverSized)
+ [self vboxReshapePerform];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetPosUIObj:(NSValue *)pPos
+{
+ COCOA_LOG_FLOW(("%s: self=%p pPos=%p (%d,%d) (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, pPos,
+ (int)[pPos pointValue].x, (int)[pPos pointValue].y, (int)m_Pos.x, (int)m_Pos.y));
+
+ NSPoint pos = [pPos pointValue];
+ [self vboxSetPosUI:pos];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetPos:(NSPoint)pos
+{
+ COCOA_LOG_FLOW(("%s: self=%p pos=%d,%d (old pos=%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (int)pos.x, (int)pos.y,
+ (int)m_Pos.x, (int)m_Pos.y));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ NSValue *pPos = [NSValue valueWithPoint:pos];
+ [pRunner addObj:self selector:@selector(vboxSetPosUIObj:) arg:pPos];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSPoint)pos
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)m_Pos.x, (int)m_Pos.y));
+ return m_Pos;
+}
+
+- (bool)isEverSized
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %d\n", __PRETTY_FUNCTION__, (void *)self, m_fEverSized));
+ return m_fEverSized;
+}
+
+- (void)vboxDestroy
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ BOOL fIsMain = [NSThread isMainThread];
+ NSWindow *pWin = nil;
+
+ Assert(fIsMain);
+
+ /* Hide the view early. */
+ [self setHidden: YES];
+
+ pWin = [self window];
+ [[NSNotificationCenter defaultCenter] removeObserver:pWin];
+ [pWin setContentView: nil];
+ [[pWin parentWindow] removeChildWindow: pWin];
+
+ if (fIsMain)
+ [pWin release];
+ else
+ {
+ /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
+ caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
+ and main hgcm thread waiting for us, this is why use waitUntilDone:NO,
+ which should cause no harm. */
+ [pWin performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
+ }
+
+ [self cleanupData];
+
+ if (fIsMain)
+ [self release];
+ else
+ {
+ /* We can NOT run synchronously with the main thread since this may lead to a deadlock,
+ caused by main thread waiting xpcom thread, xpcom thread waiting to main hgcm thread,
+ and main hgcm thread waiting for us, this is why use waitUntilDone:NO.
+ We need to avoid concurrency though, so we cleanup some data right away via a cleanupData call. */
+ [self performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
+ }
+
+#ifndef IN_VMSVGA3D
+ renderspuWinRelease(m_pWinInfo);
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetSizeUIObj:(NSValue *)pSize
+{
+ COCOA_LOG_FLOW(("%s: self=%p pSize=%p (%d,%d)\n", __PRETTY_FUNCTION__, (void *)self, (void *)pSize,
+ (int)[pSize sizeValue].width, (int)[pSize sizeValue].height));
+
+ NSSize size = [pSize sizeValue];
+ [self vboxSetSizeUI:size];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetSizeUI:(NSSize)size
+{
+ COCOA_LOG_FLOW(("%s: self=%p size=%d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)size.width, (int)size.height));
+
+ m_Size = size;
+ m_fEverSized = true;
+
+ DEBUG_MSG(("OVIW(%p): vboxSetSize: new size: %dx%d\n", (void *)self, (int)m_Size.width, (int)m_Size.height));
+ [self vboxReshapeOnResizePerform];
+
+ /* ensure window contents is updated after that */
+ [self vboxTryDrawUI];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetSize:(NSSize)size
+{
+ COCOA_LOG_FLOW(("%s: self=%p size=%d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)size.width, (int)size.height));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ NSValue *pSize = [NSValue valueWithSize:size];
+ [pRunner addObj:self selector:@selector(vboxSetSizeUIObj:) arg:pSize];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (NSSize)size
+{
+ COCOA_LOG_FLOW(("%s: self=%p returns %d,%d\n", __PRETTY_FUNCTION__, (void *)self, (int)m_Size.width, (int)m_Size.height));
+ return m_Size;
+}
+
+- (void)updateViewportCS
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ /* Update the viewport for our OpenGL view. */
+ [m_pSharedGLCtx update];
+
+#ifndef IN_VMSVGA3D
+ [self vboxBlitterSyncWindow];
+#endif
+
+ /* Clear background to transparent. */
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReshapeOnResizePerform
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ [self vboxReshapePerform];
+#ifndef IN_VMSVGA3D
+ [self createDockTile];
+#endif
+
+ /* have to rebind GL_TEXTURE_RECTANGLE_ARB as m_FBOTexId could be changed in updateFBO call */
+ m_fNeedViewportUpdate = true;
+#if 0
+ pCurCtx = [NSOpenGLContext currentContext];
+ if (pCurCtx && pCurCtx == m_pGLCtx && (pCurView = [pCurCtx view]) == self)
+ {
+ [m_pGLCtx update];
+ m_fNeedCtxUpdate = false;
+ }
+ else
+ {
+ /* do it in a lazy way */
+ m_fNeedCtxUpdate = true;
+ }
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReshapeOnReparentPerform
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ [self vboxReshapePerform];
+#ifndef IN_VMSVGA3D
+ [self createDockTile];
+#endif
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#ifdef VBOX_WITH_CONFIGURABLE_HIDPI_SCALING
+- (NSRect)safeConvertRectToBacking:(NSRect *)pRect
+{
+ NSRect resultingRect = NSZeroRect;
+
+ NSWindow *pWindow = [m_pParentView window];
+ if (pWindow)
+ {
+ if ([pWindow respondsToSelector:@selector(convertRectToBacking:)])
+ {
+ NSMethodSignature *pSignature = [pWindow methodSignatureForSelector:@selector(convertRectToBacking:)];
+ if (pSignature)
+ {
+ NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
+ if (pInvocation)
+ {
+ [pInvocation setSelector:@selector(convertRectToBacking:)];
+ [pInvocation setTarget:pWindow];
+ [pInvocation setArgument:pRect atIndex:2];
+ [pInvocation invoke];
+ [pInvocation getReturnValue:&resultingRect];
+
+ DEBUG_MSG(("safeConvertRectToBacking: convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+ }
+ }
+ }
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeConvertRectToBacking: parent widget has no window.\n"));
+
+ resultingRect = *pRect;
+
+ DEBUG_MSG(("safeConvertRectToBacking (reurn as is): convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+}
+
+
+- (CGFloat)safeGetBackingScaleFactor
+{
+ /* Assume its default value. */
+ CGFloat backingScaleFactor = 1.;
+
+ NSWindow *pWindow = [m_pParentView window];
+ if (pWindow)
+ {
+ NSScreen *pScreen = [pWindow screen];
+ if (pScreen)
+ {
+ if ([pScreen respondsToSelector:@selector(backingScaleFactor)])
+ {
+ NSMethodSignature *pSignature = [pScreen methodSignatureForSelector:@selector(backingScaleFactor)];
+ if (pSignature)
+ {
+ NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
+ if (pInvocation)
+ {
+ [pInvocation setSelector:@selector(backingScaleFactor)];
+ [pInvocation setTarget:pScreen];
+ [pInvocation invoke];
+ [pInvocation getReturnValue:&backingScaleFactor];
+
+ DEBUG_MSG(("safeGetBackingScaleFactor: %d\n", (int)backingScaleFactor));
+
+ return backingScaleFactor;
+ }
+ else
+ DEBUG_WARN(("safeGetBackingScaleFactor: unable to create invocation for backingScaleFactor method signature.\n"));
+ }
+ else
+ DEBUG_WARN(("safeGetBackingScaleFactor: unable to create method signature for backingScaleFactor selector.\n"));
+ }
+ else
+ DEBUG_WARN(("safeGetBackingScaleFactor: NSScreen does not respond to backingScaleFactor selector.\n"));
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeGetBackingScaleFactor: parent window has no screen.\n"));
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeGetBackingScaleFactor: parent widget has no window.\n"));
+
+ return backingScaleFactor;
+}
+
+#endif
+
+
+- (NSRect)safeConvertToScreen:(NSRect *)pRect
+{
+ NSRect resultingRect = NSZeroRect;
+
+ NSWindow *pWindow = [m_pParentView window];
+ if (pWindow)
+ {
+ if ([pWindow respondsToSelector:@selector(convertRectToScreen:)])
+ {
+ NSMethodSignature *pSignature = [pWindow methodSignatureForSelector:@selector(convertRectToScreen:)];
+ if (pSignature)
+ {
+ NSInvocation *pInvocation = [NSInvocation invocationWithMethodSignature:pSignature];
+ if (pInvocation)
+ {
+ [pInvocation setSelector:@selector(convertRectToScreen:)];
+ [pInvocation setTarget:pWindow];
+ [pInvocation setArgument:pRect atIndex:2];
+ [pInvocation invoke];
+ [pInvocation getReturnValue:&resultingRect];
+
+ DEBUG_MSG(("safeConvertToScreen: convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+ }
+ }
+ }
+
+ /* If we failed, let's use deprecated @selector(convertBaseToScreen:). It is a bit hacky,
+ * but what to do if we stick to SDK 10.6. */
+ resultingRect.origin = [[m_pParentView window] convertBaseToScreen:pRect->origin];
+ resultingRect.size = pRect->size;
+ }
+ else
+ /* Should never happen. */
+ DEBUG_WARN(("safeConvertToScreen: parent widget has no window.\n"));
+
+ DEBUG_MSG(("safeConvertToScreen (deprecated method): convert [X, Y, WxH]: [%d, %d, %dx%d] -> [%d, %d, %dx%d]\n",
+ (int)pRect ->origin.x, (int)pRect ->origin.y, (int)pRect ->size.width, (int)pRect ->size.width,
+ (int)resultingRect.origin.x, (int)resultingRect.origin.y, (int)resultingRect.size.width, (int)resultingRect.size.width));
+
+ return resultingRect;
+}
+
+- (void)vboxReshapePerform
+{
+#ifndef IN_VMSVGA3D
+ COCOA_LOG_FLOW(("%s: self=%p - m_DockTileView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_DockTileView));
+#else
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+#endif
+
+ /* NOTE: Please consider the next naming convention for variables.
+ *
+ * Rectangle variables:
+ *
+ * <object to represent><coordinate system>:
+ * <object to represent>:
+ * parentFrame - a frame of the parent container (NSView) object
+ * childFrame - a frame required to display guest content
+ * windowFrame - resulting window frame constructed as an intersection of parentFrame and childFrame
+ * <coordinate system>:
+ * VCS - View Coordinate System
+ * WCS - Window Coordinate System
+ * SCS - Screen Coordinate System
+ *
+ * The same convention applied to offset variables naming as well which are of format:
+ *
+ * <object to represent><coordinate><coordinate system>.
+ *
+ * https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CocoaDrawingGuide/Transforms/Transforms.html
+ */
+
+ NSRect parentFrameVCS, parentFrameWCS, parentFrameSCS;
+ NSRect childFrameWCS, childFrameSCS;
+ NSRect windowFrameSCS;
+
+ CGFloat childFrameXWCS, childFrameYWCS;
+
+ /* We need to construct a new window frame (windowFrameSCS) for entire NSWindow object in
+ * screen coordinates. In order to make 3D overlay window to do not overlap Cocoa and Qt GUI elements (titlebar,
+ * Qt statusbar, scroll bars etc) let's do the next. Get parent view visible area (parentFrameSCS) in (NS)Screen
+ * coordinates. Then get the area required to diaplay guest content (childFrameSCS) in (NS)Screen coordinates as well.
+ * The intersection of these two areas in screen coordinates will be a new frame for entire NSWindow object. */
+
+ parentFrameVCS = [m_pParentView frame];
+ parentFrameWCS = [m_pParentView convertRect:parentFrameVCS toView:nil];
+ parentFrameSCS = [self safeConvertToScreen:&parentFrameWCS];
+
+ /* Choose childFrame origin in a bit special way. Its pop-left corner should stick to its parent top-left corner. */
+ childFrameXWCS = parentFrameWCS.origin.x + m_Pos.x;
+ childFrameYWCS = parentFrameWCS.origin.y - m_Pos.y - (m_Size.height - parentFrameWCS.size.height);
+ childFrameWCS = NSMakeRect(childFrameXWCS, childFrameYWCS, m_Size.width, m_Size.height);
+ childFrameSCS = [self safeConvertToScreen:&childFrameWCS];
+
+ windowFrameSCS = NSIntersectionRect(parentFrameSCS, childFrameSCS);
+
+ DEBUG_MSG(("vboxReshapePerform: a new overlay frame [%d, %d, %dx%d] has been constructed from intersection of window frame "
+ "[%d, %d, %dx%d] and guest content rectangle [%d, %d, %dx%d]; m_Pos=[%d, %d], m_Size=%dx%d.\n",
+ (int)windowFrameSCS.origin.x, (int)windowFrameSCS.origin.y, (int)windowFrameSCS.size.width, (int)windowFrameSCS.size.width,
+ (int)parentFrameSCS.origin.x, (int)parentFrameSCS.origin.y, (int)parentFrameSCS.size.width, (int)parentFrameSCS.size.width,
+ (int)childFrameSCS .origin.x, (int)childFrameSCS .origin.y, (int)childFrameSCS .size.width, (int)childFrameSCS .size.width,
+ (int)m_Pos.x, (int)m_Pos.y, (int)m_Size.width, (int)m_Size.height));
+
+ /** @todo galitsyn: drop this!
+ * Later we have to correct the texture position in the case the window is
+ * out of the parents window frame. So save the shift values for later use. */
+ m_RootRect.origin.x = windowFrameSCS.origin.x - childFrameSCS.origin.x;
+ m_RootRect.origin.y = childFrameSCS.size.height + childFrameSCS.origin.y - (windowFrameSCS.size.height + windowFrameSCS.origin.y);
+ m_RootRect.size = windowFrameSCS.size;
+ m_yInvRootOffset = windowFrameSCS.origin.y - childFrameSCS.origin.y;
+
+ DEBUG_MSG(("vboxReshapePerform: [%#p]: m_RootRect pos[%d : %d] size[%d : %d]\n",
+ (void *)self, (int)m_RootRect.origin.x, (int)m_RootRect.origin.y, (int)m_RootRect.size.width, (int)m_RootRect.size.height));
+
+ /* Set the new frame. */
+ [[self window] setFrame:windowFrameSCS display:YES];
+
+#ifndef IN_VMSVGA3D
+ /* Inform the dock tile view as well. */
+ [self reshapeDockTile];
+#endif
+
+ /* Make sure the context is updated accordingly. */
+ /* [self updateViewport]; */
+ if (m_pSharedGLCtx)
+ {
+ VBOX_CR_RENDER_CTX_INFO CtxInfo;
+ vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
+
+ [self updateViewportCS];
+
+ vboxCtxLeave(&CtxInfo);
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#ifndef IN_VMSVGA3D
+
+- (void)createDockTile
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ NSView *pDockScreen = nil;
+
+ [self deleteDockTile];
+
+ /* Is there a dock tile preview enabled in the GUI? If so setup a
+ * additional thumbnail view for the dock tile. */
+ pDockScreen = [self dockTileScreen];
+ if (pDockScreen)
+ {
+ m_DockTileView = [[DockOverlayView alloc] init];
+ [self reshapeDockTile];
+ [pDockScreen addSubview:m_DockTileView];
+ }
+
+ COCOA_LOG_FLOW(("%s: returns - m_DockTileView\n", __PRETTY_FUNCTION__, (void *)m_DockTileView));
+}
+
+- (void)deleteDockTile
+{
+ COCOA_LOG_FLOW(("%s: self=%p - m_DockTileView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_DockTileView));
+
+ if (m_DockTileView != nil)
+ {
+ [m_DockTileView removeFromSuperview];
+ [m_DockTileView release];
+ m_DockTileView = nil;
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+- (void)makeCurrentFBO
+{
+ COCOA_LOG_FLOW(("%s: self=%p - m_pGLCtx=%p m_fNeedCtxUpdate=%d\n", __PRETTY_FUNCTION__, (void *)self,
+ (void *)m_pGLCtx, m_fNeedCtxUpdate));
+
+ if (m_pGLCtx)
+ {
+ NSOpenGLContext *pPrevCtx = [NSOpenGLContext currentContext];
+
+#ifdef IN_VMSVGA3D
+ /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
+ implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
+ if (pPrevCtx != nil)
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ glFlush();
+ DEBUG_CHECK_GL_ERROR("glFlush");
+ }
+#endif
+
+ if ([m_pGLCtx view] != self)
+ {
+#ifndef IN_VMSVGA3D
+ /* We change the active view, so flush first */
+ if (pPrevCtx != nil)
+ glFlush();
+#endif
+ DEBUG_CLEAR_GL_ERRORS();
+ [m_pGLCtx setView: self];
+ DEBUG_CHECK_GL_ERROR("setView");
+ }
+
+#if 0
+ if (pPrevCtx != m_pGLCtx)
+#endif
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ [m_pGLCtx makeCurrentContext];
+ DEBUG_CHECK_GL_ERROR("makeCurrentContext");
+ Assert([NSOpenGLContext currentContext] == m_pGLCtx);
+ Assert([m_pGLCtx view] == self);
+ }
+
+ if (m_fNeedCtxUpdate == true)
+ {
+ [m_pGLCtx update];
+ m_fNeedCtxUpdate = false;
+ }
+
+ if (!m_FBOId)
+ {
+ glGenFramebuffersEXT(1, &m_FBOId);
+ Assert(m_FBOId);
+ }
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (bool)vboxSharedCtxCreate
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ if (m_pSharedGLCtx)
+ {
+ COCOA_LOG_FLOW(("%s: returns true (m_pSharedGLCtx=%p)\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
+ return true;
+ }
+
+#ifndef IN_VMSVGA3D
+ Assert(!m_pBlitter);
+ m_pBlitter = RTMemAlloc(sizeof(*m_pBlitter));
+ if (RT_UNLIKELY(!m_pBlitter))
+ {
+ DEBUG_WARN(("m_pBlitter allocation failed"));
+ COCOA_LOG_FLOW(("%s: returns false - m_pBlitter allocation failed\n", __PRETTY_FUNCTION__));
+ return false;
+ }
+
+ int rc = CrBltInit(m_pBlitter, NULL, false /*fCreateNewCtx*/, false /*fForceDrawBlt*/,
+ &render_spu.GlobalShaders, &render_spu.blitterDispatch);
+ if (RT_FAILURE(rc))
+ {
+ DEBUG_WARN(("CrBltInit failed, rc %d", rc));
+ RTMemFree(m_pBlitter);
+ m_pBlitter = NULL;
+
+ COCOA_LOG_FLOW(("%s: returns false - CrBltInit failed with rc=%Rrc\n", __PRETTY_FUNCTION__, rc));
+ return false;
+ }
+
+ COCOA_LOG_FLOW(("%s: blitter (%p) created successfully for view 0x%p\n", (void *)m_pBlitter, (void *)self));
+#endif /* !IN_VMSVGA3D */
+
+ /* Create a shared context out of the main context. Use the same pixel format. */
+ NSOpenGLPixelFormat *pPixelFormat = [(OverlayOpenGLContext *)m_pGLCtx openGLPixelFormat];
+ NSOpenGLContext *pSharedGLCtx = [[NSOpenGLContext alloc] initWithFormat:pPixelFormat shareContext:m_pGLCtx];
+
+ /* Set the new context as non opaque */
+ GLint opaque = 0;
+ [pSharedGLCtx setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
+
+ /* Set this view as the drawable for the new context */
+ [pSharedGLCtx setView:self];
+ m_fNeedViewportUpdate = true;
+
+ m_pSharedGLCtx = pSharedGLCtx;
+
+ COCOA_LOG_FLOW(("%s: returns true - new m_pSharedGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)m_pSharedGLCtx));
+ return true;
+}
+
+- (void)vboxTryDraw
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ glFlush();
+
+ /* Issue to the gui thread. */
+ [self performSelectorOnMainThread:@selector(vboxTryDrawUI) withObject:nil waitUntilDone:NO];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetVisible:(GLboolean)fVisible
+{
+ COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ NSNumber *pVisObj = [NSNumber numberWithBool:fVisible];
+ [pRunner addObj:self selector:@selector(vboxSetVisibleUIObj:) arg:pVisObj];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetVisibleUI:(GLboolean)fVisible
+{
+ COCOA_LOG_FLOW(("%s: self=%p fVisible=%d\n", __PRETTY_FUNCTION__, (void *)self, fVisible));
+
+ [self setHidden: !fVisible];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxSetVisibleUIObj:(NSNumber *)pVisibleObj
+{
+ COCOA_LOG_FLOW(("%s: self=%p pVisibleObj=%p(%d)\n", __PRETTY_FUNCTION__,
+ (void *)self, (void *)pVisibleObj, [pVisibleObj boolValue]));
+
+ BOOL fVisible = [pVisibleObj boolValue];
+ [self vboxSetVisibleUI:fVisible];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReparent:(NSView *)pParentView
+{
+ COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner addObj:self selector:@selector(vboxReparentUI:) arg:pParentView];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxReparentUI:(NSView *)pParentView
+{
+ COCOA_LOG_FLOW(("%s: self=%p pParentView=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pParentView));
+
+ /* Make sure the window is removed from any previous parent window. */
+ if ([[self overlayWin] parentWindow] != nil)
+ {
+ [[[self overlayWin] parentWindow] removeChildWindow:[self overlayWin]];
+ }
+
+ /* Set the new parent view */
+ [self setParentView: pParentView];
+
+ /* Add the overlay window as a child to the new parent window */
+ if (pParentView != nil)
+ {
+ [[pParentView window] addChildWindow:[self overlayWin] ordered:NSWindowAbove];
+ if ([self isEverSized])
+ [self vboxReshapeOnReparentPerform];
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxTryDrawUI
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+
+ if ([self isHidden])
+ {
+ COCOA_LOG_FLOW(("%s: returns - request to draw on a hidden view\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+ if ([[self overlayWin] parentWindow] == nil)
+ {
+ COCOA_LOG_FLOW(("%s: returns - request to draw a view w/o a parent\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+#ifdef IN_VMSVGA3D
+ if (!m_pSharedGLCtx)
+ {
+ Assert(!m_fDataVisible);
+ Assert(!m_fCleanupNeeded);
+ if (![self vboxSharedCtxCreate])
+ {
+ COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
+ return;
+ }
+ Assert(m_pSharedGLCtx);
+ }
+#endif
+
+ const VBOXVR_SCR_COMPOSITOR *pCompositor = NULL;
+#ifndef IN_VMSVGA3D
+ int rc = renderspuVBoxCompositorLock(m_pWinInfo, &pCompositor);
+ if (RT_FAILURE(rc))
+ {
+ COCOA_LOG_FLOW(("%s: returns - renderspuVBoxCompositorLock failed (%Rrc)\n", __PRETTY_FUNCTION__, rc));
+ return;
+ }
+
+ if (!pCompositor && !m_fCleanupNeeded)
+ {
+ renderspuVBoxCompositorUnlock(m_pWinInfo);
+ COCOA_LOG_FLOW(("%s: returns - noCompositorUI\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+ VBOXVR_SCR_COMPOSITOR TmpCompositor;
+ if (pCompositor)
+ {
+ if (!m_pSharedGLCtx)
+ {
+ Assert(!m_fDataVisible);
+ Assert(!m_fCleanupNeeded);
+ renderspuVBoxCompositorRelease(m_pWinInfo);
+ if (![self vboxSharedCtxCreate])
+ {
+ COCOA_LOG_FLOW(("%s: returns - vboxSharedCtxCreate failed\n", __PRETTY_FUNCTION__));
+ return;
+ }
+
+ Assert(m_pSharedGLCtx);
+
+ pCompositor = renderspuVBoxCompositorAcquire(m_pWinInfo);
+ Assert(!m_fDataVisible);
+ Assert(!m_fCleanupNeeded);
+ if (!pCompositor)
+ {
+ COCOA_LOG_FLOW(("%s: returns - Failed to reacquire compositor\n", __PRETTY_FUNCTION__));
+ return;
+ }
+ }
+ }
+ else
+ {
+ DEBUG_MSG(("%s: NeedCleanup\n", __PRETTY_FUNCTION__));
+ Assert(m_fCleanupNeeded);
+ CrVrScrCompositorInit(&TmpCompositor, NULL);
+ pCompositor = &TmpCompositor;
+ }
+#endif /* !IN_VMSVGA3D */
+
+
+ if ([self lockFocusIfCanDraw])
+ {
+ COCOA_LOG_FLOW(("%s: Calling vboxPresent\n", __PRETTY_FUNCTION__));
+ [self vboxPresent:pCompositor];
+ [self unlockFocus];
+ }
+#ifndef IN_VMSVGA3D /** @todo VMSVGA3 */
+ else if (!m_pWinInfo->visible)
+ {
+ COCOA_LOG_FLOW(("%s: NotVisible\n", __PRETTY_FUNCTION__));
+ m_fCleanupNeeded = false;
+ }
+#endif
+ else
+ {
+ COCOA_LOG_FLOW(("%s: Reschedule\n", __PRETTY_FUNCTION__));
+ [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(vboxTryDrawUI) userInfo:nil repeats:NO];
+ }
+
+#ifndef IN_VMSVGA3D
+ renderspuVBoxCompositorUnlock(m_pWinInfo);
+#endif
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)swapFBO
+{
+ COCOA_LOG_FLOW(("%s: self=%p - m_pGLCtx=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)m_pGLCtx));
+ [m_pGLCtx flushBuffer];
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxPresent:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
+ /*DEBUG_MSG(("OVIW(%p): renderFBOToView\n", (void *)self));*/
+#ifndef IN_VMSVGA3D
+ AssertPtr(pCompositor);
+#endif
+
+ VBOX_CR_RENDER_CTX_INFO CtxInfo;
+ vboxCtxEnter(m_pSharedGLCtx, &CtxInfo);
+
+ [self vboxPresentCS:pCompositor];
+
+ vboxCtxLeave(&CtxInfo);
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)vboxPresentCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
+ if ([m_pSharedGLCtx view] != self)
+ {
+ COCOA_LOG_FLOW(("%s: Not current view of shared ctx! Switching... (self=%p, view=%p, m_pSharedGLCtx)\n",
+ __PRETTY_FUNCTION__, (void *)self, (void *)[m_pSharedGLCtx view], (void *)m_pSharedGLCtx));
+ [m_pSharedGLCtx setView: self];
+ m_fNeedViewportUpdate = true;
+ }
+
+ if (m_fNeedViewportUpdate)
+ {
+ [self updateViewportCS];
+ m_fNeedViewportUpdate = false;
+ }
+
+ m_fCleanupNeeded = false;
+
+#ifndef IN_VMSVGA3D
+ /* Render FBO content to the dock tile when necessary. */
+ [self vboxPresentToDockTileCS:pCompositor];
+#endif
+
+ /* change to #if 0 to see thumbnail image */
+#if 1
+ [self vboxPresentToViewCS:pCompositor];
+#else
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ [m_pSharedGLCtx flushBuffer];
+#endif
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+DECLINLINE(void) vboxNSRectToRect(const NSRect *pR, RTRECT *pRect)
+{
+ pRect->xLeft = (int)pR->origin.x;
+ pRect->yTop = (int)pR->origin.y;
+ pRect->xRight = (int)(pR->origin.x + pR->size.width);
+ pRect->yBottom = (int)(pR->origin.y + pR->size.height);
+}
+
+DECLINLINE(void) vboxNSRectToRectUnstretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
+{
+ pRect->xLeft = (int)(pR->origin.x / xStretch);
+ pRect->yTop = (int)(pR->origin.y / yStretch);
+ pRect->xRight = (int)((pR->origin.x + pR->size.width) / xStretch);
+ pRect->yBottom = (int)((pR->origin.y + pR->size.height) / yStretch);
+}
+
+DECLINLINE(void) vboxNSRectToRectStretched(const NSRect *pR, RTRECT *pRect, float xStretch, float yStretch)
+{
+ pRect->xLeft = (int)(pR->origin.x * xStretch);
+ pRect->yTop = (int)(pR->origin.y * yStretch);
+ pRect->xRight = (int)((pR->origin.x + pR->size.width) * xStretch);
+ pRect->yBottom = (int)((pR->origin.y + pR->size.height) * yStretch);
+}
+
+- (void)vboxPresentToViewCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ NSRect r = [self frame];
+ COCOA_LOG_FLOW(("%s: self=%p - r={%d,%d %d,%d}\n", __PRETTY_FUNCTION__, (void *)self,
+ (int)r.origin.x, (int)r.origin.y, (int)r.size.width, (int)r.size.height));
+
+#if 1 /* Set to 0 to see the docktile instead of the real output */
+ float backingStretchFactor = 1.;
+# if defined(VBOX_WITH_CONFIGURABLE_HIDPI_SCALING) && !defined(IN_VMSVGA3D)
+ /* Adjust viewport according to current NSView's backing store parameters. */
+ if (render_spu.fUnscaledHiDPI)
+ {
+ /* Update stretch factor in order to satisfy current NSView's backing store parameters. */
+ backingStretchFactor = [self safeGetBackingScaleFactor];
+ }
+
+ NSRect regularBounds = [self bounds];
+ NSRect backingBounds = [self safeConvertRectToBacking:&regularBounds];
+ glViewport(0, 0, backingBounds.size.width, backingBounds.size.height);
+
+ //crDebug("HiDPI: vboxPresentToViewCS: up-scaling is %s (backingStretchFactor=%d).",
+ // render_spu.fUnscaledHiDPI ? "OFF" : "ON", (int)backingStretchFactor);
+# endif
+
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glDrawBuffer(GL_BACK);
+
+ /* Clear background to transparent */
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ m_fDataVisible = false;
+
+# ifndef IN_VMSVGA3D
+ float xStretch;
+ float yStretch;
+ CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
+
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ const RTRECT *paSrcRegions, *paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrBltEnter(m_pBlitter);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = 0; i < cRegions; ++i)
+ {
+ const CR_TEXDATA *pTexData;
+ PCRTRECT pSrcRect = &paSrcRegions[i];
+ PCRTRECT pDstRect = &paDstRegions[i];
+ RTRECT DstRect, RestrictDstRect;
+ RTRECT SrcRect, RestrictSrcRect;
+
+ vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
+ VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
+
+ if (VBoxRectIsZero(&DstRect))
+ continue;
+
+ VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
+
+ vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch / backingStretchFactor, yStretch / backingStretchFactor);
+ VBoxRectTranslate(&RestrictSrcRect,
+ -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
+ -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
+ VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
+
+ if (VBoxRectIsZero(&SrcRect))
+ continue;
+
+ pSrcRect = &SrcRect;
+ pDstRect = &DstRect;
+
+ pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+
+ CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags | CRBLT_F_NOALPHA);
+
+ m_fDataVisible = true;
+ }
+ CrBltLeave(m_pBlitter);
+ }
+ else
+ {
+ DEBUG_WARN(("CrBltEnter failed rc %d", rc));
+# ifndef DEBUG_VERBOSE
+ AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
+# endif
+ }
+ }
+ else
+ {
+ AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
+ DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
+ }
+ }
+# endif /* !IN_VMSVGA3D */
+#endif
+
+ /*
+ glFinish();
+ */
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ [m_pSharedGLCtx flushBuffer];
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+- (void)presentComposition:(PCVBOXVR_SCR_COMPOSITOR_ENTRY)pChangedEntry
+{
+ COCOA_LOG_FLOW(("%s: self=%p pChangedEntry=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pChangedEntry));
+ [self vboxTryDraw];
+}
+
+#ifndef IN_VMSVGA3D
+- (void)vboxBlitterSyncWindow
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ CR_BLITTER_WINDOW WinInfo;
+ NSRect r;
+
+ if (!m_pBlitter)
+ return;
+
+ RT_ZERO(WinInfo);
+
+ r = [self frame];
+ WinInfo.width = r.size.width;
+ WinInfo.height = r.size.height;
+
+ Assert(WinInfo.width == m_RootRect.size.width);
+ Assert(WinInfo.height == m_RootRect.size.height);
+
+ /*CrBltMuralSetCurrentInfo(m_pBlitter, NULL);*/
+
+ CrBltMuralSetCurrentInfo(m_pBlitter, &WinInfo);
+ CrBltCheckUpdateViewport(m_pBlitter);
+}
+#endif /* !IN_VMSVGA3D */
+
+#ifndef IN_VMSVGA3D
+# ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
+static int g_cVBoxTgaCtr = 0;
+# endif
+- (void)vboxPresentToDockTileCS:(PCVBOXVR_SCR_COMPOSITOR)pCompositor
+{
+ COCOA_LOG_FLOW(("%s: self=%p pCompositor=%p\n", __PRETTY_FUNCTION__, (void *)self, (void *)pCompositor));
+ NSRect r = [self frame];
+ NSRect rr = NSZeroRect;
+ NSDockTile *pDT = nil;
+ float xStretch;
+ float yStretch;
+
+ if ([m_DockTileView thumbBitmap] != nil)
+ {
+ /*
+ * Only update after at least 200 ms, cause glReadPixels is
+ * heavy performance wise.
+ */
+ uint64_t msTS = RTTimeSystemMilliTS();
+ VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter;
+ const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry;
+
+ if (msTS - m_msDockUpdateTS > 200)
+ {
+ m_msDockUpdateTS = msTS;
+# if 0
+ /** @todo check this for optimization */
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_STORAGE_HINT_APPLE,
+ GL_STORAGE_SHARED_APPLE);
+ glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ sizex, sizey, 0, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, myImagePtr);
+ glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
+ 0, 0, 0, 0, 0, image_width, image_height);
+ glFlush();
+ /* Do other work processing here, using a double or triple buffer */
+ glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
+# endif
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
+ glDrawBuffer(GL_BACK);
+
+ /* Clear background to transparent */
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ rr = [m_DockTileView frame];
+
+ CrVrScrCompositorGetStretching(pCompositor, &xStretch, &yStretch);
+
+ CrVrScrCompositorConstIterInit(pCompositor, &CIter);
+ while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL)
+ {
+ uint32_t cRegions;
+ PCRTRECT paSrcRegions;
+ PCRTRECT paDstRegions;
+ int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRegions, &paSrcRegions, &paDstRegions, NULL);
+ uint32_t fFlags = CrVrScrCompositorEntryFlagsCombinedGet(pCompositor, pEntry);
+ if (RT_SUCCESS(rc))
+ {
+ rc = CrBltEnter(m_pBlitter);
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t i;
+ for (i = 0; i < cRegions; ++i)
+ {
+ const CR_TEXDATA *pTexData;
+ PCRTRECT pSrcRect = &paSrcRegions[i];
+ PCRTRECT pDstRect = &paDstRegions[i];
+ RTRECT DstRect, RestrictDstRect;
+ RTRECT SrcRect, RestrictSrcRect;
+
+ vboxNSRectToRect(&m_RootRect, &RestrictDstRect);
+ VBoxRectIntersected(&RestrictDstRect, pDstRect, &DstRect);
+
+ VBoxRectTranslate(&DstRect, -RestrictDstRect.xLeft, -RestrictDstRect.yTop);
+
+ VBoxRectScale(&DstRect, m_FBOThumbScaleX, m_FBOThumbScaleY);
+
+ if (VBoxRectIsZero(&DstRect))
+ continue;
+
+ vboxNSRectToRectUnstretched(&m_RootRect, &RestrictSrcRect, xStretch, yStretch);
+ VBoxRectTranslate(&RestrictSrcRect,
+ -CrVrScrCompositorEntryRectGet(pEntry)->xLeft,
+ -CrVrScrCompositorEntryRectGet(pEntry)->yTop);
+ VBoxRectIntersected(&RestrictSrcRect, pSrcRect, &SrcRect);
+
+ if (VBoxRectIsZero(&SrcRect))
+ continue;
+
+ pSrcRect = &SrcRect;
+ pDstRect = &DstRect;
+
+ pTexData = CrVrScrCompositorEntryTexGet(pEntry);
+
+ CrBltBlitTexMural(m_pBlitter, true, CrTdTexGet(pTexData), pSrcRect, pDstRect, 1, fFlags);
+ }
+ CrBltLeave(m_pBlitter);
+ }
+ else
+ {
+ DEBUG_WARN(("CrBltEnter failed rc %d", rc));
+# ifndef DEBUG_VERBOSE
+ AssertMsgFailed(("CrBltEnter failed rc %Rrc", rc));
+# endif
+ }
+ }
+ else
+ {
+ DEBUG_MSG_1(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %d\n", rc));
+ AssertMsgFailed(("BlitStretched: CrVrScrCompositorEntryRegionsGet failed rc %Rrc\n", rc));
+ }
+ }
+
+ glFinish();
+
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+ glReadBuffer(GL_BACK);
+
+ /* Here the magic of reading the FBO content in our own buffer
+ * happens. We have to lock this access, in the case the dock
+ * is updated currently. */
+ [m_DockTileView lock];
+ glReadPixels(0, m_RootRect.size.height - rr.size.height, rr.size.width, rr.size.height,
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8,
+ [[m_DockTileView thumbBitmap] bitmapData]);
+ [m_DockTileView unlock];
+
+# ifdef VBOX_WITH_CRDUMPER_THUMBNAIL
+ ++g_cVBoxTgaCtr;
+ crDumpNamedTGAF((GLint)rr.size.width, (GLint)rr.size.height,
+ [[m_DockTileView thumbBitmap] bitmapData], "/Users/leo/vboxdumps/dump%d.tga", g_cVBoxTgaCtr);
+# endif
+
+ pDT = [[NSApplication sharedApplication] dockTile];
+
+ /* Send a display message to the dock tile in the main thread */
+ [[[NSApplication sharedApplication] dockTile] performSelectorOnMainThread:@selector(display) withObject:nil
+ waitUntilDone:NO];
+ }
+ }
+}
+#endif /* !IN_VMSVGA3D */
+
+- (void)clearVisibleRegions
+{
+ if (m_paClipRects)
+ {
+ RTMemFree(m_paClipRects);
+ m_paClipRects = NULL;
+ }
+ m_cClipRects = 0;
+}
+
+- (GLboolean)vboxNeedsEmptyPresent
+{
+ if (m_fDataVisible)
+ {
+ m_fCleanupNeeded = true;
+ return GL_TRUE;
+ }
+
+ return GL_FALSE;
+}
+
+- (void)setVisibleRegions:(GLint)cRects paRects:(const GLint *)paRects
+{
+ COCOA_LOG_FLOW(("%s: self=%p cRects=%d paRects=%p\n", __PRETTY_FUNCTION__, (void *)self, cRects, (void *)paRects));
+ GLint cOldRects = m_cClipRects;
+
+ [self clearVisibleRegions];
+
+ if (cRects > 0)
+ {
+#ifdef DEBUG_poetzsch
+ int i = 0;
+ for (i = 0; i < cRects; ++i)
+ DEBUG_MSG_1(("OVIW(%p): setVisibleRegions: %d - %d %d %d %d\n", (void *)self, i, paRects[i * 4], paRects[i * 4 + 1], paRects[i * 4 + 2], paRects[i * 4 + 3]));
+#endif
+
+ m_paClipRects = (GLint *)RTMemDup(paRects, sizeof(GLint) * 4 * cRects);
+ m_cClipRects = cRects;
+ }
+
+ COCOA_LOG_FLOW(("%s: returns\n", __PRETTY_FUNCTION__));
+}
+
+#ifndef IN_VMSVGA3D
+
+- (NSView *)dockTileScreen
+{
+ COCOA_LOG_FLOW(("%s: self=%p\n", __PRETTY_FUNCTION__, (void *)self));
+ NSView *pContentView = [[[NSApplication sharedApplication] dockTile] contentView];
+ NSView *pScreenContent = nil;
+
+ /*
+ * First try the new variant which checks if this window is within the
+ * screen which is previewed in the dock.
+ */
+ if ([pContentView respondsToSelector:@selector(screenContentWithParentView:)])
+ pScreenContent = [pContentView performSelector:@selector(screenContentWithParentView:) withObject:(id)m_pParentView];
+ /*
+ * If it fails, fall back to the old variant (VBox...).
+ */
+ else if ([pContentView respondsToSelector:@selector(screenContent)])
+ pScreenContent = [pContentView performSelector:@selector(screenContent)];
+
+ COCOA_LOG_FLOW(("%s: returns %p (pContentView=%p)\n", __PRETTY_FUNCTION__, (void *)pScreenContent, (void *)pContentView));
+ return pScreenContent;
+}
+
+- (void)reshapeDockTile
+{
+ COCOA_LOG_FLOW(("%s:\n", __PRETTY_FUNCTION__));
+ NSRect newFrame = NSZeroRect;
+ NSView *pView = [self dockTileScreen];
+ if (pView != nil)
+ {
+ NSRect dockFrame = [pView frame];
+ /** @todo This is not correct, we should use framebuffer size here, while
+ * parent view frame size may differ in case of scrolling. */
+ NSRect parentFrame = [m_pParentView frame];
+
+ m_FBOThumbScaleX = (float)dockFrame.size.width / parentFrame.size.width;
+ m_FBOThumbScaleY = (float)dockFrame.size.height / parentFrame.size.height;
+ newFrame = NSMakeRect((int)(m_Pos.x * m_FBOThumbScaleX),
+ (int)(dockFrame.size.height - (m_Pos.y + m_Size.height - m_yInvRootOffset) * m_FBOThumbScaleY),
+ (int)(m_Size.width * m_FBOThumbScaleX),
+ (int)(m_Size.height * m_FBOThumbScaleY));
+ /*
+ NSRect newFrame = NSMakeRect ((int)roundf(m_Pos.x * m_FBOThumbScaleX), (int)roundf(dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (int)roundf(m_Size.width * m_FBOThumbScaleX), (int)roundf(m_Size.height * m_FBOThumbScaleY));
+ NSRect newFrame = NSMakeRect ((m_Pos.x * m_FBOThumbScaleX), (dockFrame.size.height - (m_Pos.y + m_Size.height) * m_FBOThumbScaleY), (m_Size.width * m_FBOThumbScaleX), (m_Size.height * m_FBOThumbScaleY));
+ printf ("%f %f %f %f - %f %f\n", newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height, m_Size.height, m_FBOThumbScaleY);
+ */
+ [m_DockTileView setFrame: newFrame];
+ }
+ COCOA_LOG_FLOW(("%s: returns - newFrame={%d,%d %d,%d} pView=%d\n", __PRETTY_FUNCTION__, (int)newFrame.origin.x,
+ (int)newFrame.origin.y, (int)newFrame.size.width, (int)newFrame.size.height, (void *)pView));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+@end /* @implementation OverlayView */
+
+
+/********************************************************************************
+*
+* OpenGL context management
+*
+********************************************************************************/
+void cocoaGLCtxCreate(NativeNSOpenGLContextRef *ppCtx, GLbitfield fVisParams, NativeNSOpenGLContextRef pSharedCtx)
+{
+ COCOA_LOG_FLOW(("cocoaGLCtxCreate: ppCtx=%p fVisParams=%#x pSharedCtx=%p\n", (void *)ppCtx, fVisParams, (void *)pSharedCtx));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ NSOpenGLPixelFormat *pFmt = vboxCreatePixelFormat(fVisParams);
+ if (pFmt)
+ {
+ *ppCtx = [[OverlayOpenGLContext alloc] initWithFormat:pFmt shareContext:pSharedCtx];
+ Assert(*ppCtx);
+
+ /* Enable multi threaded OpenGL engine */
+ /*
+ CGLContextObj cglCtx = [*ppCtx CGLContextObj];
+ CGLError err = CGLEnable(cglCtx, kCGLCEMPEngine);
+ if (err != kCGLNoError)
+ printf ("Couldn't enable MT OpenGL engine!\n");
+ */
+ }
+ else
+ {
+ AssertFailed();
+ *ppCtx = NULL;
+ }
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaGLCtxCreate: returns *ppCtx=%p\n", (void *)*ppCtx));
+}
+
+void cocoaGLCtxDestroy(NativeNSOpenGLContextRef pCtx)
+{
+ COCOA_LOG_FLOW(("cocoaGLCtxDestroy: pCtx=%p\n", (void *)pCtx));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [pCtx release];
+ /*[pCtx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];*/
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaGLCtxDestroy: returns\n"));
+}
+
+/********************************************************************************
+*
+* View management
+*
+********************************************************************************/
+static OverlayView *vboxViewCreate(WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
+{
+ COCOA_LOG_FLOW(("vboxViewCreate: pWinInfo=%p pParentView=%p fVisParams=%#x\n", pWinInfo, (void *)pParentView, fVisParams));
+
+ /* Create our worker view. */
+ OverlayView *pView = [[OverlayView alloc] initWithFrame:NSZeroRect
+ thread:RTThreadSelf()
+ parentView:pParentView
+ winInfo:pWinInfo
+ fVisParams:fVisParams];
+
+ if (pView)
+ {
+ /* We need a real window as container for the view */
+ [[OverlayWindow alloc] initWithParentView:pParentView overlayView:pView];
+ /* Return the freshly created overlay view */
+ COCOA_LOG_FLOW(("vboxViewCreate: returns %p\n", (void *)pView));
+ return pView;
+ }
+
+ COCOA_LOG_FLOW(("vboxViewCreate: returns NULL\n"));
+ return NULL;
+}
+
+#ifndef IN_VMSVGA3D
+
+typedef struct CR_RCD_CREATEVIEW
+{
+ WindowInfo *pWinInfo;
+ NSView *pParentView;
+ GLbitfield fVisParams;
+ /* out */
+ OverlayView *pView;
+} CR_RCD_CREATEVIEW;
+
+static DECLCALLBACK(void) vboxRcdCreateView(void *pvCb)
+{
+ CR_RCD_CREATEVIEW *pCreateView = (CR_RCD_CREATEVIEW *)pvCb;
+ pCreateView->pView = vboxViewCreate(pCreateView->pWinInfo, pCreateView->pParentView, pCreateView->fVisParams);
+ COCOA_LOG_FLOW(("vboxRcdCreateView: returns pView=%p\n", (void *)pCreateView->pView));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+void cocoaViewCreate(NativeNSViewRef *ppView, WindowInfo *pWinInfo, NativeNSViewRef pParentView, GLbitfield fVisParams)
+{
+ COCOA_LOG_FLOW(("cocoaViewCreate: ppView=%p pWinInfo=%p pParentView=%p fVisParams=%#x\n",
+ (void *)ppView, (void *)pWinInfo, (void *)pParentView, fVisParams));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ /* make sure all tasks are run, to preserve the order */
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner runTasksSyncIfPossible];
+
+#ifndef IN_VMSVGA3D
+ renderspuWinRetain(pWinInfo);
+
+ if (renderspuCalloutAvailable())
+ {
+ CR_RCD_CREATEVIEW CreateView;
+ CreateView.pWinInfo = pWinInfo;
+ CreateView.pParentView = pParentView;
+ CreateView.fVisParams = fVisParams;
+ CreateView.pView = NULL;
+ renderspuCalloutClient(vboxRcdCreateView, &CreateView);
+ *ppView = CreateView.pView;
+ }
+ else
+#endif
+ {
+ DEBUG_MSG_NOT_VMSVGA3D(("no callout available on createWindow\n"));
+#if 0
+ dispatch_sync(dispatch_get_main_queue(), ^{
+#endif
+ *ppView = vboxViewCreate(pWinInfo, pParentView, fVisParams);
+#if 0
+ });
+#endif
+ }
+
+#ifndef IN_VMSVGA3D
+ if (!*ppView)
+ renderspuWinRelease(pWinInfo);
+#endif
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewCreate: returns *ppView=%p\n", (void *)*ppView));
+}
+
+#ifndef IN_VMSVGA3D
+void cocoaViewReparent(NativeNSViewRef pView, NativeNSViewRef pParentView)
+{
+ COCOA_LOG_FLOW(("cocoaViewReparent: pView=%p pParentView=%p\n", (void *)pView, (void *)pParentView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ OverlayView *pOView = (OverlayView *)pView;
+ if (pOView)
+ [pOView vboxReparent:pParentView];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewReparent: returns\n"));
+}
+#endif /* !IN_VMSVGA3D */
+
+void cocoaViewDestroy(NativeNSViewRef pView)
+{
+ COCOA_LOG_FLOW(("cocoaViewDestroy: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner addObj:pView selector:@selector(vboxDestroy) arg:nil];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewDestroy: returns\n"));
+}
+
+#ifndef IN_VMSVGA3D
+void cocoaViewShow(NativeNSViewRef pView, GLboolean fShowIt)
+{
+ COCOA_LOG_FLOW(("cocoaViewShow: pView=%p fShowIt=%d\n", (void *)pView, fShowIt));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [(OverlayView *)pView vboxSetVisible:fShowIt];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewShow: returns\n"));
+}
+#endif /* IN_VMSVGA3D */
+
+void cocoaViewDisplay(NativeNSViewRef pView)
+{
+ COCOA_LOG_FLOW(("cocoaViewDisplay: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+#ifndef IN_VMSVGA3D
+ DEBUG_WARN(("cocoaViewDisplay should never happen!\n"));
+ DEBUG_MSG_1(("cocoaViewDisplay %p\n", (void *)pView));
+#endif
+ [(OverlayView *)pView swapFBO];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewDisplay: returns\n"));
+}
+
+void cocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
+{
+ COCOA_LOG_FLOW(("cocoaViewSetPosition: pView=%p pParentView=%p x=%d y=%d\n", (void *)pView, (void *)pParentView, x, y));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [(OverlayView *)pView vboxSetPos:NSMakePoint(x, y)];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewSetPosition: returns\n"));
+}
+
+void cocoaViewSetSize(NativeNSViewRef pView, int cx, int cy)
+{
+ COCOA_LOG_FLOW(("cocoaViewSetSize: pView=%p cx=%d cy=%d\n", (void *)pView, cx, cy));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ OverlayView *pOverlayView = (OverlayView *)pView;
+
+ [pOverlayView vboxSetSize:NSMakeSize(cx, cy)];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewSetSize: returns\n"));
+}
+
+#ifndef IN_VMSVGA3D
+
+typedef struct CR_RCD_GETGEOMETRY
+{
+ OverlayView *pView;
+ NSRect rect;
+} CR_RCD_GETGEOMETRY;
+
+static DECLCALLBACK(void) vboxRcdGetGeomerty(void *pvUser)
+{
+ CR_RCD_GETGEOMETRY *pGetGeometry = (CR_RCD_GETGEOMETRY *)pvUser;
+ pGetGeometry->rect = [[pGetGeometry->pView window] frame];
+ COCOA_LOG_FLOW(("vboxRcdGetGeomerty: (x,y)=(%d,%d) (cx,cy)=(%d,%d)\n", pGetGeometry->rect.origin.x, pGetGeometry->rect.origin.y,
+ pGetGeometry->rect.size.width, pGetGeometry->rect.size.height));
+}
+
+void cocoaViewGetGeometry(NativeNSViewRef pView, int *px, int *py, int *pcx, int *pcy)
+{
+ COCOA_LOG_FLOW(("cocoaViewGetGeometry: pView=%p px=%p py=%p pcx=%p pcy=%p\n",
+ (void *)pView, (void *)px, (void *)py, (void *)pcx, (void *)pcy));
+ NSAutoreleasePool *pPool;
+ pPool = [[NSAutoreleasePool alloc] init];
+
+ /* make sure all tasks are run, to preserve the order */
+ VBoxMainThreadTaskRunner *pRunner = [VBoxMainThreadTaskRunner globalInstance];
+ [pRunner runTasksSyncIfPossible];
+
+ NSRect frame;
+#ifndef IN_VMSVGA3D
+ if (renderspuCalloutAvailable())
+ {
+ CR_RCD_GETGEOMETRY GetGeometry;
+ GetGeometry.pView = (OverlayView *)pView;
+ renderspuCalloutClient(vboxRcdGetGeomerty, &GetGeometry);
+ frame = GetGeometry.rect;
+ }
+ else
+#endif
+ {
+ DEBUG_MSG_NOT_VMSVGA3D(("no callout available on getGeometry\n"));
+ frame = [[pView window] frame];
+ }
+
+ *px = frame.origin.x;
+ *py = frame.origin.y;
+ *pcx = frame.size.width;
+ *pcy = frame.size.height;
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewGetGeometry: returns *px=%d, *py=%d, *pcx=%d, *pcy=%d\n", *px, *py, *pcx, *pcy));
+}
+
+void cocoaViewPresentComposition(NativeNSViewRef pView, PCVBOXVR_SCR_COMPOSITOR_ENTRY pChangedEntry)
+{
+ COCOA_LOG_FLOW(("cocoaViewPresentComposition: pView=%p pChangedEntry=%p\n", (void *)pView, (void *)pChangedEntry));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ NSOpenGLContext *pCtx;
+
+# ifdef IN_VMSVGA3D
+ Assert([(OverlayView *)pView glCtx]);
+
+# else
+ /* The view may not necesserily have a GL context set. */
+ pCtx = [(OverlayView *)pView glCtx];
+ if (!pCtx)
+ {
+ ContextInfo *pCtxInfo = renderspuDefaultSharedContextAcquire();
+ if (!pCtxInfo)
+ {
+ DEBUG_WARN(("renderspuDefaultSharedContextAcquire returned NULL"));
+
+ [pPool release];
+ DEBUG_FUNC_LEAVE();
+ return;
+ }
+
+ pCtx = pCtxInfo->context;
+
+ [(OverlayView *)pView setGLCtx:pCtx];
+ }
+# endif
+
+ [(OverlayView *)pView presentComposition:pChangedEntry];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewPresentComposition: returns\n"));
+}
+
+#endif /* !IN_VMSVGA3D */
+
+void cocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+ COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: pView=%p pCtx=%p\n", (void *)pView, (void *)pCtx));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ if (pView)
+ {
+ [(OverlayView *)pView setGLCtx:pCtx];
+ [(OverlayView *)pView makeCurrentFBO];
+ }
+ else
+ {
+#ifdef IN_VMSVGA3D
+ /* Always flush before flush. glXMakeCurrent and wglMakeCurrent does this
+ implicitly, seemingly NSOpenGLContext::makeCurrentContext doesn't. */
+ if ([NSOpenGLContext currentContext] != nil)
+ {
+ DEBUG_CLEAR_GL_ERRORS();
+ glFlush();
+ DEBUG_CHECK_GL_ERROR("glFlush");
+ }
+#endif
+ [NSOpenGLContext clearCurrentContext];
+ }
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewMakeCurrentContext: returns\n"));
+}
+
+#ifndef IN_VMSVGA3D
+
+GLboolean cocoaViewNeedsEmptyPresent(NativeNSViewRef pView)
+{
+ COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: pView=%p\n", (void *)pView));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ GLboolean fNeedsPresent = [(OverlayView *)pView vboxNeedsEmptyPresent];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewNeedsEmptyPresent: returns %d\n", fNeedsPresent));
+ return fNeedsPresent;
+}
+
+void cocoaViewSetVisibleRegion(NativeNSViewRef pView, GLint cRects, const GLint *paRects)
+{
+ COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: pView=%p cRects=%d paRects=%p)\n", (void *)pView, cRects, (void const *)paRects));
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ [(OverlayView *)pView setVisibleRegions:cRects paRects:paRects];
+
+ [pPool release];
+ COCOA_LOG_FLOW(("cocoaViewSetVisibleRegion: returns\n"));
+}
+
+#endif /* IN_VMSVGA3D */
+
+#ifdef IN_VMSVGA3D
+/*
+ * VMSVGA3D interface.
+ */
+
+VMSVGA3DCOCOA_DECL(bool) vmsvga3dCocoaCreateViewAndContext(NativeNSViewRef *ppView, NativeNSOpenGLContextRef *ppCtx,
+ NativeNSViewRef pParentView, uint32_t cx, uint32_t cy,
+ NativeNSOpenGLContextRef pSharedCtx, bool fOtherProfile)
+{
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+ GLbitfield fVisParams = CR_ALPHA_BIT | CR_DEPTH_BIT | CR_DOUBLE_BIT | (fOtherProfile ? VMSVGA3D_NON_DEFAULT_PROFILE_BIT : 0);
+ bool fRc = false;
+
+ cocoaGLCtxCreate(ppCtx, fVisParams, pSharedCtx);
+ if (*ppCtx)
+ {
+ cocoaViewCreate(ppView, NULL, pParentView, fVisParams);
+ if (*ppView)
+ {
+ cocoaViewSetSize(*ppView, cx, cy);
+ [(OverlayView *)*ppView setGLCtx: *ppCtx];
+ fRc = true;
+ }
+ else
+ [*ppCtx release];
+ }
+
+ [pPool release];
+ return fRc;
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaDestroyViewAndContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+ cocoaGLCtxDestroy(pCtx);
+ cocoaViewDestroy(pView);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetPosition(NativeNSViewRef pView, NativeNSViewRef pParentView, int x, int y)
+{
+ cocoaViewSetPosition(pView, pParentView, x, y);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewSetSize(NativeNSViewRef pView, int w, int h)
+{
+ cocoaViewSetSize(pView, w, h);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaViewMakeCurrentContext(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+ Assert(!pView || [(OverlayView *)pView glCtx] == pCtx || [(OverlayView *)pView glCtx] == nil);
+ cocoaViewMakeCurrentContext(pView, pCtx);
+}
+
+VMSVGA3DCOCOA_DECL(void) vmsvga3dCocoaSwapBuffers(NativeNSViewRef pView, NativeNSOpenGLContextRef pCtx)
+{
+# if 1
+ Assert([(OverlayView *)pView glCtx] == pCtx);
+ Assert([pCtx view] == pView);
+ cocoaViewDisplay(pView);
+# else
+ DEBUG_FUNC_ENTER();
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ Assert([(OverlayView *)pView glCtx] == pCtx);
+ Assert([pCtx view] == pView);
+
+ [pCtx flushBuffer];
+
+ [pPool release];
+ DEBUG_FUNC_LEAVE();
+# endif
+}
+
+#endif /* IN_VMSVGA3D */
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
new file mode 100644
index 00000000..624a051f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_config.c
@@ -0,0 +1,392 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "renderspu.h"
+
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_error.h"
+#include "cr_environment.h"
+#include "cr_url.h"
+
+
+static void set_window_geometry( RenderSPU *render_spu, const char *response )
+{
+ int x, y, w, h;
+ CRASSERT(response[0] == '[');
+ sscanf( response, "[ %d, %d, %d, %d ]", &x, &y, &w, &h );
+ render_spu->defaultX = (int) x;
+ render_spu->defaultY = (int) y;
+ render_spu->defaultWidth = (unsigned int) w;
+ render_spu->defaultHeight = (unsigned int) h;
+}
+
+static void set_default_visual( RenderSPU *render_spu, const char *response )
+{
+ if (crStrlen(response) > 0) {
+ if (crStrstr(response, "rgb"))
+ render_spu->default_visual |= CR_RGB_BIT;
+ if (crStrstr(response, "alpha"))
+ render_spu->default_visual |= CR_ALPHA_BIT;
+ if (crStrstr(response, "z") || crStrstr(response, "depth"))
+ render_spu->default_visual |= CR_DEPTH_BIT;
+ if (crStrstr(response, "stencil"))
+ render_spu->default_visual |= CR_STENCIL_BIT;
+ if (crStrstr(response, "accum"))
+ render_spu->default_visual |= CR_ACCUM_BIT;
+ if (crStrstr(response, "stereo"))
+ render_spu->default_visual |= CR_STEREO_BIT;
+ if (crStrstr(response, "multisample"))
+ render_spu->default_visual |= CR_MULTISAMPLE_BIT;
+ if (crStrstr(response, "double"))
+ render_spu->default_visual |= CR_DOUBLE_BIT;
+ if (crStrstr(response, "pbuffer"))
+ render_spu->default_visual |= CR_PBUFFER_BIT;
+ }
+}
+
+static void set_display_string( RenderSPU *render_spu, const char *response )
+{
+ if (!crStrcmp(response, "DEFAULT")) {
+ const char *display = crGetenv("DISPLAY");
+ if (display)
+ crStrncpy(render_spu->display_string,
+ display,
+ sizeof(render_spu->display_string));
+ else
+ crStrcpy(render_spu->display_string, ""); /* empty string */
+ }
+ else {
+ crStrncpy(render_spu->display_string,
+ response,
+ sizeof(render_spu->display_string));
+ }
+}
+
+static void set_fullscreen( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->fullscreen) );
+}
+
+static void set_on_top( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->ontop) );
+}
+
+static void set_system_gl_path( RenderSPU *render_spu, const char *response )
+{
+ if (crStrlen(response) > 0)
+ crSetenv( "CR_SYSTEM_GL_PATH", response );
+}
+
+static void set_title( RenderSPU *render_spu, const char *response )
+{
+ crFree( render_spu->window_title );
+ render_spu->window_title = crStrdup( response );
+}
+
+#if defined(GLX)
+static void set_try_direct( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->try_direct) );
+}
+
+static void set_force_direct( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->force_direct) );
+}
+#endif /* GLX */
+
+static void render_to_app_window( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->render_to_app_window) );
+}
+
+static void render_to_crut_window( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->render_to_crut_window) );
+}
+
+static void resizable( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->resizable) );
+}
+
+static void set_borderless( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->borderless) );
+}
+
+static void set_cursor( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->drawCursor) );
+}
+
+static void gather_url( RenderSPU *render_spu, const char *response )
+{
+ char protocol[4096], hostname[4096];
+ unsigned short port;
+
+ if (!crParseURL(response, protocol, hostname, &port, 0))
+ {
+ crError( "Malformed URL: \"%s\"", response );
+ }
+
+ render_spu->gather_port = port;
+}
+
+static void gather_userbuf( RenderSPU *render_spu, const char *response )
+{
+ sscanf( response, "%d", &(render_spu->gather_userbuf_size) );
+}
+
+static void set_lut8( RenderSPU *render_spu, const char *response )
+{
+ int a;
+ char **lut;
+
+ if (!response[0]) return;
+
+ lut = crStrSplit(response, ",");
+ if (!lut) return;
+
+ for (a=0; a<256; a++)
+ {
+ render_spu->lut8[0][a] = crStrToInt(lut[a]);
+ render_spu->lut8[1][a] = crStrToInt(lut[256+a]);
+ render_spu->lut8[2][a] = crStrToInt(lut[512+a]);
+ }
+
+ crFreeStrings(lut);
+
+ render_spu->use_lut8 = 1;
+}
+
+static void set_master_url ( RenderSPU *render_spu, char *response )
+{
+ if (response[0])
+ render_spu->swap_master_url = crStrdup( response );
+ else
+ render_spu->swap_master_url = NULL;
+}
+
+static void set_is_master ( RenderSPU *render_spu, char *response )
+{
+ render_spu->is_swap_master = crStrToInt( response );
+}
+
+static void set_num_clients ( RenderSPU *render_spu, char *response )
+{
+ render_spu->num_swap_clients = crStrToInt( response );
+}
+
+static void set_use_osmesa ( RenderSPU *render_spu, char *response )
+{
+ int val = crStrToInt( response );
+#ifdef USE_OSMESA
+ render_spu->use_osmesa = val;
+#else
+ if (val != 0)
+ crError( "renderspu with Conf(use_osmesa, 1) but not compiled with -DUSE_OSMESA");
+#endif
+}
+
+static void set_nv_swap_group( RenderSPU *render_spu, char *response )
+{
+ render_spu->nvSwapGroup = crStrToInt( response );
+ if (render_spu->nvSwapGroup < 0)
+ render_spu->nvSwapGroup = 0;
+}
+
+static void set_ignore_papi( RenderSPU *render_spu, char *response )
+{
+ render_spu->ignore_papi = crStrToInt( response );
+}
+
+static void set_ignore_window_moves( RenderSPU *render_spu, char *response )
+{
+ render_spu->ignore_window_moves = crStrToInt( response );
+}
+
+static void set_pbuffer_size( RenderSPU *render_spu, const char *response )
+{
+ CRASSERT(response[0] == '[');
+ sscanf( response, "[ %d, %d ]",
+ &render_spu->pbufferWidth, &render_spu->pbufferHeight);
+}
+
+static void set_use_glxchoosevisual( RenderSPU *render_spu, char *response )
+{
+ render_spu->use_glxchoosevisual = crStrToInt( response );
+}
+
+static void set_draw_bbox( RenderSPU *render_spu, char *response )
+{
+ render_spu->draw_bbox = crStrToInt( response );
+}
+
+
+
+/* option, type, nr, default, min, max, title, callback
+ */
+SPUOptions renderSPUOptions[] = {
+ { "title", CR_STRING, 1, "Chromium Render SPU", NULL, NULL,
+ "Window Title", (SPUOptionCB)set_title },
+
+ { "window_geometry", CR_INT, 4, "[0, 0, 256, 256]", "[0, 0, 1, 1]", NULL,
+ "Default Window Geometry (x,y,w,h)", (SPUOptionCB)set_window_geometry },
+
+ { "fullscreen", CR_BOOL, 1, "0", NULL, NULL,
+ "Full-screen Window", (SPUOptionCB)set_fullscreen },
+
+ { "resizable", CR_BOOL, 1, "0", NULL, NULL,
+ "Resizable Window", (SPUOptionCB)resizable },
+
+ { "on_top", CR_BOOL, 1, "0", NULL, NULL,
+ "Display on Top", (SPUOptionCB)set_on_top },
+
+ { "borderless", CR_BOOL, 1, "0", NULL, NULL,
+ "Borderless Window", (SPUOptionCB) set_borderless },
+
+ { "default_visual", CR_STRING, 1, "rgb, double, depth", NULL, NULL,
+ "Default GL Visual", (SPUOptionCB) set_default_visual },
+
+#if defined(GLX)
+ { "try_direct", CR_BOOL, 1, "1", NULL, NULL,
+ "Try Direct Rendering", (SPUOptionCB)set_try_direct },
+
+ { "force_direct", CR_BOOL, 1, "0", NULL, NULL,
+ "Force Direct Rendering", (SPUOptionCB)set_force_direct },
+#endif
+
+ { "render_to_app_window", CR_BOOL, 1, "0", NULL, NULL,
+ "Render to Application window", (SPUOptionCB)render_to_app_window },
+
+ { "render_to_crut_window", CR_BOOL, 1, "0", NULL, NULL,
+ "Render to CRUT window", (SPUOptionCB)render_to_crut_window },
+
+ { "show_cursor", CR_BOOL, 1, "0", NULL, NULL,
+ "Show Software Cursor", (SPUOptionCB) set_cursor },
+
+ { "system_gl_path", CR_STRING, 1, "", NULL, NULL,
+ "System GL Path", (SPUOptionCB)set_system_gl_path },
+
+ { "display_string", CR_STRING, 1, "DEFAULT", NULL, NULL,
+ "X Display String", (SPUOptionCB)set_display_string },
+
+ { "gather_url", CR_STRING, 1, "", NULL, NULL,
+ "Gatherer URL", (SPUOptionCB)gather_url},
+
+ { "gather_userbuf_size", CR_INT, 1, "0", NULL, NULL,
+ "Size of Buffer to Allocate for Gathering", (SPUOptionCB)gather_userbuf},
+
+ { "lut8", CR_STRING, 1, "", NULL, NULL,
+ "8 bit RGB LUT", (SPUOptionCB)set_lut8},
+
+ { "swap_master_url", CR_STRING, 1, "", NULL, NULL,
+ "The URL to the master swapper", (SPUOptionCB)set_master_url },
+
+ { "is_swap_master", CR_BOOL, 1, "0", NULL, NULL,
+ "Is this the swap master", (SPUOptionCB)set_is_master },
+
+ { "num_swap_clients", CR_INT, 1, "1", NULL, NULL,
+ "How many swaps to wait on", (SPUOptionCB)set_num_clients },
+
+ { "use_osmesa", CR_BOOL, 1, "0", NULL, NULL,
+ "Use offscreen rendering with Mesa", (SPUOptionCB)set_use_osmesa },
+
+ { "nv_swap_group", CR_INT, 1, "0", NULL, NULL,
+ "NVIDIA Swap Group Number", (SPUOptionCB) set_nv_swap_group },
+
+ { "ignore_papi", CR_BOOL, 1, "0", NULL, NULL,
+ "Ignore Barrier and Semaphore calls", (SPUOptionCB) set_ignore_papi },
+
+ { "ignore_window_moves", CR_BOOL, 1, "0", NULL, NULL,
+ "Ignore crWindowPosition calls", (SPUOptionCB) set_ignore_window_moves },
+
+ { "pbuffer_size", CR_INT, 2, "[0, 0]", "[0, 0]", NULL,
+ "Maximum PBuffer Size", (SPUOptionCB) set_pbuffer_size },
+
+ { "use_glxchoosevisual", CR_BOOL, 1, "1", NULL, NULL,
+ "Use glXChooseVisual", (SPUOptionCB) set_use_glxchoosevisual },
+
+ { "draw_bbox", CR_BOOL, 1, "0", NULL, NULL,
+ "Draw Bounding Boxes", (SPUOptionCB) set_draw_bbox },
+ { NULL, CR_BOOL, 0, NULL, NULL, NULL, NULL, NULL },
+};
+
+
+void renderspuSetVBoxConfiguration( RenderSPU *render_spu )
+{
+ int a;
+
+ for (a=0; a<256; a++)
+ {
+ render_spu->lut8[0][a] =
+ render_spu->lut8[1][a] =
+ render_spu->lut8[2][a] = a;
+ }
+ render_spu->use_lut8 = 0;
+
+ set_title(render_spu, "Chromium Render SPU");
+ set_window_geometry(render_spu, "[0, 0, 0, 0]");
+ set_fullscreen(render_spu, "0");
+ resizable(render_spu, "0");
+ set_on_top(render_spu, "1");
+ set_borderless(render_spu, "1");
+ set_default_visual(render_spu, "rgb, double, depth");
+#if defined(GLX)
+ set_try_direct(render_spu, "1");
+ set_force_direct(render_spu, "0");
+#endif
+ render_to_app_window(render_spu, "0");
+ render_to_crut_window(render_spu, "0");
+ set_cursor(render_spu, "0");
+ set_system_gl_path(render_spu, "");
+ set_display_string(render_spu, "DEFAULT");
+ gather_url(render_spu, "");
+ gather_userbuf(render_spu, "0");
+ set_lut8(render_spu, "");
+ set_master_url(render_spu, "");
+ set_is_master(render_spu, "0");
+ set_num_clients(render_spu, "1");
+ set_use_osmesa(render_spu, "0");
+ set_nv_swap_group(render_spu, "0");
+ set_ignore_papi(render_spu, "0");
+ set_ignore_window_moves(render_spu, "0");
+ set_pbuffer_size(render_spu, "[0, 0]");
+ set_use_glxchoosevisual(render_spu, "1");
+ set_draw_bbox(render_spu, "0");
+
+ render_spu->swap_mtu = 1024 * 500;
+
+ /* Some initialization that doesn't really have anything to do
+ * with configuration but which was done here before:
+ */
+ render_spu->use_L2 = 0;
+ render_spu->cursorX = 0;
+ render_spu->cursorY = 0;
+#if defined(GLX)
+ render_spu->sync = 0;
+#endif
+
+ /* Config of "render force present main thread" (currently implemented by glx and wgl). */
+ {
+ const char *forcePresent = crGetenv("CR_RENDER_FORCE_PRESENT_MAIN_THREAD");
+ if (forcePresent)
+ render_spu->force_present_main_thread = crStrToInt(forcePresent) ? 1 : 0;
+ else
+ {
+#if defined(GLX)
+ /* Customer needed this for avoiding system 3D driver bugs. */
+ render_spu->force_present_main_thread = 1;
+#else
+ render_spu->force_present_main_thread = 0;
+#endif
+ }
+ }
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
new file mode 100644
index 00000000..8a1a61ff
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_glx.c
@@ -0,0 +1,2042 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+#if 00 /*TEMPORARY*/
+#include <unistd.h>
+#include "cr_rand.h"
+#endif
+
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xmu/StdCmap.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/shape.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#include "cr_environment.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_mem.h"
+#include "cr_process.h"
+#include "renderspu.h"
+
+
+/*
+ * Stuff from MwmUtils.h
+ */
+typedef struct
+{
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+} PropMotifWmHints;
+
+#define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+#define MWM_HINTS_DECORATIONS (1L << 1)
+
+
+#define WINDOW_NAME window->title
+
+static Bool WindowExistsFlag;
+
+static int
+WindowExistsErrorHandler( Display *dpy, XErrorEvent *xerr )
+{
+ if (xerr->error_code == BadWindow)
+ {
+ WindowExistsFlag = GL_FALSE;
+ }
+ return 0;
+}
+
+static GLboolean
+WindowExists( Display *dpy, Window w )
+{
+ XWindowAttributes xwa;
+ int (*oldXErrorHandler)(Display *, XErrorEvent *);
+
+ WindowExistsFlag = GL_TRUE;
+ oldXErrorHandler = XSetErrorHandler(WindowExistsErrorHandler);
+ XGetWindowAttributes(dpy, w, &xwa); /* dummy request */
+ XSetErrorHandler(oldXErrorHandler);
+ return WindowExistsFlag;
+}
+
+static Colormap
+GetLUTColormap( Display *dpy, XVisualInfo *vi )
+{
+ int a;
+ XColor col;
+ Colormap cmap;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ int localclass = vi->c_class; /* C++ */
+#else
+ int localclass = vi->class; /* C */
+#endif
+
+ if ( localclass != DirectColor )
+ {
+ crError( "No support for non-DirectColor visuals with LUTs" );
+ }
+
+ cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocAll );
+
+ for (a=0; a<256; a++)
+ {
+ col.red = render_spu.lut8[0][a]<<8;
+ col.green = col.blue = 0;
+ col.pixel = a<<16;
+ col.flags = DoRed;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ for (a=0; a<256; a++)
+ {
+ col.green = render_spu.lut8[1][a]<<8;
+ col.red = col.blue = 0;
+ col.pixel = a<<8;
+ col.flags = DoGreen;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ for (a=0; a<256; a++)
+ {
+ col.blue = render_spu.lut8[2][a]<<8;
+ col.red = col.green= 0;
+ col.pixel = a;
+ col.flags = DoBlue;
+ XStoreColor(dpy, cmap, &col);
+ }
+
+ return cmap;
+}
+
+static Colormap
+GetShareableColormap( Display *dpy, XVisualInfo *vi )
+{
+ Status status;
+ XStandardColormap *standardCmaps;
+ Colormap cmap;
+ int i, numCmaps;
+
+#if defined(__cplusplus) || defined(c_plusplus)
+ int localclass = vi->c_class; /* C++ */
+#else
+ int localclass = vi->class; /* C */
+#endif
+
+ if ( localclass != TrueColor )
+ {
+ crError( "No support for non-TrueColor visuals." );
+ }
+
+ status = XmuLookupStandardColormap( dpy, vi->screen, vi->visualid,
+ vi->depth, XA_RGB_DEFAULT_MAP,
+ False, True );
+
+ if ( status == 1 )
+ {
+ status = XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen),
+ &standardCmaps, &numCmaps,
+ XA_RGB_DEFAULT_MAP );
+ if ( status == 1 )
+ {
+ for (i = 0 ; i < numCmaps ; i++)
+ {
+ if (standardCmaps[i].visualid == vi->visualid)
+ {
+ cmap = standardCmaps[i].colormap;
+ XFree( standardCmaps);
+ return cmap;
+ }
+ }
+ }
+ }
+
+ cmap = XCreateColormap( dpy, RootWindow(dpy, vi->screen),
+ vi->visual, AllocNone );
+ return cmap;
+}
+
+
+static int
+WaitForMapNotify( Display *display, XEvent *event, char *arg )
+{
+ (void)display;
+ return ( event->type == MapNotify && event->xmap.window == (Window)arg );
+}
+
+
+/**
+ * Return the X Visual ID of the given window
+ */
+static int
+GetWindowVisualID( Display *dpy, Window w )
+{
+ XWindowAttributes attr;
+ int k = XGetWindowAttributes(dpy, w, &attr);
+ if (!k)
+ return -1;
+ return attr.visual->visualid;
+}
+
+
+/**
+ * Wrapper for glXGetConfig().
+ */
+static int
+Attrib( const VisualInfo *visual, int attrib )
+{
+ int value = 0;
+ render_spu.ws.glXGetConfig( visual->dpy, visual->visual, attrib, &value );
+ return value;
+}
+
+
+
+/**
+ * Find a visual with the specified attributes. If we fail, turn off an
+ * attribute (like multisample or stereo) and try again.
+ */
+static XVisualInfo *
+chooseVisualRetry( Display *dpy, int screen, GLbitfield visAttribs )
+{
+ while (1) {
+ XVisualInfo *vis = crChooseVisual(&render_spu.ws, dpy, screen,
+ (GLboolean) render_spu.use_lut8,
+ visAttribs);
+ if (vis)
+ return vis;
+
+ if (visAttribs & CR_MULTISAMPLE_BIT)
+ visAttribs &= ~CR_MULTISAMPLE_BIT;
+ else if (visAttribs & CR_OVERLAY_BIT)
+ visAttribs &= ~CR_OVERLAY_BIT;
+ else if (visAttribs & CR_STEREO_BIT)
+ visAttribs &= ~CR_STEREO_BIT;
+ else if (visAttribs & CR_ACCUM_BIT)
+ visAttribs &= ~CR_ACCUM_BIT;
+ else if (visAttribs & CR_ALPHA_BIT)
+ visAttribs &= ~CR_ALPHA_BIT;
+ else
+ return NULL;
+ }
+}
+
+
+/**
+ * Get an FBconfig for the specified attributes
+ */
+#ifdef GLX_VERSION_1_3
+static GLXFBConfig
+chooseFBConfig( Display *dpy, int screen, GLbitfield visAttribs )
+{
+ GLXFBConfig *fbconfig;
+ int attribs[1000], attrCount = 0, numConfigs;
+ int major, minor;
+
+ CRASSERT(visAttribs & CR_PBUFFER_BIT);
+
+ /* Make sure pbuffers are supported */
+ render_spu.ws.glXQueryVersion(dpy, &major, &minor);
+ if (major * 100 + minor < 103) {
+ crWarning("Render SPU: GLX %d.%d doesn't support pbuffers", major, minor);
+ return 0;
+ }
+
+ attribs[attrCount++] = GLX_DRAWABLE_TYPE;
+ attribs[attrCount++] = GLX_PBUFFER_BIT;
+
+ if (visAttribs & CR_RGB_BIT) {
+ attribs[attrCount++] = GLX_RENDER_TYPE;
+ attribs[attrCount++] = GLX_RGBA_BIT;
+ attribs[attrCount++] = GLX_RED_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_GREEN_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_BLUE_SIZE;
+ attribs[attrCount++] = 1;
+ if (visAttribs & CR_ALPHA_BIT) {
+ attribs[attrCount++] = GLX_ALPHA_SIZE;
+ attribs[attrCount++] = 1;
+ }
+ }
+
+ if (visAttribs & CR_DEPTH_BIT) {
+ attribs[attrCount++] = GLX_DEPTH_SIZE;
+ attribs[attrCount++] = 1;
+ }
+
+ if (visAttribs & CR_DOUBLE_BIT) {
+ attribs[attrCount++] = GLX_DOUBLEBUFFER;
+ attribs[attrCount++] = True;
+ }
+ else {
+ /* don't care */
+ }
+
+ if (visAttribs & CR_STENCIL_BIT) {
+ attribs[attrCount++] = GLX_STENCIL_SIZE;
+ attribs[attrCount++] = 1;
+ }
+
+ if (visAttribs & CR_ACCUM_BIT) {
+ attribs[attrCount++] = GLX_ACCUM_RED_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_ACCUM_GREEN_SIZE;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_ACCUM_BLUE_SIZE;
+ attribs[attrCount++] = 1;
+ if (visAttribs & CR_ALPHA_BIT) {
+ attribs[attrCount++] = GLX_ACCUM_ALPHA_SIZE;
+ attribs[attrCount++] = 1;
+ }
+ }
+
+ if (visAttribs & CR_MULTISAMPLE_BIT) {
+ attribs[attrCount++] = GLX_SAMPLE_BUFFERS_SGIS;
+ attribs[attrCount++] = 1;
+ attribs[attrCount++] = GLX_SAMPLES_SGIS;
+ attribs[attrCount++] = 4;
+ }
+
+ if (visAttribs & CR_STEREO_BIT) {
+ attribs[attrCount++] = GLX_STEREO;
+ attribs[attrCount++] = 1;
+ }
+
+ /* terminate */
+ attribs[attrCount++] = 0;
+
+ fbconfig = render_spu.ws.glXChooseFBConfig(dpy, screen, attribs, &numConfigs);
+ if (!fbconfig || numConfigs == 0) {
+ /* no matches! */
+ return 0;
+ }
+ if (numConfigs == 1) {
+ /* one match */
+ return fbconfig[0];
+ }
+ else {
+ /* found several matches - try to find best one */
+ int i;
+
+ crDebug("Render SPU: glXChooseFBConfig found %d matches for visBits 0x%x",
+ numConfigs, visAttribs);
+ /* Skip/omit configs that have unneeded Z buffer or unneeded double
+ * buffering. Possible add other tests in the future.
+ */
+ for (i = 0; i < numConfigs; i++) {
+ int zBits, db;
+ render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
+ GLX_DEPTH_SIZE, &zBits);
+ if ((visAttribs & CR_DEPTH_BIT) == 0 && zBits > 0) {
+ /* omit fbconfig with unneeded Z */
+ continue;
+ }
+ render_spu.ws.glXGetFBConfigAttrib(dpy, fbconfig[i],
+ GLX_DOUBLEBUFFER, &db);
+ if ((visAttribs & CR_DOUBLE_BIT) == 0 && db) {
+ /* omit fbconfig with unneeded DB */
+ continue;
+ }
+
+ /* if we get here, use this config */
+ return fbconfig[i];
+ }
+
+ /* if we get here, we didn't find a better fbconfig */
+ return fbconfig[0];
+ }
+}
+#endif /* GLX_VERSION_1_3 */
+
+static const char * renderspuGetDisplayName()
+{
+ const char *dpyName;
+
+ if (render_spu.display_string[0])
+ dpyName = render_spu.display_string;
+ else
+ {
+ crWarning("Render SPU: no display..");
+ dpyName = NULL;
+ }
+ return dpyName;
+}
+
+static int renderspuWinCmdWinCreate(WindowInfo *pWindow)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static int renderspuWinCmdWinDestroy(WindowInfo *pWindow)
+{
+ return VERR_NOT_IMPLEMENTED;
+}
+
+static int renderspuWinCmdInit()
+{
+ const char * dpyName;
+ int rc = VERR_GENERAL_FAILURE;
+
+ if (!crHashtableAllocRegisterKey(render_spu.windowTable, CR_RENDER_WINCMD_ID))
+ {
+ crError("CR_RENDER_WINCMD_ID %d is occupied already", CR_RENDER_WINCMD_ID);
+ return VERR_INVALID_STATE;
+ }
+
+ render_spu.pWinToInfoTable = crAllocHashtable();
+ if (render_spu.pWinToInfoTable)
+ {
+ dpyName = renderspuGetDisplayName();
+ if (dpyName)
+ {
+ GLboolean bRc = renderspuInitVisual(&render_spu.WinCmdVisual, dpyName, render_spu.default_visual);
+ if (bRc)
+ {
+ bRc = renderspuWinInitWithVisual(&render_spu.WinCmdWindow, &render_spu.WinCmdVisual, GL_FALSE, CR_RENDER_WINCMD_ID);
+ if (bRc)
+ {
+ XSelectInput(render_spu.WinCmdVisual.dpy, render_spu.WinCmdWindow.window, StructureNotifyMask);
+ render_spu.WinCmdAtom = XInternAtom(render_spu.WinCmdVisual.dpy, "VBoxWinCmd", False);
+ CRASSERT(render_spu.WinCmdAtom != None);
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crError("renderspuWinInitWithVisual failed");
+ }
+ /* there is no visual destroy impl currently
+ * @todo: implement */
+ }
+ else
+ {
+ crError("renderspuInitVisual failed");
+ }
+ }
+ else
+ {
+ crError("Render SPU: no display, aborting");
+ }
+ crFreeHashtable(render_spu.pWinToInfoTable, NULL);
+ render_spu.pWinToInfoTable = NULL;
+ }
+ else
+ {
+ crError("crAllocHashtable failed");
+ }
+ return rc;
+}
+
+static void renderspuWinCmdTerm()
+{
+ /* the window is not in the table, this will just ensure the key is freed */
+ crHashtableDelete(render_spu.windowTable, CR_RENDER_WINCMD_ID, NULL);
+ renderspuWinCleanup(&render_spu.WinCmdWindow);
+ crFreeHashtable(render_spu.pWinToInfoTable, NULL);
+ /* we do not have visual destroy functionality
+ * @todo implement */
+}
+
+
+static bool renderspuWinCmdProcess(CR_RENDER_WINCMD* pWinCmd)
+{
+ bool fExit = false;
+ /* process commands */
+ switch (pWinCmd->enmCmd)
+ {
+ case CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE:
+ crHashtableAdd(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, pWinCmd->pWindow);
+ XSelectInput(render_spu.WinCmdVisual.dpy, pWinCmd->pWindow->window, ExposureMask);
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY:
+ crHashtableDelete(render_spu.pWinToInfoTable, pWinCmd->pWindow->window, NULL);
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_NOP:
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_EXIT:
+ renderspuWinCmdTerm();
+ pWinCmd->rc = VINF_SUCCESS;
+ fExit = true;
+ pWinCmd->rc = VINF_SUCCESS;
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_CREATE:
+ pWinCmd->rc = renderspuWinCmdWinCreate(pWinCmd->pWindow);
+ break;
+ case CR_RENDER_WINCMD_TYPE_WIN_DESTROY:
+ pWinCmd->rc = renderspuWinCmdWinDestroy(pWinCmd->pWindow);
+ break;
+ default:
+ crError("unknown WinCmd command! %d", pWinCmd->enmCmd);
+ pWinCmd->rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ RTSemEventSignal(render_spu.hWinCmdCompleteEvent);
+ return fExit;
+}
+
+static DECLCALLBACK(int) renderspuWinCmdThreadProc(RTTHREAD ThreadSelf, void *pvUser)
+{
+ int rc;
+ bool fExit = false;
+ crDebug("RenderSPU: Window thread started (%x)", crThreadID());
+
+ rc = renderspuWinCmdInit();
+
+ /* notify the main cmd thread that we have started */
+ RTSemEventSignal(render_spu.hWinCmdCompleteEvent);
+
+ if (!RT_SUCCESS(rc))
+ {
+ CRASSERT(!render_spu.pWinToInfoTable);
+ return rc;
+ }
+
+ do
+ {
+ XEvent event;
+ XNextEvent(render_spu.WinCmdVisual.dpy, &event);
+
+ switch (event.type)
+ {
+ case ClientMessage:
+ {
+ CRASSERT(event.xclient.window == render_spu.WinCmdWindow.window);
+ if (event.xclient.window == render_spu.WinCmdWindow.window)
+ {
+ if (render_spu.WinCmdAtom == event.xclient.message_type)
+ {
+ CR_RENDER_WINCMD *pWinCmd;
+ memcpy(&pWinCmd, event.xclient.data.b, sizeof (pWinCmd));
+ fExit = renderspuWinCmdProcess(pWinCmd);
+ }
+ }
+
+ break;
+ }
+ case Expose:
+ {
+ if (!event.xexpose.count)
+ {
+ WindowInfo *pWindow = (WindowInfo*)crHashtableSearch(render_spu.pWinToInfoTable, event.xexpose.window);
+ if (pWindow)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR * pCompositor;
+
+ pCompositor = renderspuVBoxCompositorAcquire(pWindow);
+ if (pCompositor)
+ {
+ renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 0, false);
+ renderspuVBoxCompositorRelease(pWindow);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } while (!fExit);
+
+ return 0;
+}
+
+static int renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE enmCmd, WindowInfo *pWindow)
+{
+ Status status;
+ XEvent event;
+ CR_RENDER_WINCMD WinCmd, *pWinCmd;
+ int rc;
+
+ pWinCmd = &WinCmd;
+ pWinCmd->enmCmd = enmCmd;
+ pWinCmd->rc = VERR_GENERAL_FAILURE;
+ pWinCmd->pWindow = pWindow;
+
+ memset(&event, 0, sizeof (event));
+ event.type = ClientMessage;
+ event.xclient.window = render_spu.WinCmdWindow.window;
+ event.xclient.message_type = render_spu.WinCmdAtom;
+ event.xclient.format = 8;
+ memcpy(event.xclient.data.b, &pWinCmd, sizeof (pWinCmd));
+
+ status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, StructureNotifyMask, &event);
+ if (!status)
+ {
+ Assert(0);
+ crWarning("XSendEvent returned null");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ XFlush(render_spu.pCommunicationDisplay);
+ rc = RTSemEventWaitNoResume(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("RTSemEventWaitNoResume failed rc %d", rc);
+ return rc;
+ }
+ return pWinCmd->rc;
+}
+
+int renderspu_SystemInit()
+{
+ const char * dpyName;
+ int rc = VERR_GENERAL_FAILURE;
+
+ if (!render_spu.use_glxchoosevisual) {
+ /* sometimes want to set this option with ATI drivers */
+ render_spu.ws.glXChooseVisual = NULL;
+ }
+
+ /* setup communication display connection */
+ dpyName = renderspuGetDisplayName();
+ if (!dpyName)
+ {
+ crWarning("no display name, aborting");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ render_spu.pCommunicationDisplay = XOpenDisplay(dpyName);
+ if (!render_spu.pCommunicationDisplay)
+ {
+ crWarning( "Couldn't open X display named '%s'", dpyName );
+ return VERR_GENERAL_FAILURE;
+ }
+
+ if ( !render_spu.ws.glXQueryExtension( render_spu.pCommunicationDisplay, NULL, NULL ) )
+ {
+ crWarning( "Render SPU: Display %s doesn't support GLX", dpyName );
+ return VERR_GENERAL_FAILURE;
+ }
+
+ rc = RTSemEventCreate(&render_spu.hWinCmdCompleteEvent);
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTThreadCreate(&render_spu.hWinCmdThread, renderspuWinCmdThreadProc, NULL, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxCrWinCmd");
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTSemEventWait(render_spu.hWinCmdCompleteEvent, RT_INDEFINITE_WAIT);
+ if (RT_SUCCESS(rc))
+ {
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ crWarning("RTSemEventWait failed rc %d", rc);
+ }
+
+ RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL);
+ }
+ else
+ {
+ crWarning("RTThreadCreate failed rc %d", rc);
+ }
+ RTSemEventDestroy(render_spu.hWinCmdCompleteEvent);
+ }
+ else
+ {
+ crWarning("RTSemEventCreate failed rc %d", rc);
+ }
+
+ return rc;
+}
+
+int renderspu_SystemTerm()
+{
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_EXIT, NULL);
+ if (!RT_SUCCESS(rc))
+ {
+ crWarning("renderspuWinCmdSubmit EXIT failed rc %d", rc);
+ return rc;
+ }
+
+ RTThreadWait(render_spu.hWinCmdThread, RT_INDEFINITE_WAIT, NULL);
+ RTSemEventDestroy(render_spu.hWinCmdCompleteEvent);
+ return VINF_SUCCESS;
+}
+
+GLboolean
+renderspu_SystemInitVisual( VisualInfo *visual )
+{
+ const char *dpyName;
+ int screen;
+
+ CRASSERT(visual);
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ /* A dummy visual - being non null is enough. */
+ visual->visual =(XVisualInfo *) "os";
+ return GL_TRUE;
+ }
+#endif
+
+ dpyName = renderspuGetDisplayName();
+ if (!dpyName)
+ {
+ crWarning("Render SPU: no display, aborting");
+ return GL_FALSE;
+ }
+
+
+ crInfo("Render SPU: Opening display %s", dpyName);
+
+ if (dpyName &&
+ (crStrncmp(dpyName, "localhost:11", 12) == 0 ||
+ crStrncmp(dpyName, "localhost:12", 12) == 0 ||
+ crStrncmp(dpyName, "localhost:13", 12) == 0)) {
+ /* Issue both debug and warning messages to make sure the
+ * message gets noticed!
+ */
+ crDebug("Render SPU: display string looks like a proxy X server!");
+ crDebug("Render SPU: This is usually a problem!");
+ crWarning("Render SPU: display string looks like a proxy X server!");
+ crWarning("Render SPU: This is usually a problem!");
+ }
+
+ visual->dpy = XOpenDisplay(dpyName);
+ if (!visual->dpy)
+ {
+ crWarning( "Couldn't open X display named '%s'", dpyName );
+ return GL_FALSE;
+ }
+
+ if ( !render_spu.ws.glXQueryExtension( visual->dpy, NULL, NULL ) )
+ {
+ crWarning( "Render SPU: Display %s doesn't support GLX", visual->displayName );
+ return GL_FALSE;
+ }
+
+ screen = DefaultScreen(visual->dpy);
+
+#ifdef GLX_VERSION_1_3
+ if (visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ visual->fbconfig = chooseFBConfig(visual->dpy, screen, visual->visAttribs);
+ if (!visual->fbconfig) {
+ char s[1000];
+ renderspuMakeVisString( visual->visAttribs, s );
+ crWarning( "Render SPU: Display %s doesn't have the necessary fbconfig: %s",
+ dpyName, s );
+ XCloseDisplay(visual->dpy);
+ return GL_FALSE;
+ }
+ }
+ else
+#endif /* GLX_VERSION_1_3 */
+ {
+ visual->visual = chooseVisualRetry(visual->dpy, screen, visual->visAttribs);
+ if (!visual->visual) {
+ char s[1000];
+ renderspuMakeVisString( visual->visAttribs, s );
+ crWarning("Render SPU: Display %s doesn't have the necessary visual: %s",
+ dpyName, s );
+ XCloseDisplay(visual->dpy);
+ return GL_FALSE;
+ }
+ }
+
+ if ( render_spu.sync )
+ {
+ crDebug( "Render SPU: Turning on XSynchronize" );
+ XSynchronize( visual->dpy, True );
+ }
+
+ if (visual->visual) {
+ crDebug( "Render SPU: Choose visual id=0x%x: RGBA=(%d,%d,%d,%d) Z=%d"
+ " stencil=%d double=%d stereo=%d accum=(%d,%d,%d,%d)",
+ (int) visual->visual->visualid,
+ Attrib( visual, GLX_RED_SIZE ),
+ Attrib( visual, GLX_GREEN_SIZE ),
+ Attrib( visual, GLX_BLUE_SIZE ),
+ Attrib( visual, GLX_ALPHA_SIZE ),
+ Attrib( visual, GLX_DEPTH_SIZE ),
+ Attrib( visual, GLX_STENCIL_SIZE ),
+ Attrib( visual, GLX_DOUBLEBUFFER ),
+ Attrib( visual, GLX_STEREO ),
+ Attrib( visual, GLX_ACCUM_RED_SIZE ),
+ Attrib( visual, GLX_ACCUM_GREEN_SIZE ),
+ Attrib( visual, GLX_ACCUM_BLUE_SIZE ),
+ Attrib( visual, GLX_ACCUM_ALPHA_SIZE )
+ );
+ }
+ else if (visual->fbconfig) {
+ int id;
+ render_spu.ws.glXGetFBConfigAttrib(visual->dpy, visual->fbconfig,
+ GLX_FBCONFIG_ID, &id);
+ crDebug("Render SPU: Chose FBConfig 0x%x, visBits=0x%x",
+ id, visual->visAttribs);
+ }
+
+ return GL_TRUE;
+}
+
+
+/*
+ * Add a GLX window to a swap group for inter-machine SwapBuffer
+ * synchronization.
+ * Only supported on NVIDIA Quadro 3000G hardware.
+ */
+static void
+JoinSwapGroup(Display *dpy, int screen, Window window,
+ GLuint group, GLuint barrier)
+{
+ GLuint maxGroups, maxBarriers;
+ const char *ext;
+ Bool b;
+
+ /*
+ * XXX maybe query glXGetClientString() instead???
+ */
+ ext = render_spu.ws.glXQueryExtensionsString(dpy, screen);
+
+ if (!crStrstr(ext, "GLX_NV_swap_group") ||
+ !render_spu.ws.glXQueryMaxSwapGroupsNV ||
+ !render_spu.ws.glXJoinSwapGroupNV ||
+ !render_spu.ws.glXBindSwapBarrierNV) {
+ crWarning("Render SPU: nv_swap_group is set but GLX_NV_swap_group is not supported on this system!");
+ return;
+ }
+
+ b = render_spu.ws.glXQueryMaxSwapGroupsNV(dpy, screen,
+ &maxGroups, &maxBarriers);
+ if (!b)
+ crWarning("Render SPU: call to glXQueryMaxSwapGroupsNV() failed!");
+
+ if (group >= maxGroups) {
+ crWarning("Render SPU: nv_swap_group too large (%d > %d)",
+ group, (int) maxGroups);
+ return;
+ }
+ crDebug("Render SPU: max swap groups = %d, max barriers = %d",
+ maxGroups, maxBarriers);
+
+ /* add this window to the swap group */
+ b = render_spu.ws.glXJoinSwapGroupNV(dpy, window, group);
+ if (!b) {
+ crWarning("Render SPU: call to glXJoinSwapGroupNV() failed!");
+ return;
+ }
+ else {
+ crDebug("Render SPU: call to glXJoinSwapGroupNV() worked!");
+ }
+
+ /* ... and bind window to barrier of same ID */
+ b = render_spu.ws.glXBindSwapBarrierNV(dpy, group, barrier);
+ if (!b) {
+ crWarning("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) failed!", group, barrier);
+ return;
+ }
+ else {
+ crDebug("Render SPU: call to glXBindSwapBarrierNV(group=%d barrier=%d) worked!", group, barrier);
+ }
+
+ crDebug("Render SPU: window has joined swap group %d", group);
+}
+
+
+
+static GLboolean
+createWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ Display *dpy;
+ Colormap cmap;
+ XSetWindowAttributes swa;
+ XSizeHints hints = {0};
+ XEvent event;
+ XTextProperty text_prop;
+ XClassHint *class_hints = NULL;
+ Window parent;
+ char *name;
+ unsigned long flags;
+ unsigned int vncWin;
+
+ CRASSERT(visual);
+ window->visual = visual;
+ window->nativeWindow = 0;
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return GL_TRUE;
+#endif
+
+ dpy = visual->dpy;
+
+ if ( render_spu.use_L2 )
+ {
+ crWarning( "Render SPU: Going fullscreen because we think we're using Lightning-2." );
+ render_spu.fullscreen = 1;
+ }
+
+ /*
+ * Query screen size if we're going full-screen
+ */
+ if ( render_spu.fullscreen )
+ {
+ XWindowAttributes xwa;
+ Window root_window;
+
+ /* disable the screensaver */
+ XSetScreenSaver( dpy, 0, 0, PreferBlanking, AllowExposures );
+ crDebug( "Render SPU: Just turned off the screensaver" );
+
+ /* Figure out how big the screen is, and make the window that size */
+ root_window = DefaultRootWindow( dpy );
+ XGetWindowAttributes( dpy, root_window, &xwa );
+
+ crDebug( "Render SPU: root window size: %d x %d", xwa.width, xwa.height );
+
+ window->x = 0;
+ window->y = 0;
+ window->BltInfo.width = xwa.width;
+ window->BltInfo.height = xwa.height;
+ }
+
+ /* i've changed default window size to be 0,0 but X doesn't like it */
+ /*CRASSERT(window->BltInfo.width >= 1);
+ CRASSERT(window->BltInfo.height >= 1);*/
+ if (window->BltInfo.width < 1) window->BltInfo.width = 1;
+ if (window->BltInfo.height < 1) window->BltInfo.height = 1;
+
+ /*
+ * Get a colormap.
+ */
+ if (render_spu.use_lut8)
+ cmap = GetLUTColormap( dpy, visual->visual );
+ else
+ cmap = GetShareableColormap( dpy, visual->visual );
+ if ( !cmap ) {
+ crError( "Render SPU: Unable to get a colormap!" );
+ return GL_FALSE;
+ }
+
+ /* destroy existing window if there is one */
+ if (window->window) {
+ XDestroyWindow(dpy, window->window);
+ }
+
+ /*
+ * Create the window
+ *
+ * POSSIBLE OPTIMIZATION:
+ * If we're using the render_to_app_window or render_to_crut_window option
+ * (or DMX) we may never actually use this X window. So we could perhaps
+ * delay its creation until glXMakeCurrent is called. With NVIDIA's OpenGL
+ * driver, creating a lot of GLX windows can eat up a lot of VRAM and lead
+ * to slow, software-fallback rendering. Apps that use render_to_app_window,
+ * etc should set the default window size very small to avoid this.
+ * See dmx.conf for example.
+ */
+ swa.colormap = cmap;
+ swa.border_pixel = 0;
+ swa.event_mask = ExposureMask | StructureNotifyMask;
+ swa.override_redirect = 1;
+
+ flags = CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+ /*
+ * We pass the VNC's desktop windowID via an environment variable.
+ * If we don't find one, we're not on a 3D-capable vncviewer, or
+ * if we do find one, then create the renderspu subwindow as a
+ * child of the vncviewer's desktop window.
+ *
+ * This is purely for the replicateSPU.
+ *
+ * NOTE: This is crufty, and will do for now. FIXME.
+ */
+ vncWin = crStrToInt( crGetenv("CRVNCWINDOW") );
+ if (vncWin)
+ parent = (Window) vncWin;
+ else
+ parent = RootWindow(dpy, visual->visual->screen);
+
+ if (render_spu_parent_window_id>0)
+ {
+ crDebug("Render SPU: VBox parent window_id is: %x", render_spu_parent_window_id);
+ window->window = XCreateWindow(dpy, render_spu_parent_window_id,
+ window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ 0, visual->visual->depth, InputOutput,
+ visual->visual->visual, flags, &swa);
+ }
+ else
+ {
+ /* This should happen only at the call from crVBoxServerInit. At this point we don't
+ * know render_spu_parent_window_id yet, nor we need it for default window which is hidden.
+ */
+
+ crDebug("Render SPU: Creating global window, parent: %x", RootWindow(dpy, visual->visual->screen));
+ window->window = XCreateWindow(dpy, RootWindow(dpy, visual->visual->screen),
+ window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ 0, visual->visual->depth, InputOutput,
+ visual->visual->visual, flags, &swa);
+ }
+
+ if (!window->window) {
+ crWarning( "Render SPU: unable to create window" );
+ return GL_FALSE;
+ }
+
+ crDebug( "Render SPU: Created window 0x%x on display %s, Xvisual 0x%x",
+ (int) window->window,
+ DisplayString(visual->dpy),
+ (int) visual->visual->visual->visualid /* yikes */
+ );
+
+ if (render_spu.fullscreen || render_spu.borderless)
+ {
+ /* Disable border/decorations with an MWM property (observed by most
+ * modern window managers.
+ */
+ PropMotifWmHints motif_hints;
+ Atom prop, proptype;
+
+ /* setup the property */
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = 0; /* Turn off all decorations */
+
+ /* get the atom for the property */
+ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
+ if (prop) {
+ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
+ proptype = prop;
+ XChangeProperty( dpy, window->window, /* display, window */
+ prop, proptype, /* property, type */
+ 32, /* format: 32-bit datums */
+ PropModeReplace, /* mode */
+ (unsigned char *) &motif_hints, /* data */
+ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
+ );
+ }
+ }
+
+ /* Make a clear cursor to get rid of the monitor cursor */
+ if ( render_spu.fullscreen )
+ {
+ Pixmap pixmap;
+ Cursor cursor;
+ XColor colour;
+ char clearByte = 0;
+
+ /* AdB - Only bother to create a 1x1 cursor (byte) */
+ pixmap = XCreatePixmapFromBitmapData(dpy, window->window, &clearByte,
+ 1, 1, 1, 0, 1);
+ if(!pixmap){
+ crWarning("Unable to create clear cursor pixmap");
+ return GL_FALSE;
+ }
+
+ cursor = XCreatePixmapCursor(dpy, pixmap, pixmap, &colour, &colour, 0, 0);
+ if(!cursor){
+ crWarning("Unable to create clear cursor from zero byte pixmap");
+ return GL_FALSE;
+ }
+ XDefineCursor(dpy, window->window, cursor);
+ XFreePixmap(dpy, pixmap);
+ }
+
+ hints.x = window->x;
+ hints.y = window->y;
+ hints.width = window->BltInfo.width;
+ hints.height = window->BltInfo.height;
+ hints.min_width = hints.width;
+ hints.min_height = hints.height;
+ hints.max_width = hints.width;
+ hints.max_height = hints.height;
+ if (render_spu.resizable)
+ hints.flags = USPosition | USSize;
+ else
+ hints.flags = USPosition | USSize | PMinSize | PMaxSize;
+ XSetStandardProperties( dpy, window->window,
+ WINDOW_NAME, WINDOW_NAME,
+ None, NULL, 0, &hints );
+
+ /* New item! This is needed so that the sgimouse server can find
+ * the crDebug window.
+ */
+ name = WINDOW_NAME;
+ XStringListToTextProperty( &name, 1, &text_prop );
+ XSetWMName( dpy, window->window, &text_prop );
+
+ /* Set window name, resource class */
+ class_hints = XAllocClassHint( );
+ class_hints->res_name = crStrdup( "foo" );
+ class_hints->res_class = crStrdup( "Chromium" );
+ XSetClassHint( dpy, window->window, class_hints );
+ crFree( class_hints->res_name );
+ crFree( class_hints->res_class );
+ XFree( class_hints );
+
+ if (showIt) {
+ XMapWindow( dpy, window->window );
+ XIfEvent( dpy, &event, WaitForMapNotify,
+ (char *) window->window );
+ }
+
+ if ((window->visual->visAttribs & CR_DOUBLE_BIT) && render_spu.nvSwapGroup) {
+ /* NOTE:
+ * If this SPU creates N windows we don't want to gang the N windows
+ * together!
+ * By adding the window ID to the nvSwapGroup ID we can be sure each
+ * app window is in a separate swap group while all the back-end windows
+ * which form a mural are in the same swap group.
+ */
+ GLuint group = 0; /*render_spu.nvSwapGroup + window->BltInfo.Base.id;*/
+ GLuint barrier = 0;
+ JoinSwapGroup(dpy, visual->visual->screen, window->window, group, barrier);
+ }
+
+ /*
+ * End GLX code
+ */
+ crDebug( "Render SPU: actual window x, y, width, height: %d, %d, %d, %d",
+ window->x, window->y, window->BltInfo.width, window->BltInfo.height );
+
+ XSync(dpy, 0);
+
+ if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID)
+ {
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_CREATE, window);
+ AssertRC(rc);
+ }
+
+ return GL_TRUE;
+}
+
+
+static GLboolean
+createPBuffer( VisualInfo *visual, WindowInfo *window )
+{
+ window->visual = visual;
+ window->x = 0;
+ window->y = 0;
+ window->nativeWindow = 0;
+
+ CRASSERT(window->BltInfo.width > 0);
+ CRASSERT(window->BltInfo.height > 0);
+
+#ifdef GLX_VERSION_1_3
+ {
+ int attribs[100], i = 0, w, h;
+ CRASSERT(visual->fbconfig);
+ w = window->BltInfo.width;
+ h = window->BltInfo.height;
+ attribs[i++] = GLX_PRESERVED_CONTENTS;
+ attribs[i++] = True;
+ attribs[i++] = GLX_PBUFFER_WIDTH;
+ attribs[i++] = w;
+ attribs[i++] = GLX_PBUFFER_HEIGHT;
+ attribs[i++] = h;
+ attribs[i++] = 0; /* terminator */
+ window->window = render_spu.ws.glXCreatePbuffer(visual->dpy,
+ visual->fbconfig, attribs);
+ if (window->window) {
+ crDebug("Render SPU: Allocated %d x %d pbuffer", w, h);
+ return GL_TRUE;
+ }
+ else {
+ crWarning("Render SPU: Failed to allocate %d x %d pbuffer", w, h);
+ return GL_FALSE;
+ }
+ }
+#endif /* GLX_VERSION_1_3 */
+ return GL_FALSE;
+}
+
+
+GLboolean
+renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ window->BltInfo.width = render_spu.defaultWidth;
+ window->BltInfo.height = render_spu.defaultHeight;
+ return createPBuffer(visual, window);
+ }
+ else {
+ return createWindow(visual, showIt, window);
+ }
+}
+
+GLboolean
+renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ return renderspu_SystemCreateWindow(visual, showIt, window);
+}
+
+void
+renderspu_SystemDestroyWindow( WindowInfo *window )
+{
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ {
+ crFree(window->buffer);
+ window->buffer = NULL;
+ }
+ else
+#endif
+ {
+ if (window->visual->visAttribs & CR_PBUFFER_BIT) {
+#ifdef GLX_VERSION_1_3
+ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
+#endif
+ }
+ else {
+ /* The value window->nativeWindow will only be non-NULL if the
+ * render_to_app_window option is set to true. In this case, we
+ * don't want to do anything, since we're not responsible for this
+ * window. I know...personal responsibility and all...
+ */
+ if (!window->nativeWindow) {
+ if (window->BltInfo.Base.id != CR_RENDER_WINCMD_ID)
+ {
+ int rc = renderspuWinCmdSubmit(CR_RENDER_WINCMD_TYPE_WIN_ON_DESTROY, window);
+ AssertRC(rc);
+ }
+ XDestroyWindow(window->visual->dpy, window->window);
+ XSync(window->visual->dpy, 0);
+ }
+ }
+ }
+ window->visual = NULL;
+ window->window = 0;
+}
+
+
+GLboolean
+renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
+{
+ Bool is_direct;
+ GLXContext sharedSystemContext = NULL;
+
+ CRASSERT(visual);
+ CRASSERT(context);
+
+ context->visual = visual;
+
+ if (sharedContext != NULL) {
+ sharedSystemContext = sharedContext->context;
+ }
+
+
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ context->context = (GLXContext) render_spu.OSMesaCreateContext(OSMESA_RGB, 0);
+ if (context->context)
+ return GL_TRUE;
+ else
+ return GL_FALSE;
+ }
+#endif
+
+#ifdef GLX_VERSION_1_3
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ context->context = render_spu.ws.glXCreateNewContext( visual->dpy,
+ visual->fbconfig,
+ GLX_RGBA_TYPE,
+ sharedSystemContext,
+ render_spu.try_direct);
+ }
+ else
+#endif
+ {
+ context->context = render_spu.ws.glXCreateContext( visual->dpy,
+ visual->visual,
+ sharedSystemContext,
+ render_spu.try_direct);
+ }
+ if (!context->context) {
+ crError( "Render SPU: Couldn't create rendering context" );
+ return GL_FALSE;
+ }
+
+ is_direct = render_spu.ws.glXIsDirect( visual->dpy, context->context );
+ if (visual->visual)
+ crDebug("Render SPU: Created %s context (%d) on display %s for visAttribs 0x%x",
+ is_direct ? "DIRECT" : "INDIRECT",
+ context->BltInfo.Base.id,
+ DisplayString(visual->dpy),
+ visual->visAttribs);
+
+ if ( render_spu.force_direct && !is_direct )
+ {
+ crError( "Render SPU: Direct rendering not possible." );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+#define USE_GLX_COPYCONTEXT 0
+
+#if !USE_GLX_COPYCONTEXT
+
+/**
+ * Unfortunately, glXCopyContext() is broken sometimes (NVIDIA 76.76 driver).
+ * This bit of code gets and sets GL state we need to copy between contexts.
+ */
+struct saved_state
+{
+ /* XXX depending on the app, more state may be needed here */
+ GLboolean Lighting;
+ GLboolean LightEnabled[8];
+ GLfloat LightPos[8][4];
+ GLfloat LightAmbient[8][4];
+ GLfloat LightDiffuse[8][4];
+ GLfloat LightSpecular[8][4];
+ GLboolean DepthTest;
+};
+
+static struct saved_state SavedState;
+
+static void
+get_state(struct saved_state *s)
+{
+ int i;
+
+ s->Lighting = render_spu.self.IsEnabled(GL_LIGHTING);
+ for (i = 0; i < 8; i++) {
+ s->LightEnabled[i] = render_spu.self.IsEnabled(GL_LIGHT0 + i);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
+ render_spu.self.GetLightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
+ }
+
+ s->DepthTest = render_spu.self.IsEnabled(GL_DEPTH_TEST);
+}
+
+static void
+set_state(const struct saved_state *s)
+{
+ int i;
+
+ if (s->Lighting) {
+ render_spu.self.Enable(GL_LIGHTING);
+ }
+ else {
+ render_spu.self.Disable(GL_LIGHTING);
+ }
+
+ for (i = 0; i < 8; i++) {
+ if (s->LightEnabled[i]) {
+ render_spu.self.Enable(GL_LIGHT0 + i);
+ }
+ else {
+ render_spu.self.Disable(GL_LIGHT0 + i);
+ }
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_POSITION, s->LightPos[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_AMBIENT, s->LightAmbient[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_DIFFUSE, s->LightDiffuse[i]);
+ render_spu.self.Lightfv(GL_LIGHT0 + i, GL_SPECULAR, s->LightSpecular[i]);
+ }
+
+ if (s->DepthTest)
+ render_spu.self.Enable(GL_DEPTH_TEST);
+ else
+ render_spu.self.Disable(GL_DEPTH_TEST);
+}
+
+#endif /* !USE_GLX_COPYCONTEXT */
+
+/**
+ * Recreate the GLX context for ContextInfo. The new context will use the
+ * visual specified by newVisualID.
+ */
+static void
+renderspu_RecreateContext( ContextInfo *context, int newVisualID )
+{
+ XVisualInfo templateVis, *vis;
+ long templateFlags;
+ int screen = 0, count;
+ GLXContext oldContext = context->context;
+
+ templateFlags = VisualScreenMask | VisualIDMask;
+ templateVis.screen = screen;
+ templateVis.visualid = newVisualID;
+ vis = XGetVisualInfo(context->visual->dpy, templateFlags, &templateVis, &count);
+ CRASSERT(vis);
+ if (!vis)
+ return;
+
+ /* create new context */
+ crDebug("Render SPU: Creating new GLX context with visual 0x%x", newVisualID);
+ context->context = render_spu.ws.glXCreateContext(context->visual->dpy,
+ vis, NULL,
+ render_spu.try_direct);
+ CRASSERT(context->context);
+
+#if USE_GLX_COPYCONTEXT
+ /* copy old context state to new context */
+ render_spu.ws.glXCopyContext(context->visual->dpy,
+ oldContext, context->context, ~0);
+ crDebug("Render SPU: Done copying context state");
+#endif
+
+ /* destroy old context */
+ render_spu.ws.glXDestroyContext(context->visual->dpy, oldContext);
+
+ context->visual->visual = vis;
+}
+
+
+void
+renderspu_SystemDestroyContext( ContextInfo *context )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ {
+ render_spu.OSMesaDestroyContext( (OSMesaContext) context->context );
+ }
+ else
+#endif
+ {
+#if 0
+ /* XXX disable for now - causes segfaults w/ NVIDIA's driver */
+ render_spu.ws.glXDestroyContext( context->visual->dpy, context->context );
+#endif
+ }
+ context->visual = NULL;
+ context->context = 0;
+}
+
+
+#ifdef USE_OSMESA
+static void
+check_buffer_size( WindowInfo *window )
+{
+ if (window->BltInfo.width != window->in_buffer_width
+ || window->BltInfo.height != window->in_buffer_height
+ || ! window->buffer) {
+ crFree(window->buffer);
+
+ window->buffer = crCalloc(window->BltInfo.width * window->BltInfo.height
+ * 4 * sizeof (GLubyte));
+
+ window->in_buffer_width = window->BltInfo.width;
+ window->in_buffer_height = window->BltInfo.height;
+
+ crDebug("Render SPU: dimensions changed to %d x %d", window->BltInfo.width, window->BltInfo.height);
+ }
+}
+#endif
+
+
+void
+renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow,
+ ContextInfo *context )
+{
+ Bool b;
+
+ CRASSERT(render_spu.ws.glXMakeCurrent);
+
+ /*crDebug("%s nativeWindow=0x%x", __FUNCTION__, (int) nativeWindow);*/
+
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ check_buffer_size(window);
+ render_spu.OSMesaMakeCurrent( (OSMesaContext) context->context,
+ window->buffer, GL_UNSIGNED_BYTE,
+ window->BltInfo.width, window->BltInfo.height);
+ return;
+ }
+#endif
+
+ nativeWindow = 0;
+
+ if (window && context) {
+ window->appWindow = nativeWindow;
+
+ if (window->visual != context->visual) {
+ crDebug("Render SPU: MakeCurrent visual mismatch (win(%d) bits:0x%x != ctx(%d) bits:0x%x); remaking window.",
+ window->BltInfo.Base.id, window->visual->visAttribs,
+ context->BltInfo.Base.id, context->visual->visAttribs);
+ /*
+ * XXX have to revisit this issue!!!
+ *
+ * But for now we destroy the current window
+ * and re-create it with the context's visual abilities
+ */
+#ifndef SOLARIS_9_X_BUG
+ /*
+ I'm having some really weird issues if I destroy this window
+ when I'm using the version of sunX that comes with Solaris 9.
+ Subsiquent glX calls return GLXBadCurrentWindow error.
+
+ This is an issue even when running Linux version and using
+ the Solaris 9 sunX as a display.
+ -- jw
+
+ jw: we might have to call glXMakeCurrent(dpy, 0, 0) to unbind
+ the context from the window before destroying it. -Brian
+ */
+ render_spu.ws.glXMakeCurrent(window->visual->dpy, 0, 0);
+ renderspu_SystemDestroyWindow( window );
+#endif
+ renderspu_SystemCreateWindow( context->visual, window->visible, window );
+ /*
+ crError("In renderspu_SystemMakeCurrent() window and context"
+ " weren't created with same visual!");
+ */
+ }
+
+ CRASSERT(context->context);
+
+#if 0
+ if (render_spu.render_to_crut_window) {
+ if (render_spu.crut_drawable == 0) {
+ /* We don't know the X drawable ID yet. Ask mothership for it. */
+ char response[8096];
+ CRConnection *conn = crMothershipConnect();
+ if (!conn)
+ {
+ crError("Couldn't connect to the mothership to get CRUT drawable-- "
+ "I have no idea what to do!");
+ }
+ crMothershipGetParam( conn, "crut_drawable", response );
+ render_spu.crut_drawable = crStrToInt(response);
+ crMothershipDisconnect(conn);
+
+ crDebug("Render SPU: using CRUT drawable: 0x%x",
+ render_spu.crut_drawable);
+ if (!render_spu.crut_drawable) {
+ crDebug("Render SPU: Crut drawable 0 is invalid");
+ /* Continue with nativeWindow = 0; we'll render to the window that
+ * we (the Render SPU) previously created.
+ */
+ }
+ }
+
+ nativeWindow = render_spu.crut_drawable;
+ }
+#endif
+
+ if ((render_spu.render_to_crut_window || render_spu.render_to_app_window)
+ && nativeWindow)
+ {
+ /* We're about to bind the rendering context to a window that we
+ * (the Render SPU) did not create. The window was created by the
+ * application or the CRUT server.
+ * Make sure the window ID is valid and that the window's X visual is
+ * the same as the rendering context's.
+ */
+ if (WindowExists(window->visual->dpy, nativeWindow))
+ {
+ int vid = GetWindowVisualID(window->visual->dpy, nativeWindow);
+ GLboolean recreated = GL_FALSE;
+
+ /* check that the window's visual and context's visual match */
+ if (vid != (int) context->visual->visual->visualid) {
+ crWarning("Render SPU: Can't bind context %d to CRUT/native window "
+ "0x%x because of different X visuals (0x%x != 0x%x)!",
+ context->BltInfo.Base.id, (int) nativeWindow,
+ vid, (int) context->visual->visual->visualid);
+ crWarning("Render SPU: Trying to recreate GLX context to match.");
+ /* Try to recreate the GLX context so that it uses the same
+ * GLX visual as the window.
+ */
+#if !USE_GLX_COPYCONTEXT
+ if (context->everCurrent) {
+ get_state(&SavedState);
+ }
+#endif
+ renderspu_RecreateContext(context, vid);
+ recreated = GL_TRUE;
+ }
+
+ /* OK, this should work */
+ window->nativeWindow = (Window) nativeWindow;
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->nativeWindow,
+ context->context );
+ CRASSERT(b);
+#if !USE_GLX_COPYCONTEXT
+ if (recreated) {
+ set_state(&SavedState);
+ }
+#endif
+ }
+ else
+ {
+ crWarning("Render SPU: render_to_app/crut_window option is set but "
+ "the window ID 0x%x is invalid on the display named %s",
+ (unsigned int) nativeWindow,
+ DisplayString(window->visual->dpy));
+ CRASSERT(window->window);
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->window, context->context );
+ CRASSERT(b);
+ }
+ }
+ else
+ {
+ /* This is the normal case - rendering to the render SPU's own window */
+ CRASSERT(window->window);
+#if 0
+ crDebug("calling glXMakecurrent(%p, 0x%x, 0x%x)",
+ window->visual->dpy,
+ (int) window->window, (int) context->context );
+#endif
+ b = render_spu.ws.glXMakeCurrent( window->visual->dpy,
+ window->window, context->context );
+ if (!b) {
+ crWarning("glXMakeCurrent(%p, 0x%x, %p) failed! (winId %d, ctxId %d)",
+ window->visual->dpy,
+ (int) window->window, (void *) context->context,
+ window->BltInfo.Base.id, context->BltInfo.Base.id );
+ }
+ /*CRASSERT(b);*/
+ }
+
+ /* XXX this is a total hack to work around an NVIDIA driver bug */
+#if 0
+ if (render_spu.self.GetFloatv && context->haveWindowPosARB) {
+ GLfloat f[4];
+ render_spu.self.GetFloatv(GL_CURRENT_RASTER_POSITION, f);
+ if (!window->everCurrent || f[1] < 0.0) {
+ crDebug("Render SPU: Resetting raster pos");
+ render_spu.self.WindowPos2iARB(0, 0);
+ }
+ }
+#endif
+ }
+ else
+ {
+ GET_CONTEXT(pCurCtx);
+ if (pCurCtx)
+ {
+ b = render_spu.ws.glXMakeCurrent( pCurCtx->currentWindow->visual->dpy, None, NULL);
+ if (!b) {
+ crWarning("glXMakeCurrent(%p, None, NULL) failed!", pCurCtx->currentWindow->visual->dpy);
+ }
+ }
+
+ }
+}
+
+
+/**
+ * Set window (or pbuffer) size.
+ */
+void
+renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ check_buffer_size(window);
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if (window->visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ /* resizing a pbuffer */
+ if (render_spu.pbufferWidth != 0 || render_spu.pbufferHeight != 0) {
+ /* size limit check */
+ if (w > render_spu.pbufferWidth || h > render_spu.pbufferHeight) {
+ crWarning("Render SPU: Request for %d x %d pbuffer is larger than "
+ "the configured size of %d x %d. ('pbuffer_size')",
+ w, h, render_spu.pbufferWidth, render_spu.pbufferHeight);
+ return;
+ }
+ /*
+ * If the requested new pbuffer size is greater than 1/2 the size of
+ * the max pbuffer, just use the max pbuffer size. This helps avoid
+ * problems with VRAM memory fragmentation. If we run out of VRAM
+ * for pbuffers, some drivers revert to software rendering. We want
+ * to avoid that!
+ */
+ if (w * h >= render_spu.pbufferWidth * render_spu.pbufferHeight / 2) {
+ /* increase the dimensions to the max pbuffer size now */
+ w = render_spu.pbufferWidth;
+ h = render_spu.pbufferHeight;
+ }
+ }
+
+ if (window->BltInfo.width != w || window->BltInfo.height != h) {
+ /* Only resize if the new dimensions really are different */
+#ifdef CHROMIUM_THREADSAFE
+ ContextInfo *currentContext = (ContextInfo *) crGetTSD(&_RenderTSD);
+#else
+ ContextInfo *currentContext = render_spu.currentContext;
+#endif
+ /* Can't resize pbuffers, so destroy it and make a new one */
+ render_spu.ws.glXDestroyPbuffer(window->visual->dpy, window->window);
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+ crDebug("Render SPU: Creating new %d x %d PBuffer (id=%d)",
+ w, h, window->BltInfo.Base.id);
+ if (!createPBuffer(window->visual, window)) {
+ crWarning("Render SPU: Unable to create PBuffer (out of VRAM?)!");
+ }
+ else if (currentContext && currentContext->currentWindow == window) {
+ /* Determine if we need to bind the current context to new pbuffer */
+ render_spu.ws.glXMakeCurrent(window->visual->dpy,
+ window->window,
+ currentContext->context );
+ }
+ }
+ }
+ else {
+ if (!w || !h)
+ {
+ /* X can not handle zero sizes */
+ if (window->visible)
+ {
+ renderspu_SystemShowWindow( window, GL_FALSE );
+ }
+ return;
+ }
+ /* Resize ordinary X window */
+ /*
+ * This is ugly, but it seems to be the only thing that works.
+ * Basically, XResizeWindow() doesn't seem to always take effect
+ * immediately.
+ * Even after an XSync(), the GetWindowAttributes() call will sometimes
+ * return the old window size. So, we use a loop to repeat the window
+ * resize until it seems to take effect.
+ */
+ int attempt;
+ crDebug("Render SPU: XResizeWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, w, h);
+ XResizeWindow(window->visual->dpy, window->window, w, h);
+ XSync(window->visual->dpy, 0);
+
+ if (!window->BltInfo.width || !window->BltInfo.height)
+ {
+ /* we have hidden the window instead of sizing it to (0;0) since X is unable to handle zero sizes */
+ if (window->visible)
+ {
+ renderspu_SystemShowWindow( window, GL_TRUE );
+ return;
+ }
+ }
+#if 0
+ for (attempt = 0; attempt < 3; attempt++) { /* try three times max */
+ XWindowAttributes attribs;
+ /* Now, query the window size */
+ XGetWindowAttributes(window->visual->dpy, window->window, &attribs);
+ if (attribs.width == w && attribs.height == h)
+ break;
+ /* sleep for a millisecond and try again */
+ crMsleep(1);
+ }
+#endif
+ }
+}
+
+
+void
+renderspu_SystemGetWindowGeometry( WindowInfo *window,
+ GLint *x, GLint *y, GLint *w, GLint *h )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ *w = window->BltInfo.width;
+ *h = window->BltInfo.height;
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ CRASSERT(window->window);
+ if (window->visual->visAttribs & CR_PBUFFER_BIT)
+ {
+ *x = 0;
+ *y = 0;
+ *w = window->BltInfo.width;
+ *h = window->BltInfo.height;
+ }
+ else
+ {
+ Window xw, child, root;
+ unsigned int width, height, bw, d;
+ int rx, ry;
+
+ if ((render_spu.render_to_app_window || render_spu.render_to_crut_window)
+ && window->nativeWindow) {
+ xw = window->nativeWindow;
+ }
+ else {
+ xw = window->window;
+ }
+
+ XGetGeometry(window->visual->dpy, xw, &root,
+ x, y, &width, &height, &bw, &d);
+
+ /* translate x/y to screen coords */
+ if (!XTranslateCoordinates(window->visual->dpy, xw, root,
+ 0, 0, &rx, &ry, &child)) {
+ rx = ry = 0;
+ }
+ *x = rx;
+ *y = ry;
+ *w = (int) width;
+ *h = (int) height;
+ }
+}
+
+
+void
+renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h )
+{
+ int scrn;
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ *w = 2048;
+ *h = 2048;
+ return;
+ }
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ CRASSERT(window->window);
+
+ scrn = DefaultScreen(window->visual->dpy);
+ *w = DisplayWidth(window->visual->dpy, scrn);
+ *h = DisplayHeight(window->visual->dpy, scrn);
+}
+
+
+void
+renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ crDebug("Render SPU: XMoveWindow (%x, %x, %d, %d)", window->visual->dpy, window->window, x, y);
+ XMoveWindow(window->visual->dpy, window->window, x, y);
+ XSync(window->visual->dpy, 0);
+ }
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void
+renderspu_SystemWindowVisibleRegion( WindowInfo *window, GLint cRects, const GLint *pRects )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ((window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ int evb, erb, i;
+ XRectangle *pXRects;
+
+ if (!XShapeQueryExtension(window->visual->dpy, &evb, &erb))
+ {
+ crWarning("Render SPU: Display %s doesn't support SHAPE extension", window->visual->displayName);
+ return;
+ }
+
+ if (cRects>0)
+ {
+ pXRects = (XRectangle *) crAlloc(cRects * sizeof(XRectangle));
+
+ for (i=0; i<cRects; ++i)
+ {
+ pXRects[i].x = (short) pRects[4*i];
+ pXRects[i].y = (short) pRects[4*i+1];
+ pXRects[i].width = (unsigned short) (pRects[4*i+2]-pRects[4*i]);
+ pXRects[i].height = (unsigned short) (pRects[4*i+3]-pRects[4*i+1]);
+ }
+ }
+ else
+ {
+ pXRects = (XRectangle *) crAlloc(sizeof(XRectangle));
+ pXRects[0].x = 0;
+ pXRects[0].y = 0;
+ pXRects[0].width = 0;
+ pXRects[0].height = 0;
+ cRects = 1;
+ }
+
+ crDebug("Render SPU: XShapeCombineRectangles (%x, %x, cRects=%i)", window->visual->dpy, window->window, cRects);
+
+ XShapeCombineRectangles(window->visual->dpy, window->window, ShapeBounding, 0, 0,
+ pXRects, cRects, ShapeSet, YXBanded);
+ XSync(window->visual->dpy, 0);
+ crFree(pXRects);
+ }
+}
+
+/* Either show or hide the render SPU's window. */
+void
+renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
+{
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa)
+ return;
+#endif
+
+ if (window->visual->dpy && window->window &&
+ (window->visual->visAttribs & CR_PBUFFER_BIT) == 0)
+ {
+ if (showIt)
+ {
+ if (window->BltInfo.width && window->BltInfo.height)
+ {
+ XMapWindow( window->visual->dpy, window->window );
+ XSync(window->visual->dpy, 0);
+ }
+ }
+ else
+ {
+ XUnmapWindow( window->visual->dpy, window->window );
+ XSync(window->visual->dpy, 0);
+ }
+ }
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WinCmd thread rather
+ * than a Main thread. It defaults to 1, because otherwise there were
+ * 3D driver incompatibilities on some systems. Elsewhere it causes flicker
+ * on NVidia GPUs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ WARN(("renderspuVBoxCompositorTryAcquire failed rc %d", rc));
+ return;
+ }
+ }
+
+ {
+ Status status;
+ XEvent event;
+ render_spu.self.Flush();
+// renderspuVBoxPresentBlitterEnsureCreated(window, 0);
+
+ crMemset(&event, 0, sizeof (event));
+ event.type = Expose;
+ event.xexpose.window = window->window;
+ event.xexpose.width = window->BltInfo.width;
+ event.xexpose.height = window->BltInfo.height;
+ status = XSendEvent(render_spu.pCommunicationDisplay, render_spu.WinCmdWindow.window, False, 0, &event);
+ if (!status)
+ {
+ WARN(("XSendEvent returned null"));
+ }
+ XFlush(render_spu.pCommunicationDisplay);
+ }
+}
+
+static void
+MarkWindow(WindowInfo *w)
+{
+ static GC gc = 0; /* XXX per-window??? */
+ if (!gc) {
+ /* Create a GC for drawing invisible lines */
+ XGCValues gcValues;
+ gcValues.function = GXnoop;
+ gc = XCreateGC(w->visual->dpy, w->nativeWindow, GCFunction, &gcValues);
+ }
+ XDrawLine(w->visual->dpy, w->nativeWindow, gc, 0, 0, w->BltInfo.width, w->BltInfo.height);
+}
+
+
+void
+renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags )
+{
+ CRASSERT(w);
+
+#if 00 /*TEMPORARY - FOR TESTING SWAP LOCK*/
+ if (1) {
+ /* random delay */
+ int k = crRandInt(1000 * 100, 750*1000);
+ static int first = 1;
+ if (first) {
+ crRandAutoSeed();
+ first = 0;
+ }
+ usleep(k);
+ }
+#endif
+
+ /* render_to_app_window:
+ * w->nativeWindow will only be non-zero if the
+ * render_spu.render_to_app_window option is true and
+ * MakeCurrent() recorded the nativeWindow handle in the WindowInfo
+ * structure.
+ */
+ if (w->nativeWindow) {
+ render_spu.ws.glXSwapBuffers( w->visual->dpy, w->nativeWindow );
+#if 0
+ MarkWindow(w);
+#else
+ (void) MarkWindow;
+#endif
+ }
+ else {
+ render_spu.ws.glXSwapBuffers( w->visual->dpy, w->window );
+ }
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *window)
+{
+ Window parent;
+
+ parent = render_spu_parent_window_id>0 ? render_spu_parent_window_id :
+ RootWindow(window->visual->dpy, window->visual->visual->screen);
+
+ XReparentWindow(window->visual->dpy, window->window, parent, window->x, window->y);
+ XSync(window->visual->dpy, False);
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ return cFunctions;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c
new file mode 100644
index 00000000..ec494a1f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_init.c
@@ -0,0 +1,623 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_mem.h"
+#include "cr_spu.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "cr_url.h"
+#include "cr_environment.h"
+#include "renderspu.h"
+#include <stdio.h>
+
+#ifdef RT_OS_DARWIN
+# include <iprt/semaphore.h>
+#endif /* RT_OS_DARWIN */
+
+static SPUNamedFunctionTable _cr_render_table[1000];
+
+SPUFunctions render_functions = {
+ NULL, /* CHILD COPY */
+ NULL, /* DATA */
+ _cr_render_table /* THE ACTUAL FUNCTIONS */
+};
+
+RenderSPU render_spu;
+uint64_t render_spu_parent_window_id = 0;
+
+#ifdef CHROMIUM_THREADSAFE
+CRtsd _RenderTSD;
+#endif
+
+static void swapsyncConnect(void)
+{
+ char hostname[4096], protocol[4096];
+ unsigned short port;
+
+ crNetInit(NULL, NULL);
+
+ if (!crParseURL( render_spu.swap_master_url, protocol, hostname,
+ &port, 9876))
+ crError( "Bad URL: %s", render_spu.swap_master_url );
+
+ if (render_spu.is_swap_master)
+ {
+ int a;
+
+ render_spu.swap_conns = (CRConnection **)crAlloc(
+ render_spu.num_swap_clients*sizeof(CRConnection *));
+ for (a=0; a<render_spu.num_swap_clients; a++)
+ {
+ render_spu.swap_conns[a] = crNetAcceptClient( protocol, hostname, port,
+ render_spu.swap_mtu, 1);
+ }
+ }
+ else
+ {
+ render_spu.swap_conns = (CRConnection **)crAlloc(sizeof(CRConnection *));
+
+ render_spu.swap_conns[0] = crNetConnectToServer(render_spu.swap_master_url,
+ port, render_spu.swap_mtu, 1);
+ if (!render_spu.swap_conns[0])
+ crError("Failed connection");
+ }
+}
+
+#ifdef RT_OS_WINDOWS
+static DWORD WINAPI renderSPUWindowThreadProc(void* unused)
+{
+ MSG msg;
+ BOOL bRet;
+
+ (void) unused;
+
+ /* Force system to create the message queue.
+ * Else, there's a chance that render spu will issue PostThreadMessage
+ * before this thread calls GetMessage for first time.
+ */
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+ crDebug("RenderSPU: Window thread started (%x)", crThreadID());
+ SetEvent(render_spu.hWinThreadReadyEvent);
+
+ while( (bRet = GetMessage( &msg, 0, 0, 0 )) != 0)
+ {
+ if (bRet == -1)
+ {
+ crError("RenderSPU: Window thread GetMessage failed (%x)", GetLastError());
+ break;
+ }
+ else
+ {
+ if (msg.message == WM_VBOX_RENDERSPU_CREATE_WINDOW)
+ {
+ LPCREATESTRUCT pCS = (LPCREATESTRUCT) msg.lParam;
+ HWND hWnd;
+ WindowInfo *pWindow = (WindowInfo *)pCS->lpCreateParams;
+
+ CRASSERT(msg.lParam && !msg.wParam && pCS->lpCreateParams);
+
+ hWnd = CreateWindowEx(pCS->dwExStyle, pCS->lpszName, pCS->lpszClass, pCS->style,
+ pCS->x, pCS->y, pCS->cx, pCS->cy,
+ pCS->hwndParent, pCS->hMenu, pCS->hInstance, &render_spu);
+
+ pWindow->hWnd = hWnd;
+
+ SetEvent(render_spu.hWinThreadReadyEvent);
+ }
+ else if (msg.message == WM_VBOX_RENDERSPU_DESTROY_WINDOW)
+ {
+ CRASSERT(msg.lParam && !msg.wParam);
+
+ DestroyWindow(((VBOX_RENDERSPU_DESTROY_WINDOW*) msg.lParam)->hWnd);
+
+ SetEvent(render_spu.hWinThreadReadyEvent);
+ }
+ else
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ render_spu.dwWinThreadId = 0;
+
+ crDebug("RenderSPU: Window thread stopped (%x)", crThreadID());
+ SetEvent(render_spu.hWinThreadReadyEvent);
+
+ return 0;
+}
+#endif
+
+int renderspuDefaultCtxInit()
+{
+ GLint defaultWin, defaultCtx;
+ WindowInfo *windowInfo;
+
+ /*
+ * Create the default window and context. Their indexes are zero and
+ * a client can use them without calling CreateContext or WindowCreate.
+ */
+ crDebug("Render SPU: Creating default window (visBits=0x%x, id=0)",
+ render_spu.default_visual);
+ defaultWin = renderspuWindowCreateEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_WINDOW_ID );
+ if (defaultWin != CR_RENDER_DEFAULT_WINDOW_ID) {
+ crError("Render SPU: Couldn't get a double-buffered, RGB visual with Z!");
+ return VERR_GENERAL_FAILURE;
+ }
+ crDebug( "Render SPU: WindowCreate returned %d (0=normal)", defaultWin );
+
+ crDebug("Render SPU: Creating default context, visBits=0x%x",
+ render_spu.default_visual );
+ defaultCtx = renderspuCreateContextEx( NULL, render_spu.default_visual, CR_RENDER_DEFAULT_CONTEXT_ID, 0 );
+ if (defaultCtx != CR_RENDER_DEFAULT_CONTEXT_ID) {
+ crError("Render SPU: failed to create default context!");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ renderspuMakeCurrent( defaultWin, 0, defaultCtx );
+
+ /* Get windowInfo for the default window */
+ windowInfo = (WindowInfo *) crHashtableSearch(render_spu.windowTable, CR_RENDER_DEFAULT_WINDOW_ID);
+ CRASSERT(windowInfo);
+ windowInfo->mapPending = GL_TRUE;
+
+ return VINF_SUCCESS;
+}
+
+static SPUFunctions *
+renderSPUInit( int id, SPU *child, SPU *self,
+ unsigned int context_id, unsigned int num_contexts )
+{
+ int numFuncs, numSpecial;
+
+ const char * pcpwSetting;
+ int rc;
+
+ (void) child;
+ (void) context_id;
+ (void) num_contexts;
+
+ self->privatePtr = (void *) &render_spu;
+
+#ifdef CHROMIUM_THREADSAFE
+ crDebug("Render SPU: thread-safe");
+ crInitTSD(&_RenderTSD);
+#endif
+
+ crMemZero(&render_spu, sizeof(render_spu));
+
+ render_spu.id = id;
+ renderspuSetVBoxConfiguration(&render_spu);
+
+ if (render_spu.swap_master_url)
+ swapsyncConnect();
+
+
+ /* Get our special functions. */
+ numSpecial = renderspuCreateFunctions( _cr_render_table );
+
+#ifdef RT_OS_WINDOWS
+ /* Start thread to create windows and process window messages */
+ crDebug("RenderSPU: Starting windows serving thread");
+ render_spu.hWinThreadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!render_spu.hWinThreadReadyEvent)
+ {
+ crError("RenderSPU: Failed to create WinThreadReadyEvent! (%x)", GetLastError());
+ return NULL;
+ }
+
+ if (!CreateThread(NULL, 0, renderSPUWindowThreadProc, 0, 0, &render_spu.dwWinThreadId))
+ {
+ crError("RenderSPU: Failed to start windows thread! (%x)", GetLastError());
+ return NULL;
+ }
+ WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
+#endif
+
+ /* Get the OpenGL functions. */
+ numFuncs = crLoadOpenGL( &render_spu.ws, _cr_render_table + numSpecial );
+ if (numFuncs == 0) {
+ crError("The render SPU was unable to load the native OpenGL library");
+ return NULL;
+ }
+
+ numFuncs += numSpecial;
+
+ render_spu.contextTable = crAllocHashtableEx(1, INT32_MAX);
+ render_spu.windowTable = crAllocHashtableEx(1, INT32_MAX);
+
+ render_spu.dummyWindowTable = crAllocHashtable();
+
+ pcpwSetting = crGetenv("CR_RENDER_ENABLE_SINGLE_PRESENT_CONTEXT");
+ if (pcpwSetting)
+ {
+ if (pcpwSetting[0] == '0')
+ pcpwSetting = NULL;
+ }
+
+ if (pcpwSetting)
+ {
+ /** @todo need proper blitter synchronization, do not use so far!
+ * the problem is that rendering can be done in multiple thread: the main command (hgcm) thread and the redraw thread
+ * we currently use per-window synchronization, while we'll need a per-blitter synchronization if one blitter is used for multiple windows
+ * this is not done currently */
+ crWarning("TODO: need proper blitter synchronization, do not use so far!");
+ render_spu.blitterTable = crAllocHashtable();
+ CRASSERT(render_spu.blitterTable);
+ }
+ else
+ render_spu.blitterTable = NULL;
+
+ CRASSERT(render_spu.default_visual & CR_RGB_BIT);
+
+ rc = renderspu_SystemInit();
+ if (!RT_SUCCESS(rc))
+ {
+ crError("renderspu_SystemInit failed rc %d", rc);
+ return NULL;
+ }
+#ifdef USE_OSMESA
+ if (render_spu.use_osmesa) {
+ if (!crLoadOSMesa(&render_spu.OSMesaCreateContext,
+ &render_spu.OSMesaMakeCurrent,
+ &render_spu.OSMesaDestroyContext)) {
+ crError("Unable to load OSMesa library");
+ }
+ }
+#endif
+
+#ifdef DARWIN
+# ifdef VBOX_WITH_COCOA_QT
+# else /* VBOX_WITH_COCOA_QT */
+ render_spu.hRootVisibleRegion = 0;
+ render_spu.currentBufferName = 1;
+ render_spu.uiDockUpdateTS = 0;
+ /* Create a mutex for synchronizing events from the main Qt thread & this
+ thread */
+ RTSemFastMutexCreate(&render_spu.syncMutex);
+ /* Create our window groups */
+ CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pMasterGroup);
+ CreateWindowGroup(kWindowGroupAttrMoveTogether | kWindowGroupAttrLayerTogether | kWindowGroupAttrSharedActivation | kWindowGroupAttrHideOnCollapse | kWindowGroupAttrFixedLevel, &render_spu.pParentGroup);
+ /* Make the correct z-layering */
+ SendWindowGroupBehind (render_spu.pParentGroup, render_spu.pMasterGroup);
+ /* and set the gParentGroup as parent for gMasterGroup. */
+ SetWindowGroupParent (render_spu.pMasterGroup, render_spu.pParentGroup);
+ /* Install the event handlers */
+ EventTypeSpec eventList[] =
+ {
+ {kEventClassVBox, kEventVBoxUpdateContext}, /* Update the context after show/size/move events */
+ {kEventClassVBox, kEventVBoxBoundsChanged} /* Clip/Pos the OpenGL windows when the main window is changed in pos/size */
+ };
+ /* We need to process events from our main window */
+ render_spu.hParentEventHandler = NewEventHandlerUPP(windowEvtHndlr);
+ InstallApplicationEventHandler (render_spu.hParentEventHandler,
+ GetEventTypeCount(eventList), eventList,
+ NULL, NULL);
+ render_spu.fInit = true;
+# endif /* VBOX_WITH_COCOA_QT */
+#endif /* DARWIN */
+
+ rc = renderspuDefaultCtxInit();
+ if (!RT_SUCCESS(rc))
+ {
+ WARN(("renderspuDefaultCtxInit failed %d", rc));
+ return NULL;
+ }
+
+ /*
+ * Get the OpenGL extension functions.
+ * SIGH -- we have to wait until the very bitter end to load the
+ * extensions, because the context has to be bound before
+ * wglGetProcAddress will work correctly. No such issue with GLX though.
+ */
+ numFuncs += crLoadOpenGLExtensions( &render_spu.ws, _cr_render_table + numFuncs );
+ CRASSERT(numFuncs < 1000);
+
+#ifdef WINDOWS
+ /*
+ * Same problem as above, these are extensions so we need to
+ * load them after a context has been bound. As they're WGL
+ * extensions too, we can't simply tag them into the spu_loader.
+ * So we do them here for now.
+ * Grrr, NVIDIA driver uses EXT for GetExtensionsStringEXT,
+ * but ARB for others. Need further testing here....
+ */
+ render_spu.ws.wglGetExtensionsStringEXT =
+ (wglGetExtensionsStringEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglGetExtensionsStringEXT" );
+ render_spu.ws.wglChoosePixelFormatEXT =
+ (wglChoosePixelFormatEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglChoosePixelFormatARB" );
+ render_spu.ws.wglGetPixelFormatAttribivEXT =
+ (wglGetPixelFormatAttribivEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribivARB" );
+ render_spu.ws.wglGetPixelFormatAttribfvEXT =
+ (wglGetPixelFormatAttribfvEXTFunc_t)
+ render_spu.ws.wglGetProcAddress( "wglGetPixelFormatAttribfvARB" );
+
+ if (render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("CopyTexSubImage3D");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glCopyTexSubImage3D");
+ ++numFuncs;
+ crDebug("Render SPU: Found glCopyTexSubImage3D function");
+ }
+
+ if (render_spu.ws.wglGetProcAddress("glDrawRangeElements"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("DrawRangeElements");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glDrawRangeElements");
+ ++numFuncs;
+ crDebug("Render SPU: Found glDrawRangeElements function");
+ }
+
+ if (render_spu.ws.wglGetProcAddress("glTexSubImage3D"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("TexSubImage3D");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexSubImage3D");
+ ++numFuncs;
+ crDebug("Render SPU: Found glTexSubImage3D function");
+ }
+
+ if (render_spu.ws.wglGetProcAddress("glTexImage3D"))
+ {
+ _cr_render_table[numFuncs].name = crStrdup("TexImage3D");
+ _cr_render_table[numFuncs].fn = (SPUGenericFunction) render_spu.ws.wglGetProcAddress("glTexImage3D");
+ ++numFuncs;
+ crDebug("Render SPU: Found glTexImage3D function");
+ }
+
+ if (render_spu.ws.wglGetExtensionsStringEXT) {
+ crDebug("WGL - found wglGetExtensionsStringEXT\n");
+ }
+ if (render_spu.ws.wglChoosePixelFormatEXT) {
+ crDebug("WGL - found wglChoosePixelFormatEXT\n");
+ }
+#endif
+
+ render_spu.barrierHash = crAllocHashtable();
+
+ render_spu.cursorX = 0;
+ render_spu.cursorY = 0;
+ render_spu.use_L2 = 0;
+
+ render_spu.gather_conns = NULL;
+
+ numFuncs = renderspu_SystemPostprocessFunctions(_cr_render_table, numFuncs, RT_ELEMENTS(_cr_render_table));
+
+ crDebug("Render SPU: ---------- End of Init -------------");
+
+ return &render_functions;
+}
+
+static void renderSPUSelfDispatch(SPUDispatchTable *self)
+{
+ crSPUInitDispatchTable( &(render_spu.self) );
+ crSPUCopyDispatchTable( &(render_spu.self), self );
+
+ crSPUInitDispatchTable( &(render_spu.blitterDispatch) );
+ crSPUCopyDispatchTable( &(render_spu.blitterDispatch), self );
+
+ render_spu.server = (CRServer *)(self->server);
+
+ {
+ GLfloat version;
+ version = crStrToFloat((const char *) render_spu.ws.glGetString(GL_VERSION));
+
+ if (version>=2.f || crStrstr((const char*)render_spu.ws.glGetString(GL_EXTENSIONS), "GL_ARB_vertex_shader"))
+ {
+ GLint mu=0;
+ render_spu.self.GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &mu);
+ crInfo("Render SPU: GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB=%i", mu);
+ }
+ }
+}
+
+
+static void DeleteContextCallback( void *data )
+{
+ ContextInfo *context = (ContextInfo *) data;
+ renderspuContextMarkDeletedAndRelease(context);
+}
+
+static void DeleteWindowCallback( void *data )
+{
+ WindowInfo *window = (WindowInfo *) data;
+ renderspuWinTermOnShutdown(window);
+ renderspuWinRelease(window);
+}
+
+static void DeleteBlitterCallback( void *data )
+{
+ PCR_BLITTER pBlitter = (PCR_BLITTER) data;
+ CrBltTerm(pBlitter);
+ crFree(pBlitter);
+}
+
+static void renderspuBlitterCleanupCB(unsigned long key, void *data1, void *data2)
+{
+ WindowInfo *window = (WindowInfo *) data1;
+ CRASSERT(window);
+
+ renderspuVBoxPresentBlitterCleanup( window );
+}
+
+
+static void renderspuDeleteBlitterCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ DeleteBlitterCallback(data1);
+}
+
+
+static void renderspuDeleteWindowCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ DeleteWindowCallback(data1);
+}
+
+static void renderspuDeleteBarierCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ crFree(data1);
+}
+
+
+static void renderspuDeleteContextCB(unsigned long key, void *data1, void *data2)
+{
+ CRHashTable *pTbl = (CRHashTable*)data2;
+
+ crHashtableDelete( pTbl, key, NULL );
+
+ DeleteContextCallback(data1);
+}
+
+void renderspuCleanupBase(bool fDeleteTables)
+{
+ renderspuVBoxCompositorClearAll();
+
+ if (render_spu.blitterTable)
+ {
+ if (fDeleteTables)
+ {
+ crFreeHashtable(render_spu.blitterTable, DeleteBlitterCallback);
+ render_spu.blitterTable = NULL;
+ }
+ else
+ {
+ crHashtableWalk(render_spu.blitterTable, renderspuDeleteBlitterCB, render_spu.contextTable);
+ }
+ }
+ else
+ {
+ crHashtableWalk(render_spu.windowTable, renderspuBlitterCleanupCB, NULL);
+
+ crHashtableWalk(render_spu.dummyWindowTable, renderspuBlitterCleanupCB, NULL);
+ }
+
+ renderspuSetDefaultSharedContext(NULL);
+
+ if (fDeleteTables)
+ {
+ crFreeHashtable(render_spu.contextTable, DeleteContextCallback);
+ render_spu.contextTable = NULL;
+ crFreeHashtable(render_spu.windowTable, DeleteWindowCallback);
+ render_spu.windowTable = NULL;
+ crFreeHashtable(render_spu.dummyWindowTable, DeleteWindowCallback);
+ render_spu.dummyWindowTable = NULL;
+ crFreeHashtable(render_spu.barrierHash, crFree);
+ render_spu.barrierHash = NULL;
+ }
+ else
+ {
+ crHashtableWalk(render_spu.contextTable, renderspuDeleteContextCB, render_spu.contextTable);
+ crHashtableWalk(render_spu.windowTable, renderspuDeleteWindowCB, render_spu.windowTable);
+ crHashtableWalk(render_spu.dummyWindowTable, renderspuDeleteWindowCB, render_spu.dummyWindowTable);
+ crHashtableWalk(render_spu.barrierHash, renderspuDeleteBarierCB, render_spu.barrierHash);
+ }
+}
+
+static int renderSPUCleanup(void)
+{
+ renderspuCleanupBase(true);
+
+#ifdef RT_OS_DARWIN
+# ifndef VBOX_WITH_COCOA_QT
+ render_spu.fInit = false;
+ DisposeEventHandlerUPP(render_spu.hParentEventHandler);
+ ReleaseWindowGroup(render_spu.pMasterGroup);
+ ReleaseWindowGroup(render_spu.pParentGroup);
+ if (render_spu.hRootVisibleRegion)
+ {
+ DisposeRgn(render_spu.hRootVisibleRegion);
+ render_spu.hRootVisibleRegion = 0;
+ }
+ render_spu.currentBufferName = 1;
+ render_spu.uiDockUpdateTS = 0;
+ RTSemFastMutexDestroy(render_spu.syncMutex);
+# else /* VBOX_WITH_COCOA_QT */
+# endif /* VBOX_WITH_COCOA_QT */
+#endif /* RT_OS_DARWIN */
+
+#ifdef RT_OS_WINDOWS
+ if (render_spu.dwWinThreadId)
+ {
+ HANDLE hNative;
+
+ hNative = OpenThread(SYNCHRONIZE|THREAD_QUERY_INFORMATION|THREAD_TERMINATE,
+ false, render_spu.dwWinThreadId);
+ if (!hNative)
+ {
+ crWarning("Failed to get handle for window thread(%#x)", GetLastError());
+ }
+
+ if (PostThreadMessage(render_spu.dwWinThreadId, WM_QUIT, 0, 0))
+ {
+ WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
+
+ /*wait for os thread to actually finish*/
+ if (hNative && WaitForSingleObject(hNative, 3000)==WAIT_TIMEOUT)
+ {
+ crDebug("Wait failed, terminating");
+ if (!TerminateThread(hNative, 1))
+ {
+ crWarning("TerminateThread failed");
+ }
+ }
+ }
+
+ if (hNative)
+ {
+ CloseHandle(hNative);
+ }
+ }
+ CloseHandle(render_spu.hWinThreadReadyEvent);
+ render_spu.hWinThreadReadyEvent = NULL;
+#endif
+
+ crUnloadOpenGL();
+
+#ifdef CHROMIUM_THREADSAFE
+ crFreeTSD(&_RenderTSD);
+#endif
+
+ return 1;
+}
+
+
+extern SPUOptions renderSPUOptions[];
+
+int SPULoad( char **name, char **super, SPUInitFuncPtr *init,
+ SPUSelfDispatchFuncPtr *self, SPUCleanupFuncPtr *cleanup,
+ SPUOptionsPtr *options, int *flags )
+{
+ *name = "render";
+ *super = NULL;
+ *init = renderSPUInit;
+ *self = renderSPUSelfDispatch;
+ *cleanup = renderSPUCleanup;
+ *options = renderSPUOptions;
+ *flags = (SPU_NO_PACKER|SPU_IS_TERMINAL|SPU_MAX_SERVERS_ZERO);
+
+ return 1;
+}
+
+DECLEXPORT(void) renderspuSetWindowId(uint64_t winId)
+{
+ render_spu_parent_window_id = winId;
+ crDebug("Set new parent window %p (no actual reparent performed)", winId);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
new file mode 100644
index 00000000..5df60410
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/render/renderspu_wgl.c
@@ -0,0 +1,1741 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+
+#define WIN32_LEAN_AND_MEAN
+#include <iprt/win/windows.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include "cr_environment.h"
+#include "cr_error.h"
+#include "cr_string.h"
+#include "renderspu.h"
+#include "cr_mem.h"
+
+
+/* IAT patcher stuff */
+#define RVA2PTR(_t, _base, _off) ((_t*)(((uint8_t*)(_base)) + (_off)))
+
+int renderspuIatPatcherGetImportAddress(HMODULE hModule, LPCSTR pszLib, LPCSTR pszName, void** ppAdr)
+{
+ PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hModule;
+ PIMAGE_NT_HEADERS pNtHdr;
+ PIMAGE_IMPORT_DESCRIPTOR pImportDr;
+ DWORD rvaImport;
+
+ crDebug("searching entry %s from %s", pszName, pszLib);
+
+ *ppAdr = 0;
+
+ if (pDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
+ {
+ crWarning("invalid dos signature");
+ return VERR_INVALID_HANDLE;
+ }
+ pNtHdr = RVA2PTR(IMAGE_NT_HEADERS, pDosHdr, pDosHdr->e_lfanew);
+ if (pNtHdr->Signature != IMAGE_NT_SIGNATURE)
+ {
+ crWarning("invalid nt signature");
+ return VERR_INVALID_HANDLE;
+ }
+ rvaImport = pNtHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ if (!rvaImport)
+ {
+ crWarning("no imports found");
+ return VERR_NOT_FOUND;
+ }
+ pImportDr = RVA2PTR(IMAGE_IMPORT_DESCRIPTOR, pDosHdr, rvaImport);
+
+ for ( ;pImportDr->TimeDateStamp != 0 || pImportDr->Name != 0; ++pImportDr)
+ {
+ DWORD rvaINT, rvaIAT;
+ PIMAGE_THUNK_DATA pINT, pIAT;
+ LPCSTR pszLibCur = RVA2PTR(char, pDosHdr, pImportDr->Name);
+ if (stricmp(pszLibCur, pszLib))
+ continue;
+
+ /* got the necessary lib! */
+ crDebug("got info for lib");
+
+ rvaINT = pImportDr->OriginalFirstThunk;
+ rvaIAT = pImportDr->FirstThunk;
+
+ if (!rvaINT || !rvaIAT)
+ {
+ crWarning("either rvaINT(0x%x) or rvaIAT(0x%x) are NULL, nothing found!", rvaINT, rvaIAT);
+ return VERR_NOT_FOUND;
+ }
+
+ pINT = RVA2PTR(IMAGE_THUNK_DATA, pDosHdr, rvaINT);
+ pIAT = RVA2PTR(IMAGE_THUNK_DATA, pDosHdr, rvaIAT);
+
+ for ( ; pINT->u1.AddressOfData; ++pINT, ++pIAT)
+ {
+ PIMAGE_IMPORT_BY_NAME pIbn;
+
+ if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal))
+ continue;
+
+ pIbn = RVA2PTR(IMAGE_IMPORT_BY_NAME, pDosHdr, pINT->u1.AddressOfData);
+
+ if (stricmp(pszName, (char*)pIbn->Name))
+ continue;
+
+ *ppAdr = &pIAT->u1.Function;
+
+ crDebug("search succeeded!");
+ return VINF_SUCCESS;
+ }
+ }
+
+ crDebug("not found");
+ return VERR_NOT_FOUND;
+}
+
+int renderspuIatPatcherPatchEntry(void *pvEntry, void *pvValue, void **ppvOldVal)
+{
+ void **ppfn = (void**)pvEntry;
+ DWORD dwOldProtect = 0;
+
+ if (!VirtualProtect(pvEntry, sizeof (pvEntry), PAGE_READWRITE, &dwOldProtect))
+ {
+ crWarning("VirtualProtect 1 failed, %d", GetLastError());
+ return VERR_ACCESS_DENIED;
+ }
+
+ if (ppvOldVal)
+ *ppvOldVal = *ppfn;
+ *ppfn = pvValue;
+
+ if (!VirtualProtect(pvEntry, sizeof (pvEntry), dwOldProtect, &dwOldProtect))
+ {
+ crWarning("VirtualProtect 2 failed, %d.. ignoring", GetLastError());
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int renderspuIatPatcherPatchFunction(HMODULE hModule, LPCSTR pszLib, LPCSTR pszName, void* pfn)
+{
+ void* pAdr;
+ int rc = renderspuIatPatcherGetImportAddress(hModule, pszLib, pszName, &pAdr);
+ if (RT_FAILURE(rc))
+ {
+ crDebug("renderspuIatPatcherGetImportAddress failed, %d", rc);
+ return rc;
+ }
+
+ rc = renderspuIatPatcherPatchEntry(pAdr, pfn, NULL);
+ if (RT_FAILURE(rc))
+ {
+ crWarning("renderspuIatPatcherPatchEntry failed, %d", rc);
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
+/* patch */
+static HWND __stdcall renderspuAtiQuirk_GetForegroundWindow()
+{
+ crDebug("renderspuAtiQuirk_GetForegroundWindow");
+ return NULL;
+}
+
+
+#define CRREG_MAXKEYNAME 8
+static int renderspuAtiQuirk_GetICDDriverList(char *pBuf, DWORD cbBuf, DWORD *pcbResult)
+{
+ static LPCSTR aValueNames[] = {"OpenGLVendorName", "OpenGLDriverName"};
+ char *pBufPos = pBuf;
+ DWORD cbBufRemain = cbBuf, cbTotal = 0;
+ HKEY hKey, hSubkey;
+ DWORD dwIndex = 0;
+ int i;
+ int rc = VINF_SUCCESS;
+ char NameBuf[CRREG_MAXKEYNAME];
+ LONG lRc;
+
+ if (pcbResult)
+ *pcbResult = 0;
+
+ lRc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}",
+ 0, /* reserved*/
+ KEY_READ,
+ &hKey);
+ if (ERROR_SUCCESS != lRc)
+ {
+ crDebug("RegOpenKeyEx 1 failed, %d", lRc);
+ return VERR_OPEN_FAILED;
+ }
+
+ for ( ; ; ++dwIndex)
+ {
+ lRc = RegEnumKeyA(hKey, dwIndex, NameBuf, CRREG_MAXKEYNAME);
+ if (lRc == ERROR_NO_MORE_ITEMS)
+ break;
+ if (lRc == ERROR_MORE_DATA)
+ continue;
+ if (lRc != ERROR_SUCCESS)
+ {
+ crWarning("RegEnumKeyA failed, %d", lRc);
+ continue;
+ }
+
+ lRc = RegOpenKeyEx(hKey,
+ NameBuf,
+ 0, /* reserved*/
+ KEY_READ,
+ &hSubkey);
+ if (ERROR_SUCCESS != lRc)
+ {
+ crDebug("RegOpenKeyEx 2 failed, %d", lRc);
+ RegCloseKey(hKey);
+ return VERR_OPEN_FAILED;
+ }
+
+ for (i = 0; i < RT_ELEMENTS(aValueNames); ++i)
+ {
+ DWORD cbCur = cbBufRemain;
+ DWORD type;
+ lRc = RegQueryValueExA(hSubkey, aValueNames[i], NULL, /* reserved*/
+ &type,
+ (PBYTE)pBufPos, &cbCur);
+ /* exclude second null termination */
+ --cbCur;
+
+ if (ERROR_MORE_DATA == lRc)
+ {
+ if (REG_MULTI_SZ != type)
+ {
+ crWarning("unexpected data type! %d", type);
+ continue;
+ }
+ rc = VERR_BUFFER_OVERFLOW;
+ pBufPos = NULL;
+ cbBufRemain = 0;
+ CRASSERT(cbCur > 0 && cbCur < UINT32_MAX/2);
+ cbTotal += cbCur;
+ continue;
+ }
+ if (ERROR_SUCCESS != lRc)
+ {
+ crDebug("RegQueryValueExA failed, %d", lRc);
+ continue;
+ }
+
+ if (REG_MULTI_SZ != type)
+ {
+ crWarning("unexpected data type! %d", type);
+ continue;
+ }
+
+ /* succeeded */
+ CRASSERT(cbCur > 0 && cbCur < UINT32_MAX/2);
+ pBufPos += cbCur;
+ cbBufRemain -= cbCur;
+ cbTotal += cbCur;
+ CRASSERT(cbBufRemain < UINT32_MAX/2);
+ }
+
+ RegCloseKey(hSubkey);
+ }
+
+ RegCloseKey(hKey);
+
+ if (cbTotal)
+ {
+ /* include second null termination */
+ CRASSERT(!pBufPos || pBufPos[0] == '\0');
+ ++cbTotal;
+ }
+
+ if (pcbResult)
+ *pcbResult = cbTotal;
+
+ return rc;
+}
+
+static int renderspuAtiQuirk_ApplyForModule(LPCSTR pszAtiDll)
+{
+ int rc;
+ HMODULE hAtiDll;
+
+ crDebug("renderspuAtiQuirk_ApplyForModule (%s)", pszAtiDll);
+
+ hAtiDll = GetModuleHandleA(pszAtiDll);
+ if (!hAtiDll)
+ {
+ crDebug("GetModuleHandle failed, %d", GetLastError());
+ return VERR_NOT_FOUND;
+ }
+
+ rc = renderspuIatPatcherPatchFunction(hAtiDll, "user32.dll", "GetForegroundWindow", (void*)renderspuAtiQuirk_GetForegroundWindow);
+ if (RT_FAILURE(rc))
+ {
+ crDebug("renderspuIatPatcherPatchFunction failed, %d", rc);
+ return rc;
+ }
+
+ crDebug("renderspuAtiQuirk_ApplyForModule SUCCEEDED!");
+ crInfo("ATI Fullscreen quirk patch SUCCEEDED!");
+
+ return VINF_SUCCESS;
+}
+
+static LPCSTR renderspuRegMultiSzNextVal(LPCSTR pszBuf)
+{
+ pszBuf += strlen(pszBuf) + sizeof (pszBuf[0]);
+
+ if (pszBuf[0] == '\0')
+ return NULL;
+
+ return pszBuf;
+}
+
+static LPCSTR renderspuRegMultiSzCurVal(LPCSTR pszBuf)
+{
+ if (pszBuf[0] == '\0')
+ return NULL;
+
+ return pszBuf;
+}
+
+
+static int renderspuAtiQuirk_Apply()
+{
+ char aBuf[4096];
+ DWORD cbResult = 0;
+ LPCSTR pszVal;
+ int rc;
+
+ crDebug("renderspuAtiQuirk_Apply..");
+
+ rc = renderspuAtiQuirk_GetICDDriverList(aBuf, sizeof (aBuf), &cbResult);
+ if (RT_FAILURE(rc))
+ {
+ crDebug("renderspuAtiQuirk_GetICDDriverList failed, rc(%d)", rc);
+ return rc;
+ }
+
+ for (pszVal = renderspuRegMultiSzCurVal(aBuf);
+ pszVal;
+ pszVal = renderspuRegMultiSzNextVal(pszVal))
+ {
+ renderspuAtiQuirk_ApplyForModule(pszVal);
+ }
+
+ return VINF_SUCCESS;
+}
+
+static GLboolean renderspuAtiQuirk_Needed()
+{
+ const char * pszString = render_spu.ws.glGetString(GL_VENDOR);
+ if (pszString && strstr(pszString, "ATI"))
+ return GL_TRUE;
+ pszString = render_spu.ws.glGetString(GL_RENDERER);
+ if (pszString && strstr(pszString, "ATI"))
+ return GL_TRUE;
+ return GL_FALSE;
+}
+
+static void renderspuAtiQuirk_ChkApply()
+{
+ static GLboolean fChecked = GL_FALSE;
+ if (fChecked)
+ return;
+
+ fChecked = GL_TRUE;
+ if (!renderspuAtiQuirk_Needed())
+ return;
+
+ crInfo("This is an ATI card, taking care of fullscreen..");
+
+ /*
+ * ATI WDDM-based graphics have an issue with rendering fullscreen.
+ * See public tickets #9775 & #9267 .
+ * Namely ATI drivers check whether ogl window is foreground and fullscreen
+ * and if so - do D3DKMTSetDisplayMode for ogl surface,
+ * which prevented any other data from being displayed, no matter what.
+ *
+ * Here we check whether we're using an ATI card and if so, patch the ogl ICD driver's IAT
+ * to replace GetForegroundWindow reference with our renderspuAtiQuirk_GetForegroundWindow,
+ * which always returns NULL.
+ */
+ renderspuAtiQuirk_Apply();
+}
+
+#define WINDOW_NAME window->title
+
+static BOOL
+bSetupPixelFormat( HDC hdc, GLbitfield visAttribs );
+
+GLboolean renderspu_SystemInitVisual( VisualInfo *visual )
+{
+ if (visual->visAttribs & CR_PBUFFER_BIT) {
+ crWarning("Render SPU: PBuffers not support on Windows yet.");
+ }
+
+ /* In the windows world, we need a window before a context.
+ * Use the device_context as a marker to do just that */
+
+ return TRUE;
+}
+
+void renderspu_SystemDestroyWindow( WindowInfo *window )
+{
+ VBOX_RENDERSPU_DESTROY_WINDOW vrdw;
+
+ CRASSERT(window);
+
+ /*DestroyWindow( window->hWnd );*/
+
+ vrdw.hWnd = window->hWnd;
+
+ if (render_spu.dwWinThreadId)
+ {
+ PostThreadMessage(render_spu.dwWinThreadId, WM_VBOX_RENDERSPU_DESTROY_WINDOW, 0, (LPARAM) &vrdw);
+ WaitForSingleObject(render_spu.hWinThreadReadyEvent, INFINITE);
+ }
+ else
+ {
+ crError("Render SPU: window thread is not running");
+ }
+
+ window->hWnd = NULL;
+ window->visual = NULL;
+ if (window->hRgn)
+ {
+ DeleteObject(window->hRgn);
+ window->hRgn = NULL;
+ }
+}
+
+static LONG WINAPI
+MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ /* int w,h; */
+
+ switch ( uMsg ) {
+ case WM_PAINT:
+ {
+ WindowInfo *pWindow = (WindowInfo *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if (pWindow)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR * pCompositor;
+
+ pCompositor = renderspuVBoxCompositorAcquire(pWindow);
+ if (pCompositor)
+ {
+ HDC hDC;
+ PAINTSTRUCT Paint;
+
+ Assert(pWindow->device_context);
+ hDC = BeginPaint(pWindow->hWnd, &Paint);
+ if (hDC)
+ {
+ BOOL bRc;
+ pWindow->redraw_device_context = hDC;
+
+ renderspuVBoxPresentCompositionGeneric(pWindow, pCompositor, NULL, 1, true);
+
+ bRc = EndPaint(pWindow->hWnd, &Paint);
+
+ pWindow->redraw_device_context = NULL;
+
+ renderspuVBoxCompositorRelease(pWindow);
+
+ if (!bRc)
+ {
+ DWORD winEr = GetLastError();
+ crWarning("EndPaint failed, winEr %d", winEr);
+ }
+ }
+ else
+ {
+ DWORD winEr = GetLastError();
+ crWarning("BeginPaint failed, winEr %d", winEr);
+ }
+ }
+ }
+ break;
+ }
+ case WM_SIZE:
+ /* w = LOWORD( lParam );
+ * h = HIWORD( lParam ); */
+
+ /* glViewport( 0, 0, w, h ); */
+#if 0
+ glViewport( -render_spu.mural_x, -render_spu.mural_y,
+ render_spu.mural_width, render_spu.mural_height );
+ glScissor( -render_spu.mural_x, -render_spu.mural_y,
+ render_spu.mural_width, render_spu.mural_height );
+#endif
+ break;
+
+ case WM_CLOSE:
+ crWarning( "Render SPU: caught WM_CLOSE -- quitting." );
+ exit( 0 );
+ break;
+
+ case WM_DESTROY:
+ crDebug("Render SPU: caught WM_DESTROY for our window %x", hWnd);
+ break;
+
+ case WM_NCHITTEST:
+ crDebug("WM_NCHITTEST");
+ return HTNOWHERE;
+ }
+
+ return DefWindowProc( hWnd, uMsg, wParam, lParam );
+}
+
+static BOOL
+bSetupPixelFormatEXT( HDC hdc, GLbitfield visAttribs)
+{
+ PIXELFORMATDESCRIPTOR ppfd;
+ int pixelFormat;
+ int attribList[100];
+ float fattribList[] = { 0.0, 0.0 };
+ int numFormats;
+ int i = 0;
+ BOOL vis;
+
+ CRASSERT(visAttribs & CR_RGB_BIT); /* anybody need color index */
+
+ crWarning("Render SPU: Using WGL_EXT_pixel_format to select visual ID.");
+
+ attribList[i++] = WGL_DRAW_TO_WINDOW_EXT;
+ attribList[i++] = GL_TRUE;
+ attribList[i++] = WGL_ACCELERATION_EXT;
+ attribList[i++] = WGL_FULL_ACCELERATION_EXT;
+ attribList[i++] = WGL_COLOR_BITS_EXT;
+ attribList[i++] = 24;
+ attribList[i++] = WGL_RED_BITS_EXT;
+ attribList[i++] = 1;
+ attribList[i++] = WGL_GREEN_BITS_EXT;
+ attribList[i++] = 1;
+ attribList[i++] = WGL_BLUE_BITS_EXT;
+ attribList[i++] = 1;
+
+ crWarning("Render SPU: Visual chosen is... RGB");
+
+ if (visAttribs & CR_ALPHA_BIT)
+ {
+ attribList[i++] = WGL_ALPHA_BITS_EXT;
+ attribList[i++] = 1;
+ crWarning("A");
+ }
+
+ crWarning(", ");
+
+ if (visAttribs & CR_DOUBLE_BIT) {
+ attribList[i++] = WGL_DOUBLE_BUFFER_EXT;
+ attribList[i++] = GL_TRUE;
+ crWarning("DB, ");
+ }
+
+ if (visAttribs & CR_STEREO_BIT) {
+ attribList[i++] = WGL_STEREO_EXT;
+ attribList[i++] = GL_TRUE;
+ crWarning("Stereo, ");
+ }
+
+ if (visAttribs & CR_DEPTH_BIT)
+ {
+ attribList[i++] = WGL_DEPTH_BITS_EXT;
+ attribList[i++] = 1;
+ crWarning("Z, ");
+ }
+
+ if (visAttribs & CR_STENCIL_BIT)
+ {
+ attribList[i++] = WGL_STENCIL_BITS_EXT;
+ attribList[i++] = 1;
+ crWarning("Stencil, ");
+ }
+
+ if (visAttribs & CR_ACCUM_BIT)
+ {
+ attribList[i++] = WGL_ACCUM_RED_BITS_EXT;
+ attribList[i++] = 1;
+ attribList[i++] = WGL_ACCUM_GREEN_BITS_EXT;
+ attribList[i++] = 1;
+ attribList[i++] = WGL_ACCUM_BLUE_BITS_EXT;
+ attribList[i++] = 1;
+ crWarning("Accum, ");
+ if (visAttribs & CR_ALPHA_BIT)
+ {
+ attribList[i++] = WGL_ACCUM_ALPHA_BITS_EXT;
+ attribList[i++] = 1;
+ crWarning("Accum Alpha, ");
+ }
+ }
+
+ if (visAttribs & CR_MULTISAMPLE_BIT)
+ {
+ attribList[i++] = WGL_SAMPLE_BUFFERS_EXT;
+ attribList[i++] = 1;
+ attribList[i++] = WGL_SAMPLES_EXT;
+ attribList[i++] = 4;
+ crWarning("Multisample, ");
+ }
+
+ crWarning("\n");
+
+ /* End the list */
+ attribList[i++] = 0;
+ attribList[i++] = 0;
+
+ vis = render_spu.ws.wglChoosePixelFormatEXT( hdc, attribList, fattribList, 1, &pixelFormat, &numFormats);
+
+ crDebug("Render SPU: wglChoosePixelFormatEXT (vis 0x%x, LastError 0x%x, pixelFormat 0x%x", vis, GetLastError(), pixelFormat);
+
+#ifdef VBOX_CR_SERVER_FORCE_WGL
+ render_spu.ws.wglSetPixelFormat( hdc, pixelFormat, &ppfd );
+#else
+ SetPixelFormat( hdc, pixelFormat, &ppfd );
+#endif
+
+ crDebug("Render SPU: wglSetPixelFormat (Last error 0x%x)", GetLastError());
+
+ return vis;
+}
+
+static BOOL
+bSetupPixelFormatNormal( HDC hdc, GLbitfield visAttribs )
+{
+ PIXELFORMATDESCRIPTOR pfd = {
+ sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */
+ 1, /* version number */
+ PFD_DRAW_TO_WINDOW | /* support window */
+ PFD_SUPPORT_OPENGL, /* support OpenGL */
+ PFD_TYPE_RGBA, /* RGBA type */
+ 24, /* 24-bit color depth */
+ 0, 0, 0, 0, 0, 0, /* color bits ignored */
+ 0, /* no alpha buffer */
+ 0, /* shift bit ignored */
+ 0, /* no accumulation buffer */
+ 0, 0, 0, 0, /* accum bits ignored */
+ 0, /* set depth buffer */
+ 0, /* set stencil buffer */
+ 0, /* no auxiliary buffer */
+ PFD_MAIN_PLANE, /* main layer */
+ 0, /* reserved */
+ 0, 0, 0 /* layer masks ignored */
+ };
+ PIXELFORMATDESCRIPTOR *ppfd = &pfd;
+ char s[1000];
+ GLbitfield b = 0;
+ int pixelformat;
+
+ renderspuMakeVisString( visAttribs, s );
+
+ crDebug( "Render SPU: WGL wants these visual capabilities: %s", s);
+
+ /* These really come into play with sort-last configs */
+ if (visAttribs & CR_DEPTH_BIT)
+ ppfd->cDepthBits = 24;
+ if (visAttribs & CR_ACCUM_BIT)
+ ppfd->cAccumBits = 16;
+ if (visAttribs & CR_RGB_BIT)
+ ppfd->cColorBits = 24;
+ if (visAttribs & CR_STENCIL_BIT)
+ ppfd->cStencilBits = 8;
+ if (visAttribs & CR_ALPHA_BIT)
+ ppfd->cAlphaBits = 8;
+ if (visAttribs & CR_DOUBLE_BIT)
+ ppfd->dwFlags |= PFD_DOUBLEBUFFER;
+ if (visAttribs & CR_STEREO_BIT)
+ ppfd->dwFlags |= PFD_STEREO;
+
+ /*
+ * We call the wgl functions directly if the SPU was loaded
+ * by our faker library, otherwise we have to call the GDI
+ * versions.
+ */
+#ifdef VBOX_CR_SERVER_FORCE_WGL
+ if (crGetenv( "CR_WGL_DO_NOT_USE_GDI" ) != NULL)
+ {
+ pixelformat = render_spu.ws.wglChoosePixelFormat( hdc, ppfd );
+ /* doing this twice is normal Win32 magic */
+ pixelformat = render_spu.ws.wglChoosePixelFormat( hdc, ppfd );
+ if ( pixelformat == 0 )
+ {
+ crError( "render_spu.ws.wglChoosePixelFormat failed" );
+ }
+ if ( !render_spu.ws.wglSetPixelFormat( hdc, pixelformat, ppfd ) )
+ {
+ crError( "render_spu.ws.wglSetPixelFormat failed" );
+ }
+
+ render_spu.ws.wglDescribePixelFormat( hdc, pixelformat, sizeof(*ppfd), ppfd );
+ }
+ else
+#endif
+ {
+ /* Okay, we were loaded manually. Call the GDI functions. */
+ pixelformat = ChoosePixelFormat( hdc, ppfd );
+ /* doing this twice is normal Win32 magic */
+ pixelformat = ChoosePixelFormat( hdc, ppfd );
+ if ( pixelformat == 0 )
+ {
+ crError( "ChoosePixelFormat failed" );
+ }
+ if ( !SetPixelFormat( hdc, pixelformat, ppfd ) )
+ {
+ crError( "SetPixelFormat failed (Error 0x%x)", GetLastError() );
+ }
+
+ DescribePixelFormat( hdc, pixelformat, sizeof(*ppfd), ppfd );
+ }
+
+
+ if (ppfd->cDepthBits > 0)
+ b |= CR_DEPTH_BIT;
+ if (ppfd->cAccumBits > 0)
+ b |= CR_ACCUM_BIT;
+ if (ppfd->cColorBits > 8)
+ b |= CR_RGB_BIT;
+ if (ppfd->cStencilBits > 0)
+ b |= CR_STENCIL_BIT;
+ if (ppfd->cAlphaBits > 0)
+ b |= CR_ALPHA_BIT;
+ if (ppfd->dwFlags & PFD_DOUBLEBUFFER)
+ b |= CR_DOUBLE_BIT;
+ if (ppfd->dwFlags & PFD_STEREO)
+ b |= CR_STEREO_BIT;
+
+ renderspuMakeVisString( b, s );
+
+ crDebug( "Render SPU: WGL chose these visual capabilities: %s", s);
+ return TRUE;
+}
+
+static BOOL
+bSetupPixelFormat( HDC hdc, GLbitfield visAttribs )
+{
+ /* According to http://www.opengl.org/resources/faq/technical/mswindows.htm
+ we shouldn't be using wgl functions to setup pixel formats unless we're loading ICD driver.
+ In particular, bSetupPixelFormatEXT bugs with Intel drivers.
+ */
+ return bSetupPixelFormatNormal(hdc, visAttribs);
+}
+
+GLboolean renderspu_SystemCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+ HDESK desktop;
+ HINSTANCE hinstance;
+ WNDCLASS wc;
+ DWORD window_style;
+ int window_plus_caption_width;
+ int window_plus_caption_height;
+
+ window->hRgn = NULL;
+ window->visual = visual;
+ window->nativeWindow = 0;
+
+ if ( render_spu.use_L2 )
+ {
+ crWarning( "Going fullscreen because we think we're using Lightning-2." );
+ render_spu.fullscreen = 1;
+ }
+
+ /*
+ * Begin Windows / WGL code
+ */
+
+ hinstance = GetModuleHandle( NULL );
+ if (!hinstance)
+ {
+ crError( "Render SPU: Couldn't get a handle to my module." );
+ return GL_FALSE;
+ }
+ crDebug( "Render SPU: Got the module handle: 0x%x", hinstance );
+
+ /* If we were launched from a service, telnet, or rsh, we need to
+ * get the input desktop. */
+
+ desktop = OpenInputDesktop( 0, FALSE,
+ DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+ DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+ DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+ DESKTOP_SWITCHDESKTOP | GENERIC_WRITE );
+
+ if ( !desktop )
+ {
+ crError( "Render SPU: Couldn't acquire input desktop" );
+ return GL_FALSE;
+ }
+ crDebug( "Render SPU: Got the desktop: 0x%x", desktop );
+
+ if ( !SetThreadDesktop( desktop ) )
+ {
+ /* If this function fails, it's probably because
+ * it's already been called (i.e., the render SPU
+ * is bolted to an application?) */
+
+ /*crError( "Couldn't set thread to input desktop" ); */
+ }
+ crDebug( "Render SPU: Set the thread desktop -- this might have failed." );
+
+ if ( !GetClassInfo(hinstance, WINDOW_NAME, &wc) )
+ {
+ wc.style = CS_OWNDC;
+ wc.lpfnWndProc = (WNDPROC) MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hinstance;
+ wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
+ wc.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WINDOW_NAME;
+
+ if ( !RegisterClass( &wc ) )
+ {
+ crError( "Render SPU: Couldn't register window class -- you're not trying "
+ "to do multi-pipe stuff on windows, are you?\n\nNote --"
+ "This error message is from 1997 and probably doesn't make"
+ "any sense any more, but it's nostalgic for Humper." );
+ return GL_FALSE;
+ }
+ crDebug( "Render SPU: Registered the class" );
+ }
+ crDebug( "Render SPU: Got the class information" );
+
+ /* Full screen window should be a popup (undecorated) window */
+#if 1
+ window_style = ( render_spu.fullscreen ? WS_POPUP : WS_CAPTION );
+#else
+ window_style = ( WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
+ window_style |= WS_SYSMENU;
+#endif
+
+ crDebug( "Render SPU: Fullscreen: %s", render_spu.fullscreen ? "yes" : "no");
+
+ if ( render_spu.fullscreen )
+ {
+#if 0
+
+ int smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
+ int smCyFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME ) + 1;
+ int smCyCaption = GetSystemMetrics( SM_CYCAPTION );
+
+ window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
+ window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
+
+ crDebug( "Render SPU: Window Dims: %d, %d", window->BltInfo.width, window->BltInfo.height );
+
+ window->x = render_spu->defaultX - smCxFixedFrame - 1;
+ window->y = render_spu->defaultY - smCyFixedFrame - smCyCaption;
+
+ window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
+ window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
+
+#else
+ /* Since it's undecorated, we don't have to do anything fancy
+ * with these parameters. */
+
+ window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
+ window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
+ window->x = 0;
+ window->y = 0;
+ window_plus_caption_width = window->BltInfo.width;
+ window_plus_caption_height = window->BltInfo.height;
+
+#endif
+ }
+ else
+ {
+ /* CreateWindow takes the size of the entire window, so we add
+ * in the size necessary for the frame and the caption. */
+
+ int smCxFixedFrame, smCyFixedFrame, smCyCaption;
+ smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
+ crDebug( "Render SPU: Got the X fixed frame" );
+ smCyFixedFrame = GetSystemMetrics( SM_CYFIXEDFRAME );
+ crDebug( "Render SPU: Got the Y fixed frame" );
+ smCyCaption = GetSystemMetrics( SM_CYCAPTION );
+ crDebug( "Render SPU: Got the Caption " );
+
+ window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
+ window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
+
+ window->x = render_spu.defaultX - smCxFixedFrame;
+ window->y = render_spu.defaultY - smCyFixedFrame - smCyCaption;
+ }
+
+ crDebug( "Render SPU: Creating the window: (%d,%d), (%d,%d)", render_spu.defaultX, render_spu.defaultY, window_plus_caption_width, window_plus_caption_height );
+ window->hWnd = CreateWindow( WINDOW_NAME, WINDOW_NAME,
+ window_style,
+ window->x, window->y,
+ window_plus_caption_width,
+ window_plus_caption_height,
+ NULL, NULL, hinstance, &render_spu );
+
+ if ( !window->hWnd )
+ {
+ crError( "Render SPU: Create Window failed! That's almost certainly terrible." );
+ return GL_FALSE;
+ }
+
+ window->visible = showIt;
+
+ if (!showIt)
+ {
+ renderspu_SystemShowWindow( window, 0 );
+ if (window->BltInfo.height <= 0 || window->BltInfo.width <= 0)
+ {
+ renderspu_SystemWindowSize(window,
+ window->BltInfo.width > 0 ? window->BltInfo.width : 4,
+ window->BltInfo.height > 0 ? window->BltInfo.height : 4);
+ }
+ }
+ else
+ {
+ crDebug( "Render SPU: Showing the window" );
+ crDebug("renderspu_SystemCreateWindow: showwindow: %x", window->hWnd);
+ }
+
+ CRASSERT(!window->visible == !showIt);
+
+ /* Intel drivers require a window to be visible for proper 3D rendering,
+ * so set it visible and handle the visibility with visible regions (see below) */
+ ShowWindow( window->hWnd, SW_SHOWNORMAL );
+
+ SetForegroundWindow( window->hWnd );
+
+ SetWindowPos( window->hWnd, HWND_TOP, window->x, window->y,
+ window_plus_caption_width, window_plus_caption_height,
+ ( render_spu.fullscreen ? (SWP_SHOWWINDOW |
+ SWP_NOSENDCHANGING |
+ SWP_NOREDRAW |
+ SWP_NOACTIVATE ) :
+ 0 ) );
+
+ if ( render_spu.fullscreen )
+ ShowCursor( FALSE );
+
+ window->device_context = GetDC( window->hWnd );
+ if (!window->device_context)
+ {
+ DWORD winEr = GetLastError();
+ crWarning("GetDC failed, winEr %d", winEr);
+ }
+
+ crDebug( "Render SPU: Got the DC: 0x%x", window->device_context );
+
+ if ( !bSetupPixelFormat( window->device_context, visual->visAttribs ) )
+ {
+ crError( "Render SPU: Couldn't set up the device context! Yikes!" );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+GLboolean renderspu_SystemVBoxCreateWindow( VisualInfo *visual, GLboolean showIt, WindowInfo *window )
+{
+#if 0
+ HDESK desktop;
+#endif
+ HINSTANCE hinstance;
+ WNDCLASS wc;
+ DWORD window_style;
+ int window_plus_caption_width;
+ int window_plus_caption_height;
+
+ window->hRgn = NULL;
+ window->visual = visual;
+ window->nativeWindow = 0;
+
+ if ( render_spu.use_L2 )
+ {
+ crWarning( "Going fullscreen because we think we're using Lightning-2." );
+ render_spu.fullscreen = 1;
+ }
+
+ /*
+ * Begin Windows / WGL code
+ */
+
+ hinstance = GetModuleHandle( NULL );
+ if (!hinstance)
+ {
+ crError( "Render SPU: Couldn't get a handle to my module." );
+ return GL_FALSE;
+ }
+ crDebug( "Render SPU: Got the module handle: 0x%x", hinstance );
+
+#if 0
+ /* If we were launched from a service, telnet, or rsh, we need to
+ * get the input desktop. */
+
+ desktop = OpenInputDesktop( 0, FALSE,
+ DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW |
+ DESKTOP_ENUMERATE | DESKTOP_HOOKCONTROL |
+ DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS |
+ DESKTOP_SWITCHDESKTOP | GENERIC_WRITE );
+
+ if ( !desktop )
+ {
+ crError( "Render SPU: Couldn't acquire input desktop" );
+ return GL_FALSE;
+ }
+ crDebug( "Render SPU: Got the desktop: 0x%x", desktop );
+
+ if ( !SetThreadDesktop( desktop ) )
+ {
+ /* If this function fails, it's probably because
+ * it's already been called (i.e., the render SPU
+ * is bolted to an application?) */
+
+ /*crError( "Couldn't set thread to input desktop" ); */
+ }
+ crDebug( "Render SPU: Set the thread desktop -- this might have failed." );
+#endif
+
+ if ( !GetClassInfo(hinstance, WINDOW_NAME, &wc) )
+ {
+ wc.style = CS_OWNDC; // | CS_PARENTDC;
+ wc.lpfnWndProc = (WNDPROC) MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hinstance;
+ wc.hIcon = NULL; //LoadIcon( NULL, IDI_APPLICATION );
+ wc.hCursor = NULL; //LoadCursor( NULL, IDC_ARROW );
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WINDOW_NAME;
+
+ if ( !RegisterClass( &wc ) )
+ {
+ crError( "Render SPU: Couldn't register window class -- you're not trying "
+ "to do multi-pipe stuff on windows, are you?\n\nNote --"
+ "This error message is from 1997 and probably doesn't make"
+ "any sense any more, but it's nostalgic for Humper." );
+ return GL_FALSE;
+ }
+ crDebug( "Render SPU: Registered the class" );
+ }
+ crDebug( "Render SPU: Got the class information" );
+
+ /* Full screen window should be a popup (undecorated) window */
+#if 1
+ window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED;
+ if (render_spu_parent_window_id)
+ {
+ window_style |= WS_CHILD;
+ }
+#else
+ window_style = ( WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
+ window_style |= WS_SYSMENU;
+#endif
+
+ crDebug( "Render SPU: Fullscreen: %s", render_spu.fullscreen ? "yes" : "no");
+
+ if ( render_spu.fullscreen )
+ {
+#if 0
+
+ int smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
+ int smCyFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME ) + 1;
+ int smCyCaption = GetSystemMetrics( SM_CYCAPTION );
+
+ window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
+ window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
+
+ crDebug( "Render SPU: Window Dims: %d, %d", window->BltInfo.width, window->BltInfo.height );
+
+ window->x = render_spu->defaultX - smCxFixedFrame - 1;
+ window->y = render_spu->defaultY - smCyFixedFrame - smCyCaption;
+
+ window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
+ window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
+
+#else
+ /* Since it's undecorated, we don't have to do anything fancy
+ * with these parameters. */
+
+ window->BltInfo.width = GetSystemMetrics( SM_CXSCREEN ) ;
+ window->BltInfo.height = GetSystemMetrics( SM_CYSCREEN ) ;
+ window->x = 0;
+ window->y = 0;
+ window_plus_caption_width = window->BltInfo.width;
+ window_plus_caption_height = window->BltInfo.height;
+
+#endif
+ }
+ else
+ {
+ /* CreateWindow takes the size of the entire window, so we add
+ * in the size necessary for the frame and the caption. */
+ int smCxFixedFrame, smCyFixedFrame, smCyCaption;
+ smCxFixedFrame = GetSystemMetrics( SM_CXFIXEDFRAME );
+ crDebug( "Render SPU: Got the X fixed frame" );
+ smCyFixedFrame = GetSystemMetrics( SM_CYFIXEDFRAME );
+ crDebug( "Render SPU: Got the Y fixed frame" );
+ smCyCaption = GetSystemMetrics( SM_CYCAPTION );
+ crDebug( "Render SPU: Got the Caption " );
+
+ window_plus_caption_width = window->BltInfo.width + 2 * smCxFixedFrame;
+ window_plus_caption_height = window->BltInfo.height + 2 * smCyFixedFrame + smCyCaption;
+
+ window->x = render_spu.defaultX;
+ window->y = render_spu.defaultY;
+ }
+
+ crDebug( "Render SPU: Creating the window: (%d,%d), (%d,%d)", render_spu.defaultX, render_spu.defaultY, window_plus_caption_width, window_plus_caption_height );
+ /*window->hWnd = CreateWindowEx( WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY,
+ WINDOW_NAME, WINDOW_NAME,
+ window_style,
+ window->x, window->y,
+ window->BltInfo.width,
+ window->BltInfo.height,
+ (void*) render_spu_parent_window_id, NULL, hinstance, &render_spu );*/
+ {
+ CREATESTRUCT cs;
+
+ cs.lpCreateParams = window;
+
+ cs.dwExStyle = WS_EX_NOACTIVATE | WS_EX_NOPARENTNOTIFY;
+ cs.lpszName = WINDOW_NAME;
+ cs.lpszClass = WINDOW_NAME;
+ cs.style = window_style;
+ cs.x = window->x;
+ cs.y = window->y;
+ cs.cx = window->BltInfo.width;
+ cs.cy = window->BltInfo.height;
+ cs.hwndParent = (void*) render_spu_parent_window_id;
+ cs.hMenu = NULL;
+ cs.hInstance = hinstance;
+
+ if (render_spu.dwWinThreadId)
+ {
+ DWORD res;
+ int cnt=0;
+
+ if (!PostThreadMessage(render_spu.dwWinThreadId, WM_VBOX_RENDERSPU_CREATE_WINDOW, 0, (LPARAM) &cs))
+ {
+ crError("Render SPU: PostThreadMessage failed with %i", GetLastError());
+ return GL_FALSE;
+ }
+
+ do
+ {
+ res = WaitForSingleObject(render_spu.hWinThreadReadyEvent, 1000);
+ cnt++;
+ }
+ while ((res!=WAIT_OBJECT_0) && (cnt<10));
+
+ crDebug("Render SPU: window thread waited %i secs", cnt);
+
+ if (res!=WAIT_OBJECT_0)
+ {
+ crError("Render SPU: window thread not responded after %i tries", cnt);
+ return GL_FALSE;
+ }
+ }
+ else
+ {
+ crError("Render SPU: window thread is not running");
+ return GL_FALSE;
+ }
+ }
+
+ if ( !window->hWnd )
+ {
+ crError( "Render SPU: Create Window failed! That's almost certainly terrible." );
+ return GL_FALSE;
+ }
+
+ window->visible = 1;
+
+ if (!showIt)
+ {
+ renderspu_SystemShowWindow( window, 0 );
+ if (window->BltInfo.height <= 0 || window->BltInfo.width <= 0)
+ {
+ renderspu_SystemWindowSize(window,
+ window->BltInfo.width > 0 ? window->BltInfo.width : 4,
+ window->BltInfo.height > 0 ? window->BltInfo.height : 4);
+ }
+ }
+ else
+ {
+#ifdef DEBUG_misha
+ crWarning( "Render SPU: Showing the window" );
+#else
+ crDebug( "Render SPU: Showing the window" );
+#endif
+ crDebug("renderspu_SystemCreateWindow: showwindow: %x", window->hWnd);
+ }
+
+ CRASSERT(!window->visible == !showIt);
+
+ /* Intel drivers require a window to be visible for proper 3D rendering,
+ * so set it visible and handle the visibility with visible regions (see below) */
+ if (window->BltInfo.Base.id != CR_RENDER_DEFAULT_WINDOW_ID)
+ {
+ ShowWindow( window->hWnd, SW_SHOWNORMAL );
+ }
+ else
+ {
+ CRASSERT(!showIt);
+ /* dummy window is always hidden in any way */
+ }
+
+ //SetForegroundWindow( visual->hWnd );
+
+ SetWindowPos( window->hWnd, HWND_TOP, window->x, window->y,
+ window->BltInfo.width, window->BltInfo.height,
+ ( render_spu.fullscreen ?
+ (SWP_SHOWWINDOW | SWP_NOSENDCHANGING | SWP_NOREDRAW | SWP_NOACTIVATE ) : SWP_NOACTIVATE
+ ) );
+ crDebug("Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd,
+ window->x, window->y, window->BltInfo.width, window->BltInfo.height);
+
+ if ( render_spu.fullscreen )
+ ShowCursor( FALSE );
+
+ window->device_context = GetDC( window->hWnd );
+ if (!window->device_context)
+ {
+ DWORD winEr = GetLastError();
+ crWarning("GetDC failed, winEr %d", winEr);
+ }
+
+ crDebug( "Render SPU: Got the DC: 0x%x", window->device_context );
+
+ if ( !bSetupPixelFormat( window->device_context, visual->visAttribs ) )
+ {
+ crError( "Render SPU: Couldn't set up the device context! Yikes!" );
+ return GL_FALSE;
+ }
+
+ /* set the window pointer data at the last step to ensure our WM_PAINT callback does not do anything until we are fully initialized */
+#ifdef RT_STRICT
+ SetLastError(NO_ERROR);
+#endif
+ {
+ LONG_PTR oldVal = SetWindowLongPtr(window->hWnd, GWLP_USERDATA, (LONG_PTR)window);
+ Assert(!oldVal && GetLastError() == NO_ERROR); RT_NOREF_PV(oldVal);
+ }
+
+ return GL_TRUE;
+}
+
+static void renderspuWindowRgnApply(WindowInfo *window)
+{
+ HRGN hRgn = window->hRgn;
+ if (hRgn)
+ {
+ /* note: according to the docs, SetWindowRgn owns the regions after it is called,
+ * and the regions will be freed automatically when needed,
+ * i.e. the caller should not do that.
+ * this is why we need to make a copy of the regions to be passed in */
+
+ int result;
+ hRgn = CreateRectRgn(0, 0, 0, 0);
+ if (!hRgn)
+ {
+ WARN(("CreateRectRgn failed"));
+ return;
+ }
+
+ result = CombineRgn(hRgn, window->hRgn, NULL, RGN_COPY);
+ if (result == ERROR)
+ {
+ WARN(("CombineRgn failed"));
+ return;
+ }
+ }
+
+ SetWindowRgn(window->hWnd, hRgn, true);
+}
+
+/* Either show or hide the render SPU's window. */
+void renderspu_SystemShowWindow( WindowInfo *window, GLboolean showIt )
+{
+ if (showIt)
+ {
+ crDebug("SHOW renderspu_SystemShowWindow: %x", window->hWnd);
+ renderspuWindowRgnApply(window);
+ }
+ else
+ {
+ HRGN hRgn;
+ crDebug("HIDE renderspu_SystemShowWindow: %x", window->hWnd);
+ hRgn = CreateRectRgn(0, 0, 0, 0);
+ SetWindowRgn(window->hWnd, hRgn, true);
+ /* note: according to the docs, SetWindowRgn owns the regions after it is called,
+ * and the regions will be freed automatically when needed,
+ * i.e. the caller should not do that */
+ }
+ window->visible = showIt;
+}
+
+void renderspu_SystemVBoxPresentComposition( WindowInfo *window, const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pChangedEntry )
+{
+ /* The !render_spu.force_present_main_thread code flow is actually inspired
+ * by cocoa backend impl, here it forces rendering in WndProc, i.e. main
+ * thread. It defaults to 0, because it is for debugging and working around
+ * bugs. In principle would need root cause investigation. */
+ if (!render_spu.force_present_main_thread)
+ {
+ const struct VBOXVR_SCR_COMPOSITOR *pCompositor;
+ /* we do not want to be blocked with the GUI thread here, so only draw here if we are really able to do that w/o blocking */
+ int rc = renderspuVBoxCompositorTryAcquire(window, &pCompositor);
+ if (RT_SUCCESS(rc))
+ {
+ renderspuVBoxPresentCompositionGeneric(window, pCompositor, pChangedEntry, 0, false);
+ renderspuVBoxCompositorRelease(window);
+ }
+ else if (rc != VERR_SEM_BUSY)
+ {
+ /* this is somewhat we do not expect */
+ crWarning("renderspuVBoxCompositorTryAcquire failed rc %d", rc);
+ }
+ }
+
+ {
+ render_spu.self.Flush();
+ renderspuVBoxPresentBlitterEnsureCreated(window, 0);
+ RedrawWindow(window->hWnd, NULL, NULL, RDW_INTERNALPAINT);
+ }
+}
+
+GLboolean renderspu_SystemCreateContext( VisualInfo *visual, ContextInfo *context, ContextInfo *sharedContext )
+{
+ (void) sharedContext;
+ context->visual = visual;
+
+ /* Found a visual, so we're o.k. to create the context now */
+ if (0/*visual->device_context*/) {
+
+ //crDebug( "Render SPU: Using the DC: 0x%x", visual->device_context );
+
+ //context->hRC = render_spu.ws.wglCreateContext( visual->device_context );
+ if (!context->hRC)
+ {
+ crError( "Render SPU: wglCreateContext failed (error 0x%x)", GetLastError() );
+ return GL_FALSE;
+ }
+ } else {
+ crDebug( "Render SPU: Delaying DC creation " );
+ context->hRC = NULL; /* create it later in makecurrent */
+ }
+
+
+ return GL_TRUE;
+}
+
+void renderspu_SystemDestroyContext( ContextInfo *context )
+{
+ render_spu.ws.wglDeleteContext( context->hRC );
+ context->hRC = NULL;
+}
+
+static GLboolean renderspuChkActivateSharedContext(ContextInfo *sharedContext)
+{
+ WindowInfo *window;
+
+ if (sharedContext->hRC)
+ return GL_TRUE;
+
+ CRASSERT(sharedContext->BltInfo.Base.id);
+
+ if (sharedContext->shared)
+ renderspuChkActivateSharedContext(sharedContext->shared);
+
+ window = renderspuGetDummyWindow(sharedContext->visual->visAttribs);
+ if (!window)
+ {
+ crError("renderspuChkActivateSharedContext: renderspuGetDummyWindow failed!");
+ return GL_FALSE;
+ }
+
+ CRASSERT(window->device_context);
+
+ crDebug( "Render SPU: renderspuChkActivateSharedContext: made the DC: 0x%x", window->device_context );
+
+ sharedContext->hRC = render_spu.ws.wglCreateContext(window->device_context);
+ if (!sharedContext->hRC)
+ {
+ crError( "Render SPU: (renderspuChkActivateSharedContext) Couldn't create the context for the window (error 0x%x)", GetLastError() );
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+void renderspu_SystemMakeCurrent( WindowInfo *window, GLint nativeWindow, ContextInfo *context )
+{
+ CRASSERT(render_spu.ws.wglMakeCurrent);
+
+ if (context && window) {
+ if (window->visual != context->visual) {
+ /*
+ * XXX have to revisit this issue!!!
+ *
+ * But for now we destroy the current window
+ * and re-create it with the context's visual abilities
+ */
+
+ /** @todo Chromium has no correct code to remove window ids and associated info from
+ * various tables. This is hack which just hides the root case.
+ */
+ crWarning("Recreating window in renderspu_SystemMakeCurrent\n");
+ renderspu_SystemDestroyWindow( window );
+ renderspu_SystemVBoxCreateWindow( context->visual, window->visible, window );
+ }
+
+ if (0/*render_spu.render_to_app_window && nativeWindow*/)
+ {
+ /* The render_to_app_window option
+ * is set and we've got a nativeWindow
+ * handle, save the handle for
+ * later calls to swapbuffers().
+ *
+ * NOTE: This doesn't work, except
+ * for software driven Mesa.
+ * We'd need to object link the
+ * crappfaker and crserver to be able to share
+ * the HDC values between processes.. FIXME!
+ */
+ if (context->shared)
+ {
+ /* first make sure we have shared context created */
+ renderspuChkActivateSharedContext(context->shared);
+ }
+
+ window->nativeWindow = (HDC) nativeWindow;
+ if (context->hRC == 0) {
+ context->hRC = render_spu.ws.wglCreateContext( window->nativeWindow );
+ if (!context->hRC)
+ {
+ crError( "(MakeCurrent) Couldn't create the context for the window (error 0x%x)", GetLastError() );
+ }
+ }
+
+ if (context->shared
+ && context->shared->hRC
+ && context->hRC)
+ {
+ /* share lists */
+ render_spu.ws.wglShareLists(context->shared->hRC, context->hRC);
+ }
+
+ render_spu.ws.wglMakeCurrent( window->nativeWindow, context->hRC );
+ }
+ else
+ {
+ if (!context->hRC) {
+ CRASSERT(!nativeWindow);
+ if (context->shared)
+ {
+ /* first make sure we have shared context created */
+ renderspuChkActivateSharedContext(context->shared);
+ }
+
+ context->hRC = render_spu.ws.wglCreateContext(window->device_context);
+ if (!context->hRC)
+ {
+ crError( "Render SPU: (MakeCurrent) Couldn't create the context for the window (error 0x%x)", GetLastError() );
+ }
+
+ if (context->shared
+ && context->shared->hRC
+ && context->hRC)
+ {
+ /* share lists */
+ BOOL bRc = render_spu.ws.wglShareLists(context->shared->hRC, context->hRC);
+ if (!bRc)
+ {
+ DWORD winEr = GetLastError();
+ crWarning("wglShareLists failed, winEr %d", winEr);
+ }
+ }
+
+ /*Requery ext function pointers, we skip dummy ctx as it should never be used with ext functions*/
+ if (0 && context->BltInfo.Base.id)
+ {
+ int numFuncs, i;
+ SPUNamedFunctionTable ext_table[1000];
+
+
+ crDebug("Default server ctx created, requerying ext functions");
+ /*requery ext functions*/
+ numFuncs = renderspuCreateFunctions(ext_table);
+ numFuncs += crLoadOpenGLExtensions( &render_spu.ws, ext_table+numFuncs);
+ CRASSERT(numFuncs < 1000);
+
+ /*change spu dispatch*/
+ crSPUChangeDispatch(&render_spu.self, ext_table);
+
+
+ /*cleanup temp table*/
+ for (i=0; i<numFuncs; ++i)
+ {
+ if (ext_table[i].name) crFree(ext_table[i].name);
+ }
+ }
+ }
+
+ /*crDebug("MakeCurrent 0x%x, 0x%x", window->device_context, context->hRC);*/
+ if (!render_spu.ws.wglMakeCurrent(!nativeWindow ? window->device_context : window->redraw_device_context, context->hRC))
+ {
+ DWORD err = GetLastError();
+ crError("Render SPU: (MakeCurrent) failed to make 0x%x, 0x%x current with 0x%x error.", window->device_context, context->hRC, err);
+ }
+ }
+
+ renderspuAtiQuirk_ChkApply();
+ }
+ else {
+ render_spu.ws.wglMakeCurrent( 0, 0 );
+ }
+}
+
+void renderspu_SystemWindowSize( WindowInfo *window, GLint w, GLint h )
+{
+ int winprop;
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ( render_spu.fullscreen )
+ winprop = SWP_SHOWWINDOW | SWP_NOSENDCHANGING |
+ SWP_NOREDRAW | SWP_NOACTIVATE;
+ else
+ winprop = SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_NOZORDER; //SWP_SHOWWINDOW;
+
+ /*SetWindowRgn(window->hWnd, NULL, false);*/
+
+ if (!SetWindowPos( window->hWnd, HWND_TOP,
+ window->x, window->y, w, h, winprop )) {
+ crWarning("!!!FAILED!!! Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, window->x, window->y, w, h);
+ } else {
+ crDebug("Render SPU: SetWindowSize (%x, %d, %d, %d, %d)", window->hWnd, window->x, window->y, w, h);
+ }
+ /* save the new size */
+ window->BltInfo.width = w;
+ window->BltInfo.height = h;
+}
+
+
+void renderspu_SystemGetWindowGeometry( WindowInfo *window, GLint *x, GLint *y, GLint *w, GLint *h )
+{
+ RECT rect;
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+ GetClientRect( window->hWnd, &rect );
+ *x = rect.left;
+ *y = rect.top;
+ *w = rect.right - rect.left;
+ *h = rect.bottom - rect.top;
+}
+
+
+void renderspu_SystemGetMaxWindowSize( WindowInfo *window, GLint *w, GLint *h )
+{
+ /* XXX fix this */
+ (void) window;
+ *w = 1600;
+ *h = 1200;
+}
+
+
+void renderspu_SystemWindowPosition( WindowInfo *window, GLint x, GLint y )
+{
+ int winprop;
+ CRASSERT(window);
+ CRASSERT(window->visual);
+ if ( render_spu.fullscreen )
+ winprop = SWP_SHOWWINDOW | SWP_NOSENDCHANGING |
+ SWP_NOREDRAW | SWP_NOACTIVATE;
+ else
+ winprop = SWP_NOACTIVATE | SWP_DEFERERASE | SWP_NOSENDCHANGING | SWP_NOZORDER; //SWP_SHOWWINDOW;
+
+ /*SetWindowRgn(window->visual->hWnd, NULL, false);*/
+
+ if (!SetWindowPos( window->hWnd, HWND_TOP,
+ x, y, window->BltInfo.width, window->BltInfo.height, winprop )) {
+ crWarning("!!!FAILED!!! Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd, x, y, window->BltInfo.width, window->BltInfo.height);
+ } else {
+ crDebug("Render SPU: SetWindowPos (%x, %d, %d, %d, %d)", window->hWnd,
+ x, y, window->BltInfo.width, window->BltInfo.height);
+ }
+ /* save the new position */
+ window->x = x;
+ window->y = y;
+}
+
+GLboolean renderspu_SystemWindowNeedEmptyPresent(WindowInfo *window)
+{
+ return GL_FALSE;
+}
+
+void renderspu_SystemWindowVisibleRegion(WindowInfo *window, GLint cRects, const GLint* pRects)
+{
+ GLint i;
+ HRGN hRgn, hTmpRgn;
+ RECT rectRgnBound;
+
+ CRASSERT(window);
+ CRASSERT(window->visual);
+
+ if (window->hRgn)
+ {
+ DeleteObject(window->hRgn);
+ window->hRgn = NULL;
+ }
+
+ hRgn = CreateRectRgn(0, 0, 0, 0);
+
+ for (i = 0; i < cRects; i++)
+ {
+ crDebug("Render SPU: CreateRectRgn #%d: (%d, %d)-(%d, %d)", i,
+ pRects[4 * i], pRects[4 * i + 1], pRects[4 * i + 2], pRects[4 * i + 3]);
+
+ hTmpRgn = CreateRectRgn(pRects[4 * i], pRects[4 * i + 1], pRects[4 * i + 2], pRects[4 * i + 3]);
+ CombineRgn(hRgn, hRgn, hTmpRgn, RGN_OR);
+ DeleteObject(hTmpRgn);
+ }
+
+ if (GetRgnBox(hRgn, &rectRgnBound))
+ {
+ crDebug("Render SPU: Rgn bounding box (%d, %d)-(%d, %d)",
+ rectRgnBound.left, rectRgnBound.top, rectRgnBound.right, rectRgnBound.bottom);
+ }
+
+ window->hRgn = hRgn;
+
+ if (window->visible)
+ renderspuWindowRgnApply(window);
+
+ crDebug("Render SPU: SetWindowRgn (%x, cRects=%i)", window->hWnd, cRects);
+}
+
+static void renderspuHandleWindowMessages( HWND hWnd )
+{
+ MSG msg;
+ while ( PeekMessage( &msg, hWnd, 0, 0xffffffff, PM_REMOVE ) )
+ {
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+
+ //BringWindowToTop( hWnd );
+}
+
+void renderspu_SystemSwapBuffers( WindowInfo *w, GLint flags )
+{
+ int return_value;
+
+ /* peek at the windows message queue */
+// renderspuHandleWindowMessages( w->hWnd );
+
+ /* render_to_app_window:
+ * w->nativeWindow will only be non-zero if the
+ * render_spu.render_to_app_window option is true and
+ * MakeCurrent() recorded the nativeWindow handle in the WindowInfo
+ * structure.
+ */
+ if (render_spu.render_to_app_window && w->nativeWindow) {
+#ifdef VBOX_CR_SERVER_FORCE_WGL
+ return_value = render_spu.ws.wglSwapBuffers( w->nativeWindow );
+#else
+ return_value = SwapBuffers( w->nativeWindow );
+#endif
+ } else {
+ /*
+ HRGN hRgn1, hRgn2, hRgn3;
+ HWND hWndParent;
+ LONG ws;
+
+ hRgn1 = CreateRectRgn(0, 0, w->BltInfo.width, w->BltInfo.height);
+ hRgn2 = CreateRectRgn(50, 50, 100, 100);
+ hRgn3 = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(hRgn3, hRgn1, hRgn2, RGN_DIFF);
+ SetWindowRgn(w->visual->hWnd, hRgn3, true);
+ DeleteObject(hRgn1);
+ DeleteObject(hRgn2);
+
+ hWndParent = GetParent(w->visual->hWnd);
+ ws = GetWindowLong(hWndParent, GWL_STYLE);
+ ws &= ~WS_CLIPCHILDREN;
+ SetWindowLong(hWndParent, GWL_STYLE, ws);
+
+ RECT rcClip;
+
+ rcClip.left = 50;
+ rcClip.top = 50;
+ rcClip.right = 100;
+ rcClip.bottom = 100;
+ ValidateRect(w->visual->hWnd, &rcClip);
+
+ return_value = GetClipBox(w->visual->device_context, &rcClip);
+ crDebug("GetClipBox returned %d (NR=%d,SR=%d,CR=%d,ERR=%d)",
+ return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR);
+
+ crDebug("rcClip(%d, %d, %d, %d)", rcClip.left, rcClip.top, rcClip.right, rcClip.bottom);
+
+ return_value = ExcludeClipRect(w->visual->device_context, 50, 50, 100, 100);
+ crDebug("ExcludeClipRect returned %d (NR=%d,SR=%d,CR=%d,ERR=%d)",
+ return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR);
+
+ return_value = GetClipBox(w->visual->device_context, &rcClip);
+ crDebug("GetClipBox returned %d (NR=%d,SR=%d,CR=%d,ERR=%d)",
+ return_value, NULLREGION, SIMPLEREGION, COMPLEXREGION, ERROR);
+ crDebug("rcClip(%d, %d, %d, %d)", rcClip.left, rcClip.top, rcClip.right, rcClip.bottom);
+ */
+#ifdef VBOX_CR_SERVER_FORCE_WGL
+ return_value = render_spu.ws.wglSwapBuffers( w->device_context );
+#else
+ return_value = SwapBuffers( w->device_context );
+#endif
+ }
+ if (!return_value)
+ {
+ /* GOD DAMN IT. The latest versions of the NVIDIA drivers
+ * return failure from wglSwapBuffers, but it works just fine.
+ * WHAT THE HELL?! */
+
+ crWarning( "wglSwapBuffers failed: return value of %d!", return_value);
+ }
+}
+
+void renderspu_SystemReparentWindow(WindowInfo *window)
+{
+ SetParent(window->hWnd, (HWND)render_spu_parent_window_id);
+}
+
+int renderspu_SystemInit()
+{
+ return VINF_SUCCESS;
+}
+
+int renderspu_SystemTerm()
+{
+ return VINF_SUCCESS;
+}
+
+void renderspu_SystemDefaultSharedContextChanged(ContextInfo *fromContext, ContextInfo *toContext)
+{
+
+}
+
+uint32_t renderspu_SystemPostprocessFunctions(SPUNamedFunctionTable *aFunctions, uint32_t cFunctions, uint32_t cTable)
+{
+ return cFunctions;
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/Makefile.kup b/src/VBox/HostServices/SharedOpenGL/unpacker/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/Makefile.kup
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.def b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.def
new file mode 100644
index 00000000..01a07bf2
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.def
@@ -0,0 +1,11 @@
+; Copyright (c) 2001, Stanford University
+; All rights reserved.
+;
+; See the file LICENSE.txt for information on redistributing this software.
+EXPORTS
+crUnpack
+crUnpackPush
+crUnpackPop
+crUnpackSetReturnPointer
+crUnpackSetWritebackPointer
+cr_unpackData
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.py b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.py
new file mode 100755
index 00000000..052fff6c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack.py
@@ -0,0 +1,394 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys
+
+import apiutil
+
+
+apiutil.CopyrightC()
+
+print("""/* DO NOT EDIT! THIS CODE IS AUTOGENERATED BY unpack.py */
+
+#include "unpacker.h"
+#include "cr_opcodes.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "cr_spu.h"
+#include "unpack_extend.h"
+#include <stdio.h>
+#include <memory.h>
+
+#include <iprt/cdefs.h>
+
+DECLEXPORT(const unsigned char *) cr_unpackData = NULL;
+DECLEXPORT(const unsigned char *) cr_unpackDataEnd = NULL;
+SPUDispatchTable cr_unpackDispatch;
+
+static void crUnpackExtend(void);
+static void crUnpackExtendDbg(void);
+
+#if 0 //def DEBUG_misha
+//# define CR_UNPACK_DEBUG_OPCODES
+# define CR_UNPACK_DEBUG_LAST_OPCODES
+# define CR_UNPACK_DEBUG_PREV_OPCODES
+#endif
+
+#ifdef CR_UNPACK_DEBUG_PREV_OPCODES
+static GLenum g_VBoxDbgCrPrevOpcode = 0;
+static GLenum g_VBoxDbgCrPrevExtendOpcode = 0;
+#endif
+""")
+
+nodebug_opcodes = [
+ "CR_MULTITEXCOORD2FARB_OPCODE",
+ "CR_VERTEX3F_OPCODE",
+ "CR_NORMAL3F_OPCODE",
+ "CR_COLOR4UB_OPCODE",
+ "CR_LOADIDENTITY_OPCODE",
+ "CR_MATRIXMODE_OPCODE",
+ "CR_LOADMATRIXF_OPCODE",
+ "CR_DISABLE_OPCODE",
+ "CR_COLOR4F_OPCODE",
+ "CR_ENABLE_OPCODE",
+ "CR_BEGIN_OPCODE",
+ "CR_END_OPCODE",
+ "CR_SECONDARYCOLOR3FEXT_OPCODE"
+]
+
+nodebug_extopcodes = [
+ "CR_ACTIVETEXTUREARB_EXTEND_OPCODE"
+]
+
+#
+# Useful functions
+#
+
+def ReadData( offset, arg_type ):
+ """Emit a READ_DOUBLE or READ_DATA call for pulling a GL function
+ argument out of the buffer's operand area."""
+ if arg_type == "GLdouble" or arg_type == "GLclampd":
+ retval = "READ_DOUBLE(%d)" % offset
+ else:
+ retval = "READ_DATA(%d, %s)" % (offset, arg_type)
+ return retval
+
+
+def FindReturnPointer( return_type, params ):
+ """For GL functions that return values (either as the return value or
+ through a pointer parameter) emit a SET_RETURN_PTR call."""
+ arg_len = apiutil.PacketLength( params )
+ if (return_type != 'void'):
+ print('\tSET_RETURN_PTR(%d);' % (arg_len + 8)) # extended opcode plus packet length
+ else:
+ paramList = [ ('foo', 'void *', 0) ]
+ print('\tSET_RETURN_PTR(%d);' % (arg_len + 8 - apiutil.PacketLength(paramList)))
+
+
+def FindWritebackPointer( return_type, params ):
+ """Emit a SET_WRITEBACK_PTR call."""
+ arg_len = apiutil.PacketLength( params )
+ if return_type != 'void':
+ paramList = [ ('foo', 'void *', 0) ]
+ arg_len += apiutil.PacketLength( paramList )
+
+ print('\tSET_WRITEBACK_PTR(%d);' % (arg_len + 8)) # extended opcode plus packet length
+
+
+def MakeNormalCall( return_type, func_name, params, counter_init = 0 ):
+ counter = counter_init
+ copy_of_params = params[:]
+
+ for i in range( 0, len(params) ):
+ (name, type, vecSize) = params[i]
+ if apiutil.IsPointer(copy_of_params[i][1]):
+ params[i] = ('NULL', type, vecSize)
+ copy_of_params[i] = (copy_of_params[i][0], 'void', 0)
+ if not "get" in apiutil.Properties(func_name):
+ print('\tcrError( "%s needs to be special cased!" );' % func_name)
+ else:
+ print("\t%s %s = %s;" % ( copy_of_params[i][1], name, ReadData( counter, copy_of_params[i][1] ) ))
+ counter += apiutil.sizeof(copy_of_params[i][1])
+
+ if ("get" in apiutil.Properties(func_name)):
+ FindReturnPointer( return_type, params )
+ FindWritebackPointer( return_type, params )
+
+ if return_type != "void":
+ print("\t(void)", end=" ")
+ else:
+ print("\t", end="")
+ print("cr_unpackDispatch.%s(%s);" % (func_name, apiutil.MakeCallString(params)))
+
+
+def MakeVectorCall( return_type, func_name, arg_type ):
+ """Convert a call like glVertex3f to glVertex3fv."""
+ vec_func = apiutil.VectorFunction(func_name)
+ params = apiutil.Parameters(vec_func)
+ assert len(params) == 1
+ (arg_name, vecType, vecSize) = params[0]
+
+ if arg_type == "GLdouble" or arg_type == "GLclampd":
+ print("#ifdef CR_UNALIGNED_ACCESS_OKAY")
+ print("\tcr_unpackDispatch.%s((%s) cr_unpackData);" % (vec_func, vecType))
+ print("#else")
+ for index in range(0, vecSize):
+ print("\tGLdouble v" + repr(index) + " = READ_DOUBLE(" + repr(index * 8) + ");")
+ if return_type != "void":
+ print("\t(void) cr_unpackDispatch.%s(" % func_name, end="")
+ else:
+ print("\tcr_unpackDispatch.%s(" % func_name, end="")
+ for index in range(0, vecSize):
+ print("v" + repr(index), end="")
+ if index != vecSize - 1:
+ print(",", end=" ")
+ print(");")
+ print("#endif")
+ else:
+ print("\tcr_unpackDispatch.%s((%s) cr_unpackData);" % (vec_func, vecType))
+
+
+
+keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt")
+
+
+#
+# Generate unpack functions for all the simple functions.
+#
+for func_name in keys:
+ if (not "pack" in apiutil.ChromiumProps(func_name) or
+ apiutil.FindSpecial( "unpacker", func_name )):
+ continue
+
+ params = apiutil.Parameters(func_name)
+ return_type = apiutil.ReturnType(func_name)
+
+ print("static void crUnpack%s(void)" % func_name)
+ print("{")
+
+ vector_func = apiutil.VectorFunction(func_name)
+ if (vector_func and len(apiutil.Parameters(vector_func)) == 1):
+ MakeVectorCall( return_type, func_name, params[0][1] )
+ else:
+ MakeNormalCall( return_type, func_name, params )
+ packet_length = apiutil.PacketLength( params )
+ if packet_length == 0:
+ print("\tINCR_DATA_PTR_NO_ARGS( );")
+ else:
+ print("\tINCR_DATA_PTR(%d);" % packet_length)
+ print("}\n")
+
+
+#
+# Emit some code
+#
+print("""
+typedef struct __dispatchNode {
+ const unsigned char *unpackData;
+ struct __dispatchNode *next;
+} DispatchNode;
+
+static DispatchNode *unpackStack = NULL;
+
+static SPUDispatchTable *cr_lastDispatch = NULL;
+
+void crUnpackPush(void)
+{
+ DispatchNode *node = (DispatchNode*)crAlloc( sizeof( *node ) );
+ node->next = unpackStack;
+ unpackStack = node;
+ node->unpackData = cr_unpackData;
+}
+
+void crUnpackPop(void)
+{
+ DispatchNode *node = unpackStack;
+
+ if (!node)
+ {
+ crError( "crUnpackPop called with an empty stack!" );
+ }
+ unpackStack = node->next;
+ cr_unpackData = node->unpackData;
+ crFree( node );
+}
+
+CR_UNPACK_BUFFER_TYPE crUnpackGetBufferType(const void *opcodes, unsigned int num_opcodes)
+{
+ const uint8_t *pu8Codes = (const uint8_t *)opcodes;
+
+ uint8_t first;
+ uint8_t last;
+
+ if (!num_opcodes)
+ return CR_UNPACK_BUFFER_TYPE_GENERIC;
+
+ first = pu8Codes[0];
+ last = pu8Codes[1-(int)num_opcodes];
+
+ switch (last)
+ {
+ case CR_CMDBLOCKFLUSH_OPCODE:
+ return CR_UNPACK_BUFFER_TYPE_CMDBLOCK_FLUSH;
+ case CR_CMDBLOCKEND_OPCODE:
+ return (first == CR_CMDBLOCKBEGIN_OPCODE) ? CR_UNPACK_BUFFER_TYPE_GENERIC : CR_UNPACK_BUFFER_TYPE_CMDBLOCK_END;
+ default:
+ return (first != CR_CMDBLOCKBEGIN_OPCODE) ? CR_UNPACK_BUFFER_TYPE_GENERIC : CR_UNPACK_BUFFER_TYPE_CMDBLOCK_BEGIN;
+ }
+}
+
+void crUnpack( const void *data, const void *data_end, const void *opcodes,
+ unsigned int num_opcodes, SPUDispatchTable *table )
+{
+ unsigned int i;
+ const unsigned char *unpack_opcodes;
+ if (table != cr_lastDispatch)
+ {
+ crSPUCopyDispatchTable( &cr_unpackDispatch, table );
+ cr_lastDispatch = table;
+ }
+
+ unpack_opcodes = (const unsigned char *)opcodes;
+ cr_unpackData = (const unsigned char *)data;
+ cr_unpackDataEnd = (const unsigned char *)data_end;
+
+#if defined(CR_UNPACK_DEBUG_OPCODES) || defined(CR_UNPACK_DEBUG_LAST_OPCODES)
+ crDebug("crUnpack: %d opcodes", num_opcodes);
+#endif
+
+ for (i = 0; i < num_opcodes; i++)
+ {
+
+ CRDBGPTR_CHECKZ(writeback_ptr);
+ CRDBGPTR_CHECKZ(return_ptr);
+
+ /*crDebug(\"Unpacking opcode \%d\", *unpack_opcodes);*/
+#ifdef CR_UNPACK_DEBUG_PREV_OPCODES
+ g_VBoxDbgCrPrevOpcode = *unpack_opcodes;
+#endif
+ switch( *unpack_opcodes )
+ {""")
+
+#
+# Emit switch cases for all unextended opcodes
+#
+for func_name in keys:
+ if "pack" in apiutil.ChromiumProps(func_name):
+ print('\t\t\tcase %s:' % apiutil.OpcodeName( func_name ))
+ if not apiutil.OpcodeName(func_name) in nodebug_opcodes:
+ print("""
+#ifdef CR_UNPACK_DEBUG_LAST_OPCODES
+ if (i==(num_opcodes-1))
+#endif
+#if defined(CR_UNPACK_DEBUG_OPCODES) || defined(CR_UNPACK_DEBUG_LAST_OPCODES)
+ crDebug("Unpack: %s");
+#endif """ % apiutil.OpcodeName(func_name))
+ print('\t\t\t\tcrUnpack%s(); \n\t\t\t\tbreak;' % func_name)
+
+print("""
+ case CR_EXTEND_OPCODE:
+ #ifdef CR_UNPACK_DEBUG_OPCODES
+ crUnpackExtendDbg();
+ #else
+ # ifdef CR_UNPACK_DEBUG_LAST_OPCODES
+ if (i==(num_opcodes-1)) crUnpackExtendDbg();
+ else
+ # endif
+ crUnpackExtend();
+ #endif
+ break;
+ case CR_CMDBLOCKBEGIN_OPCODE:
+ case CR_CMDBLOCKEND_OPCODE:
+ case CR_CMDBLOCKFLUSH_OPCODE:
+ case CR_NOP_OPCODE:
+ INCR_DATA_PTR_NO_ARGS( );
+ break;
+ default:
+ crError( "Unknown opcode: %d", *unpack_opcodes );
+ break;
+ }
+
+ CRDBGPTR_CHECKZ(writeback_ptr);
+ CRDBGPTR_CHECKZ(return_ptr);
+
+ unpack_opcodes--;
+ }
+}""")
+
+
+#
+# Emit unpack functions for extended opcodes, non-special functions only.
+#
+for func_name in keys:
+ if ("extpack" in apiutil.ChromiumProps(func_name)
+ and not apiutil.FindSpecial("unpacker", func_name)):
+ return_type = apiutil.ReturnType(func_name)
+ params = apiutil.Parameters(func_name)
+ print('static void crUnpackExtend%s(void)' % func_name)
+ print('{')
+ MakeNormalCall( return_type, func_name, params, 8 )
+ print('}\n')
+
+print('static void crUnpackExtend(void)')
+print('{')
+print('\tGLenum extend_opcode = %s;' % ReadData( 4, 'GLenum' ))
+print('')
+print('#ifdef CR_UNPACK_DEBUG_PREV_OPCODES')
+print('\tg_VBoxDbgCrPrevExtendOpcode = extend_opcode;')
+print('#endif')
+print('')
+print('\t/*crDebug(\"Unpacking extended opcode \%d", extend_opcode);*/')
+print('\tswitch( extend_opcode )')
+print('\t{')
+
+
+#
+# Emit switch statement for extended opcodes
+#
+for func_name in keys:
+ if "extpack" in apiutil.ChromiumProps(func_name):
+ print('\t\tcase %s:' % apiutil.ExtendedOpcodeName( func_name ))
+# print('\t\t\t\tcrDebug("Unpack: %s");' % apiutil.ExtendedOpcodeName( func_name )))
+ print('\t\t\tcrUnpackExtend%s( );' % func_name)
+ print('\t\t\tbreak;')
+
+print(""" default:
+ crError( "Unknown extended opcode: %d", (int) extend_opcode );
+ break;
+ }
+ INCR_VAR_PTR();
+}""")
+
+print('static void crUnpackExtendDbg(void)')
+print('{')
+print('\tGLenum extend_opcode = %s;' % ReadData( 4, 'GLenum' ))
+print('')
+print('#ifdef CR_UNPACK_DEBUG_PREV_OPCODES')
+print('\tg_VBoxDbgCrPrevExtendOpcode = extend_opcode;')
+print('#endif')
+print('')
+print('\t/*crDebug(\"Unpacking extended opcode \%d", extend_opcode);*/')
+print('\tswitch( extend_opcode )')
+print('\t{')
+
+
+#
+# Emit switch statement for extended opcodes
+#
+for func_name in keys:
+ if "extpack" in apiutil.ChromiumProps(func_name):
+ print('\t\tcase %s:' % apiutil.ExtendedOpcodeName( func_name ))
+ if not apiutil.ExtendedOpcodeName(func_name) in nodebug_extopcodes:
+ print('\t\t\tcrDebug("Unpack: %s");' % apiutil.ExtendedOpcodeName( func_name ))
+ print('\t\t\tcrUnpackExtend%s( );' % func_name)
+ print('\t\t\tbreak;')
+
+print(""" default:
+ crError( "Unknown extended opcode: %d", (int) extend_opcode );
+ break;
+ }
+ INCR_VAR_PTR();
+}""")
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_arrays.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_arrays.c
new file mode 100644
index 00000000..847bb1ed
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_arrays.c
@@ -0,0 +1,312 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "cr_error.h"
+#include "unpack_extend.h"
+#include "unpacker.h"
+#include "cr_glstate.h"
+/**
+ * \mainpage Unpacker
+ *
+ * \section UnpackerIntroduction Introduction
+ *
+ * Chromium consists of all the top-level files in the cr
+ * directory. The unpacker module basically takes care of API dispatch,
+ * and OpenGL state management.
+ *
+ */
+
+void crUnpackExtendVertexPointer(void)
+{
+ GLint size = READ_DATA( 8, GLint );
+ GLenum type = READ_DATA( 12, GLenum );
+ GLsizei stride = READ_DATA( 16, GLsizei );
+ GLintptrARB pointer = (GLintptrARB) READ_DATA( 20, GLuint );
+ cr_unpackDispatch.VertexPointer( size, type, stride, (void *) pointer );
+}
+
+void crUnpackExtendTexCoordPointer(void)
+{
+ GLint size = READ_DATA( 8, GLint );
+ GLenum type = READ_DATA( 12, GLenum );
+ GLsizei stride = READ_DATA( 16, GLsizei );
+ GLintptrARB pointer = READ_DATA( 20, GLuint );
+ cr_unpackDispatch.TexCoordPointer( size, type, stride, (void *) pointer );
+}
+
+void crUnpackExtendNormalPointer(void)
+{
+ GLenum type = READ_DATA( 8, GLenum );
+ GLsizei stride = READ_DATA( 12, GLsizei );
+ GLintptrARB pointer = READ_DATA( 16, GLuint );
+ cr_unpackDispatch.NormalPointer( type, stride, (void *) pointer );
+}
+
+void crUnpackExtendIndexPointer(void)
+{
+ GLenum type = READ_DATA( 8, GLenum );
+ GLsizei stride = READ_DATA( 12, GLsizei );
+ GLintptrARB pointer = READ_DATA( 16, GLuint );
+ cr_unpackDispatch.IndexPointer( type, stride, (void *) pointer );
+}
+
+void crUnpackExtendEdgeFlagPointer(void)
+{
+ GLsizei stride = READ_DATA( 8, GLsizei );
+ GLintptrARB pointer = READ_DATA( 12, GLuint );
+ cr_unpackDispatch.EdgeFlagPointer( stride, (void *) pointer );
+}
+
+void crUnpackExtendColorPointer(void)
+{
+ GLint size = READ_DATA( 8, GLint );
+ GLenum type = READ_DATA( 12, GLenum );
+ GLsizei stride = READ_DATA( 16, GLsizei );
+ GLintptrARB pointer = READ_DATA( 20, GLuint );
+ cr_unpackDispatch.ColorPointer( size, type, stride, (void *) pointer );
+}
+
+void crUnpackExtendFogCoordPointerEXT(void)
+{
+ GLenum type = READ_DATA( 8, GLenum );
+ GLsizei stride = READ_DATA( 12, GLsizei );
+ GLintptrARB pointer = READ_DATA( 16, GLuint );
+ cr_unpackDispatch.FogCoordPointerEXT( type, stride, (void *) pointer );
+}
+
+void crUnpackExtendSecondaryColorPointerEXT(void)
+{
+ GLint size = READ_DATA( 8, GLint );
+ GLenum type = READ_DATA( 12, GLenum );
+ GLsizei stride = READ_DATA( 16, GLsizei );
+ GLintptrARB pointer = READ_DATA( 20, GLuint );
+ cr_unpackDispatch.SecondaryColorPointerEXT( size, type, stride, (void *) pointer );
+}
+
+void crUnpackExtendVertexAttribPointerARB(void)
+{
+ GLuint index = READ_DATA( 8, GLuint);
+ GLint size = READ_DATA( 12, GLint );
+ GLenum type = READ_DATA( 16, GLenum );
+ GLboolean normalized = READ_DATA( 20, GLboolean );
+ GLsizei stride = READ_DATA( 24, GLsizei );
+ GLintptrARB pointer = READ_DATA( 28, GLuint );
+ cr_unpackDispatch.VertexAttribPointerARB( index, size, type, normalized, stride, (void *) pointer );
+}
+
+void crUnpackExtendVertexAttribPointerNV(void)
+{
+ GLuint index = READ_DATA( 8, GLuint);
+ GLint size = READ_DATA( 12, GLint );
+ GLenum type = READ_DATA( 16, GLenum );
+ GLsizei stride = READ_DATA( 20, GLsizei );
+ GLintptrARB pointer = READ_DATA( 24, GLuint );
+ cr_unpackDispatch.VertexAttribPointerNV( index, size, type, stride, (void *) pointer );
+}
+
+void crUnpackExtendInterleavedArrays(void)
+{
+ GLenum format = READ_DATA( 8, GLenum );
+ GLsizei stride = READ_DATA( 12, GLsizei );
+ GLintptrARB pointer = READ_DATA( 16, GLuint );
+ cr_unpackDispatch.InterleavedArrays( format, stride, (void *) pointer );
+}
+
+void crUnpackExtendDrawElements(void)
+{
+ GLenum mode = READ_DATA( 8, GLenum );
+ GLsizei count = READ_DATA( 12, GLsizei );
+ GLenum type = READ_DATA( 16, GLenum );
+ GLintptrARB indices = READ_DATA( 20, GLuint );
+ void * indexptr;
+#ifdef CR_ARB_vertex_buffer_object
+ GLboolean hasidxdata = READ_DATA(24, GLint);
+ indexptr = hasidxdata ? DATA_POINTER(28, void) : (void*)indices;
+#else
+ indexptr = DATA_POINTER(24, void);
+#endif
+ cr_unpackDispatch.DrawElements(mode, count, type, indexptr);
+}
+
+void crUnpackExtendDrawRangeElements(void)
+{
+ GLenum mode = READ_DATA( 8, GLenum );
+ GLuint start = READ_DATA( 12, GLuint );
+ GLuint end = READ_DATA( 16, GLuint );
+ GLsizei count = READ_DATA( 20, GLsizei );
+ GLenum type = READ_DATA( 24, GLenum );
+ GLintptrARB indices = READ_DATA( 28, GLuint );
+ void * indexptr;
+#ifdef CR_ARB_vertex_buffer_object
+ GLboolean hasidxdata = READ_DATA(32, GLint);
+ indexptr = hasidxdata ? DATA_POINTER(36, void) : (void*)indices;
+#else
+ indexptr = DATA_POINTER(32, void);
+#endif
+ cr_unpackDispatch.DrawRangeElements(mode, start, end, count, type, indexptr);
+}
+
+void crUnpackMultiDrawArraysEXT(void)
+{
+ crError( "Can't decode MultiDrawArraysEXT" );
+}
+
+void crUnpackMultiDrawElementsEXT(void)
+{
+ crError( "Can't decode MultiDrawElementsEXT" );
+}
+
+static void crUnpackSetClientPointerByIndex(int index, GLint size,
+ GLenum type, GLboolean normalized,
+ GLsizei stride, const GLvoid *pointer, CRClientState *c)
+{
+ /*crDebug("crUnpackSetClientPointerByIndex: %i(s=%i, t=0x%x, n=%i, str=%i) -> %p", index, size, type, normalized, stride, pointer);*/
+
+ if (index<7)
+ {
+ switch (index)
+ {
+ case 0:
+ cr_unpackDispatch.VertexPointer(size, type, stride, pointer);
+ break;
+ case 1:
+ cr_unpackDispatch.ColorPointer(size, type, stride, pointer);
+ break;
+ case 2:
+ cr_unpackDispatch.FogCoordPointerEXT(type, stride, pointer);
+ break;
+ case 3:
+ cr_unpackDispatch.SecondaryColorPointerEXT(size, type, stride, pointer);
+ break;
+ case 4:
+ cr_unpackDispatch.EdgeFlagPointer(stride, pointer);
+ break;
+ case 5:
+ cr_unpackDispatch.IndexPointer(type, stride, pointer);
+ break;
+ case 6:
+ cr_unpackDispatch.NormalPointer(type, stride, pointer);
+ break;
+ }
+ }
+ else if (index<(7+CR_MAX_TEXTURE_UNITS))
+ {
+ int curTexUnit = c->curClientTextureUnit;
+ if ((index-7)!=curTexUnit)
+ {
+ cr_unpackDispatch.ClientActiveTextureARB(GL_TEXTURE0_ARB+index-7);
+ }
+ cr_unpackDispatch.TexCoordPointer(size, type, stride, pointer);
+ if ((index-7)!=curTexUnit)
+ {
+ cr_unpackDispatch.ClientActiveTextureARB(GL_TEXTURE0_ARB+curTexUnit);
+ }
+ }
+ else
+ {
+ cr_unpackDispatch.VertexAttribPointerARB(index-7-CR_MAX_TEXTURE_UNITS,
+ size, type, normalized, stride, pointer);
+ }
+}
+
+void crUnpackExtendLockArraysEXT(void)
+{
+ GLint first = READ_DATA(sizeof(int) + 4, GLint);
+ GLint count = READ_DATA(sizeof(int) + 8, GLint);
+ int numenabled = READ_DATA(sizeof(int) + 12, int);
+
+ CRContext *g = crStateGetCurrent();
+ CRClientState *c = &g->client;
+ CRClientPointer *cp;
+ int i, index, offset;
+ unsigned char *data;
+
+ if (first < 0 || count <= 0 || first >= INT32_MAX - count)
+ {
+ crError("crUnpackExtendLockArraysEXT: first(%i) count(%i), parameters out of range", first, count);
+ return;
+ }
+
+ if (numenabled <= 0 || numenabled >= CRSTATECLIENT_MAX_VERTEXARRAYS)
+ {
+ crError("crUnpackExtendLockArraysEXT: numenabled(%i), parameter out of range", numenabled);
+ return;
+ }
+
+ offset = 2 * sizeof(int) + 12;
+
+ /*crDebug("crUnpackExtendLockArraysEXT(%i, %i) ne=%i", first, count, numenabled);*/
+
+ for (i = 0; i < numenabled; ++i)
+ {
+ index = READ_DATA(offset, int);
+ offset += sizeof(int);
+
+ cp = crStateGetClientPointerByIndex(index, &c->array);
+
+ CRASSERT(cp && cp->enabled && (!cp->buffer || !cp->buffer->id));
+
+ if (cp && cp->bytesPerIndex > 0)
+ {
+ if (first + count >= INT32_MAX / cp->bytesPerIndex)
+ {
+ crError("crUnpackExtendLockArraysEXT: first(%i) count(%i) bpi(%i), parameters out of range", first, count, cp->bytesPerIndex);
+ return;
+ }
+
+ data = crAlloc((first + count) * cp->bytesPerIndex);
+
+ if (data)
+ {
+ crMemcpy(data + first * cp->bytesPerIndex, DATA_POINTER(offset, GLvoid), count * cp->bytesPerIndex);
+ /*crDebug("crUnpackExtendLockArraysEXT: old cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
+ index, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
+ crUnpackSetClientPointerByIndex(index, cp->size, cp->type, cp->normalized, 0, data, c);
+ /*crDebug("crUnpackExtendLockArraysEXT: new cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
+ index, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
+ }
+ else
+ {
+ crError("crUnpackExtendLockArraysEXT: crAlloc failed");
+ return;
+ }
+ }
+ else
+ {
+ crError("crUnpackExtendLockArraysEXT: wrong CRClientState %i", index);
+ return;
+ }
+
+ offset += count * cp->bytesPerIndex;
+ }
+
+ cr_unpackDispatch.LockArraysEXT(first, count);
+}
+
+void crUnpackExtendUnlockArraysEXT(void)
+{
+ int i;
+ CRContext *g = crStateGetCurrent();
+ CRClientState *c = &g->client;
+ CRClientPointer *cp;
+
+ /*crDebug("crUnpackExtendUnlockArraysEXT");*/
+
+ cr_unpackDispatch.UnlockArraysEXT();
+
+ for (i=0; i<CRSTATECLIENT_MAX_VERTEXARRAYS; ++i)
+ {
+ cp = crStateGetClientPointerByIndex(i, &c->array);
+ if (cp->enabled)
+ {
+ /*crDebug("crUnpackExtendUnlockArraysEXT: old cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
+ i, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
+ crUnpackSetClientPointerByIndex(i, cp->size, cp->type, cp->normalized, cp->prevStride, cp->prevPtr, c);
+ /*crDebug("crUnpackExtendUnlockArraysEXT: new cp(%i): en/l=%i(%i) p=%p size=%i type=0x%x n=%i str=%i pp=%p pstr=%i",
+ i, cp->enabled, cp->locked, cp->p, cp->size, cp->type, cp->normalized, cp->stride, cp->prevPtr, cp->prevStride);*/
+ }
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bounds.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bounds.c
new file mode 100644
index 00000000..1350a3da
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bounds.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "state/cr_statetypes.h"
+
+void crUnpackBoundsInfoCR( void )
+{
+ CRrecti bounds;
+ GLint len;
+ GLuint num_opcodes;
+ GLbyte *payload;
+
+ len = READ_DATA( 0, GLint );
+ bounds.x1 = READ_DATA( 4, GLint );
+ bounds.y1 = READ_DATA( 8, GLint );
+ bounds.x2 = READ_DATA( 12, GLint );
+ bounds.y2 = READ_DATA( 16, GLint );
+ num_opcodes = READ_DATA( 20, GLuint );
+ payload = DATA_POINTER( 24, GLbyte );
+
+ cr_unpackDispatch.BoundsInfoCR( &bounds, payload, len, num_opcodes );
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bufferobject.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bufferobject.c
new file mode 100644
index 00000000..2b9ae29c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_bufferobject.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_mem.h"
+#include "cr_error.h"
+
+
+void crUnpackExtendGetBufferSubDataARB( void )
+{
+ GLenum target = READ_DATA( 8, GLenum );
+ GLintptrARB offset = READ_DATA( 12, GLuint );
+ GLsizeiptrARB size = READ_DATA( 16, GLuint );
+
+ SET_RETURN_PTR( 20 );
+ SET_WRITEBACK_PTR( 28 );
+
+ cr_unpackDispatch.GetBufferSubDataARB( target, offset, size, NULL );
+}
+
+
+void crUnpackExtendBufferDataARB( void )
+{
+ GLenum target = READ_DATA(sizeof(int) + 4, GLenum);
+ GLsizeiptrARB size = READ_DATA(sizeof(int) + 8, GLuint);
+ GLenum usage = READ_DATA(sizeof(int) + 12, GLenum);
+ GLboolean hasdata = READ_DATA(sizeof(int) + 16, GLint);
+ GLvoid *data = DATA_POINTER(sizeof(int) + 20, GLvoid);
+
+ cr_unpackDispatch.BufferDataARB(target, size, hasdata ? data:NULL, usage);
+}
+
+
+void crUnpackExtendBufferSubDataARB( void )
+{
+ GLenum target = READ_DATA( sizeof(int) + 4, GLenum );
+ GLintptrARB offset = READ_DATA( sizeof(int) + 8, GLuint );
+ GLsizeiptrARB size = READ_DATA( sizeof(int) + 12, GLuint );
+ GLvoid *data = DATA_POINTER( sizeof(int) + 16, GLvoid );
+
+ cr_unpackDispatch.BufferSubDataARB( target, offset, size, data );
+}
+
+
+void crUnpackExtendDeleteBuffersARB(void)
+{
+ GLsizei n = READ_DATA( 8, GLsizei );
+ const GLuint *buffers = DATA_POINTER( 12, GLuint );
+ cr_unpackDispatch.DeleteBuffersARB( n, buffers );
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_calllists.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_calllists.c
new file mode 100644
index 00000000..7fa87275
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_calllists.c
@@ -0,0 +1,17 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackCallLists( void )
+{
+ GLint n = READ_DATA( sizeof( int ) + 0, GLint );
+ GLenum type = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLvoid *lists = DATA_POINTER( sizeof( int ) + 8, GLvoid );
+
+ cr_unpackDispatch.CallLists( n, type, lists );
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_clipplane.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_clipplane.c
new file mode 100644
index 00000000..462f28e5
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_clipplane.c
@@ -0,0 +1,19 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_mem.h"
+#include "unpack_extend.h"
+
+void crUnpackClipPlane( void )
+{
+ GLenum plane = READ_DATA( 0, GLenum );
+ GLdouble equation[4];
+ crMemcpy( equation, DATA_POINTER( 4, GLdouble ), sizeof(equation) );
+
+ cr_unpackDispatch.ClipPlane( plane, equation );
+ INCR_DATA_PTR( sizeof( GLenum ) + 4*sizeof( GLdouble ));
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_context.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_context.c
new file mode 100644
index 00000000..bc58dce3
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_context.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_mem.h"
+
+/* XXX duplicated in pack_context.c */
+#define DISPLAY_NAME_LEN 256
+
+#define READ_BYTES( dest, offset, len ) \
+ crMemcpy( dest, (cr_unpackData + (offset)), len )
+
+void crUnpackExtendCreateContext( void )
+{
+ char dpyName[DISPLAY_NAME_LEN];
+ GLint visBits = READ_DATA( DISPLAY_NAME_LEN + 8, GLint );
+ GLint shareCtx = READ_DATA( DISPLAY_NAME_LEN + 12, GLint );
+ GLint retVal;
+
+ READ_BYTES( dpyName, 8, DISPLAY_NAME_LEN );
+ dpyName[DISPLAY_NAME_LEN - 1] = 0; /* NULL-terminate, just in case */
+
+ SET_RETURN_PTR( DISPLAY_NAME_LEN + 16 );
+ SET_WRITEBACK_PTR( DISPLAY_NAME_LEN + 24 );
+ retVal = cr_unpackDispatch.CreateContext( dpyName, visBits, shareCtx );
+ (void) retVal;
+}
+
+void crUnpackExtendWindowCreate(void)
+{
+ char dpyName[DISPLAY_NAME_LEN];
+ GLint visBits = READ_DATA( DISPLAY_NAME_LEN + 8, GLint );
+ GLint retVal;
+
+ READ_BYTES( dpyName, 8, DISPLAY_NAME_LEN );
+ dpyName[DISPLAY_NAME_LEN - 1] = 0; /* NULL-terminate, just in case */
+
+ SET_RETURN_PTR( DISPLAY_NAME_LEN + 12 );
+ SET_WRITEBACK_PTR( DISPLAY_NAME_LEN + 20 );
+ retVal = cr_unpackDispatch.WindowCreate( dpyName, visBits );
+ (void) retVal;
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_drawpixels.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_drawpixels.c
new file mode 100644
index 00000000..e034a28b
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_drawpixels.c
@@ -0,0 +1,94 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+
+#include "state/cr_bufferobject.h"
+
+void crUnpackDrawPixels( void )
+{
+ GLsizei width = READ_DATA( sizeof( int ) + 0, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 4, GLsizei );
+ GLenum format = READ_DATA( sizeof( int ) + 8, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 12, GLenum );
+ GLint noimagedata = READ_DATA( sizeof( int ) + 16, GLint );
+ GLvoid *pixels;
+
+ if (noimagedata && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ return;
+
+ if (noimagedata)
+ pixels = (void*) (uintptr_t) READ_DATA( sizeof( int ) + 20, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 24, GLvoid );
+
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.DrawPixels( width, height, format, type, pixels );
+
+ INCR_VAR_PTR( );
+}
+
+void crUnpackBitmap( void )
+{
+ GLsizei width = READ_DATA( sizeof( int ) + 0, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 4, GLsizei );
+ GLfloat xorig = READ_DATA( sizeof( int ) + 8, GLfloat );
+ GLfloat yorig = READ_DATA( sizeof( int ) + 12, GLfloat );
+ GLfloat xmove = READ_DATA( sizeof( int ) + 16, GLfloat );
+ GLfloat ymove = READ_DATA( sizeof( int ) + 20, GLfloat );
+ GLuint noimagedata = READ_DATA( sizeof( int ) + 24, GLuint );
+ GLubyte *bitmap;
+
+ if (noimagedata && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ return;
+
+ if (noimagedata)
+ bitmap = (void*) (uintptr_t) READ_DATA(sizeof(int) + 28, GLint);
+ else
+ bitmap = DATA_POINTER( sizeof(int) + 32, GLubyte );
+
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.Bitmap( width, height, xorig, yorig, xmove, ymove, bitmap );
+
+ INCR_VAR_PTR( );
+}
+
+/*
+ * ZPixCR - compressed DrawPixels
+ */
+void crUnpackExtendZPixCR( void )
+{
+ GLsizei width = READ_DATA( 8, GLsizei );
+ GLsizei height = READ_DATA( 12, GLsizei );
+ GLenum format = READ_DATA( 16, GLenum );
+ GLenum type = READ_DATA( 20, GLenum );
+ GLenum ztype = READ_DATA( 24, GLenum );
+ GLint zparm = READ_DATA( 28, GLuint );
+ GLint length = READ_DATA( 32, GLint );
+ GLvoid *pixels = DATA_POINTER( 36, GLvoid );
+
+/*XXX JAG
+ crDebug("UnpackZPixCR: w = %d, h = %d, len = %d",
+ width, height, length);
+*/
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.ZPixCR( width, height, format, type, ztype, zparm, length, pixels );
+
+ /* Don't call INCR_VAR_PTR(); - it's done in crUnpackExtend() */
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_extend.py b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_extend.py
new file mode 100755
index 00000000..d81ff903
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_extend.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys
+
+sys.path.append( "../glapi_parser" )
+import apiutil
+
+
+apiutil.CopyrightC()
+
+print("""/* DO NOT EDIT! THIS CODE IS AUTOGENERATED BY unpack_extend.py */
+
+#ifndef UNPACK_EXTEND_H
+#define UNPACK_EXTEND_H 1
+
+""")
+
+
+#
+# Print extern declarations for all special unpacker functions
+#
+for func_name in apiutil.AllSpecials( "unpacker" ):
+ if "extpack" in apiutil.ChromiumProps(func_name):
+ print('extern void crUnpackExtend%s(void);' % func_name)
+ else:
+ print('extern void crUnpack%s(void);' % func_name)
+
+print("""
+#endif
+""")
+
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fence.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fence.c
new file mode 100644
index 00000000..fa616b31
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fence.c
@@ -0,0 +1,10 @@
+
+#include "unpacker.h"
+
+void crUnpackExtendDeleteFencesNV(void)
+{
+ GLsizei n = READ_DATA( 8, GLsizei );
+ const GLuint *fences = DATA_POINTER( 12, GLuint );
+ cr_unpackDispatch.DeleteFencesNV( n, fences );
+}
+
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fog.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fog.c
new file mode 100644
index 00000000..faf09f95
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_fog.c
@@ -0,0 +1,25 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackFogfv( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 4, GLfloat );
+
+ cr_unpackDispatch.Fogfv( pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackFogiv( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 4, GLint );
+
+ cr_unpackDispatch.Fogiv( pname, params );
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_framebuffer.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_framebuffer.c
new file mode 100644
index 00000000..0bab6d56
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_framebuffer.c
@@ -0,0 +1,37 @@
+/* $Id: unpack_framebuffer.c $ */
+/** @file
+ * VBox OpenGL: EXT_framebuffer_object
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include "cr_protocol.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+#include "cr_version.h"
+
+void crUnpackExtendDeleteFramebuffersEXT(void)
+{
+ GLsizei n = READ_DATA( 8, GLsizei );
+ const GLuint *buffers = DATA_POINTER( 12, GLuint );
+ cr_unpackDispatch.DeleteFramebuffersEXT( n, buffers );
+}
+
+void crUnpackExtendDeleteRenderbuffersEXT(void)
+{
+ GLsizei n = READ_DATA( 8, GLsizei );
+ const GLuint *buffers = DATA_POINTER( 12, GLuint );
+ cr_unpackDispatch.DeleteRenderbuffersEXT( n, buffers );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_header.py b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_header.py
new file mode 100755
index 00000000..cb42c22a
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_header.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+
+from __future__ import print_function
+import sys;
+import pickle;
+import types;
+import string;
+import re;
+
+sys.path.append( "../opengl_stub" )
+
+import stub_common;
+
+parsed_file = open( "../glapi_parser/gl_header.parsed", "rb" )
+gl_mapping = pickle.load( parsed_file )
+
+stub_common.CopyrightC()
+
+print("""#ifndef CR_UNPACKFUNCTIONS_H
+#define CR_UNPACKFUNCTIONS_H
+""")
+
+for func_name in sorted(gl_mapping.keys()):
+ ( return_type, arg_names, arg_types ) = gl_mapping[func_name]
+ print('void crUnpack%s();' %( func_name ))
+print('void crUnpackExtend();')
+print('\n#endif /* CR_UNPACKFUNCTIONS_H */')
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_lights.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_lights.c
new file mode 100644
index 00000000..01bd97b3
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_lights.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackLightfv( void )
+{
+ GLenum light = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.Lightfv( light, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackLightiv( void )
+{
+ GLenum light = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.Lightiv( light, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackLightModelfv( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 4, GLfloat );
+
+ cr_unpackDispatch.LightModelfv( pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackLightModeliv( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 4, GLint );
+
+ cr_unpackDispatch.LightModeliv( pname, params );
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_map.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_map.c
new file mode 100644
index 00000000..ac44f856
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_map.c
@@ -0,0 +1,138 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include "cr_mem.h"
+#include "state/cr_limits.h"
+
+
+void crUnpackMap2d(void)
+{
+ GLenum target = READ_DATA(sizeof(int) + 0, GLenum);
+ GLdouble u1 = READ_DOUBLE(sizeof(int) + 4);
+ GLdouble u2 = READ_DOUBLE(sizeof(int) + 12);
+ GLint ustride = READ_DATA(sizeof(int) + 20, GLint);
+ GLint uorder = READ_DATA(sizeof(int) + 24, GLint);
+ GLdouble v1 = READ_DOUBLE(sizeof(int) + 28);
+ GLdouble v2 = READ_DOUBLE(sizeof(int) + 36);
+ GLint vstride = READ_DATA(sizeof(int) + 44, GLint);
+ GLint vorder = READ_DATA(sizeof(int) + 48, GLint);
+ GLdouble *points = DATA_POINTER(sizeof(int) + 52, GLdouble);
+ GLint cbMax;
+
+ if (uorder < 1 || uorder > CR_MAX_EVAL_ORDER ||
+ vorder < 1 || vorder > CR_MAX_EVAL_ORDER ||
+ ustride < 1 || ustride > INT32_MAX / (ssize_t)sizeof(double) / uorder / 8 ||
+ vstride < 1 || vstride > INT32_MAX / (ssize_t)sizeof(double) / vorder / 8 )
+ {
+ crError("crUnpackMap2d: parameters out of range");
+ return;
+ }
+
+ cbMax = (ustride * uorder + vstride * vorder) * sizeof(double);
+ if (!DATA_POINTER_CHECK(cbMax))
+ {
+ crError("crUnpackMap2d: parameters out of range");
+ return;
+ }
+
+ cr_unpackDispatch.Map2d(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points);
+
+ INCR_VAR_PTR();
+}
+
+void crUnpackMap2f(void)
+{
+ GLenum target = READ_DATA(sizeof(int) + 0, GLenum);
+ GLfloat u1 = READ_DATA(sizeof(int) + 4, GLfloat);
+ GLfloat u2 = READ_DATA(sizeof(int) + 8, GLfloat);
+ GLint ustride = READ_DATA(sizeof(int) + 12, GLint);
+ GLint uorder = READ_DATA(sizeof(int) + 16, GLint);
+ GLfloat v1 = READ_DATA(sizeof(int) + 20, GLfloat);
+ GLfloat v2 = READ_DATA(sizeof(int) + 24, GLfloat);
+ GLint vstride = READ_DATA(sizeof(int) + 28, GLint);
+ GLint vorder = READ_DATA(sizeof(int) + 32, GLint);
+ GLfloat *points = DATA_POINTER(sizeof(int) + 36, GLfloat);
+ GLint cbMax;
+
+ if (uorder < 1 || uorder > CR_MAX_EVAL_ORDER ||
+ vorder < 1 || vorder > CR_MAX_EVAL_ORDER ||
+ ustride < 1 || ustride > INT32_MAX / (ssize_t)sizeof(float) / uorder / 8 ||
+ vstride < 1 || vstride > INT32_MAX / (ssize_t)sizeof(float) / vorder / 8)
+ {
+ crError("crUnpackMap2d: parameters out of range");
+ return;
+ }
+
+ cbMax = (ustride * uorder + vstride * vorder) * sizeof(float);
+ if (!DATA_POINTER_CHECK(cbMax))
+ {
+ crError("crUnpackMap2f: parameters out of range");
+ return;
+ }
+
+ cr_unpackDispatch.Map2f(target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points);
+
+ INCR_VAR_PTR();
+}
+
+void crUnpackMap1d(void)
+{
+ GLenum target = READ_DATA(sizeof(int) + 0, GLenum);
+ GLdouble u1 = READ_DOUBLE(sizeof(int) + 4);
+ GLdouble u2 = READ_DOUBLE(sizeof(int) + 12);
+ GLint stride = READ_DATA(sizeof(int) + 20, GLint);
+ GLint order = READ_DATA(sizeof(int) + 24, GLint);
+ GLdouble *points = DATA_POINTER(sizeof(int) + 28, GLdouble);
+ GLint cbMax;
+
+ if (order < 1 || order > CR_MAX_EVAL_ORDER ||
+ stride < 1 || stride > INT32_MAX / (ssize_t)sizeof(double) / order / 8)
+ {
+ crError("crUnpackMap1d: parameters out of range");
+ return;
+ }
+
+ cbMax = stride * order * sizeof(double);
+ if (!DATA_POINTER_CHECK(cbMax))
+ {
+ crError("crUnpackMap1d: parameters out of range");
+ return;
+ }
+
+ cr_unpackDispatch.Map1d(target, u1, u2, stride, order, points);
+
+ INCR_VAR_PTR();
+}
+
+void crUnpackMap1f(void)
+{
+ GLenum target = READ_DATA(sizeof(int) + 0, GLenum);
+ GLfloat u1 = READ_DATA(sizeof(int) + 4, GLfloat);
+ GLfloat u2 = READ_DATA(sizeof(int) + 8, GLfloat);
+ GLint stride = READ_DATA(sizeof(int) + 12, GLint);
+ GLint order = READ_DATA(sizeof(int) + 16, GLint);
+ GLfloat *points = DATA_POINTER(sizeof(int) + 20, GLfloat);
+ GLint cbMax;
+
+ if (order < 1 || order > CR_MAX_EVAL_ORDER ||
+ stride < 1 || stride > INT32_MAX / (ssize_t)sizeof(float) / order / 8)
+ {
+ crError("crUnpackMap1f: parameters out of range");
+ return;
+ }
+
+ cbMax = stride * order * sizeof(float);
+ if (!DATA_POINTER_CHECK(cbMax))
+ {
+ crError("crUnpackMap1f: parameters out of range");
+ return;
+ }
+
+ cr_unpackDispatch.Map1f(target, u1, u2, stride, order, points);
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_materials.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_materials.c
new file mode 100644
index 00000000..f5c03991
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_materials.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackMaterialfv( void )
+{
+ GLenum face = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.Materialfv( face, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackMaterialiv( void )
+{
+ GLenum face = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.Materialiv( face, pname, params );
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_matrices.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_matrices.c
new file mode 100644
index 00000000..a36db771
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_matrices.c
@@ -0,0 +1,72 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_mem.h"
+
+void crUnpackMultMatrixd( void )
+{
+ GLdouble m[16];
+ crMemcpy( m, DATA_POINTER( 0, GLdouble ), sizeof(m) );
+
+ cr_unpackDispatch.MultMatrixd( m );
+ INCR_DATA_PTR( 16*sizeof( GLdouble ) );
+}
+
+void crUnpackMultMatrixf( void )
+{
+ GLfloat *m = DATA_POINTER( 0, GLfloat );
+
+ cr_unpackDispatch.MultMatrixf( m );
+ INCR_DATA_PTR( 16*sizeof( GLfloat ) );
+}
+
+void crUnpackLoadMatrixd( void )
+{
+ GLdouble m[16];
+ crMemcpy( m, DATA_POINTER( 0, GLdouble ), sizeof(m) );
+
+ cr_unpackDispatch.LoadMatrixd( m );
+ INCR_DATA_PTR( 16*sizeof( GLdouble ) );
+}
+
+void crUnpackLoadMatrixf( void )
+{
+ GLfloat *m = DATA_POINTER( 0, GLfloat );
+
+ cr_unpackDispatch.LoadMatrixf( m );
+ INCR_DATA_PTR( 16*sizeof( GLfloat ) );
+}
+
+void crUnpackExtendMultTransposeMatrixdARB( void )
+{
+ GLdouble m[16];
+ crMemcpy( m, DATA_POINTER( 8, GLdouble ), sizeof(m) );
+
+ cr_unpackDispatch.MultTransposeMatrixdARB( m );
+}
+
+void crUnpackExtendMultTransposeMatrixfARB( void )
+{
+ GLfloat *m = DATA_POINTER( 8, GLfloat );
+
+ cr_unpackDispatch.MultTransposeMatrixfARB( m );
+}
+
+void crUnpackExtendLoadTransposeMatrixdARB( void )
+{
+ GLdouble m[16];
+ crMemcpy( m, DATA_POINTER( 8, GLdouble ), sizeof(m) );
+
+ cr_unpackDispatch.LoadTransposeMatrixdARB( m );
+}
+
+void crUnpackExtendLoadTransposeMatrixfARB( void )
+{
+ GLfloat *m = DATA_POINTER( 8, GLfloat );
+
+ cr_unpackDispatch.LoadTransposeMatrixfARB( m );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_misc.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_misc.c
new file mode 100644
index 00000000..daf2b839
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_misc.c
@@ -0,0 +1,87 @@
+/*
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackExtendChromiumParametervCR( void )
+{
+ GLenum target = READ_DATA( 8, GLenum );
+ GLenum type = READ_DATA( 12, GLenum );
+ GLsizei count = READ_DATA( 16, GLsizei );
+ GLvoid *values = DATA_POINTER( 20, GLvoid );
+
+ cr_unpackDispatch.ChromiumParametervCR(target, type, count, values);
+
+
+ /*
+ INCR_VAR_PTR();
+ */
+}
+
+void crUnpackExtendDeleteQueriesARB(void)
+{
+ GLsizei n = READ_DATA( 8, GLsizei );
+ const GLuint *ids = DATA_POINTER(12, GLuint);
+ cr_unpackDispatch.DeleteQueriesARB(n, ids);
+}
+
+void crUnpackExtendGetPolygonStipple(void)
+{
+ GLubyte *mask;
+
+ SET_RETURN_PTR( 8 );
+ SET_WRITEBACK_PTR( 16 );
+ mask = DATA_POINTER(8, GLubyte);
+
+ cr_unpackDispatch.GetPolygonStipple( mask );
+}
+
+void crUnpackExtendGetPixelMapfv(void)
+{
+ GLenum map = READ_DATA( 8, GLenum );
+ GLfloat *values;
+
+ SET_RETURN_PTR( 12 );
+ SET_WRITEBACK_PTR( 20 );
+ values = DATA_POINTER(12, GLfloat);
+
+ cr_unpackDispatch.GetPixelMapfv( map, values );
+}
+
+void crUnpackExtendGetPixelMapuiv(void)
+{
+ GLenum map = READ_DATA( 8, GLenum );
+ GLuint *values;
+
+ SET_RETURN_PTR( 12 );
+ SET_WRITEBACK_PTR( 20 );
+ values = DATA_POINTER(12, GLuint);
+
+ cr_unpackDispatch.GetPixelMapuiv( map, values );
+}
+
+void crUnpackExtendGetPixelMapusv(void)
+{
+ GLenum map = READ_DATA( 8, GLenum );
+ GLushort *values;
+
+ SET_RETURN_PTR( 12 );
+ SET_WRITEBACK_PTR( 20 );
+ values = DATA_POINTER(12, GLushort);
+
+ cr_unpackDispatch.GetPixelMapusv( map, values );
+}
+
+void crUnpackExtendVBoxTexPresent(void)
+{
+ GLuint texture = READ_DATA( 8, GLuint );
+ GLuint cfg = READ_DATA( 12, GLuint );
+ GLint xPos = READ_DATA( 16, GLint );
+ GLint yPos = READ_DATA( 20, GLint );
+ GLint cRects = READ_DATA( 24, GLint );
+ GLint *pRects = (GLint *)DATA_POINTER( 28, GLvoid );
+ cr_unpackDispatch.VBoxTexPresent( texture, cfg, xPos, yPos, cRects, pRects );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_pixelmap.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_pixelmap.c
new file mode 100644
index 00000000..9d0eb1a6
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_pixelmap.c
@@ -0,0 +1,65 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "state/cr_bufferobject.h"
+
+void crUnpackPixelMapfv( void )
+{
+ GLenum map = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLsizei mapsize = READ_DATA( sizeof( int ) + 4, GLsizei );
+ int nodata = READ_DATA( sizeof(int) + 8, int);
+ GLfloat *values;
+
+ if (nodata && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ return;
+
+ if (nodata)
+ values = (GLfloat*) (uintptr_t) READ_DATA(sizeof(int) + 12, GLint);
+ else
+ values = DATA_POINTER( sizeof( int ) + 16, GLfloat );
+
+ cr_unpackDispatch.PixelMapfv( map, mapsize, values );
+ INCR_VAR_PTR();
+}
+
+void crUnpackPixelMapuiv( void )
+{
+ GLenum map = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLsizei mapsize = READ_DATA( sizeof( int ) + 4, GLsizei );
+ int nodata = READ_DATA( sizeof(int) + 8, int);
+ GLuint *values;
+
+ if (nodata && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ return;
+
+ if (nodata)
+ values = (GLuint*) (uintptr_t) READ_DATA(sizeof(int) + 12, GLint);
+ else
+ values = DATA_POINTER( sizeof( int ) + 16, GLuint );
+
+ cr_unpackDispatch.PixelMapuiv( map, mapsize, values );
+ INCR_VAR_PTR();
+}
+
+void crUnpackPixelMapusv( void )
+{
+ GLenum map = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLsizei mapsize = READ_DATA( sizeof( int ) + 4, GLsizei );
+ int nodata = READ_DATA( sizeof(int) + 8, int);
+ GLushort *values;
+
+ if (nodata && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB))
+ return;
+
+ if (nodata)
+ values = (GLushort*) (uintptr_t) READ_DATA(sizeof(int) + 12, GLint);
+ else
+ values = DATA_POINTER( sizeof( int ) + 16, GLushort );
+
+ cr_unpackDispatch.PixelMapusv( map, mapsize, values );
+ INCR_VAR_PTR();
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_point.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_point.c
new file mode 100644
index 00000000..1faa0a53
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_point.c
@@ -0,0 +1,24 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackExtendPointParameterfvARB( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+ cr_unpackDispatch.PointParameterfvARB( pname, params );
+}
+
+#if 1
+void crUnpackExtendPointParameteriv( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 4, GLint );
+
+ cr_unpackDispatch.PointParameteriv( pname, params );
+}
+#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_program.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_program.c
new file mode 100644
index 00000000..346b623c
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_program.c
@@ -0,0 +1,386 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include "cr_protocol.h"
+#include "cr_mem.h"
+#include "cr_version.h"
+
+
+void crUnpackExtendProgramParameter4dvNV(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLdouble params[4];
+ params[0] = READ_DOUBLE(16);
+ params[1] = READ_DOUBLE(24);
+ params[2] = READ_DOUBLE(32);
+ params[3] = READ_DOUBLE(40);
+ cr_unpackDispatch.ProgramParameter4dvNV(target, index, params);
+}
+
+
+void crUnpackExtendProgramParameter4fvNV(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLfloat params[4];
+ params[0] = READ_DATA(16, GLfloat);
+ params[1] = READ_DATA(20, GLfloat);
+ params[2] = READ_DATA(24, GLfloat);
+ params[3] = READ_DATA(28, GLfloat);
+ cr_unpackDispatch.ProgramParameter4fvNV(target, index, params);
+}
+
+
+void crUnpackExtendProgramParameters4dvNV(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLuint num = READ_DATA(16, GLuint);
+ GLdouble *params;
+
+ if (num <= 0 || num >= INT32_MAX / (4 * sizeof(GLdouble)))
+ {
+ crError("crUnpackExtendProgramParameters4dvNV: parameter 'num' is out of range");
+ return;
+ }
+
+ params = (GLdouble *)crAlloc(num * 4 * sizeof(GLdouble));
+
+ if (params) {
+ GLuint i;
+ for (i = 0; i < 4 * num; i++) {
+ params[i] = READ_DATA(20 + i * sizeof(GLdouble), GLdouble);
+ }
+ cr_unpackDispatch.ProgramParameters4dvNV(target, index, num, params);
+ crFree(params);
+ }
+}
+
+
+void crUnpackExtendProgramParameters4fvNV(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLuint num = READ_DATA(16, GLuint);
+ GLfloat *params;
+
+ if (num <= 0 || num >= INT32_MAX / (4 * sizeof(GLfloat)))
+ {
+ crError("crUnpackExtendProgramParameters4fvNV: parameter 'num' is out of range");
+ return;
+ }
+
+ params = (GLfloat *)crAlloc(num * 4 * sizeof(GLfloat));
+
+ if (params) {
+ GLuint i;
+ for (i = 0; i < 4 * num; i++) {
+ params[i] = READ_DATA(20 + i * sizeof(GLfloat), GLfloat);
+ }
+ cr_unpackDispatch.ProgramParameters4fvNV(target, index, num, params);
+ crFree(params);
+ }
+}
+
+
+void crUnpackExtendAreProgramsResidentNV(void)
+{
+ GLsizei n = READ_DATA(8, GLsizei);
+ const GLuint *programs = DATA_POINTER(12, const GLuint);
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint) / 4 || !DATA_POINTER_CHECK(20 + n * sizeof(GLuint)))
+ {
+ crError("crUnpackExtendAreProgramsResidentNV: %d is out of range", n);
+ return;
+ }
+
+ SET_RETURN_PTR(12 + n * sizeof(GLuint));
+ SET_WRITEBACK_PTR(20 + n * sizeof(GLuint));
+ (void) cr_unpackDispatch.AreProgramsResidentNV(n, programs, NULL);
+}
+
+
+void crUnpackExtendLoadProgramNV(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint id = READ_DATA(12, GLuint);
+ GLsizei len = READ_DATA(16, GLsizei);
+ GLvoid *program = DATA_POINTER(20, GLvoid);
+ cr_unpackDispatch.LoadProgramNV(target, id, len, program);
+}
+
+
+void crUnpackExtendExecuteProgramNV(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint id = READ_DATA(12, GLuint);
+ GLfloat params[4];
+ params[0] = READ_DATA(16, GLfloat);
+ params[1] = READ_DATA(20, GLfloat);
+ params[2] = READ_DATA(24, GLfloat);
+ params[3] = READ_DATA(28, GLfloat);
+ cr_unpackDispatch.ExecuteProgramNV(target, id, params);
+}
+
+void crUnpackExtendRequestResidentProgramsNV(void)
+{
+ GLsizei n = READ_DATA(8, GLsizei);
+ crError("RequestResidentProgramsNV needs to be special cased!");
+ cr_unpackDispatch.RequestResidentProgramsNV(n, NULL);
+}
+
+
+void crUnpackExtendProgramLocalParameter4fvARB(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLfloat params[4];
+ params[0] = READ_DATA(16, GLfloat);
+ params[1] = READ_DATA(20, GLfloat);
+ params[2] = READ_DATA(24, GLfloat);
+ params[3] = READ_DATA(28, GLfloat);
+ cr_unpackDispatch.ProgramLocalParameter4fvARB(target, index, params);
+}
+
+
+void crUnpackExtendProgramLocalParameter4dvARB(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLdouble params[4];
+ params[0] = READ_DOUBLE(16);
+ params[1] = READ_DOUBLE(24);
+ params[2] = READ_DOUBLE(32);
+ params[3] = READ_DOUBLE(40);
+ cr_unpackDispatch.ProgramLocalParameter4dvARB(target, index, params);
+}
+
+
+
+void crUnpackExtendProgramNamedParameter4dvNV(void)
+{
+ GLuint id = READ_DATA(8, GLuint);
+ GLsizei len = READ_DATA(12, GLsizei);
+ GLdouble params[4];
+ GLubyte *name = crAlloc(len);
+ params[0] = READ_DOUBLE(16);
+ params[1] = READ_DOUBLE(24);
+ params[2] = READ_DOUBLE(32);
+ params[3] = READ_DOUBLE(40);
+ crMemcpy(name, DATA_POINTER(48, GLubyte), len);
+ cr_unpackDispatch.ProgramNamedParameter4dvNV(id, len, name, params);
+}
+
+void crUnpackExtendProgramNamedParameter4dNV(void)
+{
+ GLuint id = READ_DATA(8, GLuint);
+ GLsizei len = READ_DATA(12, GLsizei);
+ GLdouble params[4];
+ GLubyte *name = crAlloc (len);
+ params[0] = READ_DOUBLE(16);
+ params[1] = READ_DOUBLE(24);
+ params[2] = READ_DOUBLE(32);
+ params[3] = READ_DOUBLE(40);
+ crMemcpy(name, DATA_POINTER(48, GLubyte), len);
+ cr_unpackDispatch.ProgramNamedParameter4dNV(id, len, name, params[0], params[1], params[2], params[3]);
+}
+
+void crUnpackExtendProgramNamedParameter4fNV(void)
+{
+ GLenum id = READ_DATA(8, GLuint);
+ GLsizei len = READ_DATA(12, GLsizei);
+ GLfloat params[4];
+ GLubyte *name = crAlloc(len);
+ params[0] = READ_DATA(16, GLfloat);
+ params[1] = READ_DATA(20, GLfloat);
+ params[2] = READ_DATA(24, GLfloat);
+ params[3] = READ_DATA(28, GLfloat);
+ crMemcpy(name, DATA_POINTER(32, GLubyte), len);
+ cr_unpackDispatch.ProgramNamedParameter4fNV(id, len, name, params[0], params[1], params[2], params[3]);
+}
+
+void crUnpackExtendProgramNamedParameter4fvNV(void)
+{
+ GLenum id = READ_DATA(8, GLuint);
+ GLsizei len = READ_DATA(12, GLsizei);
+ GLfloat params[4];
+ GLubyte *name = crAlloc(len);
+ params[0] = READ_DATA(16, GLfloat);
+ params[1] = READ_DATA(20, GLfloat);
+ params[2] = READ_DATA(24, GLfloat);
+ params[3] = READ_DATA(28, GLfloat);
+ crMemcpy(name, DATA_POINTER(32, GLubyte), len);
+ cr_unpackDispatch.ProgramNamedParameter4fvNV(id, len, name, params);
+}
+
+void crUnpackExtendGetProgramNamedParameterdvNV(void)
+{
+ GLuint id = READ_DATA(8, GLuint);
+ GLsizei len = READ_DATA(12, GLsizei);
+ const GLubyte *name = DATA_POINTER(16, GLubyte);
+
+ if (len <= 0 || len >= INT32_MAX / 4 || !DATA_POINTER_CHECK(16 + len + 8))
+ {
+ crError("crUnpackExtendGetProgramNamedParameterdvNV: len %d is out of range", len);
+ return;
+ }
+
+ SET_RETURN_PTR(16+len);
+ SET_WRITEBACK_PTR(16+len+8);
+ cr_unpackDispatch.GetProgramNamedParameterdvNV(id, len, name, NULL);
+}
+
+void crUnpackExtendGetProgramNamedParameterfvNV(void)
+{
+ GLuint id = READ_DATA(8, GLuint);
+ GLsizei len = READ_DATA(12, GLsizei);
+ const GLubyte *name = DATA_POINTER(16, GLubyte);
+
+ if (len <= 0 || len >= INT32_MAX / 4 || !DATA_POINTER_CHECK(16 + len + 8))
+ {
+ crError("crUnpackExtendGetProgramNamedParameterfvNV: len %d is out of range", len);
+ return;
+ }
+
+ SET_RETURN_PTR(16+len);
+ SET_WRITEBACK_PTR(16+len+8);
+ cr_unpackDispatch.GetProgramNamedParameterfvNV(id, len, name, NULL);
+}
+
+void crUnpackExtendProgramStringARB(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLenum format = READ_DATA(12, GLuint);
+ GLsizei len = READ_DATA(16, GLsizei);
+ GLvoid *program = DATA_POINTER(20, GLvoid);
+ cr_unpackDispatch.ProgramStringARB(target, format, len, program);
+}
+
+void crUnpackExtendGetProgramStringARB(void)
+{
+}
+
+void crUnpackExtendProgramEnvParameter4dvARB(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLdouble params[4];
+ params[0] = READ_DOUBLE(16);
+ params[1] = READ_DOUBLE(24);
+ params[2] = READ_DOUBLE(32);
+ params[3] = READ_DOUBLE(40);
+ cr_unpackDispatch.ProgramEnvParameter4dvARB(target, index, params);
+}
+
+void crUnpackExtendProgramEnvParameter4fvARB(void)
+{
+ GLenum target = READ_DATA(8, GLenum);
+ GLuint index = READ_DATA(12, GLuint);
+ GLfloat params[4];
+ params[0] = READ_DATA(16, GLfloat);
+ params[1] = READ_DATA(20, GLfloat);
+ params[2] = READ_DATA(24, GLfloat);
+ params[3] = READ_DATA(28, GLfloat);
+ cr_unpackDispatch.ProgramEnvParameter4fvARB(target, index, params);
+}
+
+void crUnpackExtendDeleteProgramsARB(void)
+{
+ GLsizei n = READ_DATA(8, GLsizei);
+ const GLuint *programs = DATA_POINTER(12, GLuint);
+ cr_unpackDispatch.DeleteProgramsARB(n, programs);
+}
+
+void crUnpackVertexAttrib4NbvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLbyte *v = DATA_POINTER(4, const GLbyte);
+ cr_unpackDispatch.VertexAttrib4NbvARB(index, v);
+ INCR_DATA_PTR(8);
+}
+
+void crUnpackVertexAttrib4NivARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLint *v = DATA_POINTER(4, const GLint);
+ cr_unpackDispatch.VertexAttrib4NivARB(index, v);
+ INCR_DATA_PTR(20);
+}
+
+void crUnpackVertexAttrib4NsvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLshort *v = DATA_POINTER(4, const GLshort);
+ cr_unpackDispatch.VertexAttrib4NsvARB(index, v);
+ INCR_DATA_PTR(12);
+}
+
+void crUnpackVertexAttrib4NubvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLubyte *v = DATA_POINTER(4, const GLubyte);
+ cr_unpackDispatch.VertexAttrib4NubvARB(index, v);
+ INCR_DATA_PTR(8);
+}
+
+void crUnpackVertexAttrib4NuivARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLuint *v = DATA_POINTER(4, const GLuint);
+ cr_unpackDispatch.VertexAttrib4NuivARB(index, v);
+ INCR_DATA_PTR(20);
+}
+
+void crUnpackVertexAttrib4NusvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLushort *v = DATA_POINTER(4, const GLushort);
+ cr_unpackDispatch.VertexAttrib4NusvARB(index, v);
+ INCR_DATA_PTR(12);
+}
+
+void crUnpackVertexAttrib4bvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLbyte *v = DATA_POINTER(4, const GLbyte);
+ cr_unpackDispatch.VertexAttrib4bvARB(index, v);
+ INCR_DATA_PTR(8);
+}
+
+void crUnpackVertexAttrib4ivARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLint *v = DATA_POINTER(4, const GLint);
+ cr_unpackDispatch.VertexAttrib4ivARB(index, v);
+ INCR_DATA_PTR(20);
+}
+
+void crUnpackVertexAttrib4ubvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLubyte *v = DATA_POINTER(4, const GLubyte);
+ cr_unpackDispatch.VertexAttrib4ubvARB(index, v);
+ INCR_DATA_PTR(8);
+}
+
+void crUnpackVertexAttrib4uivARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLuint *v = DATA_POINTER(4, const GLuint);
+ cr_unpackDispatch.VertexAttrib4uivARB(index, v);
+ INCR_DATA_PTR(20);
+}
+
+void crUnpackVertexAttrib4usvARB(void)
+{
+ GLuint index = READ_DATA(0, GLuint);
+ const GLushort *v = DATA_POINTER(4, const GLushort);
+ cr_unpackDispatch.VertexAttrib4usvARB(index, v);
+ INCR_DATA_PTR(12);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_readpixels.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_readpixels.c
new file mode 100644
index 00000000..34b73616
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_readpixels.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_pixeldata.h"
+#include "cr_mem.h"
+
+void crUnpackReadPixels( void )
+{
+ GLint x = READ_DATA( 0, GLint );
+ GLint y = READ_DATA( 4, GLint );
+ GLsizei width = READ_DATA( 8, GLsizei );
+ GLsizei height = READ_DATA( 12, GLsizei );
+ GLenum format = READ_DATA( 16, GLenum );
+ GLenum type = READ_DATA( 20, GLenum );
+ GLint stride = READ_DATA( 24, GLint );
+ GLint alignment = READ_DATA( 28, GLint );
+ GLint skipRows = READ_DATA( 32, GLint );
+ GLint skipPixels = READ_DATA( 36, GLint );
+ GLint bytes_per_row = READ_DATA( 40, GLint );
+ GLint rowLength = READ_DATA( 44, GLint );
+ GLvoid *pixels;
+
+ /* point <pixels> at the 8-byte network pointer */
+ pixels = DATA_POINTER( 48, GLvoid );
+
+ (void) stride;
+ (void) bytes_per_row;
+ (void) alignment;
+ (void) skipRows;
+ (void) skipPixels;
+ (void) rowLength;
+
+ /* we always pack densely on the server side! */
+ cr_unpackDispatch.PixelStorei( GL_PACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_PACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_PACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_PACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.ReadPixels( x, y, width, height, format, type, pixels);
+
+ INCR_DATA_PTR(48+sizeof(CRNetworkPointer));
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_regcombiner.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_regcombiner.c
new file mode 100644
index 00000000..9ebd777f
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_regcombiner.c
@@ -0,0 +1,35 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackExtendCombinerParameterfvNV( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.CombinerParameterfvNV( pname, params );
+ /* Don't call INCR_VAR_PTR(); - it's done in crUnpackExtend() */
+}
+
+void crUnpackExtendCombinerParameterivNV( void )
+{
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.CombinerParameterivNV( pname, params );
+ /* Don't call INCR_VAR_PTR(); - it's done in crUnpackExtend() */
+}
+
+void crUnpackExtendCombinerStageParameterfvNV( void )
+{
+ GLenum stage = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 8, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 12, GLfloat );
+
+ cr_unpackDispatch.CombinerStageParameterfvNV( stage, pname, params );
+ /* Don't call INCR_VAR_PTR(); - it's done in crUnpackExtend() */
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_shaders.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_shaders.c
new file mode 100644
index 00000000..8bc04e2d
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_shaders.c
@@ -0,0 +1,386 @@
+/* $Id: unpack_shaders.c $ */
+/** @file
+ * VBox OpenGL DRI driver functions
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include "cr_protocol.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+#include "cr_version.h"
+
+void crUnpackExtendBindAttribLocation(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLuint index = READ_DATA(12, GLuint);
+ const char *name = DATA_POINTER(16, const char);
+
+ cr_unpackDispatch.BindAttribLocation(program, index, name);
+}
+
+void crUnpackExtendShaderSource(void)
+{
+ GLint *length = NULL;
+ GLuint shader = READ_DATA(8, GLuint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLint hasNonLocalLen = READ_DATA(16, GLsizei);
+ GLint *pLocalLength = DATA_POINTER(20, GLint);
+ char **ppStrings = NULL;
+ GLsizei i, j, jUpTo;
+ int pos, pos_check;
+
+ if (count <= 0 || count >= INT32_MAX / sizeof(char *) / 4)
+ {
+ crError("crUnpackExtendShaderSource: count %u is out of range", count);
+ return;
+ }
+
+ pos = 20 + count * sizeof(*pLocalLength);
+
+ if (hasNonLocalLen > 0)
+ {
+ length = DATA_POINTER(pos, GLint);
+ pos += count * sizeof(*length);
+ }
+
+ pos_check = pos;
+
+ if (!DATA_POINTER_CHECK(pos_check))
+ {
+ crError("crUnpackExtendShaderSource: pos %d is out of range", pos_check);
+ return;
+ }
+
+ for (i = 0; i < count; ++i)
+ {
+ if (pLocalLength[i] <= 0 || pos_check >= INT32_MAX - pLocalLength[i] || !DATA_POINTER_CHECK(pos_check))
+ {
+ crError("crUnpackExtendShaderSource: pos %d is out of range", pos_check);
+ return;
+ }
+
+ pos_check += pLocalLength[i];
+ }
+
+ ppStrings = crAlloc(count * sizeof(char*));
+ if (!ppStrings) return;
+
+ for (i = 0; i < count; ++i)
+ {
+ ppStrings[i] = DATA_POINTER(pos, char);
+ pos += pLocalLength[i];
+ if (!length)
+ {
+ pLocalLength[i] -= 1;
+ }
+
+ Assert(pLocalLength[i] > 0);
+ jUpTo = i == count -1 ? pLocalLength[i] - 1 : pLocalLength[i];
+ for (j = 0; j < jUpTo; ++j)
+ {
+ char *pString = ppStrings[i];
+
+ if (pString[j] == '\0')
+ {
+ Assert(j == jUpTo - 1);
+ pString[j] = '\n';
+ }
+ }
+ }
+
+// cr_unpackDispatch.ShaderSource(shader, count, ppStrings, length ? length : pLocalLength);
+ cr_unpackDispatch.ShaderSource(shader, 1, (const char**)ppStrings, 0);
+
+ crFree(ppStrings);
+}
+
+void crUnpackExtendUniform1fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLfloat *value = DATA_POINTER(16, const GLfloat);
+ cr_unpackDispatch.Uniform1fv(location, count, value);
+}
+
+void crUnpackExtendUniform1iv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLint *value = DATA_POINTER(16, const GLint);
+ cr_unpackDispatch.Uniform1iv(location, count, value);
+}
+
+void crUnpackExtendUniform2fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLfloat *value = DATA_POINTER(16, const GLfloat);
+ cr_unpackDispatch.Uniform2fv(location, count, value);
+}
+
+void crUnpackExtendUniform2iv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLint *value = DATA_POINTER(16, const GLint);
+ cr_unpackDispatch.Uniform2iv(location, count, value);
+}
+
+void crUnpackExtendUniform3fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLfloat *value = DATA_POINTER(16, const GLfloat);
+ cr_unpackDispatch.Uniform3fv(location, count, value);
+}
+
+void crUnpackExtendUniform3iv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLint *value = DATA_POINTER(16, const GLint);
+ cr_unpackDispatch.Uniform3iv(location, count, value);
+}
+
+void crUnpackExtendUniform4fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLfloat *value = DATA_POINTER(16, const GLfloat);
+ cr_unpackDispatch.Uniform4fv(location, count, value);
+}
+
+void crUnpackExtendUniform4iv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ const GLint *value = DATA_POINTER(16, const GLint);
+ cr_unpackDispatch.Uniform4iv(location, count, value);
+}
+
+void crUnpackExtendUniformMatrix2fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix2fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix3fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix3fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix4fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix4fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix2x3fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix2x3fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix3x2fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix3x2fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix2x4fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix2x4fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix4x2fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix4x2fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix3x4fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix3x4fv(location, count, transpose, value);
+}
+
+void crUnpackExtendUniformMatrix4x3fv(void)
+{
+ GLint location = READ_DATA(8, GLint);
+ GLsizei count = READ_DATA(12, GLsizei);
+ GLboolean transpose = READ_DATA(16, GLboolean);
+ const GLfloat *value = DATA_POINTER(16+sizeof(GLboolean), const GLfloat);
+ cr_unpackDispatch.UniformMatrix4x3fv(location, count, transpose, value);
+}
+
+void crUnpackExtendDrawBuffers(void)
+{
+ GLsizei n = READ_DATA(8, GLsizei);
+ const GLenum *bufs = DATA_POINTER(8+sizeof(GLsizei), const GLenum);
+ cr_unpackDispatch.DrawBuffers(n, bufs);
+}
+
+void crUnpackExtendGetActiveAttrib(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLuint index = READ_DATA(12, GLuint);
+ GLsizei bufSize = READ_DATA(16, GLsizei);
+ SET_RETURN_PTR(20);
+ SET_WRITEBACK_PTR(28);
+ cr_unpackDispatch.GetActiveAttrib(program, index, bufSize, NULL, NULL, NULL, NULL);
+}
+
+void crUnpackExtendGetActiveUniform(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLuint index = READ_DATA(12, GLuint);
+ GLsizei bufSize = READ_DATA(16, GLsizei);
+ SET_RETURN_PTR(20);
+ SET_WRITEBACK_PTR(28);
+ cr_unpackDispatch.GetActiveUniform(program, index, bufSize, NULL, NULL, NULL, NULL);
+}
+
+void crUnpackExtendGetAttachedShaders(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLsizei maxCount = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetAttachedShaders(program, maxCount, NULL, NULL);
+}
+
+void crUnpackExtendGetAttachedObjectsARB(void)
+{
+ VBoxGLhandleARB containerObj = READ_DATA(8, VBoxGLhandleARB);
+ GLsizei maxCount = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetAttachedObjectsARB(containerObj, maxCount, NULL, NULL);
+}
+
+void crUnpackExtendGetInfoLogARB(void)
+{
+ VBoxGLhandleARB obj = READ_DATA(8, VBoxGLhandleARB);
+ GLsizei maxLength = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetInfoLogARB(obj, maxLength, NULL, NULL);
+}
+
+void crUnpackExtendGetProgramInfoLog(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLsizei bufSize = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetProgramInfoLog(program, bufSize, NULL, NULL);
+}
+
+void crUnpackExtendGetShaderInfoLog(void)
+{
+ GLuint shader = READ_DATA(8, GLuint);
+ GLsizei bufSize = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetShaderInfoLog(shader, bufSize, NULL, NULL);
+}
+
+void crUnpackExtendGetShaderSource(void)
+{
+ GLuint shader = READ_DATA(8, GLuint);
+ GLsizei bufSize = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetShaderSource(shader, bufSize, NULL, NULL);
+}
+
+void crUnpackExtendGetAttribLocation(void)
+{
+ int packet_length = READ_DATA(0, int);
+ GLuint program = READ_DATA(8, GLuint);
+ const char *name = DATA_POINTER(12, const char);
+
+ if (!DATA_POINTER_CHECK(packet_length))
+ {
+ crError("crUnpackExtendGetAttribLocation: packet_length is out of range");
+ return;
+ }
+
+ SET_RETURN_PTR(packet_length-16);
+ SET_WRITEBACK_PTR(packet_length-8);
+ cr_unpackDispatch.GetAttribLocation(program, name);
+}
+
+void crUnpackExtendGetUniformLocation(void)
+{
+ int packet_length = READ_DATA(0, int);
+ GLuint program = READ_DATA(8, GLuint);
+ const char *name = DATA_POINTER(12, const char);
+
+ if (!DATA_POINTER_CHECK(packet_length))
+ {
+ crError("crUnpackExtendGetUniformLocation: packet_length is out of range");
+ return;
+ }
+
+ SET_RETURN_PTR(packet_length-16);
+ SET_WRITEBACK_PTR(packet_length-8);
+ cr_unpackDispatch.GetUniformLocation(program, name);
+}
+
+void crUnpackExtendGetUniformsLocations(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLsizei maxcbData = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetUniformsLocations(program, maxcbData, NULL, NULL);
+}
+
+void crUnpackExtendGetAttribsLocations(void)
+{
+ GLuint program = READ_DATA(8, GLuint);
+ GLsizei maxcbData = READ_DATA(12, GLsizei);
+ SET_RETURN_PTR(16);
+ SET_WRITEBACK_PTR(24);
+ cr_unpackDispatch.GetAttribsLocations(program, maxcbData, NULL, NULL);
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_stipple.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_stipple.c
new file mode 100644
index 00000000..dcc3ab58
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_stipple.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+
+void crUnpackPolygonStipple( void )
+{
+ int nodata = READ_DATA(0, int);
+
+ if (nodata)
+ {
+ crError("crUnpackPolygonStipple: GL_PIXEL_UNPACK_BUFFER is not supported");
+ INCR_DATA_PTR(8);
+ }
+ else
+ {
+ GLubyte *mask;
+
+ mask = DATA_POINTER(4, GLubyte);
+ cr_unpackDispatch.PolygonStipple(mask);
+ // Stipple mask consists of 32 * 32 bits
+ INCR_DATA_PTR(4 + 32 * 32 / 8);
+ }
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_texture.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_texture.c
new file mode 100644
index 00000000..8c757e95
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_texture.c
@@ -0,0 +1,507 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include "cr_protocol.h"
+#include "cr_mem.h"
+#include "cr_version.h"
+
+#if defined( GL_EXT_texture3D )
+void crUnpackTexImage3DEXT( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLenum internalformat = READ_DATA( sizeof( int ) + 8, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 12, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 16, GLsizei );
+ GLsizei depth = READ_DATA( sizeof( int ) + 20, GLsizei );
+ GLint border = READ_DATA( sizeof( int ) + 24, GLint );
+ GLenum format = READ_DATA( sizeof( int ) + 28, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 32, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 36, int );
+ GLvoid *pixels;
+
+ /*If there's no imagedata send, it's either that passed pointer was NULL or
+ there was GL_PIXEL_UNPACK_BUFFER_ARB bound, in both cases 4bytes of passed
+ pointer would convert to either NULL or offset in the bound buffer.
+ */
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+40, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 44, GLvoid );
+
+ cr_unpackDispatch.TexImage3DEXT(target, level, internalformat, width,
+ height, depth, border, format, type,
+ pixels);
+ INCR_VAR_PTR();
+}
+#endif /* GL_EXT_texture3D */
+
+#if defined( CR_OPENGL_VERSION_1_2 )
+void crUnpackTexImage3D( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLint internalformat = READ_DATA( sizeof( int ) + 8, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 12, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 16, GLsizei );
+ GLsizei depth = READ_DATA( sizeof( int ) + 20, GLsizei );
+ GLint border = READ_DATA( sizeof( int ) + 24, GLint );
+ GLenum format = READ_DATA( sizeof( int ) + 28, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 32, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 36, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+40, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 44, GLvoid );
+
+ cr_unpackDispatch.TexImage3D( target, level, internalformat, width, height,
+ depth, border, format, type, pixels );
+ INCR_VAR_PTR();
+}
+#endif /* CR_OPENGL_VERSION_1_2 */
+
+void crUnpackTexImage2D( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLint internalformat = READ_DATA( sizeof( int ) + 8, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 12, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 16, GLsizei );
+ GLint border = READ_DATA( sizeof( int ) + 20, GLint );
+ GLenum format = READ_DATA( sizeof( int ) + 24, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 28, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 32, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+36, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 40, GLvoid );
+
+ cr_unpackDispatch.TexImage2D( target, level, internalformat, width, height,
+ border, format, type, pixels );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexImage1D( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLint internalformat = READ_DATA( sizeof( int ) + 8, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 12, GLsizei );
+ GLint border = READ_DATA( sizeof( int ) + 16, GLint );
+ GLenum format = READ_DATA( sizeof( int ) + 20, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 24, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 28, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+32, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 36, GLvoid );
+
+ cr_unpackDispatch.TexImage1D( target, level, internalformat, width, border,
+ format, type, pixels );
+ INCR_VAR_PTR();
+}
+
+void crUnpackDeleteTextures( void )
+{
+ GLsizei n = READ_DATA( sizeof( int ) + 0, GLsizei );
+ GLuint *textures = DATA_POINTER( sizeof( int ) + 4, GLuint );
+
+ cr_unpackDispatch.DeleteTextures( n, textures );
+ INCR_VAR_PTR();
+}
+
+
+void crUnpackPrioritizeTextures( void )
+{
+ GLsizei n = READ_DATA( sizeof( int ) + 0, GLsizei );
+ GLuint *textures = DATA_POINTER( sizeof( int ) + 4, GLuint );
+ GLclampf *priorities = DATA_POINTER( sizeof( int ) + 4 + n*sizeof( GLuint ),
+ GLclampf );
+
+ cr_unpackDispatch.PrioritizeTextures( n, textures, priorities );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexParameterfv( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.TexParameterfv( target, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexParameteriv( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.TexParameteriv( target, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexParameterf( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat param = READ_DATA( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.TexParameterf( target, pname, param );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexParameteri( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint param = READ_DATA( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.TexParameteri( target, pname, param );
+ INCR_VAR_PTR();
+}
+
+#if defined(CR_OPENGL_VERSION_1_2)
+void crUnpackTexSubImage3D( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLint xoffset = READ_DATA( sizeof( int ) + 8, GLint );
+ GLint yoffset = READ_DATA( sizeof( int ) + 12, GLint );
+ GLint zoffset = READ_DATA( sizeof( int ) + 16, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 20, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 24, GLsizei );
+ GLsizei depth = READ_DATA( sizeof( int ) + 28, GLsizei );
+ GLenum format = READ_DATA( sizeof( int ) + 32, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 36, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 40, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+44, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 48, GLvoid );
+
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.TexSubImage3D(target, level, xoffset, yoffset, zoffset,
+ width, height, depth, format, type, pixels);
+ INCR_VAR_PTR();
+}
+#endif /* CR_OPENGL_VERSION_1_2 */
+
+void crUnpackTexSubImage2D( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLint xoffset = READ_DATA( sizeof( int ) + 8, GLint );
+ GLint yoffset = READ_DATA( sizeof( int ) + 12, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 16, GLsizei );
+ GLsizei height = READ_DATA( sizeof( int ) + 20, GLsizei );
+ GLenum format = READ_DATA( sizeof( int ) + 24, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 28, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 32, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+36, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 40, GLvoid );
+
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.TexSubImage2D( target, level, xoffset, yoffset, width,
+ height, format, type, pixels );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexSubImage1D( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( sizeof( int ) + 4, GLint );
+ GLint xoffset = READ_DATA( sizeof( int ) + 8, GLint );
+ GLsizei width = READ_DATA( sizeof( int ) + 12, GLsizei );
+ GLenum format = READ_DATA( sizeof( int ) + 16, GLenum );
+ GLenum type = READ_DATA( sizeof( int ) + 20, GLenum );
+ int noimagedata = READ_DATA( sizeof( int ) + 24, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(sizeof(int)+28, GLint);
+ else
+ pixels = DATA_POINTER( sizeof( int ) + 32, GLvoid );
+
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ cr_unpackDispatch.PixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ cr_unpackDispatch.TexSubImage1D( target, level, xoffset, width, format,
+ type, pixels );
+ INCR_VAR_PTR();
+}
+
+
+void crUnpackTexEnvfv( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.TexEnvfv( target, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexEnviv( void )
+{
+ GLenum target = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.TexEnviv( target, pname, params );
+ INCR_VAR_PTR();
+}
+
+#define DATA_POINTER_DOUBLE( offset )
+
+void crUnpackTexGendv( void )
+{
+ GLenum coord = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLdouble params[4];
+ unsigned int n_param = READ_DATA( 0, int ) - ( sizeof(int) + 8 );
+
+ if (n_param > sizeof(params))
+ {
+ crError("crUnpackTexGendv: n_param=%d, expected <= %d\n", n_param,
+ (unsigned int)sizeof(params));
+ return;
+ }
+
+ crMemcpy( params, DATA_POINTER( sizeof( int ) + 8, GLdouble ), n_param );
+
+ cr_unpackDispatch.TexGendv( coord, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexGenfv( void )
+{
+ GLenum coord = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLfloat *params = DATA_POINTER( sizeof( int ) + 8, GLfloat );
+
+ cr_unpackDispatch.TexGenfv( coord, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackTexGeniv( void )
+{
+ GLenum coord = READ_DATA( sizeof( int ) + 0, GLenum );
+ GLenum pname = READ_DATA( sizeof( int ) + 4, GLenum );
+ GLint *params = DATA_POINTER( sizeof( int ) + 8, GLint );
+
+ cr_unpackDispatch.TexGeniv( coord, pname, params );
+ INCR_VAR_PTR();
+}
+
+void crUnpackExtendAreTexturesResident( void )
+{
+ GLsizei n = READ_DATA( 8, GLsizei );
+ const GLuint *textures = DATA_POINTER( 12, const GLuint );
+
+ if (n <= 0 || n >= INT32_MAX / sizeof(GLuint) / 4 || !DATA_POINTER_CHECK(20 + n * sizeof(GLuint)))
+ {
+ crError("crUnpackExtendAreTexturesResident: %d is out of range", n);
+ return;
+ }
+
+ SET_RETURN_PTR(12 + n * sizeof(GLuint));
+ SET_WRITEBACK_PTR(20 + n * sizeof(GLuint));
+ (void) cr_unpackDispatch.AreTexturesResident( n, textures, NULL );
+}
+
+
+void crUnpackExtendCompressedTexImage3DARB( void )
+{
+ GLenum target = READ_DATA( 4 + sizeof(int) + 0, GLenum );
+ GLint level = READ_DATA( 4 + sizeof(int) + 4, GLint );
+ GLenum internalformat = READ_DATA( 4 + sizeof(int) + 8, GLenum );
+ GLsizei width = READ_DATA( 4 + sizeof(int) + 12, GLsizei );
+ GLsizei height = READ_DATA( 4 + sizeof(int) + 16, GLsizei );
+ GLsizei depth = READ_DATA( 4 + sizeof(int) + 20, GLsizei );
+ GLint border = READ_DATA( 4 + sizeof(int) + 24, GLint );
+ GLsizei imagesize = READ_DATA( 4 + sizeof(int) + 28, GLsizei );
+ int noimagedata = READ_DATA( 4 + sizeof(int) + 32, int );
+ GLvoid *pixels;
+
+ if( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(4+sizeof(int)+36, GLint);
+ else
+ pixels = DATA_POINTER( 4 + sizeof(int) + 40, GLvoid );
+
+ cr_unpackDispatch.CompressedTexImage3DARB(target, level, internalformat,
+ width, height, depth, border,
+ imagesize, pixels);
+}
+
+
+void crUnpackExtendCompressedTexImage2DARB( void )
+{
+ GLenum target = READ_DATA( 4 + sizeof( int ) + 0, GLenum );
+ GLint level = READ_DATA( 4 + sizeof( int ) + 4, GLint );
+ GLenum internalformat = READ_DATA( 4 + sizeof( int ) + 8, GLenum );
+ GLsizei width = READ_DATA( 4 + sizeof( int ) + 12, GLsizei );
+ GLsizei height = READ_DATA( 4 + sizeof( int ) + 16, GLsizei );
+ GLint border = READ_DATA( 4 + sizeof( int ) + 20, GLint );
+ GLsizei imagesize = READ_DATA( 4 + sizeof( int ) + 24, GLsizei );
+ int noimagedata = READ_DATA( 4 + sizeof( int ) + 28, int );
+ GLvoid *pixels;
+
+ if ( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(4+sizeof(int)+32, GLint);
+ else
+ pixels = DATA_POINTER( 4 + sizeof( int ) + 36, GLvoid );
+
+ cr_unpackDispatch.CompressedTexImage2DARB( target, level, internalformat,
+ width, height, border, imagesize,
+ pixels );
+}
+
+
+void crUnpackExtendCompressedTexImage1DARB( void )
+{
+ GLenum target = READ_DATA( 4 + sizeof(int) + 0, GLenum );
+ GLint level = READ_DATA( 4 + sizeof(int) + 4, GLint );
+ GLenum internalformat = READ_DATA( 4 + sizeof(int) + 8, GLenum );
+ GLsizei width = READ_DATA( 4 + sizeof(int) + 12, GLsizei );
+ GLint border = READ_DATA( 4 + sizeof(int) + 16, GLint );
+ GLsizei imagesize = READ_DATA( 4 + sizeof(int) + 20, GLsizei );
+ int noimagedata = READ_DATA( 4 + sizeof(int) + 24, int );
+ GLvoid *pixels;
+
+ if( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(4+sizeof(int)+28, GLint);
+ else
+ pixels = DATA_POINTER( 4 + sizeof(int) + 32, GLvoid );
+
+ cr_unpackDispatch.CompressedTexImage1DARB(target, level, internalformat,
+ width, border, imagesize, pixels);
+}
+
+
+void crUnpackExtendCompressedTexSubImage3DARB( void )
+{
+ GLenum target = READ_DATA( 4 + sizeof(int) + 0, GLenum );
+ GLint level = READ_DATA( 4 + sizeof(int) + 4, GLint );
+ GLint xoffset = READ_DATA( 4 + sizeof(int) + 8, GLint );
+ GLint yoffset = READ_DATA( 4 + sizeof(int) + 12, GLint );
+ GLint zoffset = READ_DATA( 4 + sizeof(int) + 16, GLint );
+ GLsizei width = READ_DATA( 4 + sizeof(int) + 20, GLsizei );
+ GLsizei height = READ_DATA( 4 + sizeof(int) + 24, GLsizei );
+ GLsizei depth = READ_DATA( 4 + sizeof(int) + 28, GLsizei );
+ GLenum format = READ_DATA( 4 + sizeof(int) + 32, GLenum );
+ GLsizei imagesize = READ_DATA( 4 + sizeof(int) + 36, GLsizei );
+ int noimagedata = READ_DATA( 4 + sizeof(int) + 40, int );
+ GLvoid *pixels;
+
+ if( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(4+sizeof(int)+44, GLint);
+ else
+ pixels = DATA_POINTER( 4 + sizeof(int) + 48, GLvoid );
+
+ cr_unpackDispatch.CompressedTexSubImage3DARB(target, level, xoffset,
+ yoffset, zoffset, width,
+ height, depth, format,
+ imagesize, pixels);
+}
+
+
+void crUnpackExtendCompressedTexSubImage2DARB( void )
+{
+ GLenum target = READ_DATA( 4 + sizeof(int) + 0, GLenum );
+ GLint level = READ_DATA( 4 + sizeof(int) + 4, GLint );
+ GLint xoffset = READ_DATA( 4 + sizeof(int) + 8, GLint );
+ GLint yoffset = READ_DATA( 4 + sizeof(int) + 12, GLint );
+ GLsizei width = READ_DATA( 4 + sizeof(int) + 16, GLsizei );
+ GLsizei height = READ_DATA( 4 + sizeof(int) + 20, GLsizei );
+ GLenum format = READ_DATA( 4 + sizeof(int) + 24, GLenum );
+ GLsizei imagesize = READ_DATA( 4 + sizeof(int) + 28, GLsizei );
+ int noimagedata = READ_DATA( 4 + sizeof(int) + 32, int );
+ GLvoid *pixels;
+
+ if( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(4+sizeof(int)+36, GLint);
+ else
+ pixels = DATA_POINTER( 4 + sizeof(int) + 40, GLvoid );
+
+ cr_unpackDispatch.CompressedTexSubImage2DARB(target, level, xoffset,
+ yoffset, width, height,
+ format, imagesize, pixels);
+}
+
+
+void crUnpackExtendCompressedTexSubImage1DARB( void )
+{
+ GLenum target = READ_DATA( 4 + sizeof(int) + 0, GLenum );
+ GLint level = READ_DATA( 4 + sizeof(int) + 4, GLint );
+ GLint xoffset = READ_DATA( 4 + sizeof(int) + 8, GLint );
+ GLsizei width = READ_DATA( 4 + sizeof(int) + 12, GLsizei );
+ GLenum format = READ_DATA( 4 + sizeof(int) + 16, GLenum );
+ GLsizei imagesize = READ_DATA( 4 + sizeof(int) + 20, GLsizei );
+ int noimagedata = READ_DATA( 4 + sizeof(int) + 24, int );
+ GLvoid *pixels;
+
+ if( noimagedata )
+ pixels = (void*) (uintptr_t) READ_DATA(4+sizeof(int)+28, GLint);
+ else
+ pixels = DATA_POINTER( 4 + sizeof(int) + 32, GLvoid );
+
+ cr_unpackDispatch.CompressedTexSubImage1DARB(target, level, xoffset, width,
+ format, imagesize, pixels);
+}
+
+void crUnpackExtendGetTexImage(void)
+{
+ GLenum target = READ_DATA( 8, GLenum );
+ GLint level = READ_DATA( 12, GLint );
+ GLenum format = READ_DATA( 16, GLenum );
+ GLenum type = READ_DATA( 20, GLenum );
+ GLvoid *pixels;
+
+ SET_RETURN_PTR(24);
+ SET_WRITEBACK_PTR(32);
+ pixels = DATA_POINTER(24, GLvoid);
+
+ cr_unpackDispatch.GetTexImage(target, level, format, type, pixels);
+}
+
+void crUnpackExtendGetCompressedTexImageARB(void)
+{
+ GLenum target = READ_DATA( 8, GLenum );
+ GLint level = READ_DATA( 12, GLint );
+ GLvoid *img;
+
+ SET_RETURN_PTR( 16 );
+ SET_WRITEBACK_PTR( 24 );
+ img = DATA_POINTER(16, GLvoid);
+
+ cr_unpackDispatch.GetCompressedTexImageARB( target, level, img );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_visibleregion.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_visibleregion.c
new file mode 100644
index 00000000..ece7c710
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_visibleregion.c
@@ -0,0 +1,37 @@
+/* $Id: unpack_visibleregion.c $ */
+/** @file
+ * VBox Packing VisibleRegion information
+ */
+
+/*
+ * Copyright (C) 2008-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include "cr_protocol.h"
+#include "cr_mem.h"
+#include "cr_version.h"
+
+void crUnpackExtendWindowVisibleRegion( void )
+{
+ GLint window = READ_DATA( 8, GLint );
+ GLint cRects = READ_DATA( 12, GLint );
+ GLvoid *pRects = DATA_POINTER( 16, GLvoid );
+
+ if (cRects <= 0 || cRects >= INT32_MAX / sizeof(GLint) / 8 || !DATA_POINTER_CHECK(16 + 4 * cRects * sizeof(GLint)))
+ {
+ crError("crUnpackExtendWindowVisibleRegion: parameter 'cRects' is out of range");
+ return;
+ }
+
+ cr_unpackDispatch.WindowVisibleRegion( window, cRects, pRects );
+}
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_writeback.c b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_writeback.c
new file mode 100644
index 00000000..f55a4c37
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpack_writeback.c
@@ -0,0 +1,35 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#include "unpacker.h"
+#include "cr_error.h"
+#include <stdio.h>
+
+CRNetworkPointer *return_ptr = NULL, *writeback_ptr = NULL;
+
+void crUnpackSetReturnPointer( CRNetworkPointer *ret )
+{
+ return_ptr = ret;
+}
+
+void crUnpackSetWritebackPointer( CRNetworkPointer *wri )
+{
+ writeback_ptr = wri;
+}
+
+void crUnpackExtendWriteback(void)
+{
+ /* This copies the unpack buffer's CRNetworkPointer to writeback_ptr */
+ SET_WRITEBACK_PTR( 8 );
+ cr_unpackDispatch.Writeback( NULL );
+}
+
+#if 0
+void crUnpackWriteback(void)
+{
+ crError( "crUnpackWriteback should never be called" );
+}
+#endif
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpacker.h b/src/VBox/HostServices/SharedOpenGL/unpacker/unpacker.h
new file mode 100644
index 00000000..708a89d0
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpacker.h
@@ -0,0 +1,19 @@
+/* Copyright (c) 2001, Stanford University
+ * All rights reserved.
+ *
+ * See the file LICENSE.txt for information on redistributing this software.
+ */
+
+#ifndef CR_UNPACKER_H
+#define CR_UNPACKER_H
+
+#ifdef DLLDATA
+#undef DLLDATA
+#endif
+#define DLLDATA(type) DECLEXPORT(type)
+
+#include "cr_version.h"
+#include "cr_unpack.h"
+#include "unpack_extend.h"
+
+#endif /* CR_UNPACKER_H */
diff --git a/src/VBox/HostServices/SharedOpenGL/unpacker/unpacker_special b/src/VBox/HostServices/SharedOpenGL/unpacker/unpacker_special
new file mode 100644
index 00000000..ff1cb7ae
--- /dev/null
+++ b/src/VBox/HostServices/SharedOpenGL/unpacker/unpacker_special
@@ -0,0 +1,184 @@
+# Copyright (c) 2001, Stanford University
+# All rights reserved.
+#
+# See the file LICENSE.txt for information on redistributing this software.
+#
+# Unpack functions which can't be auto-generated
+#
+Bitmap
+CallLists
+ClipPlane
+ColorPointer
+DeleteTextures
+DrawElements
+DrawRangeElements
+DrawPixels
+EdgeFlagPointer
+Fogfv
+Fogiv
+IndexPointer
+InterleavedArrays
+Lightfv
+Lightiv
+LightModelfv
+LightModeliv
+LoadMatrixf
+LoadMatrixd
+Map1d
+Map1f
+Map2d
+Map2f
+Materialfv
+Materialiv
+MultMatrixd
+MultMatrixf
+NormalPointer
+PixelMapfv
+PixelMapuiv
+PixelMapusv
+PolygonStipple
+PrioritizeTextures
+ReadPixels
+TexCoordPointer
+TexEnvfv
+TexEnviv
+TexGendv
+TexGenfv
+TexGeniv
+TexImage1D
+TexImage2D
+TexImage3D
+TexImage3DEXT
+TexParameterf
+TexParameteri
+TexParameterfv
+TexParameteriv
+TexSubImage1D
+TexSubImage2D
+TexSubImage3D
+VertexPointer
+BoundsInfoCR
+SecondaryColorPointerEXT
+FogCoordPointerEXT
+MultiDrawArraysEXT
+MultiDrawElementsEXT
+VertexAttrib1dvARB
+VertexAttrib1fvARB
+VertexAttrib1svARB
+VertexAttrib2dvARB
+VertexAttrib2fvARB
+VertexAttrib2svARB
+VertexAttrib3dvARB
+VertexAttrib3fvARB
+VertexAttrib3svARB
+VertexAttrib4dvARB
+VertexAttrib4fvARB
+VertexAttrib4svARB
+VertexAttribPointerARB
+VertexAttrib4NbvARB
+VertexAttrib4NivARB
+VertexAttrib4NsvARB
+VertexAttrib4NubvARB
+VertexAttrib4NuivARB
+VertexAttrib4NusvARB
+VertexAttrib4bvARB
+VertexAttrib4ivARB
+VertexAttrib4ubvARB
+VertexAttrib4uivARB
+VertexAttrib4usvARB
+VertexAttribPointerNV
+Writeback
+CombinerParameterfvNV
+CombinerParameterivNV
+CombinerStageParameterfvNV
+ChromiumParametervCR
+CreateContext
+WindowCreate
+AreTexturesResident
+LoadTransposeMatrixfARB
+LoadTransposeMatrixdARB
+MultTransposeMatrixdARB
+MultTransposeMatrixfARB
+PointParameteriv
+PointParameterfvARB
+AreProgramsResidentNV
+DeleteProgramsNV
+ExecuteProgramNV
+GetProgramNamedParameterdvNV
+GetProgramNamedParameterfvNV
+LoadProgramNV
+ProgramLocalParameter4dvARB
+ProgramLocalParameter4fvARB
+ProgramNamedParameter4dNV
+ProgramNamedParameter4dvNV
+ProgramNamedParameter4fNV
+ProgramNamedParameter4fvNV
+ProgramParameter4dvNV
+ProgramParameter4fvNV
+ProgramParameters4dvNV
+ProgramParameters4fvNV
+RequestResidentProgramsNV
+DeleteProgramsARB
+GetProgramStringARB
+ProgramEnvParameter4dvARB
+ProgramEnvParameter4fvARB
+ProgramLocalParameter4dvARB
+ProgramLocalParameter4fvARB
+ProgramStringARB
+BufferDataARB
+BufferSubDataARB
+GetBufferSubDataARB
+DeleteBuffersARB
+ZPixCR
+CompressedTexImage1DARB
+CompressedTexImage2DARB
+CompressedTexImage3DARB
+CompressedTexSubImage1DARB
+CompressedTexSubImage2DARB
+CompressedTexSubImage3DARB
+DeleteFencesNV
+WindowVisibleRegion
+BindAttribLocation
+ShaderSource
+Uniform1fv
+Uniform1iv
+Uniform2fv
+Uniform2iv
+Uniform3fv
+Uniform3iv
+Uniform4fv
+Uniform4iv
+UniformMatrix2fv
+UniformMatrix3fv
+UniformMatrix4fv
+DrawBuffers
+GetActiveAttrib
+GetActiveUniform
+GetAttachedShaders
+GetShaderInfoLog
+GetProgramInfoLog
+GetShaderSource
+GetAttribLocation
+GetUniformLocation
+GetAttachedObjectsARB
+GetInfoLogARB
+DeleteQueriesARB
+DeleteFramebuffersEXT
+DeleteRenderbuffersEXT
+LockArraysEXT
+UnlockArraysEXT
+GetUniformsLocations
+GetAttribsLocations
+GetTexImage
+GetCompressedTexImageARB
+GetPolygonStipple
+GetPixelMapfv
+GetPixelMapuiv
+GetPixelMapusv
+UniformMatrix2x3fv
+UniformMatrix3x2fv
+UniformMatrix2x4fv
+UniformMatrix4x2fv
+UniformMatrix3x4fv
+UniformMatrix4x3fv
+VBoxTexPresent \ No newline at end of file