diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/HostServices/SharedOpenGL | |
parent | Initial commit. (diff) | |
download | virtualbox-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')
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*)¤t); + 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:®ularBounds]; + 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 |