summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL/crserverlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/crserverlib.def14
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py468
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/Makefile.kup0
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_base.cpp390
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_composite.cpp341
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_vrdp.cpp381
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window.cpp574
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/display_window_rootvr.cpp347
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.cpp4063
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/server_presenter.h440
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/presenter/window.cpp480
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server.h718
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_boundsinfo.c329
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c111
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c492
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_clip.c588
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c404
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c481
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py137
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py51
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c237
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_gentextures.c142
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py145
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getmap.c247
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpixelmap.c142
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getpointer.c32
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c395
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getstring.c38
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getteximage.c156
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c262
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c284
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c4039
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c2016
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp840
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_occlude.c37
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_papi.c272
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_projmatrix.c402
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_readpixels.c91
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py83
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp755
-rwxr-xr-xsrc/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py152
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_special268
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c934
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c323
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_viewport.c288
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c484
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_winpos.c95
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_writeback.c28
49 files changed, 23996 insertions, 0 deletions
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 );
+}