diff options
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib')
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 ); +} |