diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
|---|---|---|
| committer | <> | 2014-05-08 15:03:54 +0000 |
| commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
| tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/GuestHost | |
| parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
| download | VirtualBox-master.tar.gz | |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/GuestHost')
87 files changed, 14271 insertions, 2050 deletions
diff --git a/src/VBox/GuestHost/HGSMI/HGSMICommon.cpp b/src/VBox/GuestHost/HGSMI/HGSMICommon.cpp index db78000a..83cfeb8e 100644 --- a/src/VBox/GuestHost/HGSMI/HGSMICommon.cpp +++ b/src/VBox/GuestHost/HGSMI/HGSMICommon.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/GuestHost/OpenGL/Makefile.kmk b/src/VBox/GuestHost/OpenGL/Makefile.kmk index 2cbb0b84..2a1d1dac 100644 --- a/src/VBox/GuestHost/OpenGL/Makefile.kmk +++ b/src/VBox/GuestHost/OpenGL/Makefile.kmk @@ -4,7 +4,7 @@ # # -# Copyright (C) 2008-2012 Oracle Corporation +# Copyright (C) 2008-2013 Oracle Corporation # # This file is part of VirtualBox Open Source Edition (OSE), as # available from http://www.virtualbox.org. This file is free software; @@ -27,6 +27,12 @@ BLDDIRS += \ $(VBOX_PATH_CROGL_GENFILES)/state/ ifdef VBOX_WITH_ADDITIONS + ifn1of ($(KBUILD_TARGET), darwin os2) + VBOX_WITH_CROGL_ADDITIONS = 1 + endif +endif + +ifdef VBOX_WITH_CROGL_ADDITIONS DLLS += VBoxOGLcrutil VBoxOGLerrorspu LIBRARIES += VBoxOGLcrpacker VBoxOGLspuload VBoxOGLcrstate endif @@ -76,6 +82,11 @@ VBoxOGLcrutil_SOURCES = \ util/timer.c \ util/url.c \ util/warp.c \ + util/vreg.cpp \ + util/blitter.cpp \ + util/compositor.cpp \ + util/htable.cpp \ + util/bmpscale.cpp \ util/vboxhgcm.c \ $(VBOX_PATH_CROGL_GENFILES)/debug_opcodes.c VBoxOGLcrutil_SOURCES.win.x86 = \ @@ -83,10 +94,16 @@ VBoxOGLcrutil_SOURCES.win.x86 = \ util/util.rc VBoxOGLcrutil_LIBS.win = \ $(PATH_SDK_$(VBOX_WINDDK)_LIB)/ddraw.lib \ - $(PATH_SDK_$(VBOX_WINDDK)_LIB)/dxguid.lib + $(PATH_SDK_$(VBOX_WINDDK)_LIB)/dxguid.lib \ + $(PATH_SDK_$(VBOX_WINDDK)_LIB)/shlwapi.lib VBoxOGLcrutil_LIBS = \ $(VBOX_LIB_IPRT_GUEST_R3_SHARED) \ $(VBOX_LIB_VBGL_R3_SHARED) + +# Needed by GDEbuger +ifdef CR_NO_GL_SYSTEM_PATH +VBoxOGLcrutil_DEFS += CR_NO_GL_SYSTEM_PATH +endif ifdef VBOX_WITH_CRHGSMI VBoxOGLcrutil_DEFS.win += VBOX_WITH_CRHGSMI VBoxOGLcrutil_LIBS.win += $(VBOX_PATH_ADDITIONS_LIB)/VBoxCrHgsmi$(VBOX_SUFF_LIB) @@ -104,7 +121,7 @@ VBoxOGLcrutil_CLEAN = \ VBoxOGLcrutil_pixel.c_CFLAGS.win.x86 += -Od VBoxOGLhostcrutil_pixel.c_CFLAGS.win.x86 += -Od -if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_ADDITIONS) +if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_CROGL_ADDITIONS) # # VBoxOGLcrutil-x86 - x86 VBoxOGLcrutil version built for amd64 build # @@ -161,6 +178,12 @@ $(VBOX_PATH_CROGL_GENFILES)/debug_opcodes.c: $(PATH_SUB_CURRENT)/util/debug_opco $(call MSG_GENERATE,python,$@,$<) $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) +ifdef VBOX_WITH_CRDUMPER +$(VBOX_PATH_CROGL_GENFILES)/dump_gen.cpp: $(PATH_SUB_CURRENT)/state_tracker/dump_gen.py $(PATH_ROOT)/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_isenabled.txt state_extensions_isenabled.txt) $(VBOX_CROGL_API_FILES) | $$(dir $$@) + $(call MSG_GENERATE,python,$@,$<) + $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $< $(VBOX_PATH_CROGL_GLAPI) $(<D) +endif + # # VBoxOGLcrpacker # @@ -259,7 +282,7 @@ ifdef VBOX_WITH_WDDM VBoxOGLcrpacker_DEFS.win += VBOX_WITH_WDDM endif -if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_ADDITIONS) +if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_CROGL_ADDITIONS) # # VBoxOGLcrpacker-x86 - x86 VBoxOGLcrpacker version built for amd64 build # @@ -343,7 +366,7 @@ ifdef VBOX_WITH_WDDM VBoxOGLspuload_DEFS.win += VBOX_WITH_WDDM endif -if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_ADDITIONS) +if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_CROGL_ADDITIONS) # # VBoxOGLspuload-x86 - x86 VBoxOGLspuload version built for amd64 build # @@ -443,13 +466,16 @@ VBoxOGLcrstate_SOURCES = \ $(VBOX_PATH_CROGL_GENFILES)/state_lighting_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_line_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_multisample_gen.c \ - $(VBOX_PATH_CROGL_GENFILES)/state_point_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_polygon_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_regcombiner_gen.c \ - $(VBOX_PATH_CROGL_GENFILES)/state_stencil_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_viewport_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_get.c \ $(VBOX_PATH_CROGL_GENFILES)/state_isenabled.c +ifdef VBOX_WITH_CRDUMPER +VBoxOGLcrstate_SOURCES += state_tracker/dump.cpp \ + $(VBOX_PATH_CROGL_GENFILES)/dump_gen.cpp +endif + VBoxOGLcrstate_CLEAN = \ $(VBOX_PATH_CROGL_GENFILES)/state_buffer_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_current_gen.c \ @@ -458,17 +484,21 @@ VBoxOGLcrstate_CLEAN = \ $(VBOX_PATH_CROGL_GENFILES)/state_lighting_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_line_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_multisample_gen.c \ - $(VBOX_PATH_CROGL_GENFILES)/state_point_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_polygon_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_regcombiner_gen.c \ - $(VBOX_PATH_CROGL_GENFILES)/state_stencil_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_viewport_gen.c \ $(VBOX_PATH_CROGL_GENFILES)/state_get.c \ $(VBOX_PATH_CROGL_GENFILES)/state_isenabled.c \ $(VBOX_PATH_CROGL_GENFILES)/state/cr_statefuncs.h +ifdef VBOX_WITH_CRDUMPER +VBoxOGLcrstate_CLEAN += $(VBOX_PATH_CROGL_GENFILES)/dump_gen.cpp +endif + ifneq ($(KBUILD_TARGET),win) + ifeq ($(VBOX_WITH_COMPATIBLE_LINUX_GUEST_PACKAGE),) state_tracker/state_lists.c_CFLAGS += $(VBOX_GCC_Wno-pointer-sign) VBoxOGLcrstate_CFLAGS += + endif endif ifdef VBOX_WITH_CRHGSMI VBoxOGLcrstate_DEFS.win += VBOX_WITH_CRHGSMI @@ -476,8 +506,14 @@ endif ifdef VBOX_WITH_WDDM VBoxOGLcrstate_DEFS.win += VBOX_WITH_WDDM endif +ifdef VBOX_WITH_CRDUMPER +VBoxOGLcrstate_DEFS += VBOX_WITH_CRDUMPER +#VBoxOGLcrutil_LIBS += \ + $(PATH_STAGE_LIB)/additions/VBoxOGLcrstate$(VBOX_SUFF_LIB) \ + $(PATH_STAGE_LIB)/additions/VBoxOGLspuload$(VBOX_SUFF_LIB) +endif -if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_ADDITIONS) +if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_CROGL_ADDITIONS) # # VBoxOGLcrstate-x86 - x86 VBoxOGLcrstate version built for amd64 build # @@ -535,10 +571,6 @@ $(VBOX_PATH_CROGL_GENFILES)/state_multisample_gen.c: $(addprefix $(PATH_SUB_CURR $(call MSG_GENERATE,python,$@,$<) $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/gendiffcode.py multisample Multisample $(<D) -$(VBOX_PATH_CROGL_GENFILES)/state_point_gen.c: $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_point.txt gendiffcode.py) | $$(dir $$@) - $(call MSG_GENERATE,python,$@,$<) - $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/gendiffcode.py point Point $(<D) - $(VBOX_PATH_CROGL_GENFILES)/state_polygon_gen.c: $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_polygon.txt gendiffcode.py) | $$(dir $$@) $(call MSG_GENERATE,python,$@,$<) $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/gendiffcode.py polygon Polygon $(<D) @@ -547,15 +579,11 @@ $(VBOX_PATH_CROGL_GENFILES)/state_regcombiner_gen.c: $(addprefix $(PATH_SUB_CURR $(call MSG_GENERATE,python,$@,$<) $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/gendiffcode.py regcombiner RegCombiner $(<D) -$(VBOX_PATH_CROGL_GENFILES)/state_stencil_gen.c: $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_stencil.txt gendiffcode.py) | $$(dir $$@) - $(call MSG_GENERATE,python,$@,$<) - $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/gendiffcode.py stencil Stencil $(<D) - $(VBOX_PATH_CROGL_GENFILES)/state_viewport_gen.c: $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_viewport.txt gendiffcode.py) | $$(dir $$@) $(call MSG_GENERATE,python,$@,$<) $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/gendiffcode.py viewport Viewport $(<D) -$(VBOX_PATH_CROGL_GENFILES)/state_get.c: $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_get.py state_get.txt state_extensions_get.txt) $(VBOX_CROGL_API_FILES) | $$(dir $$@) +$(VBOX_PATH_CROGL_GENFILES)/state_get.c: $(addprefix $(PATH_SUB_CURRENT)/state_tracker/, state_get.py state_get.txt state_extensions_get.txt get_components.py) $(VBOX_CROGL_API_FILES) | $$(dir $$@) $(call MSG_GENERATE,python,$@,$<) $(QUIET)$(call VBOX_CROGL_PYTHON_ENV,$(VBOX_PATH_CROGL_PYTHON_INCLUDE),$@) $(VBOX_BLD_PYTHON) $(<D)/state_get.py $(VBOX_PATH_CROGL_GLAPI) $(<D) @@ -606,7 +634,7 @@ VBoxOGLerrorspu_DEFS.win += VBOX_WITH_WDDM endif -if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_ADDITIONS) +if defined(VBOX_WITH_WDDM) && defined(VBOX_WITH_CROGL_ADDITIONS) # # VBoxOGLerrorspu-x86 - x86 VBoxOGLerrorspu version built for amd64 build # diff --git a/src/VBox/GuestHost/OpenGL/glapi_parser/APIspec.txt b/src/VBox/GuestHost/OpenGL/glapi_parser/APIspec.txt index 560b2fed..3df1d92e 100644 --- a/src/VBox/GuestHost/OpenGL/glapi_parser/APIspec.txt +++ b/src/VBox/GuestHost/OpenGL/glapi_parser/APIspec.txt @@ -2579,7 +2579,7 @@ chromium pack name GetBooleanv return void param pname GLenum -paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV +paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV GL_READ_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_ACTIVE_STENCIL_FACE_EXT param params GLboolean * category 1.0 props get @@ -2599,7 +2599,7 @@ chromium extpack name GetDoublev return void param pname GLenum -paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV +paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV GL_READ_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_READ_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_ACTIVE_STENCIL_FACE_EXT param params GLdouble * category 1.0 props get @@ -2614,7 +2614,7 @@ chromium extpack name GetFloatv return void param pname GLenum -paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV +paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV GL_READ_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_ACTIVE_STENCIL_FACE_EXT param params GLfloat * category 1.0 props get @@ -2623,7 +2623,7 @@ chromium extpack name GetIntegerv return void param pname GLenum -paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV GL_FRAMEBUFFER_BINDING_EXT GL_RENDERBUFFER_BINDING_EXT GL_MAX_COLOR_ATTACHMENTS_EXT GL_MAX_RENDERBUFFER_SIZE_EXT +paramprop pname GL_ACCUM_ALPHA_BITS GL_ACCUM_BLUE_BITS GL_ACCUM_CLEAR_VALUE GL_ACCUM_GREEN_BITS GL_ACCUM_RED_BITS GL_ACTIVE_TEXTURE_ARB GL_ALIASED_LINE_WIDTH_RANGE GL_ALIASED_POINT_SIZE_RANGE GL_ALPHA_BIAS GL_ALPHA_BITS GL_ALPHA_SCALE GL_ALPHA_TEST GL_ALPHA_TEST_FUNC GL_ALPHA_TEST_REF GL_ATTRIB_STACK_DEPTH GL_AUTO_NORMAL GL_AUX_BUFFERS GL_BLEND GL_BLEND_COLOR GL_BLEND_DST GL_BLEND_EQUATION GL_BLEND_SRC GL_BLUE_BIAS GL_BLUE_BITS GL_BLUE_SCALE GL_CLIENT_ACTIVE_TEXTURE_ARB GL_CLIENT_ATTRIB_STACK_DEPTH GL_COLOR_ARRAY GL_COLOR_ARRAY_SIZE GL_COLOR_ARRAY_STRIDE GL_COLOR_ARRAY_TYPE GL_COLOR_CLEAR_VALUE GL_COLOR_LOGIC_OP GL_COLOR_MATERIAL GL_COLOR_MATERIAL_FACE GL_COLOR_MATERIAL_PARAMETER GL_COLOR_MATRIX_STACK_DEPTH GL_COLOR_WRITEMASK GL_CULL_FACE GL_CULL_FACE_MODE GL_CURRENT_COLOR GL_CURRENT_INDEX GL_CURRENT_NORMAL GL_CURRENT_RASTER_COLOR GL_CURRENT_RASTER_DISTANCE GL_CURRENT_RASTER_INDEX GL_CURRENT_RASTER_POSITION GL_CURRENT_RASTER_POSITION_VALID GL_CURRENT_RASTER_TEXTURE_COORDS GL_CURRENT_TEXTURE_COORDS GL_DEPTH_BIAS GL_DEPTH_BITS GL_DEPTH_CLEAR_VALUE GL_DEPTH_FUNC GL_DEPTH_RANGE GL_DEPTH_SCALE GL_DEPTH_TEST GL_DEPTH_WRITEMASK GL_DITHER GL_DOUBLEBUFFER GL_DRAW_BUFFER GL_EDGE_FLAG GL_EDGE_FLAG_ARRAY GL_EDGE_FLAG_ARRAY_STRIDE GL_FEEDBACK_BUFFER_SIZE GL_FEEDBACK_BUFFER_TYPE GL_FOG GL_FOG_COLOR GL_FOG_DENSITY GL_FOG_END GL_FOG_HINT GL_FOG_INDEX GL_FOG_MODE GL_FOG_START GL_FRONT_FACE GL_GREEN_BIAS GL_GREEN_BITS GL_GREEN_SCALE GL_INDEX_ARRAY GL_INDEX_ARRAY_STRIDE GL_INDEX_ARRAY_TYPE GL_INDEX_BITS GL_INDEX_CLEAR_VALUE GL_INDEX_LOGIC_OP GL_INDEX_MODE GL_INDEX_OFFSET GL_INDEX_SHIFT GL_INDEX_WRITEMASK GL_LIGHTING GL_LIGHT_MODEL_AMBIENT GL_LIGHT_MODEL_COLOR_CONTROL GL_LIGHT_MODEL_LOCAL_VIEWER GL_LIGHT_MODEL_TWO_SIDE GL_LINE_SMOOTH GL_LINE_SMOOTH_HINT GL_LINE_STIPPLE GL_LINE_STIPPLE_PATTERN GL_LINE_STIPPLE_REPEAT GL_LINE_WIDTH GL_LINE_WIDTH_GRANULARITY GL_LINE_WIDTH_RANGE GL_LIST_BASE GL_LIST_INDEX GL_LIST_MODE GL_LOGIC_OP_MODE GL_MAP1_COLOR_4 GL_MAP1_GRID_DOMAIN GL_MAP1_GRID_SEGMENTS GL_MAP1_INDEX GL_MAP1_NORMAL GL_MAP1_TEXTURE_COORD_1 GL_MAP1_TEXTURE_COORD_2 GL_MAP1_TEXTURE_COORD_3 GL_MAP1_TEXTURE_COORD_4 GL_MAP1_VERTEX_3 GL_MAP1_VERTEX_4 GL_MAP2_COLOR_4 GL_MAP2_GRID_DOMAIN GL_MAP2_GRID_SEGMENTS GL_MAP2_INDEX GL_MAP2_NORMAL GL_MAP2_TEXTURE_COORD_1 GL_MAP2_TEXTURE_COORD_2 GL_MAP2_TEXTURE_COORD_3 GL_MAP2_TEXTURE_COORD_4 GL_MAP2_VERTEX_3 GL_MAP2_VERTEX_4 GL_MAP_COLOR GL_MAP_STENCIL GL_MATRIX_MODE GL_MAX_3D_TEXTURE_SIZE GL_MAX_ATTRIB_STACK_DEPTH GL_MAX_CLIENT_ATTRIB_STACK_DEPTH GL_MAX_CLIP_PLANES GL_MAX_COLOR_MATRIX_STACK_DEPTH GL_MAX_ELEMENTS_INDICES GL_MAX_ELEMENTS_VERTICES GL_MAX_EVAL_ORDER GL_MAX_LIGHTS GL_MAX_LIST_NESTING GL_MAX_MODELVIEW_STACK_DEPTH GL_MAX_NAME_STACK_DEPTH GL_MAX_PIXEL_MAP_TABLE GL_MAX_PROJECTION_STACK_DEPTH GL_MAX_TEXTURE_SIZE GL_MAX_TEXTURE_STACK_DEPTH GL_MAX_TEXTURE_UNITS_ARB GL_MAX_VIEWPORT_DIMS GL_MODELVIEW_MATRIX GL_MODELVIEW_STACK_DEPTH GL_NAME_STACK_DEPTH GL_NORMAL_ARRAY GL_NORMAL_ARRAY_STRIDE GL_NORMAL_ARRAY_TYPE GL_NORMALIZE GL_PACK_ALIGNMENT GL_PACK_IMAGE_HEIGHT GL_PACK_LSB_FIRST GL_PACK_ROW_LENGTH GL_PACK_SKIP_IMAGES GL_PACK_SKIP_PIXELS GL_PACK_SKIP_ROWS GL_PACK_SWAP_BYTES GL_PERSPECTIVE_CORRECTION_HINT GL_PIXEL_MAP_A_TO_A_SIZE GL_PIXEL_MAP_B_TO_B_SIZE GL_PIXEL_MAP_G_TO_G_SIZE GL_PIXEL_MAP_I_TO_A_SIZE GL_PIXEL_MAP_I_TO_B_SIZE GL_PIXEL_MAP_I_TO_G_SIZE GL_PIXEL_MAP_I_TO_I_SIZE GL_PIXEL_MAP_I_TO_R_SIZE GL_PIXEL_MAP_R_TO_R_SIZE GL_PIXEL_MAP_S_TO_S_SIZE GL_POINT_SIZE GL_POINT_SIZE_GRANULARITY GL_POINT_SIZE_RANGE GL_POINT_SMOOTH GL_POINT_SMOOTH_HINT GL_POLYGON_MODE GL_POLYGON_OFFSET_FACTOR GL_POLYGON_OFFSET_FILL GL_POLYGON_OFFSET_LINE GL_POLYGON_OFFSET_POINT GL_POLYGON_OFFSET_UNITS GL_POLYGON_SMOOTH GL_POLYGON_SMOOTH_HINT GL_POLYGON_STIPPLE GL_PROJECTION_MATRIX GL_PROJECTION_STACK_DEPTH GL_READ_BUFFER GL_RED_BIAS GL_RED_BITS GL_RED_SCALE GL_RENDER_MODE GL_RESCALE_NORMAL GL_RGBA_MODE GL_SCISSOR_BOX GL_SCISSOR_TEST GL_SELECTION_BUFFER_SIZE GL_SHADE_MODEL GL_SMOOTH_LINE_WIDTH_GRANULARITY GL_SMOOTH_LINE_WIDTH_RANGE GL_SMOOTH_POINT_SIZE_GRANULARITY GL_SMOOTH_POINT_SIZE_RANGE GL_STENCIL_BITS GL_STENCIL_CLEAR_VALUE GL_STENCIL_FAIL GL_STENCIL_FUNC GL_STENCIL_PASS_DEPTH_FAIL GL_STENCIL_PASS_DEPTH_PASS GL_STENCIL_REF GL_STENCIL_TEST GL_STENCIL_VALUE_MASK GL_STENCIL_WRITEMASK GL_STEREO GL_SUBPIXEL_BITS GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D GL_TEXTURE_BINDING_1D GL_TEXTURE_BINDING_2D GL_TEXTURE_BINDING_3D GL_TEXTURE_COORD_ARRAY GL_TEXTURE_COORD_ARRAY_SIZE GL_TEXTURE_COORD_ARRAY_STRIDE GL_TEXTURE_COORD_ARRAY_TYPE GL_TEXTURE_GEN_Q GL_TEXTURE_GEN_R GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_TEXTURE_MATRIX GL_TEXTURE_STACK_DEPTH GL_UNPACK_ALIGNMENT GL_UNPACK_IMAGE_HEIGHT GL_UNPACK_LSB_FIRST GL_UNPACK_ROW_LENGTH GL_UNPACK_SKIP_IMAGES GL_UNPACK_SKIP_PIXELS GL_UNPACK_SKIP_ROWS GL_UNPACK_SWAP_BYTES GL_VERTEX_ARRAY GL_VERTEX_ARRAY_SIZE GL_VERTEX_ARRAY_STRIDE GL_VERTEX_ARRAY_TYPE GL_VIEWPORT GL_ZOOM_X GL_ZOOM_Y GL_CLIP_PLANE0 GL_CLIP_PLANE1 GL_CLIP_PLANE2 GL_CLIP_PLANE3 GL_CLIP_PLANE4 GL_CLIP_PLANE5 GL_LIGHT0 GL_LIGHT1 GL_LIGHT2 GL_LIGHT3 GL_LIGHT4 GL_LIGHT5 GL_LIGHT6 GL_LIGHT7 GL_MULTISAMPLE_ARB GL_SAMPLE_ALPHA_TO_COVERAGE_ARB GL_SAMPLE_ALPHA_TO_ONE_ARB GL_SAMPLE_COVERAGE_ARB GL_SAMPLE_BUFFERS_ARB GL_SAMPLES_ARB GL_SAMPLE_COVERAGE_VALUE_ARB GL_SAMPLE_COVERAGE_INVERT_ARB GL_POINT_SPRITE_ARB GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB GL_CLIP_VOLUME_CLIPPING_HINT_EXT GL_RASTER_POSITION_UNCLIPPED_IBM GL_GENERATE_MIPMAP_HINT_SGIS GL_FOG_DISTANCE_MODE_NV GL_TRANSPOSE_MODELVIEW_MATRIX_ARB GL_TRANSPOSE_PROJECTION_MATRIX_ARB GL_TRANSPOSE_TEXTURE_MATRIX_ARB GL_TRANSPOSE_COLOR_MATRIX_ARB GL_MAX_TEXTURE_LOD_BIAS_EXT GL_PER_STAGE_CONSTANTS_NV GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT GL_CURRENT_FOG_COORDINATE_EXT GL_FOG_COORDINATE_ARRAY_TYPE_EXT GL_FOG_COORDINATE_ARRAY_STRIDE_EXT GL_COLOR_SUM_EXT GL_CURRENT_SECONDARY_COLOR_EXT GL_SECONDARY_COLOR_ARRAY_SIZE_EXT GL_SECONDARY_COLOR_ARRAY_TYPE_EXT GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT GL_ARRAY_BUFFER_BINDING_ARB GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB GL_VERTEX_ARRAY_BUFFER_BINDING_ARB GL_NORMAL_ARRAY_BUFFER_BINDING_ARB GL_COLOR_ARRAY_BUFFER_BINDING_ARB GL_INDEX_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB GL_TEXTURE_RECTANGLE_NV GL_TEXTURE_BINDING_RECTANGLE_NV GL_MAX_RECTANGLE_TEXTURE_SIZE_NV GL_FRAMEBUFFER_BINDING_EXT GL_RENDERBUFFER_BINDING_EXT GL_MAX_COLOR_ATTACHMENTS_EXT GL_MAX_RENDERBUFFER_SIZE_EXT GL_READ_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_ACTIVE_STENCIL_FACE_EXT param params GLint * category 1.0 props get @@ -8366,11 +8366,24 @@ name WindowVisibleRegion return void param window GLint param cRects GLint -param pRects GLint * +param pRects const GLint * category Chromium props nolist chromium extpack +name VBoxTexPresent +return void +param texture GLuint +param cfg GLuint +param xPos GLint +param yPos GLint +param cRects GLint +param pRects const GLint * +category Chromium +props nolist +chromium extpack +chrelopcode 0 + name WindowShow return void param window GLint @@ -8536,6 +8549,15 @@ param shareCtx GLint category VBox chromium nopack +name VBoxConChromiumParameteriCR +return void +param con GLint +param target GLenum +paramprop target GL_CURSOR_POSITION_CR GL_DEFAULT_BBOX_CR GL_SCREEN_BBOX_CR GL_OBJECT_BBOX_CR GL_PRINT_STRING_CR GL_MURAL_SIZE_CR GL_NUM_SERVERS_CR GL_NUM_TILES_CR GL_TILE_BOUNDS_CR GL_VERTEX_COUNTS_CR GL_RESET_VERTEX_COUNTERS_CR GL_SET_MAX_VIEWPORT_CR GL_HEAD_SPU_NAME_CR GL_PERF_GET_FRAME_DATA_CR GL_PERF_GET_TIMER_DATA_CR GL_PERF_DUMP_COUNTERS_CR GL_PERF_SET_TOKEN_CR GL_PERF_SET_DUMP_ON_SWAP_CR GL_PERF_SET_DUMP_ON_FINISH_CR GL_PERF_SET_DUMP_ON_FLUSH_CR GL_PERF_START_TIMER_CR GL_PERF_STOP_TIMER_CR GL_WINDOW_SIZE_CR GL_TILE_INFO_CR GL_GATHER_DRAWPIXELS_CR GL_GATHER_PACK_CR GL_GATHER_CONNECT_CR GL_GATHER_POST_SWAPBUFFERS_CR GL_SAVEFRAME_ENABLED_CR GL_SAVEFRAME_FRAMENUM_CR GL_SAVEFRAME_STRIDE_CR GL_SAVEFRAME_SINGLE_CR GL_SAVEFRAME_FILESPEC_CR GL_READBACK_BARRIER_SIZE_CR +param value GLint +category VBox +chromium nopack + name VBoxWindowCreate return GLint param con GLint @@ -8569,6 +8591,15 @@ param con GLint category VBox chromium nopack +name VBoxPresentComposition +return void +param win GLint +param pCompositor const struct VBOXVR_SCR_COMPOSITOR * +param pChangedEntry const struct VBOXVR_SCR_COMPOSITOR_ENTRY * +category VBox +chromium nopack + + # OpenGL 1.5 name BindBuffer @@ -9723,7 +9754,7 @@ chromium nopack # GL_ARB_shader_objects name GetHandleARB -return GLhandleARB +return VBoxGLhandleARB param pname GLenum paramprop pname GL_PROGRAM_OBJECT_ARB category GL_ARB_shader_objects @@ -9732,7 +9763,7 @@ chromium extpack serverdependent name DeleteObjectARB return void -param obj GLhandleARB +param obj VBoxGLhandleARB category GL_ARB_shader_objects props nolist chromium extpack @@ -9740,14 +9771,14 @@ chromium extpack name DetachObjectARB alias DetachShader return void -param containerObj GLhandleARB -param attachedObj GLhandleARB +param containerObj VBoxGLhandleARB +param attachedObj VBoxGLhandleARB category GL_ARB_shader_objects chromium extpack name CreateShaderObjectARB alias CreateShader -return GLhandleARB +return VBoxGLhandleARB param shaderType GLenum paramprop shaderType GL_FRAGMENT_SHADER_ARB GL_VERTEX_SHADER_ARB category GL_ARB_shader_objects @@ -9757,7 +9788,7 @@ chromium nopack name ShaderSourceARB alias ShaderSource return void -param shaderObj GLhandleARB +param shaderObj VBoxGLhandleARB param count GLsizei param string const GLcharARB ** param length const GLint * @@ -9767,13 +9798,13 @@ chromium nopack name CompileShaderARB alias CompileShader return void -param shaderObj GLhandleARB +param shaderObj VBoxGLhandleARB category GL_ARB_shader_objects chromium nopack name CreateProgramObjectARB alias CreateProgram -return GLhandleARB +return VBoxGLhandleARB category GL_ARB_shader_objects props get chromium nopack @@ -9781,29 +9812,29 @@ chromium nopack name AttachObjectARB alias AttachShader return void -param containerObj GLhandleARB -param obj GLhandleARB +param containerObj VBoxGLhandleARB +param obj VBoxGLhandleARB category GL_ARB_shader_objects chromium extpack name LinkProgramARB alias LinkProgram return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB category GL_ARB_shader_objects chromium nopack name UseProgramObjectARB alias UseProgram return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB category GL_ARB_shader_objects chromium nopack name ValidateProgramARB alias ValidateProgram return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB category GL_ARB_shader_objects chromium nopack @@ -9987,7 +10018,7 @@ chromium nopack name GetObjectParameterfvARB return void -param obj GLhandleARB +param obj VBoxGLhandleARB param pname GLenum paramprop pname GL_OBJECT_TYPE_ARB GL_OBJECT_SUBTYPE_ARB GL_OBJECT_DELETE_STATUS_ARB GL_OBJECT_COMPILE_STATUS_ARB GL_OBJECT_LINK_STATUS_ARB GL_OBJECT_VALIDATE_STATUS_ARB GL_OBJECT_INFO_LOG_LENGTH_ARB GL_OBJECT_ATTACHED_OBJECTS_ARB GL_OBJECT_ACTIVE_UNIFORMS_ARB GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB GL_OBJECT_SHADER_SOURCE_LENGTH_ARB param params GLfloat * @@ -9997,7 +10028,7 @@ chromium extpack name GetObjectParameterivARB return void -param obj GLhandleARB +param obj VBoxGLhandleARB param pname GLenum paramprop pname GL_OBJECT_TYPE_ARB GL_OBJECT_SUBTYPE_ARB GL_OBJECT_DELETE_STATUS_ARB GL_OBJECT_COMPILE_STATUS_ARB GL_OBJECT_LINK_STATUS_ARB GL_OBJECT_VALIDATE_STATUS_ARB GL_OBJECT_INFO_LOG_LENGTH_ARB GL_OBJECT_ATTACHED_OBJECTS_ARB GL_OBJECT_ACTIVE_UNIFORMS_ARB GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB GL_OBJECT_SHADER_SOURCE_LENGTH_ARB param params GLint * @@ -10007,7 +10038,7 @@ chromium extpack name GetInfoLogARB return void -param obj GLhandleARB +param obj VBoxGLhandleARB param maxLength GLsizei param length GLsizei * param infoLog GLcharARB * @@ -10017,10 +10048,10 @@ chromium extpack name GetAttachedObjectsARB return void -param containerObj GLhandleARB +param containerObj VBoxGLhandleARB param maxCount GLsizei param count GLsizei * -param obj GLhandleARB * +param obj VBoxGLhandleARB * category GL_ARB_shader_objects props get chromium extpack @@ -10028,7 +10059,7 @@ chromium extpack name GetUniformLocationARB alias GetUniformLocation return GLint -param programObj GLhandleARB +param programObj VBoxGLhandleARB param name const GLcharARB * category GL_ARB_shader_objects props get @@ -10037,7 +10068,7 @@ chromium nopack name GetActiveUniformARB alias GetActiveUniform return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB param index GLuint param maxLength GLsizei param length GLsizei * @@ -10051,7 +10082,7 @@ chromium nopack name GetShaderSourceARB alias GetShaderSource return void -param obj GLhandleARB +param obj VBoxGLhandleARB param maxLength GLsizei param length GLsizei * param source GLcharARB * @@ -10062,7 +10093,7 @@ chromium nopack name GetUniformfvARB alias GetUniformfv return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB param location GLint param params GLfloat * category GL_ARB_shader_objects @@ -10072,7 +10103,7 @@ chromium nopack name GetUniformivARB alias GetUniformiv return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB param location GLint param params GLint * category GL_ARB_shader_objects @@ -10084,7 +10115,7 @@ chromium nopack name GetActiveAttribARB alias GetActiveAttrib return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB param index GLuint param maxLength GLsizei param length GLsizei * @@ -10098,7 +10129,7 @@ chromium nopack name GetAttribLocationARB alias GetAttribLocation return GLint -param programObj GLhandleARB +param programObj VBoxGLhandleARB param name const GLcharARB * category GL_ARB_vertex_shader props get @@ -10107,7 +10138,7 @@ chromium nopack name BindAttribLocationARB alias BindAttribLocation return void -param programObj GLhandleARB +param programObj VBoxGLhandleARB param index GLuint param name const GLcharARB * category GL_ARB_vertex_shader @@ -10383,6 +10414,14 @@ paramprop modeAlpha GL_FUNC_ADD GL_FUNC_SUBTRACT GL_FUNC_REVERSE_SUBTRACT category GL_EXT_blend_equation_separate chromium nopack +# GL_GREMEDY_string_marker +name StringMarkerGREMEDY +return void +param len GLsizei +param string const GLvoid* +category GL_GREMEDY_string_marker +chromium nopack + # end of file sentinel name dummy diff --git a/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py b/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py index e7b7e30c..bce38f18 100755 --- a/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py +++ b/src/VBox/GuestHost/OpenGL/glapi_parser/apiutil.py @@ -46,6 +46,7 @@ class APIFunction: self.paramset = [] self.props = [] self.chromium = [] + self.chrelopcode = -1 @@ -161,6 +162,9 @@ def ProcessSpecFile(filename, userFunc): record.params[i] = (name, type, vecSize) break + elif tokens[0] == 'chrelopcode': + record.chrelopcode = int(tokens[1]) + else: print 'Invalid token %s after function %s' % (tokens[0], record.name) #endif @@ -223,6 +227,17 @@ def GetAllFunctions(specFile = ""): funcs.sort() return funcs +def GetAllFunctionsAndOmittedAliases(specFile = ""): + """Return sorted list of all functions known to Chromium.""" + d = GetFunctionDict(specFile) + funcs = [] + for func in d.keys(): + rec = d[func] + if (not "omit" in rec.chromium or + rec.alias != ''): + funcs.append(func) + funcs.sort() + return funcs def GetDispatchedFunctions(specFile = ""): """Return sorted list of all functions handled by SPU dispatch table.""" @@ -300,6 +315,12 @@ def ChromiumProps(funcName): """Return list of Chromium-specific properties of the named GL function.""" d = GetFunctionDict() return d[funcName].chromium + +def ChromiumRelOpCode(funcName): + """Return list of Chromium-specific properties of the named GL function.""" + d = GetFunctionDict() + return d[funcName].chrelopcode + def ParamProps(funcName): """Return list of Parameter-specific properties of the named GL function.""" @@ -356,10 +377,10 @@ def GetCategoryWrapper(func_name): cat == "VBox"): return '' elif (cat == '1.3' or - cat == '1.4' or - cat == '1.5' or - cat == '2.0' or - cat == '2.1'): + cat == '1.4' or + cat == '1.5' or + cat == '2.0' or + cat == '2.1'): # i.e. OpenGL 1.3 or 1.4 or 1.5 return "OPENGL_VERSION_" + string.replace(cat, ".", "_") else: @@ -568,16 +589,16 @@ def MakeDeclarationString(params): #enddef def MakeDeclarationStringWithContext(ctx_macro_prefix, params): - """Same as MakeDeclarationString, but adds a context macro - """ - - n = len(params) - if n == 0: - return ctx_macro_prefix + '_ARGSINGLEDECL' - else: - result = MakeDeclarationString(params) - return ctx_macro_prefix + '_ARGDECL ' + result - #endif + """Same as MakeDeclarationString, but adds a context macro + """ + + n = len(params) + if n == 0: + return ctx_macro_prefix + '_ARGSINGLEDECL' + else: + result = MakeDeclarationString(params) + return ctx_macro_prefix + '_ARGDECL ' + result + #endif #enddef @@ -625,9 +646,9 @@ __lengths = { 'int': 4, 'GLintptrARB': 4, # XXX or 8 bytes? 'GLsizeiptrARB': 4, # XXX or 8 bytes? - 'GLhandleARB': 4, + 'VBoxGLhandleARB': 4, 'GLcharARB': 1, - 'uintptr_t': 4 + 'uintptr_t': 4 } def sizeof(type): diff --git a/src/VBox/GuestHost/OpenGL/include/GL/glext.h b/src/VBox/GuestHost/OpenGL/include/GL/glext.h index 90cd2c01..7f754544 100644 --- a/src/VBox/GuestHost/OpenGL/include/GL/glext.h +++ b/src/VBox/GuestHost/OpenGL/include/GL/glext.h @@ -3722,29 +3722,17 @@ typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; #endif -/* VBox: HACK ALERT! When building the host side against Mac OS X 10.7 headers, - /Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/OpenGL.framework/Headers/gltypes.h - is included and it typedefs GLhandleARB differently. In 10.6 and earlier, - gl.h was included instead of gltypes.h (new file) avoiding the conflicting - typedef in Headers/glext.h. - - Since sizeof the gltypes.h typedef is 64-bit on 64-bit platforms, we're in - trouble if the type is used for anything important. Fortunately, the - conflict only occurs in three files: renderspu_config.c, renderspu_cocoa.c - and renderspu_cocoa_helper.m. */ -#ifdef RT_OS_DARWIN -# ifndef MAC_OS_X_VERSION_MIN_REQUIRED -# error "MAC_OS_X_VERSION_MIN_REQUIRED is not defined" -# endif -# if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 && defined(__gltypes_h_) -# define GLhandleARB VBoxGLhandleARB -# endif -#endif - #ifndef GL_ARB_shader_objects /* GL types for handling shader object handles and program/shader text */ typedef char GLcharARB; /* native character */ -typedef unsigned int GLhandleARB; /* shader object handle */ +typedef unsigned int VBoxGLhandleARB; /* shader object handle */ +# ifdef RT_OS_DARWIN +typedef void* GLhandleARB; /* shader object handle */ +# else +typedef unsigned int GLhandleARB; /* native shader object handle */ +# endif +#else +# error "GL_ARB_shader_objects should NOT be defined here!!" #endif /* GL types for "half" precision (s10e5) float data in host memory */ @@ -4770,17 +4758,17 @@ typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVARBPROC) (GLuint id, GLenum pname, #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects 1 #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB); -GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum); -GLAPI void APIENTRY glDetachObjectARB (GLhandleARB, GLhandleARB); -GLAPI GLhandleARB APIENTRY glCreateShaderObjectARB (GLenum); -GLAPI void APIENTRY glShaderSourceARB (GLhandleARB, GLsizei, const GLcharARB* *, const GLint *); -GLAPI void APIENTRY glCompileShaderARB (GLhandleARB); -GLAPI GLhandleARB APIENTRY glCreateProgramObjectARB (void); -GLAPI void APIENTRY glAttachObjectARB (GLhandleARB, GLhandleARB); -GLAPI void APIENTRY glLinkProgramARB (GLhandleARB); -GLAPI void APIENTRY glUseProgramObjectARB (GLhandleARB); -GLAPI void APIENTRY glValidateProgramARB (GLhandleARB); +GLAPI void APIENTRY glDeleteObjectARB (VBoxGLhandleARB); +GLAPI VBoxGLhandleARB APIENTRY glGetHandleARB (GLenum); +GLAPI void APIENTRY glDetachObjectARB (VBoxGLhandleARB, VBoxGLhandleARB); +GLAPI VBoxGLhandleARB APIENTRY glCreateShaderObjectARB (GLenum); +GLAPI void APIENTRY glShaderSourceARB (VBoxGLhandleARB, GLsizei, const GLcharARB* *, const GLint *); +GLAPI void APIENTRY glCompileShaderARB (VBoxGLhandleARB); +GLAPI VBoxGLhandleARB APIENTRY glCreateProgramObjectARB (void); +GLAPI void APIENTRY glAttachObjectARB (VBoxGLhandleARB, VBoxGLhandleARB); +GLAPI void APIENTRY glLinkProgramARB (VBoxGLhandleARB); +GLAPI void APIENTRY glUseProgramObjectARB (VBoxGLhandleARB); +GLAPI void APIENTRY glValidateProgramARB (VBoxGLhandleARB); GLAPI void APIENTRY glUniform1fARB (GLint, GLfloat); GLAPI void APIENTRY glUniform2fARB (GLint, GLfloat, GLfloat); GLAPI void APIENTRY glUniform3fARB (GLint, GLfloat, GLfloat, GLfloat); @@ -4800,27 +4788,27 @@ GLAPI void APIENTRY glUniform4ivARB (GLint, GLsizei, const GLint *); GLAPI void APIENTRY glUniformMatrix2fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix3fvARB (GLint, GLsizei, GLboolean, const GLfloat *); GLAPI void APIENTRY glUniformMatrix4fvARB (GLint, GLsizei, GLboolean, const GLfloat *); -GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB, GLenum, GLfloat *); -GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB, GLenum, GLint *); -GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); -GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB, GLsizei, GLsizei *, GLhandleARB *); -GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB, const GLcharARB *); -GLAPI void APIENTRY glGetActiveUniformARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); -GLAPI void APIENTRY glGetUniformfvARB (GLhandleARB, GLint, GLfloat *); -GLAPI void APIENTRY glGetUniformivARB (GLhandleARB, GLint, GLint *); -GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB, GLsizei, GLsizei *, GLcharARB *); -#endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (GLhandleARB obj); -typedef GLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); -typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB attachedObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); -typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (GLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); -typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (GLhandleARB shaderObj); -typedef GLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); -typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (GLhandleARB containerObj, GLhandleARB obj); -typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (GLhandleARB programObj); -typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (GLhandleARB programObj); +GLAPI void APIENTRY glGetObjectParameterfvARB (VBoxGLhandleARB, GLenum, GLfloat *); +GLAPI void APIENTRY glGetObjectParameterivARB (VBoxGLhandleARB, GLenum, GLint *); +GLAPI void APIENTRY glGetInfoLogARB (VBoxGLhandleARB, GLsizei, GLsizei *, GLcharARB *); +GLAPI void APIENTRY glGetAttachedObjectsARB (VBoxGLhandleARB, GLsizei, GLsizei *, VBoxGLhandleARB *); +GLAPI GLint APIENTRY glGetUniformLocationARB (VBoxGLhandleARB, const GLcharARB *); +GLAPI void APIENTRY glGetActiveUniformARB (VBoxGLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); +GLAPI void APIENTRY glGetUniformfvARB (VBoxGLhandleARB, GLint, GLfloat *); +GLAPI void APIENTRY glGetUniformivARB (VBoxGLhandleARB, GLint, GLint *); +GLAPI void APIENTRY glGetShaderSourceARB (VBoxGLhandleARB, GLsizei, GLsizei *, GLcharARB *); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLDELETEOBJECTARBPROC) (VBoxGLhandleARB obj); +typedef VBoxGLhandleARB (APIENTRYP PFNGLGETHANDLEARBPROC) (GLenum pname); +typedef void (APIENTRYP PFNGLDETACHOBJECTARBPROC) (VBoxGLhandleARB containerObj, VBoxGLhandleARB attachedObj); +typedef VBoxGLhandleARB (APIENTRYP PFNGLCREATESHADEROBJECTARBPROC) (GLenum shaderType); +typedef void (APIENTRYP PFNGLSHADERSOURCEARBPROC) (VBoxGLhandleARB shaderObj, GLsizei count, const GLcharARB* *string, const GLint *length); +typedef void (APIENTRYP PFNGLCOMPILESHADERARBPROC) (VBoxGLhandleARB shaderObj); +typedef VBoxGLhandleARB (APIENTRYP PFNGLCREATEPROGRAMOBJECTARBPROC) (void); +typedef void (APIENTRYP PFNGLATTACHOBJECTARBPROC) (VBoxGLhandleARB containerObj, VBoxGLhandleARB obj); +typedef void (APIENTRYP PFNGLLINKPROGRAMARBPROC) (VBoxGLhandleARB programObj); +typedef void (APIENTRYP PFNGLUSEPROGRAMOBJECTARBPROC) (VBoxGLhandleARB programObj); +typedef void (APIENTRYP PFNGLVALIDATEPROGRAMARBPROC) (VBoxGLhandleARB programObj); typedef void (APIENTRYP PFNGLUNIFORM1FARBPROC) (GLint location, GLfloat v0); typedef void (APIENTRYP PFNGLUNIFORM2FARBPROC) (GLint location, GLfloat v0, GLfloat v1); typedef void (APIENTRYP PFNGLUNIFORM3FARBPROC) (GLint location, GLfloat v0, GLfloat v1, GLfloat v2); @@ -4840,27 +4828,27 @@ typedef void (APIENTRYP PFNGLUNIFORM4IVARBPROC) (GLint location, GLsizei count, typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVARBPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (GLhandleARB obj, GLenum pname, GLfloat *params); -typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (GLhandleARB obj, GLenum pname, GLint *params); -typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); -typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); -typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint location, GLfloat *params); -typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); -typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERFVARBPROC) (VBoxGLhandleARB obj, GLenum pname, GLfloat *params); +typedef void (APIENTRYP PFNGLGETOBJECTPARAMETERIVARBPROC) (VBoxGLhandleARB obj, GLenum pname, GLint *params); +typedef void (APIENTRYP PFNGLGETINFOLOGARBPROC) (VBoxGLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); +typedef void (APIENTRYP PFNGLGETATTACHEDOBJECTSARBPROC) (VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei *count, VBoxGLhandleARB *obj); +typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONARBPROC) (VBoxGLhandleARB programObj, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMARBPROC) (VBoxGLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (VBoxGLhandleARB programObj, GLint location, GLfloat *params); +typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (VBoxGLhandleARB programObj, GLint location, GLint *params); +typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (VBoxGLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #endif #ifndef GL_ARB_vertex_shader #define GL_ARB_vertex_shader 1 #ifdef GL_GLEXT_PROTOTYPES -GLAPI void APIENTRY glBindAttribLocationARB (GLhandleARB, GLuint, const GLcharARB *); -GLAPI void APIENTRY glGetActiveAttribARB (GLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); -GLAPI GLint APIENTRY glGetAttribLocationARB (GLhandleARB, const GLcharARB *); +GLAPI void APIENTRY glBindAttribLocationARB (VBoxGLhandleARB, GLuint, const GLcharARB *); +GLAPI void APIENTRY glGetActiveAttribARB (VBoxGLhandleARB, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLcharARB *); +GLAPI GLint APIENTRY glGetAttribLocationARB (VBoxGLhandleARB, const GLcharARB *); #endif /* GL_GLEXT_PROTOTYPES */ -typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (GLhandleARB programObj, GLuint index, const GLcharARB *name); -typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); -typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programObj, const GLcharARB *name); +typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONARBPROC) (VBoxGLhandleARB programObj, GLuint index, const GLcharARB *name); +typedef void (APIENTRYP PFNGLGETACTIVEATTRIBARBPROC) (VBoxGLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name); +typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONARBPROC) (VBoxGLhandleARB programObj, const GLcharARB *name); #endif #ifndef GL_ARB_fragment_shader diff --git a/src/VBox/GuestHost/OpenGL/include/chromium.h b/src/VBox/GuestHost/OpenGL/include/chromium.h index f316e23a..4e1ed628 100644 --- a/src/VBox/GuestHost/OpenGL/include/chromium.h +++ b/src/VBox/GuestHost/OpenGL/include/chromium.h @@ -21,24 +21,24 @@ #include "cr_compiler.h" #ifdef IN_RING0 -#include <common/VBoxMPUtils.h> -#define WINGDIAPI +# include <common/VBoxMPUtils.h> +# define WINGDIAPI #endif /* * We effectively wrap gl.h, glu.h, etc, just like GLUT */ #ifndef GL_GLEXT_PROTOTYPES -#define GL_GLEXT_PROTOTYPES +# define GL_GLEXT_PROTOTYPES #endif #if defined(WINDOWS) # ifdef IN_RING0 # error "should not happen!" # endif -#define WIN32_LEAN_AND_MEAN -#define WGL_APIENTRY __stdcall -#include <windows.h> +# define WIN32_LEAN_AND_MEAN +# define WGL_APIENTRY __stdcall +# include <windows.h> #elif defined(DARWIN) /* nothing */ #else @@ -55,23 +55,23 @@ #ifdef GLX -#ifndef GLX_GLXEXT_PROTOTYPES -#define GLX_GLXEXT_PROTOTYPES -#endif -#include <GL/glx.h> +# ifndef GLX_GLXEXT_PROTOTYPES +# define GLX_GLXEXT_PROTOTYPES +# endif +# include <GL/glx.h> #endif #ifdef USE_OSMESA -#include <GL/osmesa.h> +# include <GL/osmesa.h> #endif #ifdef DARWIN -#include <stddef.h> +# include <stddef.h> #elif !defined(FreeBSD) -#include <malloc.h> /* to get ptrdiff_t used below */ +# include <malloc.h> /* to get ptrdiff_t used below */ #endif -#include <GL/glext.h> +#include "cr_glext.h" #ifdef __cplusplus extern "C" { @@ -79,6 +79,11 @@ extern "C" { /* to shut up gcc warning for struct VBOXUHGSMI * parameters */ struct VBOXUHGSMI; +struct VBOXVR_SCR_COMPOSITOR; +struct VBOXVR_SCR_COMPOSITOR_ENTRY; + +#define CR_RENDER_DEFAULT_CONTEXT_ID (INT32_MAX-1) +#define CR_RENDER_DEFAULT_WINDOW_ID (INT32_MAX-1) #if defined(IN_GUEST) && (WINDOWS) && defined(VBOX_WITH_WDDM) # ifdef VBOX_WDDM_WOW64 @@ -607,6 +612,7 @@ extern void APIENTRY glGetChromiumParametervCR(GLenum target, GLuint index, GLen #define GL_WINDOW_SIZE_CR 0x8B06 #define GL_MAX_WINDOW_SIZE_CR 0x8B24 /* new */ +#define GL_WINDOW_VISIBILITY_CR 0x8B25 /* new */ #endif /* GL_CR_window_size */ @@ -714,7 +720,13 @@ extern void APIENTRY glZPixCR(GLsizei width, GLsizei height, GLenum format, /*report that the shared resource is no longer used by this context, the parameter value is a texture name*/ #define GL_RCUSAGE_TEXTURE_CLEAR_CR 0x8B2A /*configures host to create windows initially hidden*/ -#define GL_HOST_WND_CREATED_HIDDEN 0x8B2B +#define GL_HOST_WND_CREATED_HIDDEN_CR 0x8B2B +/* guest requests host whether e debug break is needed*/ +#define GL_DBG_CHECK_BREAK_CR 0x8B2C +/* Tells renderspu the default context id being used by the crserver */ +#define GL_HH_SET_DEFAULT_SHARED_CTX 0x8B2D + +#define GL_HH_SET_TMPCTX_MAKE_CURRENT 0x8B2E /**********************************************************************/ /***** Chromium-specific API *****/ @@ -765,8 +777,9 @@ extern GLint APIENTRY crWindowCreate(const char *dpyName, GLint visBits); extern void APIENTRY crWindowDestroy(GLint window); extern void APIENTRY crWindowSize(GLint window, GLint w, GLint h); extern void APIENTRY crWindowPosition(GLint window, GLint x, GLint y); -extern void APIENTRY crWindowVisibleRegion( GLint window, GLint cRects, void *pRects ); +extern void APIENTRY crWindowVisibleRegion( GLint window, GLint cRects, const void *pRects ); extern void APIENTRY crWindowShow( GLint window, GLint flag ); +extern void APIENTRY crVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects); typedef int (CR_APIENTRY *CR_PROC)(); CR_PROC APIENTRY crGetProcAddress( const char *name ); diff --git a/src/VBox/GuestHost/OpenGL/include/cr_blitter.h b/src/VBox/GuestHost/OpenGL/include/cr_blitter.h new file mode 100644 index 00000000..2a01d3b6 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_blitter.h @@ -0,0 +1,323 @@ +/* $Id$ */ + +/** @file + * Blitter API + */ +/* + * Copyright (C) 2013 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 ___cr_blitter_h__ +#define ___cr_blitter_h__ + +#include <iprt/cdefs.h> +#include <iprt/asm.h> +#include "cr_spu.h" +#include "cr_vreg.h" + +#ifndef IN_RING0 +# define VBOXBLITTERDECL(_type) DECLEXPORT(_type) +#else +# define VBOXBLITTERDECL(_type) RTDECL(_type) +#endif + +RT_C_DECLS_BEGIN +/* GLSL Cache */ +typedef struct CR_GLSL_CACHE +{ + int iGlVersion; + GLuint uNoAlpha2DProg; + GLuint uNoAlpha2DRectProg; + SPUDispatchTable *pDispatch; +} CR_GLSL_CACHE; + +DECLINLINE(void) CrGlslInit(CR_GLSL_CACHE *pCache, SPUDispatchTable *pDispatch) +{ + memset(pCache, 0, sizeof (*pCache)); + pCache->pDispatch = pDispatch; +} + +DECLINLINE(bool) CrGlslIsInited(const CR_GLSL_CACHE *pCache) +{ + return !!pCache->pDispatch; +} + +/* clients should set proper context before calling these funcs */ +VBOXBLITTERDECL(bool) CrGlslIsSupported(CR_GLSL_CACHE *pCache); +VBOXBLITTERDECL(int) CrGlslProgGenAllNoAlpha(CR_GLSL_CACHE *pCache); +VBOXBLITTERDECL(int) CrGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget); +VBOXBLITTERDECL(int) CrGlslProgUseGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget); +VBOXBLITTERDECL(int) CrGlslProgUseNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget); +VBOXBLITTERDECL(void) CrGlslProgClear(const CR_GLSL_CACHE *pCache); +VBOXBLITTERDECL(bool) CrGlslNeedsCleanup(const CR_GLSL_CACHE *pCache); +VBOXBLITTERDECL(void) CrGlslCleanup(CR_GLSL_CACHE *pCache); +VBOXBLITTERDECL(void) CrGlslTerm(CR_GLSL_CACHE *pCache); + +/* BLITTER */ +typedef struct CR_BLITTER_BUFFER +{ + GLuint cbBuffer; + GLvoid * pvBuffer; +} CR_BLITTER_BUFFER, *PCR_BLITTER_BUFFER; + +typedef union CR_BLITTER_FLAGS +{ + struct + { + uint32_t Initialized : 1; + uint32_t CtxCreated : 1; + uint32_t SupportsFBO : 1; + uint32_t SupportsPBO : 1; + uint32_t CurrentMuralChanged : 1; + uint32_t LastWasFBODraw : 1; + uint32_t ForceDrawBlit : 1; + uint32_t ShadersGloal : 1; + uint32_t Reserved : 24; + }; + uint32_t Value; +} CR_BLITTER_FLAGS, *PCR_BLITTER_FLAGS; + +struct CR_BLITTER; + +typedef DECLCALLBACK(int) FNCRBLT_BLITTER(struct CR_BLITTER *pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags); +typedef FNCRBLT_BLITTER *PFNCRBLT_BLITTER; + +typedef struct CR_BLITTER_SPUITEM +{ + int id; + GLint visualBits; +} CR_BLITTER_SPUITEM, *PCR_BLITTER_SPUITEM; + +typedef struct CR_BLITTER_CONTEXT +{ + CR_BLITTER_SPUITEM Base; +} CR_BLITTER_CONTEXT, *PCR_BLITTER_CONTEXT; + +typedef struct CR_BLITTER_WINDOW +{ + CR_BLITTER_SPUITEM Base; + GLuint width, height; +} CR_BLITTER_WINDOW, *PCR_BLITTER_WINDOW; + +typedef struct CR_BLITTER_IMG +{ + void *pvData; + GLuint cbData; + GLenum enmFormat; + GLuint width, height; + GLuint bpp; + GLuint pitch; +} CR_BLITTER_IMG, *PCR_BLITTER_IMG; + +typedef struct CR_BLITTER +{ + GLuint idFBO; + CR_BLITTER_FLAGS Flags; + uint32_t cEnters; + PFNCRBLT_BLITTER pfnBlt; + CR_BLITTER_BUFFER Verticies; + CR_BLITTER_BUFFER Indicies; + RTRECTSIZE CurrentSetSize; + CR_BLITTER_WINDOW CurrentMural; + CR_BLITTER_CONTEXT CtxInfo; + int32_t i32MakeCurrentUserData; + SPUDispatchTable *pDispatch; + const CR_GLSL_CACHE *pGlslCache; + CR_GLSL_CACHE LocalGlslCache; +} CR_BLITTER, *PCR_BLITTER; + +DECLINLINE(GLboolean) CrBltIsInitialized(PCR_BLITTER pBlitter) +{ + return !!pBlitter->pDispatch; +} + +VBOXBLITTERDECL(int) CrBltInit(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pCtxBase, bool fCreateNewCtx, bool fForceDrawBlt, const CR_GLSL_CACHE *pShaders, SPUDispatchTable *pDispatch); + +VBOXBLITTERDECL(void) CrBltTerm(PCR_BLITTER pBlitter); + +VBOXBLITTERDECL(int) CrBltCleanup(PCR_BLITTER pBlitter); + +DECLINLINE(GLboolean) CrBltSupportsTexTex(PCR_BLITTER pBlitter) +{ + return pBlitter->Flags.SupportsFBO; +} + +DECLINLINE(GLboolean) CrBltIsEntered(PCR_BLITTER pBlitter) +{ + return !!pBlitter->cEnters; +} + +DECLINLINE(GLint) CrBltGetVisBits(PCR_BLITTER pBlitter) +{ + return pBlitter->CtxInfo.Base.visualBits; +} + + +DECLINLINE(GLboolean) CrBltIsEverEntered(PCR_BLITTER pBlitter) +{ + return !!pBlitter->Flags.Initialized; +} + +DECLINLINE(void) CrBltSetMakeCurrentUserData(PCR_BLITTER pBlitter, int32_t i32MakeCurrentUserData) +{ + pBlitter->i32MakeCurrentUserData = i32MakeCurrentUserData; +} + +VBOXBLITTERDECL(int) CrBltMuralSetCurrentInfo(PCR_BLITTER pBlitter, const CR_BLITTER_WINDOW *pMural); +DECLINLINE(const CR_BLITTER_WINDOW *) CrBltMuralGetCurrentInfo(PCR_BLITTER pBlitter) +{ + return &pBlitter->CurrentMural; +} + +VBOXBLITTERDECL(void) CrBltCheckUpdateViewport(PCR_BLITTER pBlitter); + +VBOXBLITTERDECL(void) CrBltLeave(PCR_BLITTER pBlitter); +VBOXBLITTERDECL(int) CrBltEnter(PCR_BLITTER pBlitter); +VBOXBLITTERDECL(void) CrBltBlitTexMural(PCR_BLITTER pBlitter, bool fBb, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags); +VBOXBLITTERDECL(void) CrBltBlitTexTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, const VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags); +VBOXBLITTERDECL(int) CrBltImgGetTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, GLenum enmFormat, CR_BLITTER_IMG *pDst); + +VBOXBLITTERDECL(int) CrBltImgGetMural(PCR_BLITTER pBlitter, bool fBb, CR_BLITTER_IMG *pDst); +VBOXBLITTERDECL(void) CrBltImgFree(PCR_BLITTER pBlitter, CR_BLITTER_IMG *pDst); +VBOXBLITTERDECL(void) CrBltPresent(PCR_BLITTER pBlitter); +/* */ +struct CR_TEXDATA; + +typedef DECLCALLBACK(void) FNCRTEXDATA_RELEASED(struct CR_TEXDATA *pTexture); +typedef FNCRTEXDATA_RELEASED *PFNCRTEXDATA_RELEASED; + +typedef union CR_TEXDATA_FLAGS +{ + struct + { + uint32_t DataValid : 1; + uint32_t DataAcquired : 1; + uint32_t DataInverted : 1; + uint32_t Entered : 1; + uint32_t Reserved : 28; + }; + uint32_t Value; +} CR_TEXDATA_FLAGS, *PCR_TEXDATA_FLAGS; + + +typedef struct CR_TEXDATA +{ + VBOXVR_TEXTURE Tex; + volatile uint32_t cRefs; + /* fields specific to texture data download */ + uint32_t idInvertTex; + uint32_t idPBO; + CR_TEXDATA_FLAGS Flags; + PCR_BLITTER pBlitter; + CR_BLITTER_IMG Img; + /*dtor*/ + PFNCRTEXDATA_RELEASED pfnTextureReleased; + struct CR_TEXDATA *pScaledCache; +} CR_TEXDATA, *PCR_TEXDATA; + +DECLINLINE(void) CrTdInit(PCR_TEXDATA pTex, const VBOXVR_TEXTURE *pVrTex, PCR_BLITTER pBlitter, PFNCRTEXDATA_RELEASED pfnTextureReleased) +{ + memset(pTex, 0, sizeof (*pTex)); + pTex->Tex = *pVrTex; + pTex->cRefs = 1; + pTex->pBlitter = pBlitter; + pTex->pfnTextureReleased = pfnTextureReleased; +} + +DECLINLINE(const VBOXVR_TEXTURE*) CrTdTexGet(const CR_TEXDATA *pTex) +{ + return &pTex->Tex; +} + +DECLINLINE(PCR_BLITTER) CrTdBlitterGet(CR_TEXDATA *pTex) +{ + return pTex->pBlitter; +} + +DECLINLINE(int) CrTdBltEnter(PCR_TEXDATA pTex) +{ + int rc; + if (pTex->Flags.Entered) + return VERR_INVALID_STATE; + rc = CrBltEnter(pTex->pBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed rc %d", rc)); + return rc; + } + pTex->Flags.Entered = 1; + return VINF_SUCCESS; +} + +DECLINLINE(bool) CrTdBltIsEntered(PCR_TEXDATA pTex) +{ + return pTex->Flags.Entered; +} + +DECLINLINE(void) CrTdBltLeave(PCR_TEXDATA pTex) +{ + if (!pTex->Flags.Entered) + { + WARN(("invalid Blt Leave")); + return; + } + + CrBltLeave(pTex->pBlitter); + + pTex->Flags.Entered = 0; +} + +/* the CrTdBltXxx calls are done with the entered blitter */ +/* acquire the texture data, returns the cached data in case it is cached. + * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup. + * */ +VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg); + +VBOXBLITTERDECL(int) CrTdBltDataAcquireScaled(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, uint32_t width, uint32_t height, const CR_BLITTER_IMG**ppImg); + +VBOXBLITTERDECL(int) CrTdBltDataReleaseScaled(PCR_TEXDATA pTex, const CR_BLITTER_IMG *pImg); + +VBOXBLITTERDECL(void) CrTdBltScaleCacheMoveTo(PCR_TEXDATA pTex, PCR_TEXDATA pDstTex); + +/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup */ +VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex); +/* discard the texture data cached with previous CrTdBltDataAcquire. + * Must be called wit data released (CrTdBltDataRelease) */ +VBOXBLITTERDECL(int) CrTdBltDataFree(PCR_TEXDATA pTex); +VBOXBLITTERDECL(int) CrTdBltDataFreeNe(PCR_TEXDATA pTex); +VBOXBLITTERDECL(void) CrTdBltDataInvalidateNe(PCR_TEXDATA pTex); +/* does same as CrTdBltDataFree, and in addition cleans up. + * this is kind of a texture destructor, which clients should call on texture object destruction, e.g. from the PFNCRTEXDATA_RELEASED callback */ +VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex); + +VBOXBLITTERDECL(int) CrTdBltDataCleanupNe(PCR_TEXDATA pTex); + +DECLINLINE(uint32_t) CrTdAddRef(PCR_TEXDATA pTex) +{ + return ASMAtomicIncU32(&pTex->cRefs); +} + +DECLINLINE(uint32_t) CrTdRelease(PCR_TEXDATA pTex) +{ + uint32_t cRefs = ASMAtomicDecU32(&pTex->cRefs); + if (!cRefs) + { + if (pTex->pfnTextureReleased) + pTex->pfnTextureReleased(pTex); + else + CrTdBltDataCleanupNe(pTex); + } + + return cRefs; +} + +RT_C_DECLS_END + +#endif /* #ifndef ___cr_blitter_h__ */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_bmpscale.h b/src/VBox/GuestHost/OpenGL/include/cr_bmpscale.h new file mode 100644 index 00000000..fda56bac --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_bmpscale.h @@ -0,0 +1,25 @@ +#ifndef ___cr_bmpscale_h__ +#define ___cr_bmpscale_h__ + +#include <iprt/types.h> +#include <iprt/cdefs.h> + + +RT_C_DECLS_BEGIN + +#ifndef IN_RING0 +# define VBOXBMPSCALEDECL(_type) DECLEXPORT(_type) +#else +# define VBOXBLITTERDECL(_type) RTDECL(_type) +#endif + +VBOXBMPSCALEDECL(void) CrBmpScale32 (uint8_t *dst, + int iDstDeltaLine, + int dstW, int dstH, + const uint8_t *src, + int iSrcDeltaLine, + int srcW, int srcH); + +RT_C_DECLS_END + +#endif /* #ifndef ___cr_bmpscale_h__ */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_compositor.h b/src/VBox/GuestHost/OpenGL/include/cr_compositor.h new file mode 100644 index 00000000..4ad56936 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_compositor.h @@ -0,0 +1,233 @@ +/* $Id: cr_compositor.h $ */ + +/** @file + * uint32_t compositor API + */ + +/* + * Copyright (C) 2013 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 ___cr_compositor_h_ +#define ___cr_compositor_h_ +#include <cr_vreg.h> +#include <cr_blitter.h> + +/* Compositor with Stretching & Cached Rectangles info */ + +RT_C_DECLS_BEGIN + +struct VBOXVR_SCR_COMPOSITOR_ENTRY; +struct VBOXVR_SCR_COMPOSITOR; + +typedef DECLCALLBACK(void) FNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry); +typedef FNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED *PFNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED; + + +typedef struct VBOXVR_SCR_COMPOSITOR_ENTRY +{ + VBOXVR_COMPOSITOR_ENTRY Ce; + RTRECT Rect; + uint32_t fChanged; + uint32_t fFlags; + uint32_t cRects; + PRTRECT paSrcRects; + PRTRECT paDstRects; + PRTRECT paDstUnstretchedRects; + PFNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased; + PCR_TEXDATA pTex; +} VBOXVR_SCR_COMPOSITOR_ENTRY, *PVBOXVR_SCR_COMPOSITOR_ENTRY; + +typedef struct VBOXVR_SCR_COMPOSITOR +{ + VBOXVR_COMPOSITOR Compositor; + RTRECT Rect; +#ifndef IN_RING0 + float StretchX; + float StretchY; +#endif + uint32_t fFlags; + uint32_t cRects; + uint32_t cRectsBuffer; + PRTRECT paSrcRects; + PRTRECT paDstRects; + PRTRECT paDstUnstretchedRects; +} VBOXVR_SCR_COMPOSITOR, *PVBOXVR_SCR_COMPOSITOR; + + +typedef DECLCALLBACK(bool) FNVBOXVRSCRCOMPOSITOR_VISITOR(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, void *pvVisitor); +typedef FNVBOXVRSCRCOMPOSITOR_VISITOR *PFNVBOXVRSCRCOMPOSITOR_VISITOR; + +DECLINLINE(void) CrVrScrCompositorEntryInit(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTRECT *pRect, CR_TEXDATA *pTex, PFNVBOXVRSCRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased) +{ + memset(pEntry, 0, sizeof (*pEntry)); + VBoxVrCompositorEntryInit(&pEntry->Ce); + pEntry->Rect = *pRect; + pEntry->pfnEntryReleased = pfnEntryReleased; + if (pTex) + { + CrTdAddRef(pTex); + pEntry->pTex = pTex; + } +} + +DECLINLINE(void) CrVrScrCompositorEntryCleanup(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry) +{ + if (pEntry->pTex) + { + CrTdRelease(pEntry->pTex); + pEntry->pTex = NULL; + } +} + +DECLINLINE(bool) CrVrScrCompositorEntryIsUsed(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return VBoxVrCompositorEntryIsInList(&pEntry->Ce); +} + +DECLINLINE(void) CrVrScrCompositorEntrySetChanged(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, bool fChanged) +{ + pEntry->fChanged = !!fChanged; +} + +DECLINLINE(void) CrVrScrCompositorEntryTexSet(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, CR_TEXDATA *pTex) +{ + if (pEntry->pTex) + CrTdRelease(pEntry->pTex); + + if (pTex) + CrTdAddRef(pTex); + + pEntry->pTex = pTex; +} + +DECLINLINE(CR_TEXDATA *) CrVrScrCompositorEntryTexGet(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return pEntry->pTex; +} + +DECLINLINE(bool) CrVrScrCompositorEntryIsChanged(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return !!pEntry->fChanged; +} + +DECLINLINE(bool) CrVrScrCompositorIsEmpty(const VBOXVR_SCR_COMPOSITOR *pCompositor) +{ + return VBoxVrCompositorIsEmpty(&pCompositor->Compositor); +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTRECT *pRect); +VBOXVREGDECL(int) CrVrScrCompositorEntryTexAssign(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, CR_TEXDATA *pTex); +VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor); +VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged); +DECLINLINE(bool) CrVrScrCompositorEntryIsInList(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return VBoxVrCompositorEntryIsInList(&pEntry->Ce); +} +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangeFlags); +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, bool *pfChanged); +VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged); +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged); +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged); +VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged); +VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos); +DECLINLINE(const RTRECT*) CrVrScrCompositorEntryRectGet(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return &pEntry->Rect; +} + +/* regions are valid until the next CrVrScrCompositor call */ +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects); +VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry); +VBOXVREGDECL(bool) CrVrScrCompositorEntryReplace(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pNewEntry); +VBOXVREGDECL(void) CrVrScrCompositorEntryFlagsSet(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t fFlags); +VBOXVREGDECL(uint32_t) CrVrScrCompositorEntryFlagsCombinedGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry); +DECLINLINE(uint32_t) CrVrScrCompositorEntryFlagsGet(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return pEntry->fFlags; +} + +VBOXVREGDECL(void) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect); +VBOXVREGDECL(int) CrVrScrCompositorRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect, bool *pfChanged); +DECLINLINE(const RTRECT*) CrVrScrCompositorRectGet(const VBOXVR_SCR_COMPOSITOR *pCompositor) +{ + return &pCompositor->Rect; +} + +VBOXVREGDECL(void) CrVrScrCompositorClear(PVBOXVR_SCR_COMPOSITOR pCompositor); +VBOXVREGDECL(void) CrVrScrCompositorRegionsClear(PVBOXVR_SCR_COMPOSITOR pCompositor, bool *pfChanged); + +typedef DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) FNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR(const VBOXVR_SCR_COMPOSITOR_ENTRY*pEntry, void *pvContext); +typedef FNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR *PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR; + +VBOXVREGDECL(int) CrVrScrCompositorClone(const VBOXVR_SCR_COMPOSITOR *pCompositor, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor); +VBOXVREGDECL(int) CrVrScrCompositorIntersectList(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pVr, bool *pfChanged); +VBOXVREGDECL(int) CrVrScrCompositorIntersectedList(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_LIST *pVr, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor, bool *pfChanged); +#ifndef IN_RING0 +VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY); +DECLINLINE(void) CrVrScrCompositorGetStretching(const VBOXVR_SCR_COMPOSITOR *pCompositor, float *pStretchX, float *pStretchY) +{ + if (pStretchX) + *pStretchX = pCompositor->StretchX; + + if (pStretchY) + *pStretchY = pCompositor->StretchY; +} +#endif +/* regions are valid until the next CrVrScrCompositor call */ +VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects); + +#define VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(_p) ((PVBOXVR_SCR_COMPOSITOR_ENTRY)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVR_SCR_COMPOSITOR_ENTRY, Ce))) +#define VBOXVR_SCR_COMPOSITOR_CONST_ENTRY_FROM_ENTRY(_p) ((const VBOXVR_SCR_COMPOSITOR_ENTRY*)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVR_SCR_COMPOSITOR_ENTRY, Ce))) +#define VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(_p) ((PVBOXVR_SCR_COMPOSITOR)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVR_SCR_COMPOSITOR, Compositor))) + +typedef struct VBOXVR_SCR_COMPOSITOR_ITERATOR +{ + VBOXVR_COMPOSITOR_ITERATOR Base; +} VBOXVR_SCR_COMPOSITOR_ITERATOR ,*PVBOXVR_SCR_COMPOSITOR_ITERATOR; + +typedef struct VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR +{ + VBOXVR_COMPOSITOR_CONST_ITERATOR Base; +} VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR ,*PVBOXVR_SCR_COMPOSITOR_CONST_ITERATOR; + +DECLINLINE(void) CrVrScrCompositorIterInit(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ITERATOR pIter) +{ + VBoxVrCompositorIterInit(&pCompositor->Compositor, &pIter->Base); +} + +DECLINLINE(void) CrVrScrCompositorConstIterInit(const VBOXVR_SCR_COMPOSITOR *pCompositor, PVBOXVR_SCR_COMPOSITOR_CONST_ITERATOR pIter) +{ + VBoxVrCompositorConstIterInit(&pCompositor->Compositor, &pIter->Base); +} + +DECLINLINE(PVBOXVR_SCR_COMPOSITOR_ENTRY) CrVrScrCompositorIterNext(PVBOXVR_SCR_COMPOSITOR_ITERATOR pIter) +{ + PVBOXVR_COMPOSITOR_ENTRY pCe = VBoxVrCompositorIterNext(&pIter->Base); + if (pCe) + { + return VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCe); + } + return NULL; +} + +DECLINLINE(const VBOXVR_SCR_COMPOSITOR_ENTRY*) CrVrScrCompositorConstIterNext(PVBOXVR_SCR_COMPOSITOR_CONST_ITERATOR pIter) +{ + const VBOXVR_COMPOSITOR_ENTRY *pCe = VBoxVrCompositorConstIterNext(&pIter->Base); + if (pCe) + { + return VBOXVR_SCR_COMPOSITOR_CONST_ENTRY_FROM_ENTRY(pCe); + } + return NULL; +} + +RT_C_DECLS_END + +#endif /* ___cr_compositor_h_ */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_dump.h b/src/VBox/GuestHost/OpenGL/include/cr_dump.h new file mode 100644 index 00000000..0946f56e --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_dump.h @@ -0,0 +1,177 @@ +/* $Id: cr_dump.h $ */ + +/** @file + * Debugging: Dump API + */ +/* + * Copyright (C) 2013 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 ___cr_dump_h__ +#define ___cr_dump_h__ + +/* dump stuff */ +//#define VBOX_WITH_CRDUMPER +#ifdef VBOX_WITH_CRDUMPER + +#include <iprt/cdefs.h> +#include <iprt/string.h> +#include <cr_spu.h> +#include <cr_glstate.h> +#include <cr_blitter.h> + +# define VBOXDUMPDECL(_type) DECLEXPORT(_type) + +RT_C_DECLS_BEGIN + +#ifdef RT_OS_WINDOWS +DECLEXPORT(void) crDmpDumpImgDmlBreak(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc); + +DECLEXPORT(void) crDmpDumpStrDbgPrint(struct CR_DUMPER * pDumper, const char*pszStr); +#endif + +struct CR_DUMPER; + +typedef DECLCALLBACKPTR(void, PFNCRDUMPIMG)(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc); +typedef DECLCALLBACKPTR(void, PFNCRDUMPSTR)(struct CR_DUMPER * pDumper, const char*pszStr); + +typedef struct CR_DUMPER +{ + PFNCRDUMPIMG pfnDumpImg; + PFNCRDUMPSTR pfnDumpStr; +} CR_DUMPER; + +#define crDmpImg(_pDumper, _pImg, _pDesc) do { \ + (_pDumper)->pfnDumpImg((_pDumper), (_pImg), (_pDesc)); \ + } while (0) + +#define crDmpStr(_pDumper, _pDesc) do { \ + (_pDumper)->pfnDumpStr((_pDumper), (_pDesc)); \ + } while (0) + +#ifndef RT_OS_WINDOWS +# define vsprintf_s vsnprintf +# define sprintf_s snprintf +#endif + +DECLINLINE(void) crDmpStrV(CR_DUMPER *pDumper, const char *pszStr, va_list pArgList) +{ + char szBuffer[4096] = {0}; + vsprintf_s(szBuffer, sizeof (szBuffer), pszStr, pArgList); + crDmpStr(pDumper, szBuffer); +} + +DECLINLINE(void) crDmpStrF(CR_DUMPER *pDumper, const char *pszStr, ...) +{ + va_list pArgList; + va_start(pArgList, pszStr); + crDmpStrV(pDumper, pszStr, pArgList); + va_end(pArgList); +} + +DECLINLINE(void) crDmpImgV(CR_DUMPER *pDumper, CR_BLITTER_IMG *pImg, const char *pszStr, va_list pArgList) +{ + char szBuffer[4096] = {0}; + vsprintf_s(szBuffer, sizeof (szBuffer), pszStr, pArgList); + crDmpImg(pDumper, pImg, szBuffer); +} + +DECLINLINE(void) crDmpImgF(CR_DUMPER *pDumper, CR_BLITTER_IMG *pImg, const char *pszStr, ...) +{ + va_list pArgList; + va_start(pArgList, pszStr); + crDmpImgV(pDumper, pImg, pszStr, pArgList); + va_end(pArgList); +} + +VBOXDUMPDECL(size_t) crDmpFormatArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pVal, uint32_t cVal); +VBOXDUMPDECL(size_t) crDmpFormatRawArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pVal, uint32_t cVal); +VBOXDUMPDECL(size_t) crDmpFormatMatrixArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pVal, uint32_t cX, uint32_t cY); + +typedef struct CR_DBGPRINT_DUMPER +{ + CR_DUMPER Base; +} CR_DBGPRINT_DUMPER; + +typedef struct CR_HTML_DUMPER +{ + CR_DUMPER Base; + const char* pszFile; + const char* pszDir; + FILE *pFile; + uint32_t cImg; +} CR_HTML_DUMPER; + +DECLEXPORT(bool) crDmpHtmlIsInited(struct CR_HTML_DUMPER * pDumper); +DECLEXPORT(void) crDmpHtmlTerm(struct CR_HTML_DUMPER * pDumper); +DECLEXPORT(int) crDmpHtmlInit(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile); +DECLEXPORT(int) crDmpHtmlInitV(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, va_list pArgList); +DECLEXPORT(int) crDmpHtmlInitF(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, ...); + +#ifdef RT_OS_WINDOWS +DECLINLINE(void) crDmpDbgPrintInit(CR_DBGPRINT_DUMPER *pDumper) +{ + pDumper->Base.pfnDumpImg = crDmpDumpImgDmlBreak; + pDumper->Base.pfnDumpStr = crDmpDumpStrDbgPrint; +} +#endif + +typedef struct CR_RECORDER +{ + CR_BLITTER *pBlitter; + SPUDispatchTable *pDispatch; + CR_DUMPER *pDumper; +} CR_RECORDER; + +DECLINLINE(void) crRecInit(CR_RECORDER *pRec, CR_BLITTER *pBlitter, SPUDispatchTable *pDispatch, CR_DUMPER *pDumper) +{ + pRec->pBlitter = pBlitter; + pRec->pDispatch = pDispatch; + pRec->pDumper = pDumper; +} + +VBOXDUMPDECL(void) crRecDumpBuffer(CR_RECORDER *pRec, CRContext *ctx, CR_BLITTER_CONTEXT *pCurCtx, CR_BLITTER_WINDOW *pCurWin, GLint idRedirFBO, VBOXVR_TEXTURE *pRedirTex); +VBOXDUMPDECL(void) crRecDumpTextures(CR_RECORDER *pRec, CRContext *ctx, CR_BLITTER_CONTEXT *pCurCtx, CR_BLITTER_WINDOW *pCurWin); +VBOXDUMPDECL(void) crRecDumpTextureV(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, CR_BLITTER_CONTEXT *pCurCtx, CR_BLITTER_WINDOW *pCurWin, const char *pszStr, va_list pArgList); +VBOXDUMPDECL(void) crRecDumpTextureF(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, CR_BLITTER_CONTEXT *pCurCtx, CR_BLITTER_WINDOW *pCurWin, const char *pszStr, ...); +VBOXDUMPDECL(void) crRecDumpTextureByIdV(CR_RECORDER *pRec, CRContext *ctx, GLint id, CR_BLITTER_CONTEXT *pCurCtx, CR_BLITTER_WINDOW *pCurWin, const char *pszStr, va_list pArgList); +VBOXDUMPDECL(void) crRecDumpTextureByIdF(CR_RECORDER *pRec, CRContext *ctx, GLint id, CR_BLITTER_CONTEXT *pCurCtx, CR_BLITTER_WINDOW *pCurWin, const char *pszStr, ...); +VBOXDUMPDECL(void) crRecDumpShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid); +VBOXDUMPDECL(void) crRecDumpProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid); +VBOXDUMPDECL(void) crRecRecompileShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid); +VBOXDUMPDECL(void) crRecRecompileProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid); +VBOXDUMPDECL(void) crRecDumpCurrentProgram(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecDumpProgramUniforms(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid); +VBOXDUMPDECL(void) crRecDumpCurrentProgramUniforms(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecRecompileCurrentProgram(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecDumpProgramAttribs(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid); +VBOXDUMPDECL(void) crRecDumpCurrentProgramAttribs(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecDumpGlGetState(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecDumpGlEnableState(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecDumpVertAttrv(CR_RECORDER *pRec, CRContext *ctx, GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal); +VBOXDUMPDECL(void) crRecDumpVertAttrF(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, ...); +VBOXDUMPDECL(void) crRecDumpVertAttrV(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, va_list pArgList); +VBOXDUMPDECL(void) crRecDumpTexParam(CR_RECORDER *pRec, CRContext *ctx, GLenum enmTarget); +VBOXDUMPDECL(void) crRecDumpTexEnv(CR_RECORDER *pRec, CRContext *ctx); +VBOXDUMPDECL(void) crRecDumpTexGen(CR_RECORDER *pRec, CRContext *ctx); + +VBOXDUMPDECL(int) crRecAlphaImgCreate(const CR_BLITTER_IMG *pImg, CR_BLITTER_IMG *pAlphaImg); +VBOXDUMPDECL(void) crRecAlphaImgDestroy(CR_BLITTER_IMG *pImg); + + +typedef DECLCALLBACKPTR(GLuint, PFNCRDUMPGETHWID)(void *pvObj); +void* crDmpHashtableSearchByHwid(CRHashTable *pHash, GLuint hwid, PFNCRDUMPGETHWID pfnGetHwid, unsigned long *pKey); + +RT_C_DECLS_END + +#endif /* VBOX_WITH_CRDUMPER */ +/* */ + +#endif /* #ifndef ___cr_dump_h__ */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_error.h b/src/VBox/GuestHost/OpenGL/include/cr_error.h index a73a47bc..ca472d28 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_error.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_error.h @@ -24,10 +24,29 @@ extern "C" { #define PRINTF #endif +#ifndef WARN +# ifndef IN_RING0 +# define LOG(_m) do { crDebug _m ; } while (0) +# define LOGREL(_m) do { crDebug _m ; } while (0) +# define WARN(_m) do { crWarning _m ; AssertMsgFailed(_m); } while (0) +# else +# define LOG(_m) do { } while (0) +# define LOGREL(_m) do { } while (0) +# define WARN(_m) do { AssertMsgFailed(_m); } while (0) +# endif +#endif + DECLEXPORT(void) crEnableWarnings(int onOff); DECLEXPORT(void) crDebug(const char *format, ... ) PRINTF; +#if defined(DEBUG_misha) && defined(RT_OS_WINDOWS) +typedef void FNCRDEBUG(const char *format, ... ) PRINTF; +typedef FNCRDEBUG *PFNCRDEBUG; +DECLINLINE(PFNCRDEBUG) crGetDebug() {return crDebug;} +# define crWarning (RT_BREAKPOINT(), crDebug) +#else DECLEXPORT(void) crWarning(const char *format, ... ) PRINTF; +#endif DECLEXPORT(void) crInfo(const char *format, ... ) PRINTF; DECLEXPORT(void) crError(const char *format, ... ) NORETURN_PRINTF; diff --git a/src/VBox/GuestHost/OpenGL/include/cr_extstring.h b/src/VBox/GuestHost/OpenGL/include/cr_extstring.h index 1d894983..5940379e 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_extstring.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_extstring.h @@ -237,6 +237,10 @@ static const char *crExtensions = #ifdef CR_EXT_stencil_two_side "GL_EXT_stencil_two_side " #endif +#ifdef CR_GREMEDY_string_marker + "GL_GREMEDY_string_marker " +#endif + ""; /* diff --git a/src/VBox/GuestHost/OpenGL/include/cr_glext.h b/src/VBox/GuestHost/OpenGL/include/cr_glext.h new file mode 100644 index 00000000..429e218c --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_glext.h @@ -0,0 +1,34 @@ +/* $Id: cr_glext.h $ */ + +/** @file + * GL chromium platform specifics + */ +/* + * Copyright (C) 2014 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 ___cr_glext_h__ +#define ___cr_glext_h__ + +#include <iprt/assert.h> + +#ifndef __glext_h_ +/* glext NOT included yet */ +# include "GL/glext.h" +#else +/* glext IS included yet */ +# ifndef RT_OS_DARWIN +typedef unsigned int VBoxGLhandleARB; /* shader object handle */ +AssertCompile(sizeof (VBoxGLhandleARB) == sizeof (GLhandleARB)); +# else +# error "patched glext is required for OSX!" +# endif +#endif +#endif /*___cr_glext_h__*/ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_glstate.h b/src/VBox/GuestHost/OpenGL/include/cr_glstate.h index fd82b576..95b3477d 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_glstate.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_glstate.h @@ -51,20 +51,19 @@ typedef struct CRContext CRContext; #include <iprt/cdefs.h> -#ifndef IN_GUEST # include <VBox/vmm/ssm.h> # include <iprt/asm.h> # define CR_STATE_SHAREDOBJ_USAGE_INIT(_pObj) (crMemset((_pObj)->ctxUsage, 0, sizeof ((_pObj)->ctxUsage))) # define CR_STATE_SHAREDOBJ_USAGE_SET(_pObj, _pCtx) (ASMBitSet((_pObj)->ctxUsage, (_pCtx)->id)) -# define CR_STATE_SHAREDOBJ_USAGE_CLEAR(_pObj, _pCtx) (ASMBitClear((_pObj)->ctxUsage, (_pCtx)->id)) +# define CR_STATE_SHAREDOBJ_USAGE_IS_SET(_pObj, _pCtx) (ASMBitTest((_pObj)->ctxUsage, (_pCtx)->id)) +# define CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(_pObj, _i) (ASMBitClear((_pObj)->ctxUsage, (_i))) +# define CR_STATE_SHAREDOBJ_USAGE_CLEAR(_pObj, _pCtx) (CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX((_pObj), (_pCtx)->id)) # define CR_STATE_SHAREDOBJ_USAGE_IS_USED(_pObj) (ASMBitFirstSet((_pObj)->ctxUsage, sizeof ((_pObj)->ctxUsage)<<3) >= 0) -#else -# define CR_STATE_SHAREDOBJ_USAGE_INIT(_pObj) do {} while (0) -# define CR_STATE_SHAREDOBJ_USAGE_SET(_pObj, _pCtx) do {} while (0) -# define CR_STATE_SHAREDOBJ_USAGE_CLEAR(_pObj, _pCtx) do {} while (0) -# define CR_STATE_SHAREDOBJ_USAGE_IS_USED(_pObj) (GL_FALSE) -#endif +# define CR_STATE_SHAREDOBJ_USAGE_GET_FIRST_USED_IDX(_pObj) (ASMBitFirstSet((_pObj)->ctxUsage, sizeof ((_pObj)->ctxUsage)<<3)) +# define CR_STATE_SHAREDOBJ_USAGE_GET_NEXT_USED_IDX(_pObj, _i) (ASMBitNextSet((_pObj)->ctxUsage, sizeof ((_pObj)->ctxUsage)<<3, (_i))) + +# define CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(_pObj, _i) for ((_i) = CR_STATE_SHAREDOBJ_USAGE_GET_FIRST_USED_IDX(_pObj); ((int)(_i)) >= 0; (_i) = CR_STATE_SHAREDOBJ_USAGE_GET_NEXT_USED_IDX((_pObj), ((int)(_i)))) #define CR_MAX_EXTENTS 256 @@ -218,8 +217,10 @@ DECLEXPORT(CRContext *) crStateGetCurrent(void); DECLEXPORT(void) crStateDestroyContext(CRContext *ctx); DECLEXPORT(GLboolean) crStateEnableDiffOnMakeCurrent(GLboolean fEnable); -CRContext * crStateSwichPrepare(CRContext *toCtx, GLboolean fMultipleContexts, GLuint idFBO); -void crStateSwichPostprocess(CRContext *fromCtx, GLboolean fMultipleContexts, GLuint idFBO); +void crStateSwitchPrepare(CRContext *toCtx, CRContext *fromCtx, GLuint idDrawFBO, GLuint idReadFBO); +void crStateSwitchPostprocess(CRContext *toCtx, CRContext *fromCtx, GLuint idDrawFBO, GLuint idReadFBO); + +void crStateSyncHWErrorState(CRContext *ctx); DECLEXPORT(void) crStateFlushFunc( CRStateFlushFunc ff ); DECLEXPORT(void) crStateFlushArg( void *arg ); @@ -233,15 +234,53 @@ DECLEXPORT(void) crStateSetExtensionString( CRContext *ctx, const GLubyte *exten DECLEXPORT(void) crStateDiffContext( CRContext *from, CRContext *to ); DECLEXPORT(void) crStateSwitchContext( CRContext *from, CRContext *to ); -DECLEXPORT(void) crStateApplyFBImage(CRContext *to); + +DECLEXPORT(unsigned int) crStateHlpComponentsCount( GLenum pname ); + +typedef struct CRFBDataElement +{ + /* FBO, can be NULL */ + GLint idFBO; + /* to be used for glDraw/ReadBuffer, i.e. GL_FRONT, GL_BACK, GL_COLOR_ATTACHMENTX */ + GLenum enmBuffer; + GLint posX; + GLint posY; + GLint width; + GLint height; + GLenum enmFormat; + GLenum enmType; + GLuint cbData; + GLvoid *pvData; +} CRFBDataElement; + +typedef struct CRFBData +{ + /* override default draw and read buffers to be used for offscreen rendering */ + GLint idOverrrideFBO; + uint32_t cElements; + CRFBDataElement aElements[1]; +} CRFBData; + +DECLEXPORT(void) crStateApplyFBImage(CRContext *to, CRFBData *data); +DECLEXPORT(int) crStateAcquireFBImage(CRContext *to, CRFBData *data); +DECLEXPORT(void) crStateFreeFBImageLegacy(CRContext *to); + +DECLEXPORT(void) crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, + CRTextureObj **obj, CRTextureLevel **img); + #ifndef IN_GUEST DECLEXPORT(int32_t) crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM); typedef DECLCALLBACK(CRContext*) FNCRSTATE_CONTEXT_GET(void*); typedef FNCRSTATE_CONTEXT_GET *PFNCRSTATE_CONTEXT_GET; DECLEXPORT(int32_t) crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRSTATE_CONTEXT_GET pfnCtxGet, PSSMHANDLE pSSM, uint32_t u32Version); -DECLEXPORT(void) crStateFreeShared(CRContext *pContext, CRSharedState *s); DECLEXPORT(void) crStateFreeShared(CRContext *pContext, CRSharedState *s); + +DECLEXPORT(int32_t) crStateLoadGlobals(PSSMHANDLE pSSM, uint32_t u32Version); +DECLEXPORT(int32_t) crStateSaveGlobals(PSSMHANDLE pSSM); + +DECLEXPORT(CRSharedState *) crStateGlobalSharedAcquire(); +DECLEXPORT(void) crStateGlobalSharedRelease(); #endif DECLEXPORT(void) crStateSetTextureUsed(GLuint texture, GLboolean used); @@ -270,7 +309,7 @@ DECLEXPORT(void) STATE_APIENTRY crStateShareContext(GLboolean value); DECLEXPORT(void) STATE_APIENTRY crStateSetSharedContext(CRContext *pCtx); DECLEXPORT(GLboolean) STATE_APIENTRY crStateContextIsShared(CRContext *pCtx); -DECLEXPORT(void) STATE_APIENTRY crStateQueryHWState(); +DECLEXPORT(void) STATE_APIENTRY crStateQueryHWState(GLuint fbFbo, GLuint bbFbo); #ifdef __cplusplus } #endif diff --git a/src/VBox/GuestHost/OpenGL/include/cr_hash.h b/src/VBox/GuestHost/OpenGL/include/cr_hash.h index 9bda7454..0f28c798 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_hash.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_hash.h @@ -15,17 +15,36 @@ extern "C" { #endif +typedef struct CRHashIdPool CRHashIdPool; typedef struct CRHashTable CRHashTable; /* Callback function used for freeing/deleting table entries */ typedef void (*CRHashtableCallback)(void *data); /* Callback function used for walking through table entries */ typedef void (*CRHashtableWalkCallback)(unsigned long key, void *data1, void *data2); +/* Callback function used for walking through allocated keys */ +typedef void (*CRHashIdWalkKeys)(unsigned long firstKey, unsigned long count, void *data); + +DECLEXPORT(CRHashIdPool *) crAllocHashIdPool( void ); +DECLEXPORT(CRHashIdPool *) crAllocHashIdPoolEx( GLuint min, GLuint max ); +DECLEXPORT(void) crFreeHashIdPool( CRHashIdPool *pool ); +DECLEXPORT(GLboolean) crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id ); +DECLEXPORT(GLuint) crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count ); +DECLEXPORT(void) crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count ); +/* @return GL_TRUE if the id is allocated, and GL_FALSE if the id was already allocated */ +DECLEXPORT(GLboolean) crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id ); +DECLEXPORT(void) crHashIdWalkKeys( CRHashIdPool *pool, CRHashIdWalkKeys walkFunc , void *data); DECLEXPORT(CRHashTable *) crAllocHashtable( void ); +DECLEXPORT(CRHashTable *) crAllocHashtableEx( GLuint min, GLuint max ); DECLEXPORT(void) crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteCallback ); DECLEXPORT(void) crHashtableAdd( CRHashTable *h, unsigned long key, void *data ); +/* to ensure hash table pool id consistency, there is no crHashTableFreeKeys/UnregisterKey, + * one should call crHashtableDelete to free unneeded keys, + * which will also ensure there is no entry with the specified key left in the table */ DECLEXPORT(GLuint) crHashtableAllocKeys( CRHashTable *h, GLsizei range ); +/* @return GL_TRUE if the id is allocated, and GL_FALSE if the id was already allocated */ +DECLEXPORT(GLboolean) crHashtableAllocRegisterKey( CRHashTable *h, GLuint key); DECLEXPORT(void) crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteCallback ); DECLEXPORT(void) crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc ); DECLEXPORT(void *) crHashtableSearch( const CRHashTable *h, unsigned long key ); @@ -33,10 +52,13 @@ DECLEXPORT(void) crHashtableReplace( CRHashTable *h, unsigned long key, void *da DECLEXPORT(unsigned int) crHashtableNumElements( const CRHashTable *h) ; DECLEXPORT(GLboolean) crHashtableIsKeyUsed( const CRHashTable *h, GLuint id ); DECLEXPORT(void) crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *data); +/* walk the hashtable w/o holding the table lock */ +DECLEXPORT(void) crHashtableWalkUnlocked( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *data); /*Returns GL_TRUE if given hashtable hold the data, pKey is updated with key value for data in this case*/ DECLEXPORT(GLboolean) crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey); DECLEXPORT(void) crHashtableLock(CRHashTable *h); DECLEXPORT(void) crHashtableUnlock(CRHashTable *h); +DECLEXPORT(void) crHashtableWalkKeys(CRHashTable *hash, CRHashIdWalkKeys walkFunc , void *data); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_htable.h b/src/VBox/GuestHost/OpenGL/include/cr_htable.h new file mode 100644 index 00000000..26c8bffd --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_htable.h @@ -0,0 +1,120 @@ +/* $Id: cr_htable.h $ */ + +/** @file + * uint32_t handle to void simple table API + */ + +/* + * Copyright (C) 2013 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 ___cr_htable_h_ +#define ___cr_htable_h_ + +#include <iprt/types.h> +#include <iprt/cdefs.h> + +#include <cr_error.h> + +#ifndef IN_RING0 +# define VBOXHTABLEDECL(_type) DECLEXPORT(_type) +#else +# define VBOXHTABLEDECL(_type) RTDECL(_type) +#endif + + + +RT_C_DECLS_BEGIN + +typedef uint32_t CRHTABLE_HANDLE; +#define CRHTABLE_HANDLE_INVALID 0UL + +typedef struct CRHTABLE +{ + uint32_t cData; + uint32_t iNext2Search; + uint32_t cSize; + void **paData; +} CRHTABLE, *PCRHTABLE; + +typedef struct CRHTABLE_ITERATOR +{ + PCRHTABLE pTbl; + uint32_t iCur; + uint32_t cLeft; +} VCRHTABLE_ITERATOR, *PCRHTABLE_ITERATOR; + +/*private stuff, not to be used directly */ +DECLINLINE(CRHTABLE_HANDLE) crHTableIndex2Handle(uint32_t iIndex) +{ + return iIndex+1; +} + +DECLINLINE(uint32_t) crHTableHandle2Index(CRHTABLE_HANDLE hHandle) +{ + return hHandle-1; +} + +/* public API */ +DECLINLINE(void) CrHTableIterInit(PCRHTABLE pTbl, PCRHTABLE_ITERATOR pIter) +{ + pIter->pTbl = pTbl; + pIter->iCur = 0; + pIter->cLeft = pTbl->cData; +} + +DECLINLINE(void*) CrHTableIterNext(PCRHTABLE_ITERATOR pIter, CRHTABLE_HANDLE *phHandle) +{ + PCRHTABLE pTbl; + uint32_t i; + if (!pIter->cLeft) + { + if (phHandle) + *phHandle = 0; + return NULL; + } + + pTbl = pIter->pTbl; + + for (i = pIter->iCur; i < pTbl->cSize; ++i) + { + if (pTbl->paData[i]) + { + pIter->iCur = i+1; + --(pIter->cLeft); + if (phHandle) + *phHandle = crHTableIndex2Handle(i); + return pTbl->paData[i]; + } + } + + crWarning("interator concurent modification!"); + return NULL; +} + +VBOXHTABLEDECL(int) CrHTableCreate(PCRHTABLE pTbl, uint32_t cSize); +DECLINLINE(void) CrHTableMoveTo(PCRHTABLE pSrcTbl, PCRHTABLE pDstTbl) +{ + *pDstTbl = *pSrcTbl; + CrHTableCreate(pSrcTbl, 0); +} +VBOXHTABLEDECL(void) CrHTableEmpty(PCRHTABLE pTbl); +VBOXHTABLEDECL(void) CrHTableDestroy(PCRHTABLE pTbl); +VBOXHTABLEDECL(int) CrHTableRealloc(PCRHTABLE pTbl, uint32_t cNewSize); +VBOXHTABLEDECL(CRHTABLE_HANDLE) CrHTablePut(PCRHTABLE pTbl, void *pvData); +VBOXHTABLEDECL(int) CrHTablePutToSlot(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle, void* pvData); + +/* note: can be called for the element returned with CrHTableIterNext w/o corrupting the iterator */ +VBOXHTABLEDECL(void*) CrHTableRemove(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle); +VBOXHTABLEDECL(void*) CrHTableGet(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle); + +RT_C_DECLS_END + +#endif /* #ifndef ___cr_htable_h_*/ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_pack.h b/src/VBox/GuestHost/OpenGL/include/cr_pack.h index 82f7d5d7..3f7f930e 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_pack.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_pack.h @@ -117,7 +117,11 @@ extern DECLEXPORT(void) crPackResetPointers( CRPackContext *pc ); extern DECLEXPORT(int) crPackMaxOpcodes( int buffer_size ); extern DECLEXPORT(int) crPackMaxData( int buffer_size ); -extern DECLEXPORT(void) crPackInitBuffer( CRPackBuffer *buffer, void *buf, int size, int mtu ); +extern DECLEXPORT(void) crPackInitBuffer( CRPackBuffer *buffer, void *buf, int size, int mtu +#ifdef IN_RING0 + , unsigned int num_opcodes +#endif + ); extern DECLEXPORT(void) crPackFlushFunc( CRPackContext *pc, CRPackFlushFunc ff ); extern DECLEXPORT(void) crPackFlushArg( CRPackContext *pc, void *flush_arg ); extern DECLEXPORT(void) crPackSendHugeFunc( CRPackContext *pc, CRPackSendHugeFunc shf ); @@ -140,8 +144,10 @@ extern DECLEXPORT(int) crPackCanHoldBoundedBuffer( CR_PACKER_CONTEXT_ARGDECL con #else #undef CR_UNALIGNED_ACCESS_OKAY #endif +#ifndef IN_RING0 extern DECLEXPORT(void) crWriteUnalignedDouble( void *buffer, double d ); extern DECLEXPORT(void) crWriteSwappedDouble( void *buffer, double d ); +#endif extern DECLEXPORT(void) *crPackAlloc( CR_PACKER_CONTEXT_ARGDECL unsigned int len ); extern DECLEXPORT(void) crHugePacket( CR_PACKER_CONTEXT_ARGDECL CROpcode op, void *ptr ); @@ -304,12 +310,22 @@ crPackCanHoldOpcode(const CRPackContext *pc, int num_opcode, int num_data) #define WRITE_DOUBLE( offset, data ) \ WRITE_DATA( offset, GLdouble, data ) #else -#define WRITE_DOUBLE( offset, data ) \ - crWriteUnalignedDouble( data_ptr + (offset), (data) ) +# ifndef IN_RING0 +# define WRITE_DOUBLE( offset, data ) \ + crWriteUnalignedDouble( data_ptr + (offset), (data) ) +# else +# define WRITE_DOUBLE( offset, data ) \ + AssertReleaseFailed() +# endif #endif +#ifndef IN_RING0 #define WRITE_SWAPPED_DOUBLE( offset, data ) \ crWriteSwappedDouble( data_ptr + (offset), (data) ) +#else +#define WRITE_SWAPPED_DOUBLE( offset, data ) \ + AssertReleaseFailed() +#endif #define WRITE_OPCODE( pc, opcode ) \ *(pc->buffer.opcode_current--) = (unsigned char) opcode diff --git a/src/VBox/GuestHost/OpenGL/include/cr_pixeldata.h b/src/VBox/GuestHost/OpenGL/include/cr_pixeldata.h index 9b194eef..da3ebe34 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_pixeldata.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_pixeldata.h @@ -11,6 +11,7 @@ #include "state/cr_client.h" #include <iprt/cdefs.h> +#include <stdarg.h> #ifdef __cplusplus extern "C" { @@ -43,6 +44,8 @@ DECLEXPORT(void) crBitmapCopy( GLsizei width, GLsizei height, GLubyte *dstPtr, const GLubyte *srcPtr, const CRPixelPackState *srcPacking ); DECLEXPORT(void) crDumpNamedTGA(const char *fname, GLint w, GLint h, GLvoid *data); +DECLEXPORT(void) crDumpNamedTGAV(GLint w, GLint h, GLvoid *data, const char* fname, va_list va); +DECLEXPORT(void) crDumpNamedTGAF(GLint w, GLint h, GLvoid *data, const char* fname, ...); DECLEXPORT(void) crDumpTGA(GLint w, GLint h, GLvoid *data); #ifdef __cplusplus } diff --git a/src/VBox/GuestHost/OpenGL/include/cr_protocol.h b/src/VBox/GuestHost/OpenGL/include/cr_protocol.h index 5e24f207..1bf785ba 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_protocol.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_protocol.h @@ -7,6 +7,7 @@ #ifndef CR_PROTOCOL_H #define CR_PROTOCOL_H +#include <iprt/types.h> #include <iprt/cdefs.h> #ifdef DEBUG_misha #include "cr_error.h" @@ -21,6 +22,23 @@ extern "C" { #define CR_PROTOCOL_VERSION_MAJOR 9 #define CR_PROTOCOL_VERSION_MINOR 1 +/* new TexPresent mechanism is available */ +#define CR_VBOX_CAP_TEX_PRESENT 0x00000001 +/* vbva command submission mechanism supported */ +#define CR_VBOX_CAP_CMDVBVA 0x00000002 + + +#define CR_PRESENT_SCREEN_MASK 0xffff +#define CR_PRESENT_FLAGS_OFFSET 16 +#define CR_PRESENT_FLAGS_MASK 0xffff0000 +#define CR_PRESENT_DEFINE_FLAG(_f) (1 << (CR_PRESENT_FLAGS_OFFSET + _f)) + +#define CR_PRESENT_FLAG_CLEAR_RECTS CR_PRESENT_DEFINE_FLAG(0) +#define CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD CR_PRESENT_DEFINE_FLAG(1) + +#define CR_PRESENT_GET_SCREEN(_cfg) ((_cfg) & CR_PRESENT_SCREEN_MASK) +#define CR_PRESENT_GET_FLAGS(_cfg) ((_cfg) & CR_PRESENT_FLAGS_MASK) + typedef enum { /* first message types is 'wGL\001', so we can immediately recognize bad message types */ @@ -51,7 +69,7 @@ typedef union { /* unsigned int junk[512]; */ } CRNetworkPointer; -#ifdef DEBUG_misha +#if 0 //def DEBUG_misha #define CRDBGPTR_SETZ(_p) crMemset((_p), 0, sizeof (CRNetworkPointer)) #define CRDBGPTR_CHECKZ(_p) do { \ CRNetworkPointer _ptr = {0}; \ @@ -80,26 +98,32 @@ typedef union { #ifdef VBOX_WITH_CRHGSMI typedef struct CRVBOXHGSMI_CMDDATA { - struct VBOXVDMACMD_CHROMIUM_CMD *pCmd; + union + { + struct VBOXVDMACMD_CHROMIUM_CMD *pHgsmiCmd; + struct VBOXCMDVBVA_CRCMD_CMD *pVbvaCmd; + void *pvCmd; + }; int *pCmdRc; char *pWriteback; unsigned int *pcbWriteback; unsigned int cbWriteback; + bool fHgsmiCmd; } CRVBOXHGSMI_CMDDATA, *PCRVBOXHGSMI_CMDDATA; #ifdef DEBUG # define CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(_pData) do { \ - CRASSERT(!(_pData)->pCmd == !(_pData)->pCmdRc); \ + CRASSERT(!(_pData)->pvCmd == !(_pData)->pCmdRc); \ CRASSERT(!(_pData)->pWriteback == !(_pData)->pcbWriteback); \ CRASSERT(!(_pData)->pWriteback == !(_pData)->cbWriteback); \ if ((_pData)->pWriteback) \ { \ - CRASSERT((_pData)->pCmd); \ + CRASSERT((_pData)->pvCmd); \ } \ } while (0) # define CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(_pData) do { \ - CRASSERT(!(_pData)->pCmd); \ + CRASSERT(!(_pData)->pvCmd); \ CRASSERT(!(_pData)->pCmdRc); \ CRASSERT(!(_pData)->pWriteback); \ CRASSERT(!(_pData)->pcbWriteback); \ @@ -122,7 +146,8 @@ typedef struct CRVBOXHGSMI_CMDDATA { # define CRVBOXHGSMI_CMDDATA_ASSERT_ISSETWB(_pData) do { } while (0) #endif -#define CRVBOXHGSMI_CMDDATA_IS_SET(_pData) (!!(_pData)->pCmd) +#define CRVBOXHGSMI_CMDDATA_IS_HGSMICMD(_pData) (!!(_pData)->fHgsmiCmd) +#define CRVBOXHGSMI_CMDDATA_IS_SET(_pData) (!!(_pData)->pvCmd) #define CRVBOXHGSMI_CMDDATA_IS_SETWB(_pData) (!!(_pData)->pWriteback) #define CRVBOXHGSMI_CMDDATA_CLEANUP(_pData) do { \ @@ -131,15 +156,16 @@ typedef struct CRVBOXHGSMI_CMDDATA { CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(_pData); \ } while (0) -#define CRVBOXHGSMI_CMDDATA_SET(_pData, _pCmd, _pHdr) do { \ +#define CRVBOXHGSMI_CMDDATA_SET(_pData, _pCmd, _pHdr, _fHgsmiCmd) do { \ CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(_pData); \ - (_pData)->pCmd = (_pCmd); \ + (_pData)->pvCmd = (_pCmd); \ (_pData)->pCmdRc = &(_pHdr)->result; \ + (_pData)->fHgsmiCmd = (_fHgsmiCmd); \ CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(_pData); \ } while (0) -#define CRVBOXHGSMI_CMDDATA_SETWB(_pData, _pCmd, _pHdr, _pWb, _cbWb, _pcbWb) do { \ - CRVBOXHGSMI_CMDDATA_SET(_pData, _pCmd, _pHdr); \ +#define CRVBOXHGSMI_CMDDATA_SETWB(_pData, _pCmd, _pHdr, _pWb, _cbWb, _pcbWb, _fHgsmiCmd) do { \ + CRVBOXHGSMI_CMDDATA_SET(_pData, _pCmd, _pHdr, _fHgsmiCmd); \ (_pData)->pWriteback = (_pWb); \ (_pData)->pcbWriteback = (_pcbWb); \ (_pData)->cbWriteback = (_cbWb); \ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_server.h b/src/VBox/GuestHost/OpenGL/include/cr_server.h index 027354a2..b215d4cb 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_server.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_server.h @@ -12,19 +12,28 @@ #include "cr_hash.h" #include "cr_protocol.h" #include "cr_glstate.h" +#include "cr_vreg.h" +#include "cr_blitter.h" #include "spu_dispatch_table.h" +#include "cr_dump.h" #include "state/cr_currentpointers.h" #include <iprt/types.h> #include <iprt/err.h> #include <iprt/string.h> +#include <iprt/list.h> +#include <iprt/thread.h> +#include <iprt/critsect.h> +#include <iprt/semaphore.h> +#include <iprt/memcache.h> #include <VBox/vmm/ssm.h> -#ifdef VBOX_WITH_CRHGSMI -# include <VBox/VBoxVideo.h> -#endif +#include <VBox/VBoxVideo.h> +#include <VBox/Hardware/VBoxVideoVBE.h> +#include <VBox/VBoxVideo3D.h> +#include <VBox/VBoxVideoHost3D.h> #ifdef __cplusplus extern "C" { @@ -34,7 +43,7 @@ extern "C" { #define CR_MAX_CLIENTS 64 /*@todo must match MaxGuestMonitors from SchemaDefs.h*/ -#define CR_MAX_GUEST_MONITORS 8 +#define CR_MAX_GUEST_MONITORS VBOX_VIDEO_MAX_SCREENS typedef DECLCALLBACKPTR(void, PFNCRSERVERPRESENTFBO) (void *data, int32_t screenId, int32_t x, int32_t y, uint32_t w, uint32_t h); @@ -54,7 +63,7 @@ typedef struct { DECLR3CALLBACKMEMBER(void, CRORGeometry, (void *pvInstance, int32_t x, int32_t y, uint32_t w, uint32_t h)); DECLR3CALLBACKMEMBER(void, CRORVisibleRegion, (void *pvInstance, - uint32_t cRects, RTRECT *paRects)); + uint32_t cRects, const RTRECT *paRects)); DECLR3CALLBACKMEMBER(void, CRORFrame, (void *pvInstance, void *pvData, uint32_t cbData)); DECLR3CALLBACKMEMBER(void, CROREnd, (void *pvInstance)); @@ -75,6 +84,140 @@ typedef struct { struct BucketingInfo; +typedef struct { + char *pszDpyName; + GLint visualBits; + int32_t externalID; +} CRCreateInfo_t; + +typedef struct { + char *pszDpyName; + int32_t externalID; + GLint requestedVisualBits; + GLint realVisualBits; +} CRCreateInfoEx_t; + +/* VRAM->RAM worker thread */ + +typedef enum +{ + CR_SERVER_RPW_STATE_UNINITIALIZED = 0, + CR_SERVER_RPW_STATE_INITIALIZING, + CR_SERVER_RPW_STATE_INITIALIZED, + CR_SERVER_RPW_STATE_UNINITIALIZING, +} CR_SERVER_RPW_STATE; + +/* worker control command */ +typedef enum +{ + CR_SERVER_RPW_CTL_TYPE_UNDEFINED = 0, + CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE, + CR_SERVER_RPW_CTL_TYPE_TERM +} CR_SERVER_RPW_CTL_TYPE; + +struct CR_SERVER_RPW_ENTRY; + +typedef struct CR_SERVER_RPW_CTL { + CR_SERVER_RPW_CTL_TYPE enmType; + int rc; + RTSEMEVENT hCompleteEvent; + /* valid for *_WAIT_COMPLETE and *_CANCEL */ + struct CR_SERVER_RPW_ENTRY *pEntry; +} CR_SERVER_RPW_CTL; + + +struct CR_SERVER_RPW_ENTRY; + +typedef DECLCALLBACKPTR(void, PFNCR_SERVER_RPW_DATA) (const struct CR_SERVER_RPW_ENTRY* pEntry, void *pvEntryTexData); + +typedef DECLCALLBACKPTR(void, PFNCRSERVERNOTIFYEVENT) (int32_t screenId, uint32_t uEvent, void*pvData); + +typedef struct CR_SERVER_RPW_ENTRY +{ + RTRECTSIZE Size; + /* We have to use 4 textures here. + * + * 1. iDrawTex - the texture clients can draw to and then submit it for contents acquisition via crServerRpwEntrySubmit + * 2. iSubmittedTex - the texture submitted to the worker for processing and, whose processing has not start yet, + * i.e. it is being in the queue and can be safely removed/replaced [from] there + * 3. iWorkerTex - the texture being prepared & passed by the worker to the GPU (stage 1 of a worker contents acquisition process) + * 4. iGpuTex - the texture passed/processed to/by the GPU, whose data is then acquired by the server (stage 2 of a worker contents acquisition process) + * + * - There can be valid distinct iGpuTex, iWorkerTex, iSubmittedTex and iDrawTex present simultaneously. + * - Either or both of iSubmittedTex and iFreeTex are always valid + * + * Detail: + * + * - iSubmittedTex and iFreeTex modifications are performed under CR_SERVER_RPW::CritSect lock. + * + * - iDrawTex can only be changed by client side (i.e. the crServerRpwEntrySubmit caller), this is why client thread can access it w/o a lock + * - iSubmittedTex and iFreeTex can be modified by both client and worker, so lock is always required + * + * - iDrawTex can be accessed by client code only + * - iWorkerTex and iGpuTex can be accessed by worker code only + * - iSubmittedTex and iFreeTex can be accessed under CR_SERVER_RPW::CritSect lock only + * - either or both of iSubmittedTex and iFreeTex are always valid (see below for more explanation), + * this is why client can easily determine the new iDrawTex value on Submit, i.e. : + * + * (if initial iSubmittedTex was valid) + * --------------- + * | ^ + * > | + * Submit-> iDrawTex -> iSubmittedTex + * ^ + * | (if initial iSubmittedTex was NOT valid) + * iFreeTex + * + * - The worker can invalidate the iSubmittedTex (i.e. do iSubmittedTex -> iWorkerTex) only after it is done + * with the last iWorkerTex -> iGpuTex transformation freeing the previously used iGpuTex to iFreeTex. + * + * - A simplified worker iXxxTex transformation logic is: + * 1. iFreeTex is initially valid + * 2. iSubmittedTex -> iWorkerTex; + * 3. submit iWorkerTex acquire request to the GPU + * 4. complete current iGpuTex + * 5. iGpuTex -> iFreeTex + * 6. iWorkerTex -> iGpuTex + * 7. goto 1 + * + * */ + int8_t iTexDraw; + int8_t iTexSubmitted; + int8_t iTexWorker; + int8_t iTexGpu; + int8_t iCurPBO; + GLuint aidWorkerTexs[4]; + GLuint aidPBOs[2]; + RTLISTNODE WorkEntry; + RTLISTNODE WorkerWorkEntry; + RTLISTNODE GpuSubmittedEntry; + PFNCR_SERVER_RPW_DATA pfnData; +} CR_SERVER_RPW_ENTRY; + +typedef struct CR_SERVER_RPW { + RTLISTNODE WorkList; + RTCRITSECT CritSect; + RTSEMEVENT hSubmitEvent; + /* only one outstanding command is supported, + * and ctl requests must be cynchronized, hold it right here */ + CR_SERVER_RPW_CTL Ctl; + int ctxId; + GLint ctxVisBits; + RTTHREAD hThread; +} CR_SERVER_RPW; +/* */ + +/* FRAMEBUFFER */ +typedef struct CR_FRAMEBUFFER *HCR_FRAMEBUFFER; +typedef struct CR_FRAMEBUFFER_ENTRY *HCR_FRAMEBUFFER_ENTRY; +/* */ + +typedef struct CR_FBDATA +{ + HCR_FRAMEBUFFER hFb; + HCR_FRAMEBUFFER_ENTRY hFbEntry; + CR_TEXDATA* apTexDatas[2]; +} CR_FBDATA; /** * Mural info */ @@ -88,30 +231,55 @@ typedef struct { int screenId; GLboolean bVisible; /*guest window is visible*/ - GLboolean bUseFBO; /*redirect to FBO instead of real host window*/ + GLubyte u8Unused; /*redirect to FBO instead of real host window*/ GLboolean bFbDraw; /*GL_FRONT buffer is drawn to directly*/ + GLboolean fIsDummyRefference; GLint cVisibleRects; /*count of visible rects*/ GLint *pVisibleRects; /*visible rects left, top, right, bottom*/ GLboolean bReceivedRects; /*indicates if guest did any updates for visible regions*/ - GLuint idFBO, idColorTex, idDepthStencilRB; + GLuint cBuffers; + GLuint iBbBuffer; + GLuint aidFBOs[2]; + GLuint aidColorTexs[2]; + + void *pvReserved; + + CRCreateInfoEx_t CreateInfo; + + /* to avoid saved state breakage we need to keep RT_OFFSETOF(CRMuralInfo, CreateInfo) intact + * this is why we place some FBO stuff to the tail + * @todo: once we need to increment a saved state version, we could refactor this structure */ + GLint iCurDrawBuffer; + GLint iCurReadBuffer; + + GLuint idDepthStencilRB; GLuint fboWidth, fboHeight; - GLuint idPBO; - void *pvOutputRedirectInstance; -} CRMuralInfo; + GLboolean fHasParentWindow; -typedef struct { - char *pszDpyName; - GLint visualBits; - int32_t externalID; -} CRCreateInfo_t; + GLboolean fRedirected; + GLboolean fForcePresentState; + GLboolean fOrPresentOnReenable; + + GLboolean fIsVisible; + + CR_TEXDATA aTexs[2]; + uint32_t cUsedFBDatas; + CR_FBDATA *apUsedFBDatas[CR_MAX_GUEST_MONITORS]; + CR_FBDATA aFBDatas[CR_MAX_GUEST_MONITORS]; + + /* bitfield representing contexts the mural has been ever current with + * we just reuse CR_STATE_SHAREDOBJ_USAGE_XXX API here for simplicity */ + CRbitvalue ctxUsage[CR_MAX_BITARRAY]; +} CRMuralInfo; typedef struct { CRContext *pContext; int SpuContext; - CRCreateInfo_t CreateInfo; + CRCreateInfoEx_t CreateInfo; + CRMuralInfo * currentMural; } CRContextInfo; /** @@ -168,10 +336,15 @@ typedef struct { } CRScreenInfo; typedef struct { - int32_t x, y; - uint32_t w, h; + RTRECT Rect; } CRScreenViewportInfo; +/* BFB (BlitFramebuffer Blitter) flags + * so far only CR_SERVER_BFB_ON_ALWAIS is supported and is alwais used if any flag is set */ +#define CR_SERVER_BFB_DISABLED 0 +#define CR_SERVER_BFB_ON_INVERTED_BLIT 1 +#define CR_SERVER_BFB_ON_STRAIGHT_BLIT 2 +#define CR_SERVER_BFB_ON_ALWAIS (CR_SERVER_BFB_ON_INVERTED_BLIT | CR_SERVER_BFB_ON_STRAIGHT_BLIT) typedef struct { unsigned short tcpip_port; @@ -194,14 +367,12 @@ typedef struct { CRContextInfo *currentCtxInfo; GLint currentWindow; GLint currentNativeWindow; + CRMuralInfo *currentMural; CRHashTable *muralTable; /**< hash table where all murals are stored */ - CRHashTable *pWindowCreateInfoTable; /**< hash table with windows creation info */ int client_spu_id; - CRServerFreeIDsPool_t idsPool; - int mtu; int buffer_size; char protocol[1024]; @@ -221,6 +392,23 @@ typedef struct { CRHashTable *programTable; /**< for vertex programs */ GLuint currentProgram; + /* visBits -> dummy mural association */ + CRHashTable *dummyMuralTable; + + GLboolean fRootVrOn; + VBOXVR_LIST RootVr; + /* we need to translate Root Vr to each window coords, this one cpecifies the current translation point + * note that since window attributes modifications is performed in HGCM thread only and thus is serialized, + * we deal with the global RootVr data directly */ + RTPOINT RootVrCurPoint; + + /* blitter so far used for working around host drivers BlitFramebuffer bugs + * by implementing */ + uint32_t fBlitterMode; + CR_BLITTER Blitter; + + CR_SERVER_RPW RpwWorker; + /** configuration options */ /*@{*/ int useL2; @@ -276,14 +464,38 @@ typedef struct { GLuint currentSerialNo; PFNCRSERVERPRESENTFBO pfnPresentFBO; - GLboolean bForceOffscreenRendering; /*Force server to render 3d data offscreen - *using callback above to update vbox framebuffers*/ + + GLuint fVisualBitsDefault; GLboolean bUsePBOForReadback; /*Use PBO's for data readback*/ - GLboolean bUseOutputRedirect; /* Whether the output redirect was set. */ CROutputRedirect outputRedirect; GLboolean bUseMultipleContexts; + + GLboolean bWindowsInitiallyHidden; + + /* OR-ed CR_VBOX_CAP_XXX cap values + * describing VBox Chromium functionality caps visible to guest + * Currently can have only CR_VBOX_CAP_TEX_PRESENT cap to notify + * that the TexPresent mechanism is available and enabled */ + uint32_t u32Caps; + + PFNCRSERVERNOTIFYEVENT pfnNotifyEventCB; + + SPUDispatchTable TmpCtxDispatch; + + VBOXCRCMD_SVRENABLE_INFO CrCmdClientInfo; + +#ifdef VBOX_WITH_CRSERVER_DUMPER + CR_RECORDER Recorder; + CR_BLITTER RecorderBlitter; + CR_DBGPRINT_DUMPER DbgPrintDumper; + CR_HTML_DUMPER HtmlDumper; + CR_DUMPER *pDumper; +#endif + + int RcToGuest; + int RcToGuestOnce; } CRServer; @@ -301,16 +513,31 @@ extern DECLEXPORT(void) crVBoxServerRemoveClient(uint32_t u32ClientID); extern DECLEXPORT(int32_t) crVBoxServerClientWrite(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t cbBuffer); extern DECLEXPORT(int32_t) crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t *pcbBuffer); extern DECLEXPORT(int32_t) crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor); +extern DECLEXPORT(int32_t) crVBoxServerClientGetCaps(uint32_t u32ClientID, uint32_t *pu32Caps); extern DECLEXPORT(int32_t) crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid); extern DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM); extern DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version); +typedef struct +{ + CR_BLITTER_IMG Img; + uint32_t u32Screen; + uint32_t fDataAllocated; +} CR_SCREENSHOT; + +extern DECLEXPORT(int) crServerVBoxWindowsShow(bool fShow); +extern DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, uint32_t width, uint32_t height, uint32_t pitch, void *pvBuffer, CR_SCREENSHOT *pScreenshot); +extern DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot); + +extern DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable); extern DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount); extern DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex); extern DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h, uint64_t winID); - -extern DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects); +extern DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable); +struct VBVAINFOSCREEN; +extern DECLEXPORT(int) crVBoxServerNotifyResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM); +extern DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects); extern DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO); @@ -320,6 +547,8 @@ extern DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect extern DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h); +extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb); + #ifdef VBOX_WITH_CRHGSMI /* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place. * @@ -336,8 +565,14 @@ extern DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, * */ extern DECLEXPORT(int32_t) crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd); extern DECLEXPORT(int32_t) crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl); + #endif +extern DECLEXPORT(int32_t) crVBoxServerHgcmEnable(HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd, PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd); +extern DECLEXPORT(int32_t) crVBoxServerHgcmDisable(); + +extern int crVBoxServerHostCtl(VBOXCRCMDCTL *pCtl, uint32_t cbCtl); + #ifdef __cplusplus } #endif diff --git a/src/VBox/GuestHost/OpenGL/include/cr_string.h b/src/VBox/GuestHost/OpenGL/include/cr_string.h index 87f1df38..972d08f1 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_string.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_string.h @@ -36,6 +36,30 @@ DECLEXPORT(int) crIsDigit( char c ); DECLEXPORT(void) crBytesToString( char *string, int nstring, void *data, int ndata ); DECLEXPORT(void) crWordsToString( char *string, int nstring, void *data, int ndata ); +#define CR_GLVERSION_OFFSET_MAJOR (24) +#define CR_GLVERSION_OFFSET_MINOR (16) +#define CR_GLVERSION_OFFSET_BUILD (0) + +#define CR_GLVERSION_MAX_MAJOR (0x7f) +#define CR_GLVERSION_MAX_MINOR (0xff) +#define CR_GLVERSION_MAX_BUILD (0xffff) + +#define CR_GLVERSION_MASK_MAJOR (CR_GLVERSION_MAX_MAJOR << CR_GLVERSION_OFFSET_MAJOR) +#define CR_GLVERSION_MASK_MINOR (CR_GLVERSION_MAX_MINOR << CR_GLVERSION_OFFSET_MINOR) +#define CR_GLVERSION_MASK_BUILD (CR_GLVERSION_MAX_BUILD << CR_GLVERSION_OFFSET_BUILD) + +#define CR_GLVERSION_COMPOSE_EL(_val, _type) (((_val) << CR_GLVERSION_OFFSET_##_type) & CR_GLVERSION_MASK_##_type) + +#define CR_GLVERSION_COMPOSE(_maj, _min, _build) (CR_GLVERSION_COMPOSE_EL((_maj), MAJOR) \ + + CR_GLVERSION_COMPOSE_EL((_min), MINOR) \ + + CR_GLVERSION_COMPOSE_EL((_build), BUILD)) + +#define CR_GLVERSION_GET_EL(_val, _type) (((_val) & CR_GLVERSION_MASK_##_type) >> CR_GLVERSION_OFFSET_##_type) +#define CR_GLVERSION_GET_MAJOR(_val) CR_GLVERSION_GET_EL((_val), MAJOR) +#define CR_GLVERSION_GET_MINOR(_val) CR_GLVERSION_GET_EL((_val), MINOR) +#define CR_GLVERSION_GET_BUILD(_val) CR_GLVERSION_GET_EL((_val), BUILD) + +DECLEXPORT(int) crStrParseGlVersion(const char * ver); RT_C_DECLS_END #endif /* CR_STRING_H */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_version.h b/src/VBox/GuestHost/OpenGL/include/cr_version.h index 06d99de6..6b6a7c5f 100644 --- a/src/VBox/GuestHost/OpenGL/include/cr_version.h +++ b/src/VBox/GuestHost/OpenGL/include/cr_version.h @@ -7,9 +7,40 @@ #ifndef CR_VERSION_H #define CR_VERSION_H -#define SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS 28 -#define SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING 29 -#define SHCROGL_SSM_VERSION 30 +#define SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS 28 +/* version which might have context usage bits saved */ +#define SHCROGL_SSM_VERSION_WITH_SAVED_CTXUSAGE_BITS SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS +#define SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING 29 +/* version that might have corrupted state data */ +#define SHCROGL_SSM_VERSION_WITH_CORUPTED_STATE 30 +/* version with invalid glGetError state */ +#define SHCROGL_SSM_VERSION_WITH_INVALID_ERROR_STATE 30 +/* VBox 4.2.12 had a bug that incorrectly CRMuralInfo data + * in a different format without changing the state version, + * i.e. 30 version can have both "correct" and "incorrect" CRMuralInfo data */ +#define SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO 30 +/* the saved state has incorrect front and back buffer image data */ +#define SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA 31 +#define SHCROGL_SSM_VERSION_WITH_STATE_BITS 33 +#define SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE 33 +#define SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL 34 +#define SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER 35 +/* some ogl drivers fail to Read/DrawPixels for DEPTH and STENCIL separately + * from DEPTH_STENCIL renderbuffer we used for offscreen rendering + * this is why we switched to glReadDrawPixels(GL_DEPTH_STENCIL) in one run */ +#define SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL 36 +#define SHCROGL_SSM_VERSION_WITH_PRESENT_STATE 37 +/* older state did not have glPointParameter ( GL_POINT_SPRITE_COORD_ORIGIN ) implementation */ +#define SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN 38 +/* dirty bits are not needed for now, remove */ +#define SHCROGL_SSM_VERSION_WITHOUT_DIRTY_BITS 38 +/* dummy windows and contexts have 0 external IDs, so never get stored to the state */ +#define SHCROGL_SSM_VERSION_WITH_FIXED_DUMMYIDS 39 +#define SHCROGL_SSM_VERSION_WITH_SCREEN_INFO 40 +#define SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS 41 +#define SHCROGL_SSM_VERSION_WITH_FB_INFO 42 +#define SHCROGL_SSM_VERSION_WITH_BUGGY_KEYS 42 +#define SHCROGL_SSM_VERSION 43 /* These define the Chromium release number. * Alpha Release = 0.1.0, Beta Release = 0.2.0 @@ -139,4 +170,6 @@ #define CR_EXT_blend_equation_separate 1 #define CR_EXT_stencil_two_side 1 +#define CR_GREMEDY_string_marker 1 + #endif /* CR_VERSION_H */ diff --git a/src/VBox/GuestHost/OpenGL/include/cr_vreg.h b/src/VBox/GuestHost/OpenGL/include/cr_vreg.h new file mode 100644 index 00000000..0f5786be --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/include/cr_vreg.h @@ -0,0 +1,377 @@ +/* $Id: cr_vreg.h $ */ + +/** @file + * Visible Regions processing API + */ + +/* + * Copyright (C) 2012 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 ___cr_vreg_h_ +#define ___cr_vreg_h_ + +#include <iprt/list.h> +#include <iprt/types.h> +#include <iprt/mem.h> +#include <iprt/string.h> +#include <iprt/assert.h> +#include <iprt/critsect.h> +#include <iprt/asm.h> + +#ifndef IN_RING0 +# define VBOXVREGDECL(_type) DECLEXPORT(_type) +#else +# define VBOXVREGDECL(_type) RTDECL(_type) +#endif + + + +RT_C_DECLS_BEGIN + +typedef struct VBOXVR_LIST +{ + RTLISTNODE ListHead; + uint32_t cEntries; +} VBOXVR_LIST, *PVBOXVR_LIST; + +DECLINLINE(int) VBoxRectCmp(const RTRECT * pRect1, const RTRECT * pRect2) +{ + return memcmp(pRect1, pRect2, sizeof (*pRect1)); +} + +#ifndef IN_RING0 +#define CR_FLOAT_RCAST(_t, _v) ((_t)((float)(_v) + 0.5)) + +DECLINLINE(void) VBoxRectScale(PRTRECT pRect, float xScale, float yScale) +{ + pRect->xLeft = CR_FLOAT_RCAST(int32_t, pRect->xLeft * xScale); + pRect->yTop = CR_FLOAT_RCAST(int32_t, pRect->yTop * yScale); + pRect->xRight = CR_FLOAT_RCAST(int32_t, pRect->xRight * xScale); + pRect->yBottom = CR_FLOAT_RCAST(int32_t, pRect->yBottom * yScale); +} + +DECLINLINE(void) VBoxRectScaled(const RTRECT *pRect, float xScale, float yScale, PRTRECT pResult) +{ + *pResult = *pRect; + VBoxRectScale(pResult, xScale, yScale); +} + +DECLINLINE(void) VBoxRectUnscale(PRTRECT pRect, float xScale, float yScale) +{ + pRect->xLeft = CR_FLOAT_RCAST(int32_t, pRect->xLeft / xScale); + pRect->yTop = CR_FLOAT_RCAST(int32_t, pRect->yTop / yScale); + pRect->xRight = CR_FLOAT_RCAST(int32_t, pRect->xRight / xScale); + pRect->yBottom = CR_FLOAT_RCAST(int32_t, pRect->yBottom / yScale); +} + +DECLINLINE(void) VBoxRectUnscaled(const RTRECT *pRect, float xScale, float yScale, PRTRECT pResult) +{ + *pResult = *pRect; + VBoxRectUnscale(pResult, xScale, yScale); +} +#endif + +DECLINLINE(void) VBoxRectIntersect(PRTRECT pRect1, const RTRECT * pRect2) +{ + Assert(pRect1); + Assert(pRect2); + pRect1->xLeft = RT_MAX(pRect1->xLeft, pRect2->xLeft); + pRect1->yTop = RT_MAX(pRect1->yTop, pRect2->yTop); + pRect1->xRight = RT_MIN(pRect1->xRight, pRect2->xRight); + pRect1->yBottom = RT_MIN(pRect1->yBottom, pRect2->yBottom); +} + +DECLINLINE(void) VBoxRectIntersected(const RTRECT *pRect1, const RTRECT * pRect2, RTRECT *pResult) +{ + *pResult = *pRect1; + VBoxRectIntersect(pResult, pRect2); +} + + +DECLINLINE(void) VBoxRectTranslate(RTRECT * pRect, int32_t x, int32_t y) +{ + pRect->xLeft += x; + pRect->yTop += y; + pRect->xRight += x; + pRect->yBottom += y; +} + +DECLINLINE(void) VBoxRectTranslated(const RTRECT * pRect, int32_t x, int32_t y, RTRECT *pResult) +{ + *pResult = *pRect; + VBoxRectTranslate(pResult, x, y); +} + +DECLINLINE(void) VBoxRectInvertY(RTRECT * pRect) +{ + int32_t y = pRect->yTop; + pRect->yTop = pRect->yBottom; + pRect->yBottom = y; +} + +DECLINLINE(void) VBoxRectInvertedY(const RTRECT * pRect, RTRECT * pResult) +{ + *pResult = *pRect; + VBoxRectInvertY(pResult); +} + +DECLINLINE(void) VBoxRectMove(RTRECT * pRect, int32_t x, int32_t y) +{ + int32_t w = pRect->xRight - pRect->xLeft; + int32_t h = pRect->yBottom - pRect->yTop; + pRect->xLeft = x; + pRect->yTop = y; + pRect->xRight = w + x; + pRect->yBottom = h + y; +} + +DECLINLINE(void) VBoxRectMoved(const RTRECT * pRect, int32_t x, int32_t y, RTRECT *pResult) +{ + *pResult = *pRect; + VBoxRectMove(pResult, x, y); +} + +DECLINLINE(bool) VBoxRectCovers(const RTRECT *pRect, const RTRECT *pCovered) +{ + Assert(pRect); + Assert(pCovered); + if (pRect->xLeft > pCovered->xLeft) + return false; + if (pRect->yTop > pCovered->yTop) + return false; + if (pRect->xRight < pCovered->xRight) + return false; + if (pRect->yBottom < pCovered->yBottom) + return false; + return true; +} + +DECLINLINE(bool) VBoxRectIsZero(const RTRECT *pRect) +{ + return pRect->xLeft == pRect->xRight || pRect->yTop == pRect->yBottom; +} + +DECLINLINE(bool) VBoxRectIsIntersect(const RTRECT * pRect1, const RTRECT * pRect2) +{ + return !((pRect1->xLeft < pRect2->xLeft && pRect1->xRight <= pRect2->xLeft) + || (pRect2->xLeft < pRect1->xLeft && pRect2->xRight <= pRect1->xLeft) + || (pRect1->yTop < pRect2->yTop && pRect1->yBottom <= pRect2->yTop) + || (pRect2->yTop < pRect1->yTop && pRect2->yBottom <= pRect1->yTop)); +} + +DECLINLINE(uint32_t) VBoxVrListRectsCount(const VBOXVR_LIST *pList) +{ + return pList->cEntries; +} + +DECLINLINE(bool) VBoxVrListIsEmpty(const VBOXVR_LIST *pList) +{ + return !VBoxVrListRectsCount(pList); +} + +DECLINLINE(void) VBoxVrListInit(PVBOXVR_LIST pList) +{ + RTListInit(&pList->ListHead); + pList->cEntries = 0; +} + +VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList); + +/* moves list data to pDstList and empties the pList */ +VBOXVREGDECL(void) VBoxVrListMoveTo(PVBOXVR_LIST pList, PVBOXVR_LIST pDstList); + +VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y); + +VBOXVREGDECL(int) VBoxVrListCmp(const VBOXVR_LIST *pList1, const VBOXVR_LIST *pList2); + +VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects); + +VBOXVREGDECL(int) VBoxVrListClone(const VBOXVR_LIST *pList, VBOXVR_LIST *pDstList); + +/* NOTE: with the current implementation the VBoxVrListIntersect is faster than VBoxVrListRectsIntersect, + * i.e. VBoxVrListRectsIntersect is actually a convenience function that create a temporary list and calls VBoxVrListIntersect internally */ +VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged); + +VBOXVREGDECL(int) VBoxVrInit(void); +VBOXVREGDECL(void) VBoxVrTerm(void); + +typedef struct VBOXVR_LIST_ITERATOR +{ + PVBOXVR_LIST pList; + PRTLISTNODE pNextEntry; +} VBOXVR_LIST_ITERATOR, *PVBOXVR_LIST_ITERATOR; + +DECLINLINE(void) VBoxVrListIterInit(PVBOXVR_LIST pList, PVBOXVR_LIST_ITERATOR pIter) +{ + pIter->pList = pList; + pIter->pNextEntry = pList->ListHead.pNext; +} + +typedef struct VBOXVR_REG +{ + RTLISTNODE ListEntry; + RTRECT Rect; +} VBOXVR_REG, *PVBOXVR_REG; + +#define PVBOXVR_REG_FROM_ENTRY(_pEntry) ((PVBOXVR_REG)(((uint8_t*)(_pEntry)) - RT_OFFSETOF(VBOXVR_REG, ListEntry))) + +DECLINLINE(PCRTRECT) VBoxVrListIterNext(PVBOXVR_LIST_ITERATOR pIter) +{ + PRTLISTNODE pNextEntry = pIter->pNextEntry; + if (pNextEntry != &pIter->pList->ListHead) + { + PCRTRECT pRect = &(PVBOXVR_REG_FROM_ENTRY(pNextEntry)->Rect); + pIter->pNextEntry = pNextEntry->pNext; + return pRect; + } + return NULL; +} + +typedef struct VBOXVR_COMPOSITOR_ENTRY +{ + RTLISTNODE Node; + VBOXVR_LIST Vr; + uint32_t cRefs; +} VBOXVR_COMPOSITOR_ENTRY, *PVBOXVR_COMPOSITOR_ENTRY; + +struct VBOXVR_COMPOSITOR; + +typedef DECLCALLBACK(void) FNVBOXVRCOMPOSITOR_ENTRY_RELEASED(const struct VBOXVR_COMPOSITOR *pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry); +typedef FNVBOXVRCOMPOSITOR_ENTRY_RELEASED *PFNVBOXVRCOMPOSITOR_ENTRY_RELEASED; + +typedef struct VBOXVR_COMPOSITOR +{ + RTLISTNODE List; + PFNVBOXVRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased; +} VBOXVR_COMPOSITOR, *PVBOXVR_COMPOSITOR; + +typedef DECLCALLBACK(bool) FNVBOXVRCOMPOSITOR_VISITOR(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor); +typedef FNVBOXVRCOMPOSITOR_VISITOR *PFNVBOXVRCOMPOSITOR_VISITOR; + +VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased); +VBOXVREGDECL(void) VBoxVrCompositorClear(PVBOXVR_COMPOSITOR pCompositor); +VBOXVREGDECL(void) VBoxVrCompositorRegionsClear(PVBOXVR_COMPOSITOR pCompositor, bool *pfChanged); +VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry); +DECLINLINE(bool) VBoxVrCompositorEntryIsInList(const VBOXVR_COMPOSITOR_ENTRY *pEntry) +{ + return !VBoxVrListIsEmpty(&pEntry->Vr); +} + +#define CRBLT_F_LINEAR 0x00000001 +#define CRBLT_F_INVERT_SRC_YCOORDS 0x00000002 +#define CRBLT_F_INVERT_DST_YCOORDS 0x00000004 +#define CRBLT_F_INVERT_YCOORDS (CRBLT_F_INVERT_SRC_YCOORDS | CRBLT_F_INVERT_DST_YCOORDS) +/* the blit operation with discard the source alpha channel values and set the destination alpha values to 1.0 */ +#define CRBLT_F_NOALPHA 0x00000010 + +#define CRBLT_FTYPE_XOR CRBLT_F_INVERT_YCOORDS +#define CRBLT_FTYPE_OR (CRBLT_F_LINEAR | CRBLT_F_NOALPHA) +#define CRBLT_FOP_COMBINE(_f1, _f2) ((((_f1) ^ (_f2)) & CRBLT_FTYPE_XOR) | (((_f1) | (_f2)) & CRBLT_FTYPE_OR)) + +#define CRBLT_FLAGS_FROM_FILTER(_f) ( ((_f) & GL_LINEAR) ? CRBLT_F_LINEAR : 0) +#define CRBLT_FILTER_FROM_FLAGS(_f) (((_f) & CRBLT_F_LINEAR) ? GL_LINEAR : GL_NEAREST) + +/* compositor regions changed */ +#define VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED 0x00000001 +/* other entries changed along while doing current entry modification + * always comes with VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED */ +#define VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED 0x00000002 +/* only current entry regions changed + * can come wither with VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED or with VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED */ +#define VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED 0x00000004 +/* the given entry has replaced some other entry, while overal regions did NOT change. + * always comes with VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED */ +#define VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED 0x00000008 + + +VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry); +VBOXVREGDECL(bool) VBoxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pNewEntry); +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, PVBOXVR_COMPOSITOR_ENTRY *ppReplacedEntry, uint32_t *pfChangeFlags); +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged); +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged); +VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor); + +DECLINLINE(bool) VBoxVrCompositorIsEmpty(const VBOXVR_COMPOSITOR *pCompositor) +{ + return RTListIsEmpty(&pCompositor->List); +} + +typedef struct VBOXVR_COMPOSITOR_ITERATOR +{ + PVBOXVR_COMPOSITOR pCompositor; + PRTLISTNODE pNextEntry; +} VBOXVR_COMPOSITOR_ITERATOR ,*PVBOXVR_COMPOSITOR_ITERATOR; + +typedef struct VBOXVR_COMPOSITOR_CONST_ITERATOR +{ + const VBOXVR_COMPOSITOR *pCompositor; + const RTLISTNODE *pNextEntry; +} VBOXVR_COMPOSITOR_CONST_ITERATOR ,*PVBOXVR_COMPOSITOR_CONST_ITERATOR; + +DECLINLINE(void) VBoxVrCompositorIterInit(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ITERATOR pIter) +{ + pIter->pCompositor = pCompositor; + pIter->pNextEntry = pCompositor->List.pNext; +} + +DECLINLINE(void) VBoxVrCompositorConstIterInit(const VBOXVR_COMPOSITOR *pCompositor, PVBOXVR_COMPOSITOR_CONST_ITERATOR pIter) +{ + pIter->pCompositor = pCompositor; + pIter->pNextEntry = pCompositor->List.pNext; +} + +#define VBOXVR_COMPOSITOR_ENTRY_FROM_NODE(_p) ((PVBOXVR_COMPOSITOR_ENTRY)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVR_COMPOSITOR_ENTRY, Node))) +#define VBOXVR_COMPOSITOR_CONST_ENTRY_FROM_NODE(_p) ((const VBOXVR_COMPOSITOR_ENTRY*)(((uint8_t*)(_p)) - RT_OFFSETOF(VBOXVR_COMPOSITOR_ENTRY, Node))) + +DECLINLINE(PVBOXVR_COMPOSITOR_ENTRY) VBoxVrCompositorIterNext(PVBOXVR_COMPOSITOR_ITERATOR pIter) +{ + PRTLISTNODE pNextEntry = pIter->pNextEntry; + if (pNextEntry != &pIter->pCompositor->List) + { + PVBOXVR_COMPOSITOR_ENTRY pEntry = VBOXVR_COMPOSITOR_ENTRY_FROM_NODE(pNextEntry); + pIter->pNextEntry = pNextEntry->pNext; + return pEntry; + } + return NULL; +} + +DECLINLINE(const VBOXVR_COMPOSITOR_ENTRY*) VBoxVrCompositorConstIterNext(PVBOXVR_COMPOSITOR_CONST_ITERATOR pIter) +{ + const RTLISTNODE *pNextEntry = pIter->pNextEntry; + if (pNextEntry != &pIter->pCompositor->List) + { + const VBOXVR_COMPOSITOR_ENTRY *pEntry = VBOXVR_COMPOSITOR_CONST_ENTRY_FROM_NODE(pNextEntry); + pIter->pNextEntry = pNextEntry->pNext; + return pEntry; + } + return NULL; +} + +typedef struct VBOXVR_TEXTURE +{ + int32_t width; + int32_t height; + uint32_t target; + uint32_t hwid; +} VBOXVR_TEXTURE, *PVBOXVR_TEXTURE; + +RT_C_DECLS_END + +#endif /* #ifndef ___cr_vreg_h_ */ diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_attrib.h b/src/VBox/GuestHost/OpenGL/include/state/cr_attrib.h index 855f5736..579e71dd 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_attrib.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_attrib.h @@ -245,6 +245,18 @@ typedef struct { GLenum passDepthPass; GLint clearValue; GLint writeMask; +} CRStencilBufferStack_v_33; + +typedef struct { + /* true if stencil test is enabled */ + GLboolean stencilTest; + /* true if GL_EXT_stencil_two_side is enabled (glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)) */ + GLboolean stencilTwoSideEXT; + /* GL_FRONT or GL_BACK */ + GLenum activeStencilFace; + GLint clearValue; + GLint writeMask; + CRStencilBufferState buffers[CRSTATE_STENCIL_BUFFER_COUNT]; } CRStencilBufferStack; typedef struct { diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_bufferobject.h b/src/VBox/GuestHost/OpenGL/include/state/cr_bufferobject.h index d83ac973..8584adc0 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_bufferobject.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_bufferobject.h @@ -41,10 +41,8 @@ typedef struct { so we need to resync every time guest wants to read from it*/ CRbitvalue dirty[CR_MAX_BITARRAY]; /* dirty data or state */ GLintptrARB dirtyStart, dirtyLength; /* dirty region */ -#ifndef IN_GUEST /* bitfield representing the object usage. 1 means the object is used by the context with the given bitid */ CRbitvalue ctxUsage[CR_MAX_BITARRAY]; -#endif } CRBufferObject; typedef struct { @@ -59,10 +57,13 @@ typedef struct { DECLEXPORT(CRBufferObject *) crStateGetBoundBufferObject(GLenum target, CRBufferObjectState *b); DECLEXPORT(GLboolean) crStateIsBufferBound(GLenum target); +struct CRContext; +DECLEXPORT(GLboolean) crStateIsBufferBoundForCtx(struct CRContext *g, GLenum target); DECLEXPORT(GLuint) STATE_APIENTRY crStateBufferHWIDtoID(GLuint hwid); DECLEXPORT(GLuint) STATE_APIENTRY crStateGetBufferHWID(GLuint id); +DECLEXPORT(void) crStateRegBuffers(GLsizei n, GLuint *buffers); #ifdef __cplusplus } #endif diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_client.h b/src/VBox/GuestHost/OpenGL/include/state/cr_client.h index e328857a..a727f260 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_client.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_client.h @@ -125,10 +125,12 @@ typedef struct { extern const CRPixelPackState crStateNativePixelPacking; +struct CRContext; + DECLEXPORT(void) crStateClientInitBits(CRClientBits *c); DECLEXPORT(void) crStateClientDestroyBits(CRClientBits *c); -DECLEXPORT(void) crStateClientInit(CRClientState *c); -DECLEXPORT(void) crStateClientDestroy(CRClientState *c); +DECLEXPORT(void) crStateClientInit(struct CRContext *g); +DECLEXPORT(void) crStateClientDestroy(struct CRContext *g); DECLEXPORT(GLboolean) crStateUseServerArrays(void); DECLEXPORT(GLboolean) crStateUseServerArrayElements(void); diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_framebuffer.h b/src/VBox/GuestHost/OpenGL/include/state/cr_framebuffer.h index adc7b3b2..f8da8a7c 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_framebuffer.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_framebuffer.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -48,10 +48,9 @@ typedef struct { GLenum drawbuffer[1]; #ifdef IN_GUEST GLenum status; -#else +#endif /* bitfield representing the object usage. 1 means the object is used by the context with the given bitid */ CRbitvalue ctxUsage[CR_MAX_BITARRAY]; -#endif } CRFramebufferObject; typedef struct { @@ -59,10 +58,8 @@ typedef struct { GLsizei width, height; GLenum internalformat; GLuint redBits, greenBits, blueBits, alphaBits, depthBits, stencilBits; -#ifndef IN_GUEST /* bitfield representing the object usage. 1 means the object is used by the context with the given bitid */ CRbitvalue ctxUsage[CR_MAX_BITARRAY]; -#endif } CRRenderbufferObject; typedef struct { @@ -74,8 +71,8 @@ DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectInit(CRContext *ctx); DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectDestroy(CRContext *ctx); DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectSwitch(CRContext *from, CRContext *to); -DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idFBO); -DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idFBO); +DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idDrawFBO, GLuint idReadFBO); +DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idDrawFBO, GLuint idReadFBO); DECLEXPORT(GLuint) STATE_APIENTRY crStateGetFramebufferHWID(GLuint id); DECLEXPORT(GLuint) STATE_APIENTRY crStateGetRenderbufferHWID(GLuint id); @@ -96,6 +93,9 @@ DECLEXPORT(void) STATE_APIENTRY crStateGenerateMipmapEXT(GLenum target); DECLEXPORT(GLuint) STATE_APIENTRY crStateFBOHWIDtoID(GLuint hwid); DECLEXPORT(GLuint) STATE_APIENTRY crStateRBOHWIDtoID(GLuint hwid); +DECLEXPORT(void) crStateRegFramebuffers(GLsizei n, GLuint *buffers); +DECLEXPORT(void) crStateRegRenderbuffers(GLsizei n, GLuint *buffers); + #ifdef IN_GUEST DECLEXPORT(GLenum) STATE_APIENTRY crStateCheckFramebufferStatusEXT(GLenum target); DECLEXPORT(GLenum) STATE_APIENTRY crStateSetFramebufferStatus(GLenum target, GLenum status); diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_glsl.h b/src/VBox/GuestHost/OpenGL/include/state/cr_glsl.h index 2713c434..81ed568e 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_glsl.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_glsl.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -99,6 +99,7 @@ DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsIntUniform(GLenum type); DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateShader(GLuint id, GLenum type); DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateProgram(GLuint id); +DECLEXPORT(GLuint) STATE_APIENTRY crStateDeleteObjectARB( VBoxGLhandleARB obj ); DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsProgramUniformsCached(GLuint program); diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_point.h b/src/VBox/GuestHost/OpenGL/include/state/cr_point.h index 4f5987b0..fe3dffe3 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_point.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_point.h @@ -28,6 +28,7 @@ typedef struct { CRbitvalue enableSprite[CR_MAX_BITARRAY]; CRbitvalue coordReplacement[CR_MAX_TEXTURE_UNITS][CR_MAX_BITARRAY]; #endif + CRbitvalue spriteCoordOrigin[CR_MAX_BITARRAY]; CRbitvalue dirty[CR_MAX_BITARRAY]; } CRPointBits; @@ -43,6 +44,8 @@ typedef struct { GLboolean pointSprite; GLboolean coordReplacement[CR_MAX_TEXTURE_UNITS]; #endif + GLfloat spriteCoordOrigin; + GLfloat reserved; /* added to make sure alignment of sttructures following CRPointState in CRContext does not change */ } CRPointState; DECLEXPORT(void) crStatePointInit (CRContext *ctx); diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_stencil.h b/src/VBox/GuestHost/OpenGL/include/state/cr_stencil.h index 1443e951..27823eb2 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_stencil.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_stencil.h @@ -11,33 +11,89 @@ #include "state/cr_statetypes.h" #include <iprt/cdefs.h> +#include <iprt/assert.h> #ifdef __cplusplus extern "C" { #endif +#define CRSTATE_STENCIL_BUFFER_ID_FRONT 0 +#define CRSTATE_STENCIL_BUFFER_ID_BACK 1 +#define CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK 2 +#define CRSTATE_STENCIL_BUFFER_COUNT 3 + +/* stencil buffer settings were accessed with StencilXxx with ActiveStencilFaceEXT == GL_FRONT or StencilXxxSeparate(GL_FRONT_AND_BACK) */ +#define CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK 0 +/* stencil buffer settings were accessed with StencilXxxSeparate(GL_FRONT_FRONT) */ +#define CRSTATE_STENCIL_BUFFER_REF_ID_FRONT 1 +/* stencil buffer settings were accessed with StencilXxxSeparate(GL_FRONT_BACK) */ +#define CRSTATE_STENCIL_BUFFER_REF_ID_BACK 2 +/* stencil buffer settings were accessed with StencilXxx with ActiveStencilFaceEXT == GL_BACK */ +#define CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK 3 +#define CRSTATE_STENCIL_BUFFER_REF_COUNT 4 + +typedef struct { + CRbitvalue dirty[CR_MAX_BITARRAY]; + CRbitvalue enable[CR_MAX_BITARRAY]; + CRbitvalue func[CR_MAX_BITARRAY]; + CRbitvalue op[CR_MAX_BITARRAY]; + CRbitvalue clearValue[CR_MAX_BITARRAY]; + CRbitvalue writeMask[CR_MAX_BITARRAY]; +} CRStencilBits_v_33; + +typedef struct { + CRbitvalue func[CR_MAX_BITARRAY]; + CRbitvalue op[CR_MAX_BITARRAY]; +} CRStencilBufferRefBits; + typedef struct { - CRbitvalue dirty[CR_MAX_BITARRAY]; - CRbitvalue enable[CR_MAX_BITARRAY]; - CRbitvalue func[CR_MAX_BITARRAY]; - CRbitvalue op[CR_MAX_BITARRAY]; - CRbitvalue clearValue[CR_MAX_BITARRAY]; - CRbitvalue writeMask[CR_MAX_BITARRAY]; + CRbitvalue dirty[CR_MAX_BITARRAY]; + CRbitvalue enable[CR_MAX_BITARRAY]; + CRbitvalue enableTwoSideEXT[CR_MAX_BITARRAY]; + CRbitvalue activeStencilFace[CR_MAX_BITARRAY]; + CRbitvalue clearValue[CR_MAX_BITARRAY]; + CRbitvalue writeMask[CR_MAX_BITARRAY]; + /* note: here we use _BUFFER_REF_ rather than _REF_ because we track the way buffers are accessed here, + * to ensure the correct function is called on hw->chromium state restoration, + * i.e. we want to avoid always calling StencilXxxSeparate, but call StencilXxx when it was actually called */ + CRStencilBufferRefBits bufferRefs[CRSTATE_STENCIL_BUFFER_REF_COUNT]; } CRStencilBits; typedef struct { + GLboolean stencilTest; + GLenum func; + GLint mask; + GLint ref; + GLenum fail; + GLenum passDepthFail; + GLenum passDepthPass; + GLint clearValue; + GLint writeMask; +} CRStencilState_v_33; + +typedef struct { + GLenum func; + GLint mask; + GLint ref; + GLenum fail; + GLenum passDepthFail; + GLenum passDepthPass; +} CRStencilBufferState; + +typedef struct { + /* true if stencil test is enabled */ GLboolean stencilTest; - GLenum func; - GLint mask; - GLint ref; - GLenum fail; - GLenum passDepthFail; - GLenum passDepthPass; - GLint clearValue; - GLint writeMask; + /* true if GL_EXT_stencil_two_side is enabled (glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT)) */ + GLboolean stencilTwoSideEXT; + /* GL_FRONT or GL_BACK */ + GLenum activeStencilFace; + GLint clearValue; + GLint writeMask; + CRStencilBufferState buffers[CRSTATE_STENCIL_BUFFER_COUNT]; } CRStencilState; DECLEXPORT(void) crStateStencilInit(CRContext *ctx); +DECLEXPORT(void) crStateStencilBufferInit(CRStencilBufferState *s); DECLEXPORT(void) crStateStencilDiff(CRStencilBits *bb, CRbitvalue *bitID, CRContext *fromCtx, CRContext *toCtx); diff --git a/src/VBox/GuestHost/OpenGL/include/state/cr_texture.h b/src/VBox/GuestHost/OpenGL/include/state/cr_texture.h index 5d0262d4..c55d0da9 100644 --- a/src/VBox/GuestHost/OpenGL/include/state/cr_texture.h +++ b/src/VBox/GuestHost/OpenGL/include/state/cr_texture.h @@ -96,10 +96,8 @@ typedef struct { CRbitvalue dirty[CR_MAX_BITARRAY]; CRbitvalue imageBit[CR_MAX_BITARRAY]; CRbitvalue paramsBit[CR_MAX_TEXTURE_UNITS][CR_MAX_BITARRAY]; -#ifndef IN_GUEST /* bitfield representing the object usage. 1 means the object is used by the context with the given bitid */ CRbitvalue ctxUsage[CR_MAX_BITARRAY]; -#endif } CRTextureObj; typedef struct { @@ -242,6 +240,8 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateTextureHWIDtoID(GLuint hwid); DECLEXPORT(GLuint) STATE_APIENTRY crStateGetTextureHWID(GLuint id); DECLEXPORT(GLuint) STATE_APIENTRY crStateGetTextureObjHWID(CRTextureObj *tobj); +void crStateRegTextures(GLsizei n, GLuint *names); + #ifdef __cplusplus } #endif diff --git a/src/VBox/GuestHost/OpenGL/packer/opcodes.py b/src/VBox/GuestHost/OpenGL/packer/opcodes.py index e198150b..f359d218 100644 --- a/src/VBox/GuestHost/OpenGL/packer/opcodes.py +++ b/src/VBox/GuestHost/OpenGL/packer/opcodes.py @@ -50,21 +50,50 @@ print "} CROpcode;\n" # count up number of extended opcode commands num_extends = 0 +num_auto_codes = 0 for func in keys: if "extpack" in apiutil.ChromiumProps(func): num_extends += 1 + if apiutil.ChromiumRelOpCode(func) < 0: + num_auto_codes += 1 + +# sanity check for compatibility breakage +# we currently have 304 +if num_auto_codes != 304: + print >> sys.stderr, "number of auto-generated op-codes should be 304, but is " + str(num_auto_codes) + print >> sys.stderr, "which breaks backwards compatibility" + print >> sys.stderr, "if this is really what you want to do, please adjust this script" + print >> sys.stderr, "to handle a new auto-generated opcodes count" + print "#error -- num_auto_codes should be 304, but is " + str(num_auto_codes) + sys.exit(-1) print "/* Functions with a return value or output parameters */" print "typedef enum {" +opcode_index = 0 enum_index = 0 +chrelopcodes = {} for func in keys: if "extpack" in apiutil.ChromiumProps(func): opcodeName = apiutil.ExtendedOpcodeName(func) + chrelopcode = apiutil.ChromiumRelOpCode(func) + opcode = -1 + if chrelopcode >= 0: + if not chrelopcode in chrelopcodes.keys(): + chrelopcodes[chrelopcode] = chrelopcode + else: + print >> sys.stderr, "non-unique chrelopcode: " + str(chrelopcode) + print "#error -- non-unique chrelopcode: " + str(num_auto_codes) + sys.exit(-1) + opcode = num_auto_codes + chrelopcode + else: + opcode = opcode_index + opcode_index = opcode_index + 1 + if enum_index != num_extends-1: - print "\t%s = %d," % (opcodeName, enum_index ) + print "\t%s = %d," % (opcodeName, opcode ) else: - print "\t%s = %d" % (opcodeName, enum_index ) + print "\t%s = %d" % (opcodeName, opcode ) enum_index = enum_index + 1 print "} CRExtendOpcode;\n" print "#endif /* CR_OPCODES_H */" diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c b/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c index 48d1250a..d4ddaf5f 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_buffer.c @@ -149,7 +149,11 @@ void crPackResetPointers( CRPackContext *pc ) const GLboolean canBarf = pc->buffer.canBarf; CRPackBuffer *buf = pc->currentBuffer; CRASSERT(buf); - crPackInitBuffer( buf, buf->pack, buf->size, buf->mtu ); + crPackInitBuffer( buf, buf->pack, buf->size, buf->mtu +#ifdef IN_RING0 + , 0 +#endif + ); pc->buffer.geometry_only = geom_only; /* restore the flag */ pc->buffer.holds_BeginEnd = holds_BeginEnd; pc->buffer.in_BeginEnd = in_BeginEnd; @@ -221,9 +225,15 @@ crPackMaxData( int buffer_size ) * has 'mtu' bytes in it, we have to send it. The MTU might * be somewhat smaller than the buffer size. */ -void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int mtu ) +void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int mtu +#ifdef IN_RING0 + , unsigned int num_opcodes +#endif + ) { +#ifndef IN_RING0 unsigned int num_opcodes; +#endif CRASSERT(mtu <= size); @@ -231,7 +241,16 @@ void crPackInitBuffer( CRPackBuffer *buf, void *pack, int size, int mtu ) buf->mtu = mtu; buf->pack = pack; - num_opcodes = crPackMaxOpcodes( buf->size ); +#ifdef IN_RING0 + if(num_opcodes) + { + num_opcodes = (num_opcodes + 0x3) & (~0x3); + } + else +#endif + { + num_opcodes = crPackMaxOpcodes( buf->size ); + } buf->data_start = (unsigned char *) buf->pack + num_opcodes + sizeof(CRMessageOpcodes); diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_extensions.c b/src/VBox/GuestHost/OpenGL/packer/pack_extensions.c index 14b86a91..a8ae7fc4 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_extensions.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_extensions.c @@ -6,8 +6,6 @@ #include "packer.h" -#include <GL/glext.h> - int __packTexParameterNumParams( GLenum param ) { switch( param ) diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_framebuffer.c b/src/VBox/GuestHost/OpenGL/packer/pack_framebuffer.c index ab904d37..bc1ab543 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_framebuffer.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_framebuffer.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_misc.c b/src/VBox/GuestHost/OpenGL/packer/pack_misc.c index 40da1223..ebc0e5bd 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_misc.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_misc.c @@ -7,7 +7,7 @@ #include "packer.h" #include "cr_error.h" -void PACK_APIENTRY crPackChromiumParametervCR(GLenum target, GLenum type, GLsizei count, const GLvoid *values) +void PACK_APIENTRY crPackChromiumParametervCR(CR_PACKER_CONTEXT_ARGDECL GLenum target, GLenum type, GLsizei count, const GLvoid *values) { CR_GET_PACKER_CONTEXT(pc); unsigned int header_length = 2 * sizeof(int) + sizeof(target) + sizeof(type) + sizeof(count); @@ -29,9 +29,11 @@ void PACK_APIENTRY crPackChromiumParametervCR(GLenum target, GLenum type, GLsize case GL_UNSIGNED_INT: params_length = sizeof(GLint) * count; break; +#ifndef IN_RING0 case GL_FLOAT: params_length = sizeof(GLfloat) * count; break; +#endif #if 0 case GL_DOUBLE: params_length = sizeof(GLdouble) * count; @@ -74,11 +76,13 @@ void PACK_APIENTRY crPackChromiumParametervCR(GLenum target, GLenum type, GLsize WRITE_DATA( pos, GLint, ((GLint *) values)[i]); } break; +#ifndef IN_RING0 case GL_FLOAT: for (i = 0; i < count; i++, pos += sizeof(GLfloat)) { WRITE_DATA( pos, GLfloat, ((GLfloat *) values)[i]); } break; +#endif #if 0 case GL_DOUBLE: for (i = 0; i < count; i++) { @@ -95,7 +99,8 @@ void PACK_APIENTRY crPackChromiumParametervCR(GLenum target, GLenum type, GLsize CR_UNLOCK_PACKER_CONTEXT(pc); } -void PACK_APIENTRY crPackDeleteQueriesARB(GLsizei n, const GLuint * ids) +#ifndef IN_RING0 +void PACK_APIENTRY crPackDeleteQueriesARB(CR_PACKER_CONTEXT_ARGDECL GLsizei n, const GLuint * ids) { unsigned char *data_ptr; int packet_length = sizeof(GLenum)+sizeof(n)+n*sizeof(*ids); @@ -107,3 +112,78 @@ void PACK_APIENTRY crPackDeleteQueriesARB(GLsizei n, const GLuint * ids) crHugePacket(CR_EXTEND_OPCODE, data_ptr); crPackFree(data_ptr); } +#endif + +void PACK_APIENTRY crPackVBoxTexPresent( CR_PACKER_CONTEXT_ARGDECL GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint * pRects ) +{ + GLint i, size, cnt; + + CR_GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + size = 28 + cRects * 4 * sizeof(GLint); + CR_GET_BUFFERED_POINTER( pc, size ); + WRITE_DATA( 0, GLint, size ); + WRITE_DATA( 4, GLenum, CR_VBOXTEXPRESENT_EXTEND_OPCODE ); + WRITE_DATA( 8, GLuint, texture ); + WRITE_DATA( 12, GLuint, cfg ); + WRITE_DATA( 16, GLint, xPos ); + WRITE_DATA( 20, GLint, yPos ); + WRITE_DATA( 24, GLint, cRects ); + + cnt = 28; + for (i=0; i<cRects; ++i) + { + WRITE_DATA(cnt, GLint, (GLint) pRects[4*i+0]); + WRITE_DATA(cnt+4, GLint, (GLint) pRects[4*i+1]); + WRITE_DATA(cnt+8, GLint, (GLint) pRects[4*i+2]); + WRITE_DATA(cnt+12, GLint, (GLint) pRects[4*i+3]); + cnt += 16; + } + WRITE_OPCODE( pc, CR_EXTEND_OPCODE ); + CR_UNLOCK_PACKER_CONTEXT(pc); +} + +void PACK_APIENTRY crPackWindowPosition( CR_PACKER_CONTEXT_ARGDECL GLint window, GLint x, GLint y ) +{ + CR_GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + CR_GET_BUFFERED_POINTER( pc, 20 ); + WRITE_DATA( 0, GLint, 20 ); + WRITE_DATA( 4, GLenum, CR_WINDOWPOSITION_EXTEND_OPCODE ); + WRITE_DATA( 8, GLint, window ); + WRITE_DATA( 12, GLint, x ); + WRITE_DATA( 16, GLint, y ); + WRITE_OPCODE( pc, CR_EXTEND_OPCODE ); + CR_UNLOCK_PACKER_CONTEXT(pc); +} + +void PACK_APIENTRY crPackWindowShow( CR_PACKER_CONTEXT_ARGDECL GLint window, GLint flag ) +{ + CR_GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + CR_GET_BUFFERED_POINTER( pc, 16 ); + WRITE_DATA( 0, GLint, 16 ); + WRITE_DATA( 4, GLenum, CR_WINDOWSHOW_EXTEND_OPCODE ); + WRITE_DATA( 8, GLint, window ); + WRITE_DATA( 12, GLint, flag ); + WRITE_OPCODE( pc, CR_EXTEND_OPCODE ); + CR_UNLOCK_PACKER_CONTEXT(pc); +} + +void PACK_APIENTRY crPackWindowSize( CR_PACKER_CONTEXT_ARGDECL GLint window, GLint w, GLint h ) +{ + CR_GET_PACKER_CONTEXT(pc); + unsigned char *data_ptr; + (void) pc; + CR_GET_BUFFERED_POINTER( pc, 20 ); + WRITE_DATA( 0, GLint, 20 ); + WRITE_DATA( 4, GLenum, CR_WINDOWSIZE_EXTEND_OPCODE ); + WRITE_DATA( 8, GLint, window ); + WRITE_DATA( 12, GLint, w ); + WRITE_DATA( 16, GLint, h ); + WRITE_OPCODE( pc, CR_EXTEND_OPCODE ); + CR_UNLOCK_PACKER_CONTEXT(pc); +} diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_pixels.c b/src/VBox/GuestHost/OpenGL/packer/pack_pixels.c index 19f2a1d5..2508643a 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_pixels.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_pixels.c @@ -143,7 +143,8 @@ void PACK_APIENTRY crPackBitmap(GLsizei width, GLsizei height, WRITE_DATA( 24, GLuint, noimagedata ); WRITE_DATA( 28, GLint, (GLint) (uintptr_t) bitmap); - crBitmapCopy(width, height, (GLubyte *)(data_ptr + 32), bitmap, unpack); + if (!noimagedata) + crBitmapCopy(width, height, (GLubyte *)(data_ptr + 32), bitmap, unpack); crHugePacket( CR_BITMAP_OPCODE, data_ptr ); crPackFree( data_ptr ); diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_shaders.c b/src/VBox/GuestHost/OpenGL/packer/pack_shaders.c index 36fc6bea..b788bd4d 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_shaders.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_shaders.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -52,7 +52,7 @@ void PACK_APIENTRY crPackShaderSource(GLuint shader, GLsizei count, const char * for (i=0; i<count; ++i) { - pLocalLength[i] = (length && (length[i]>=0)) ? length[i] : crStrlen(string[i])+1; + pLocalLength[i] = ((length && (length[i]>=0)) ? length[i] : crStrlen(string[i]))+1; packet_length += pLocalLength[i]; } @@ -80,7 +80,17 @@ void PACK_APIENTRY crPackShaderSource(GLuint shader, GLsizei count, const char * { if (string[i]) { - crMemcpy(data_ptr, string[i], pLocalLength[i]); + if (length && (length[i]>=0)) + { + /* include \0 in the string to make intel drivers happy */ + crMemcpy(data_ptr, string[i], pLocalLength[i] - 1); + data_ptr[pLocalLength[i] - 1] = '\0'; + } + else + { + /* the \0 s already in the string */ + crMemcpy(data_ptr, string[i], pLocalLength[i]); + } } else { @@ -458,7 +468,7 @@ void PACK_APIENTRY crPackGetAttachedShaders(GLuint program, GLsizei maxCount, GL CR_UNLOCK_PACKER_CONTEXT(pc); } -void PACK_APIENTRY crPackGetAttachedObjectsARB(GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj, int * writeback) +void PACK_APIENTRY crPackGetAttachedObjectsARB(VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * count, VBoxGLhandleARB * obj, int * writeback) { CR_GET_PACKER_CONTEXT(pc); unsigned char *data_ptr; @@ -466,7 +476,7 @@ void PACK_APIENTRY crPackGetAttachedObjectsARB(GLhandleARB containerObj, GLsizei CR_GET_BUFFERED_POINTER(pc, 32); WRITE_DATA(0, GLint, 32); WRITE_DATA(4, GLenum, CR_GETATTACHEDOBJECTSARB_EXTEND_OPCODE); - WRITE_DATA(8, GLhandleARB, containerObj); + WRITE_DATA(8, VBoxGLhandleARB, containerObj); WRITE_DATA(12, GLsizei, maxCount); WRITE_NETWORK_POINTER(16, (void *) count); WRITE_NETWORK_POINTER(24, (void *) writeback); @@ -474,7 +484,7 @@ void PACK_APIENTRY crPackGetAttachedObjectsARB(GLhandleARB containerObj, GLsizei CR_UNLOCK_PACKER_CONTEXT(pc); } -void PACK_APIENTRY crPackGetInfoLogARB(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog, int * writeback) +void PACK_APIENTRY crPackGetInfoLogARB(VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog, int * writeback) { CR_GET_PACKER_CONTEXT(pc); unsigned char *data_ptr; @@ -482,7 +492,7 @@ void PACK_APIENTRY crPackGetInfoLogARB(GLhandleARB obj, GLsizei maxLength, GLsiz CR_GET_BUFFERED_POINTER(pc, 32); WRITE_DATA(0, GLint, 32); WRITE_DATA(4, GLenum, CR_GETINFOLOGARB_EXTEND_OPCODE); - WRITE_DATA(8, GLhandleARB, obj); + WRITE_DATA(8, VBoxGLhandleARB, obj); WRITE_DATA(12, GLsizei, maxLength); WRITE_NETWORK_POINTER(16, (void *) length); WRITE_NETWORK_POINTER(24, (void *) writeback); diff --git a/src/VBox/GuestHost/OpenGL/packer/pack_visibleregion.c b/src/VBox/GuestHost/OpenGL/packer/pack_visibleregion.c index d76fc29c..e0155fc7 100644 --- a/src/VBox/GuestHost/OpenGL/packer/pack_visibleregion.c +++ b/src/VBox/GuestHost/OpenGL/packer/pack_visibleregion.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,7 +22,7 @@ #include <windows.h> #endif -void PACK_APIENTRY crPackWindowVisibleRegion( GLint window, GLint cRects, GLint * pRects ) +void PACK_APIENTRY crPackWindowVisibleRegion( CR_PACKER_CONTEXT_ARGDECL GLint window, GLint cRects, const GLint * pRects ) { GLint i, size, cnt; @@ -49,7 +49,7 @@ void PACK_APIENTRY crPackWindowVisibleRegion( GLint window, GLint cRects, GLint CR_UNLOCK_PACKER_CONTEXT(pc); } -void PACK_APIENTRY crPackWindowVisibleRegionSWAP( GLint window, GLint cRects, GLint * pRects ) +void PACK_APIENTRY crPackWindowVisibleRegionSWAP( CR_PACKER_CONTEXT_ARGDECL GLint window, GLint cRects, const GLint * pRects ) { crError( "crPackWindowVisibleRegionSWAP unimplemented and shouldn't be called" ); } diff --git a/src/VBox/GuestHost/OpenGL/packer/packer.h b/src/VBox/GuestHost/OpenGL/packer/packer.h index 965799a0..f70a5bb4 100644 --- a/src/VBox/GuestHost/OpenGL/packer/packer.h +++ b/src/VBox/GuestHost/OpenGL/packer/packer.h @@ -18,6 +18,10 @@ #include "packer_extensions.h" #include "cr_mem.h" +#ifndef IN_RING0 extern void __PackError( int line, const char *file, GLenum error, const char *info ); +#else +# define __PackError( line, file, error, info) do { AssertReleaseFailed(); } while (0) +#endif #endif /* CR_PACKER_H */ diff --git a/src/VBox/GuestHost/OpenGL/packer/packer.py b/src/VBox/GuestHost/OpenGL/packer/packer.py index a2708438..386b6bec 100644 --- a/src/VBox/GuestHost/OpenGL/packer/packer.py +++ b/src/VBox/GuestHost/OpenGL/packer/packer.py @@ -113,9 +113,9 @@ def UpdateCurrentPointer( func_name ): def PrintFunc( func_name, params, is_swapped, can_have_pointers ): """Emit a packer function.""" if is_swapped: - print 'void PACK_APIENTRY crPack%sSWAP( %s )' % (func_name, apiutil.MakeDeclarationString(params)) + print 'void PACK_APIENTRY crPack%sSWAP( %s )' % (func_name, apiutil.MakeDeclarationStringWithContext('CR_PACKER_CONTEXT', params)) else: - print 'void PACK_APIENTRY crPack%s( %s )' % (func_name, apiutil.MakeDeclarationString(params)) + print 'void PACK_APIENTRY crPack%s( %s )' % (func_name, apiutil.MakeDeclarationStringWithContext('CR_PACKER_CONTEXT', params)) print '{' print '\tCR_GET_PACKER_CONTEXT(pc);' diff --git a/src/VBox/GuestHost/OpenGL/packer/packer_special b/src/VBox/GuestHost/OpenGL/packer/packer_special index 848a05c5..b37cf2f3 100644 --- a/src/VBox/GuestHost/OpenGL/packer/packer_special +++ b/src/VBox/GuestHost/OpenGL/packer/packer_special @@ -176,3 +176,7 @@ UniformMatrix2x4fv UniformMatrix4x2fv UniformMatrix3x4fv UniformMatrix4x3fv +VBoxTexPresent +WindowPosition +WindowShow +WindowSize diff --git a/src/VBox/GuestHost/OpenGL/spu_loader/glloader.py b/src/VBox/GuestHost/OpenGL/spu_loader/glloader.py index 0eb78aa2..a84f7299 100644 --- a/src/VBox/GuestHost/OpenGL/spu_loader/glloader.py +++ b/src/VBox/GuestHost/OpenGL/spu_loader/glloader.py @@ -65,10 +65,6 @@ static CRDLL *aglDll = NULL; #define GLLOADER_APIENTRY #endif -#if defined(WINDOWS) && (defined(DEBUG_leo) || defined(DEBUG_ll158262) || defined(DEBUG_misha)) -# define CR_NO_GL_SYSTEM_PATH 1 -#endif - /* * Add an entry to the SPUNamedFunctionTable */ diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp b/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp new file mode 100644 index 00000000..8132d9f9 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp @@ -0,0 +1,1741 @@ +/* $Id: dump.cpp $ */ + +/** @file + * Blitter API implementation + */ +/* + * Copyright (C) 2013 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_blitter.h" +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "cr_mem.h" +#include "cr_string.h" +#include <cr_dump.h> +#include "cr_pixeldata.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/mem.h> + +#include <stdio.h> + +#ifdef VBOX_WITH_CRDUMPER + +static uint32_t g_CrDbgDumpRecTexInfo = 1; +static uint32_t g_CrDbgDumpAlphaData = 1; + +/* dump stuff */ +#pragma pack(1) +typedef struct VBOX_BITMAPFILEHEADER { + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +} VBOX_BITMAPFILEHEADER; + +typedef struct VBOX_BITMAPINFOHEADER { + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +} VBOX_BITMAPINFOHEADER; +#pragma pack() + +void crDmpImgBmp(CR_BLITTER_IMG *pImg, const char *pszFilename) +{ + static int sIdx = 0; + + if ( pImg->bpp != 16 + && pImg->bpp != 24 + && pImg->bpp != 32) + { + crWarning("not supported bpp %d", pImg->bpp); + return; + } + + FILE *f = fopen (pszFilename, "wb"); + if (!f) + { + crWarning("fopen failed"); + return; + } + + VBOX_BITMAPFILEHEADER bf; + + bf.bfType = 'MB'; + bf.bfSize = sizeof (VBOX_BITMAPFILEHEADER) + sizeof (VBOX_BITMAPINFOHEADER) + pImg->cbData; + bf.bfReserved1 = 0; + bf.bfReserved2 = 0; + bf.bfOffBits = sizeof (VBOX_BITMAPFILEHEADER) + sizeof (VBOX_BITMAPINFOHEADER); + + VBOX_BITMAPINFOHEADER bi; + + bi.biSize = sizeof (bi); + bi.biWidth = pImg->width; + bi.biHeight = pImg->height; + bi.biPlanes = 1; + bi.biBitCount = pImg->bpp; + bi.biCompression = 0; + bi.biSizeImage = pImg->cbData; + bi.biXPelsPerMeter = 0; + bi.biYPelsPerMeter = 0; + bi.biClrUsed = 0; + bi.biClrImportant = 0; + + fwrite (&bf, 1, sizeof (bf), f); + fwrite (&bi, 1, sizeof (bi), f); + fwrite (pImg->pvData, 1, pImg->cbData, f); + + fclose (f); +} + +typedef struct CRDUMPGETHWID_DATA +{ + GLuint hwid; + PFNCRDUMPGETHWID pfnGetHwid; + unsigned long Key; + void* pvObj; +} CRDUMPGETHWID_DATA; + +static void crDmpHashtableSearchByHwidCB(unsigned long key, void *pData1, void *pData2) +{ + CRDUMPGETHWID_DATA *pData = (CRDUMPGETHWID_DATA*)pData2; + if (pData->pvObj) + return; + + if (pData->hwid == pData->pfnGetHwid(pData1)) + { + pData->Key = key; + pData->pvObj = pData1; + } +} + +void* crDmpHashtableSearchByHwid(CRHashTable *pHash, GLuint hwid, PFNCRDUMPGETHWID pfnGetHwid, unsigned long *pKey) +{ + CRDUMPGETHWID_DATA Data = {0}; + Data.hwid = hwid; + Data.pfnGetHwid = pfnGetHwid; + crHashtableWalk(pHash, crDmpHashtableSearchByHwidCB, &Data); + + Assert(Data.pvObj); + + if (pKey) + *pKey = Data.Key; + return Data.pvObj; +} + +#if 0 +typedef struct CR_SERVER_DUMP_FIND_TEX +{ + GLint hwid; + CRTextureObj *pTobj +} CR_SERVER_DUMP_FIND_TEX; + +void crServerDumpFindTexCb(unsigned long key, void *pData1, void *pData2) +{ + CR_SERVER_DUMP_FIND_TEX *pTex = (CR_SERVER_DUMP_FIND_TEX*)pData2; + CRTextureObj *pTobj = (CRTextureObj *)pData1; + if (pTobj->hwid == pTex->hwid) + pTex->pTobj = pTobj; +} +#endif + +#define CR_DUMP_MAKE_CASE(_val) case _val: return #_val +#define CR_DUMP_MAKE_CASE_UNKNOWN(_val, _str, _pDumper) default: { \ + crWarning("%s %d", (_str), _val); \ + crDmpStrF((_pDumper), "WARNING: %s %d", (_str), _val); \ + return (_str); \ +} + +DECLINLINE(size_t) crDmpFormatVal(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbVal, const void *pvVal) +{ + if (pszElFormat[0] != '%' || pszElFormat[1] == '\0') + { + crWarning("invalid format %s", pszElFormat); + return 0; + } + switch (cbVal) + { + case 8: + return sprintf_s(pString, cbString, pszElFormat, *((double*)pvVal)); + case 4: + { + /* we do not care only about type specifiers, all the rest is not accepted */ + switch (pszElFormat[1]) + { + case 'f': + /* float would be promoted to double */ + return sprintf_s(pString, cbString, pszElFormat, *((float*)pvVal)); + default: + return sprintf_s(pString, cbString, pszElFormat, *((uint32_t*)pvVal)); + } + } + case 2: + return sprintf_s(pString, cbString, pszElFormat, *((uint16_t*)pvVal)); + case 1: + return sprintf_s(pString, cbString, pszElFormat, *((uint8_t*)pvVal)); + default: + crWarning("unsupported size %d", cbVal); + return 0; + } +} + +VBOXDUMPDECL(size_t) crDmpFormatRawArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + if (cbString < 2) + { + crWarning("too few buffer size"); + return 0; + } + + const size_t cbInitString = cbString; + *pString++ = '{'; + --cbString; + size_t cbWritten; + const uint8_t *pu8Val = (const uint8_t *)pvVal; + for (uint32_t i = 0; i < cVal; ++i) + { + cbWritten = crDmpFormatVal(pString, cbString, pszElFormat, cbEl, (const void *)pu8Val); + pu8Val += cbEl; + Assert(cbString >= cbWritten); + pString += cbWritten; + cbString -= cbWritten; + if (i != cVal - 1) + { + cbWritten = sprintf_s(pString, cbString, ", "); + Assert(cbString >= cbWritten); + pString += cbWritten; + cbString -= cbWritten; + } + } + + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '}'; + --cbString; + + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '\0'; + + return cbInitString - cbString; +} + +VBOXDUMPDECL(size_t) crDmpFormatMatrixArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cX, uint32_t cY) +{ + if (cbString < 2) + { + crWarning("too few buffer size"); + return 0; + } + + const size_t cbInitString = cbString; + *pString++ = '{'; + --cbString; + size_t cbWritten; + const uint8_t *pu8Val = (const uint8_t *)pvVal; + for (uint32_t i = 0; i < cY; ++i) + { + cbWritten = crDmpFormatRawArray(pString, cbString, pszElFormat, cbEl, (const void *)pu8Val, cX); + pu8Val += (cbEl * cX); + Assert(cbString >= cbWritten); + pString += cbWritten; + cbString -= cbWritten; + if (i != cY - 1) + { + if (cbString < 3) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = ','; + --cbString; + *pString++ = '\n'; + --cbString; + } + } + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '}'; + --cbString; + + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '\0'; + + return cbInitString - cbString; +} + +VBOXDUMPDECL(size_t) crDmpFormatArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + switch(cVal) + { + case 1: + return crDmpFormatVal(pString, cbString, pszElFormat, cbEl, pvVal); + case 16: + return crDmpFormatMatrixArray(pString, cbString, pszElFormat, cbEl, pvVal, 4, 4); + case 9: + return crDmpFormatMatrixArray(pString, cbString, pszElFormat, cbEl, pvVal, 3, 3); + case 0: + crWarning("value array is empty"); + return 0; + default: + return crDmpFormatRawArray(pString, cbString, pszElFormat, cbEl, pvVal, cVal); + } +} + +VBOXDUMPDECL(void) crRecDumpVertAttrv(CR_RECORDER *pRec, CRContext *ctx, GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + char aBuf[1024]; + crDmpFormatRawArray(aBuf, sizeof (aBuf), pszElFormat, cbEl, pvVal, cVal); + crDmpStrF(pRec->pDumper, "(%u, %s)", idx, aBuf); +} + +VBOXDUMPDECL(void) crRecDumpVertAttrV(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, va_list pArgList) +{ + crDmpStrV(pRec->pDumper, pszFormat, pArgList); +} + +VBOXDUMPDECL(void) crRecDumpVertAttrF(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, ...) +{ + va_list pArgList; + va_start(pArgList, pszFormat); + crRecDumpVertAttrV(pRec, ctx, pszFormat, pArgList); + va_end(pArgList); +} + +void crRecDumpBuffer(CR_RECORDER *pRec, CRContext *ctx, GLint idRedirFBO, VBOXVR_TEXTURE *pRedirTex) +{ + GLenum texTarget = 0; + GLint hwBuf = 0, hwDrawBuf = 0; + GLint hwTex = 0, hwObjType = 0, hwTexLevel = 0, hwCubeFace = 0; + GLint width = 0, height = 0, depth = 0; + GLint id = 0; + CR_BLITTER_IMG Img = {0}; + VBOXVR_TEXTURE Tex; + int rc; + + pRec->pDispatch->GetIntegerv(GL_DRAW_BUFFER, &hwDrawBuf); + pRec->pDispatch->GetIntegerv(GL_FRAMEBUFFER_BINDING, &hwBuf); + if (hwBuf) + { + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &hwTex); + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &hwObjType); + if (hwObjType == GL_TEXTURE) + { + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &hwTexLevel); + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, &hwCubeFace); + if (hwCubeFace) + { + crWarning("cube face: unsupported"); + return; + } + + if (hwTexLevel) + { + crWarning("non-zero tex level attached, unsupported"); + return; + } + } + else + { + crWarning("unsupported"); + return; + } + } + else + { + crWarning("no buffer attached: unsupported"); + return; + } + + if (ctx->framebufferobject.drawFB) + { + GLuint iColor = (hwDrawBuf - GL_COLOR_ATTACHMENT0_EXT); + CRTextureObj *pTobj = (CRTextureObj *)crHashtableSearch(ctx->shared->textureTable, ctx->framebufferobject.drawFB->color[iColor].name); + CRTextureLevel *pTl = NULL; + + id = pTobj->id; + + Assert(iColor < RT_ELEMENTS(ctx->framebufferobject.drawFB->color)); + + if (!pTobj) + { + crWarning("no tobj"); + return; + } + Assert(pTobj->hwid == hwTex); + Assert(pTobj); + Assert(ctx->framebufferobject.drawFB->hwid); + Assert(ctx->framebufferobject.drawFB->hwid == hwBuf); + Assert(ctx->framebufferobject.drawFB->drawbuffer[0] == hwDrawBuf); + + Assert(ctx->framebufferobject.drawFB->color[iColor].level == hwTexLevel); + Assert(ctx->framebufferobject.drawFB->color[iColor].type == hwObjType); + + texTarget = pTobj->target; + + Assert(texTarget == GL_TEXTURE_2D); + + pTl = &pTobj->level[0][hwTexLevel]; + + rc = CrBltEnter(pRec->pBlitter); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltEnter failed, rc %d", rc); + return; + } + + pRec->pDispatch->BindTexture(texTarget, hwTex); + + pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_WIDTH, &width); + pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_HEIGHT, &height); + pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pTl->width); + Assert(height == pTl->height); + Assert(depth == pTl->depth); + + pRec->pDispatch->BindTexture(texTarget, 0); + } + else + { + Assert(hwBuf == idRedirFBO); + if (!pRedirTex) + { + crWarning("pRedirTex is expected for non-FBO state!"); + return; + } + + Assert(hwTex == pRedirTex->hwid); + + texTarget = pRedirTex->target; + + width = pRedirTex->width; + height = pRedirTex->height; + + rc = CrBltEnter(pRec->pBlitter); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltEnter failed, rc %d", rc); + return; + } + } + + Tex.width = width; + Tex.height = height; + Tex.target = texTarget; + Tex.hwid = hwTex; + + rc = CrBltImgGetTex(pRec->pBlitter, &Tex, GL_BGRA, &Img); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &Img, "ctx(%d), BUFFER: id(%d) hwid(%d), width(%d), height(%d)", ctx, id, Tex.hwid, width, height); + + if (g_CrDbgDumpAlphaData) + { + CR_BLITTER_IMG AlphaImg = {0}; + rc = crRecAlphaImgCreate(&Img, &AlphaImg); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &AlphaImg, "Buffer ALPHA Data"); + crRecAlphaImgDestroy(&AlphaImg); + } + else + { + crWarning("crRecAlphaImgCreate failed rc %d", rc); + } + } + + CrBltImgFree(pRec->pBlitter, &Img); + } + else + { + crWarning("CrBltImgGetTex failed, rc %d", rc); + } + + CrBltLeave(pRec->pBlitter); +} + +static const char *crRecDumpShaderTypeString(GLenum enmType, CR_DUMPER *pDumper) +{ + switch (enmType) + { + CR_DUMP_MAKE_CASE(GL_VERTEX_SHADER_ARB); + CR_DUMP_MAKE_CASE(GL_FRAGMENT_SHADER_ARB); + CR_DUMP_MAKE_CASE(GL_GEOMETRY_SHADER_ARB); + CR_DUMP_MAKE_CASE_UNKNOWN(enmType, "Unknown Shader Type", pDumper); + } +} + +static const char *crRecDumpVarTypeString(GLenum enmType, CR_DUMPER *pDumper) +{ + switch (enmType) + { + CR_DUMP_MAKE_CASE(GL_BYTE); + CR_DUMP_MAKE_CASE(GL_UNSIGNED_BYTE); + CR_DUMP_MAKE_CASE(GL_SHORT); + CR_DUMP_MAKE_CASE(GL_UNSIGNED_SHORT); + CR_DUMP_MAKE_CASE(GL_FLOAT); + CR_DUMP_MAKE_CASE(GL_DOUBLE); + CR_DUMP_MAKE_CASE(GL_FLOAT_VEC2); + CR_DUMP_MAKE_CASE(GL_FLOAT_VEC3); + CR_DUMP_MAKE_CASE(GL_FLOAT_VEC4); + CR_DUMP_MAKE_CASE(GL_INT); + CR_DUMP_MAKE_CASE(GL_UNSIGNED_INT); + CR_DUMP_MAKE_CASE(GL_INT_VEC2); + CR_DUMP_MAKE_CASE(GL_INT_VEC3); + CR_DUMP_MAKE_CASE(GL_INT_VEC4); + CR_DUMP_MAKE_CASE(GL_BOOL); + CR_DUMP_MAKE_CASE(GL_BOOL_VEC2); + CR_DUMP_MAKE_CASE(GL_BOOL_VEC3); + CR_DUMP_MAKE_CASE(GL_BOOL_VEC4); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4); + CR_DUMP_MAKE_CASE(GL_SAMPLER_1D); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D); + CR_DUMP_MAKE_CASE(GL_SAMPLER_3D); + CR_DUMP_MAKE_CASE(GL_SAMPLER_CUBE); + CR_DUMP_MAKE_CASE(GL_SAMPLER_1D_SHADOW); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_SHADOW); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_RECT_ARB); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_RECT_SHADOW_ARB); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2x3); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2x4); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3x2); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3x4); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4x2); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4x3); + CR_DUMP_MAKE_CASE_UNKNOWN(enmType, "Unknown Variable Type", pDumper); + } +} + +static char *crRecDumpGetLine(char **ppszStr, uint32_t *pcbStr) +{ + char *pszStr, *pNewLine; + const uint32_t cbStr = *pcbStr; + + if (!cbStr) + { + /* zero-length string */ + return NULL; + } + + if ((*ppszStr)[cbStr-1] != '\0') + { + crWarning("string should be null-rerminated, forcing it!"); + (*ppszStr)[cbStr-1] = '\0'; + } + pszStr = *ppszStr; + if (!*pszStr) + { + *pcbStr = 0; + return NULL; + } + + if (!(pNewLine = strstr(pszStr, "\n"))) + { + /* the string contains a single line! */ + *ppszStr += strlen(pszStr); + *pcbStr = 0; + return pszStr; + } + + *pNewLine = '\0'; + *pcbStr = cbStr - (((uintptr_t)pNewLine) - ((uintptr_t)pszStr)) - 1; + Assert((*pcbStr) < UINT32_MAX/2); + Assert((*pcbStr) < cbStr); + *ppszStr = pNewLine + 1; + + return pszStr; +} + +static void crRecDumpStrByLine(CR_DUMPER *pDumper, char *pszStr, uint32_t cbStr) +{ + char *pszCurLine; + while ((pszCurLine = crRecDumpGetLine(&pszStr, &cbStr)) != NULL) + { + crDmpStrF(pDumper, "%s", pszCurLine); + } +} + +static DECLCALLBACK(GLuint) crDmpGetHwidShaderCB(void *pvObj) +{ + return ((CRGLSLShader*)pvObj)->hwid; +} + +static DECLCALLBACK(GLuint) crDmpGetHwidProgramCB(void *pvObj) +{ + return ((CRGLSLProgram*)pvObj)->hwid; +} + +/* Context activation is done by the caller. */ +void crRecDumpLog(CR_RECORDER *pRec, GLint hwid) +{ + GLint cbLog = 0; + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_INFO_LOG_LENGTH_ARB, &cbLog); + + crDmpStrF(pRec->pDumper, "Log===%d===", hwid); + + if (cbLog > 1) + { + GLchar *pszLog = (GLchar *) crAlloc(cbLog*sizeof (GLchar)); + + pRec->pDispatch->GetInfoLogARB(hwid, cbLog, NULL, pszLog); + + crRecDumpStrByLine(pRec->pDumper, pszLog, cbLog); + + crFree(pszLog); + } + crDmpStrF(pRec->pDumper, "End Log======"); +} + +void crRecDumpShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint length = 0; + GLint type = 0; + GLint compileStatus = 0; + +#ifndef IN_GUEST + CRGLSLShader *pShad; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pShad = (CRGLSLShader *)crDmpHashtableSearchByHwid(ctx->glsl.shaders, hwid, crDmpGetHwidShaderCB, &tstKey); + Assert(pShad); + if (!pShad) + return; + id = pShad->id; + Assert(tstKey == id); + } + else + { + pShad = (CRGLSLShader *)crHashtableSearch(ctx->glsl.shaders, id); + Assert(pShad); + if (!pShad) + return; + } + + if (!hwid) + hwid = pShad->hwid; + + Assert(pShad->hwid == hwid); + Assert(pShad->id == id); +#else + if (!id) + id = hwid; + else if (!hwid) + hwid = id; + + Assert(id); + Assert(hwid); + Assert(hwid == id); +#endif + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SUBTYPE_ARB, &type); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); + crDmpStrF(pRec->pDumper, "SHADER ctx(%d) id(%d) hwid(%d) type(%s) status(%d):", ctx->id, id, hwid, crRecDumpShaderTypeString(type, pRec->pDumper), compileStatus); + + crRecDumpLog(pRec, hwid); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &length); + + char *pszSource = (char*)crCalloc(length + 1); + if (!pszSource) + { + crWarning("crCalloc failed"); + crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed"); + return; + } + + pRec->pDispatch->GetShaderSource(hwid, length, NULL, pszSource); + crRecDumpStrByLine(pRec->pDumper, pszSource, length); + + crFree(pszSource); + + crDmpStr(pRec->pDumper, "===END SHADER===="); +} + +void crRecDumpProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint cShaders = 0, linkStatus = 0; + char *source = NULL; + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_ATTACHED_OBJECTS_ARB, &cShaders); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); + + crDmpStrF(pRec->pDumper, "PROGRAM ctx(%d) id(%d) hwid(%d) status(%d) shaders(%d):", ctx->id, id, hwid, linkStatus, cShaders); + + crRecDumpLog(pRec, hwid); + + VBoxGLhandleARB *pShaders = (VBoxGLhandleARB*)crCalloc(cShaders * sizeof (*pShaders)); + if (!pShaders) + { + crWarning("crCalloc failed"); + crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed"); + return; + } + + pRec->pDispatch->GetAttachedObjectsARB(hwid, cShaders, NULL, pShaders); + for (GLint i = 0; i < cShaders; ++i) + { + if (pShaders[i]) + crRecDumpShader(pRec, ctx, 0, pShaders[i]); + else + crDmpStrF(pRec->pDumper, "WARNING: Shader[%d] is null", i); + } + + crFree(pShaders); + + GLsizei cbLog = 0; + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_INFO_LOG_LENGTH_ARB, &cbLog); + if (cbLog) + { + char *pszLog = (char *)crCalloc(cbLog+1); + pRec->pDispatch->GetInfoLogARB(hwid, cbLog, NULL, pszLog); + crDmpStrF(pRec->pDumper, "==LOG=="); + crRecDumpStrByLine(pRec->pDumper, pszLog, cbLog); + crDmpStrF(pRec->pDumper, "==Done LOG=="); + crFree(pszLog); + } + else + { + crDmpStrF(pRec->pDumper, "==No LOG=="); + } + + crDmpStr(pRec->pDumper, "===END PROGRAM===="); +} + +void crRecRecompileShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint length = 0; + GLint type = 0; + GLint compileStatus = 0; + CRGLSLShader *pShad; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pShad = (CRGLSLShader *)crDmpHashtableSearchByHwid(ctx->glsl.shaders, hwid, crDmpGetHwidShaderCB, &tstKey); + Assert(pShad); + if (!pShad) + return; + id = pShad->id; + Assert(tstKey == id); + } + else + { + pShad = (CRGLSLShader *)crHashtableSearch(ctx->glsl.shaders, id); + Assert(pShad); + if (!pShad) + return; + } + + if (!hwid) + hwid = pShad->hwid; + + Assert(pShad->hwid == hwid); + Assert(pShad->id == id); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SUBTYPE_ARB, &type); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); + crDmpStrF(pRec->pDumper, "==RECOMPILE SHADER ctx(%d) id(%d) hwid(%d) type(%s) status(%d)==", ctx->id, id, hwid, crRecDumpShaderTypeString(type, pRec->pDumper), compileStatus); + + compileStatus = 0; + GLenum status; + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {/*Assert(0);*/} + pRec->pDispatch->CompileShader(hwid); + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {Assert(0);} + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); + + crDmpStrF(pRec->pDumper, "==Done RECOMPILE SHADER, status(%d)==", compileStatus); +} + +void crRecRecompileProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint cShaders = 0, linkStatus = 0; + char *source = NULL; + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_ATTACHED_OBJECTS_ARB, &cShaders); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); + + crDmpStrF(pRec->pDumper, "==RECOMPILE PROGRAM ctx(%d) id(%d) hwid(%d) status(%d) shaders(%d)==", ctx->id, id, hwid, linkStatus, cShaders); + + VBoxGLhandleARB *pShaders = (VBoxGLhandleARB*)crCalloc(cShaders * sizeof (*pShaders)); + if (!pShaders) + { + crWarning("crCalloc failed"); + crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed"); + return; + } + + pRec->pDispatch->GetAttachedObjectsARB(hwid, cShaders, NULL, pShaders); + for (GLint i = 0; i < cShaders; ++i) + { + crRecRecompileShader(pRec, ctx, 0, pShaders[i]); + } + + crFree(pShaders); + + linkStatus = 0; + GLenum status; + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {/*Assert(0);*/} + pRec->pDispatch->LinkProgram(hwid); + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {Assert(0);} + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); + + crDmpStrF(pRec->pDumper, "==Done RECOMPILE PROGRAM, status(%d)==", linkStatus); +} + +VBOXDUMPDECL(void) crRecDumpCurrentProgram(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecDumpProgram(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +void crRecDumpProgramUniforms(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + GLint maxUniformLen = 0, activeUniforms = 0, i, j, uniformsCount = 0; + GLenum type; + GLint size, location; + GLchar *pszName = NULL; + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen); + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_UNIFORMS, &activeUniforms); + + if (!maxUniformLen) + { + if (activeUniforms) + { + crWarning("activeUniforms (%d), while maxUniformLen is zero", activeUniforms); + activeUniforms = 0; + } + } + + if (activeUniforms>0) + { + pszName = (GLchar *) crAlloc((maxUniformLen+8)*sizeof(GLchar)); + + if (!pszName) + { + crWarning("crRecDumpProgramUniforms: out of memory"); + return; + } + } + + for (i=0; i<activeUniforms; ++i) + { + pRec->pDispatch->GetActiveUniform(hwid, i, maxUniformLen, NULL, &size, &type, pszName); + uniformsCount += size; + } + Assert(uniformsCount>=activeUniforms); + + if (activeUniforms>0) + { + GLfloat fdata[16]; + GLint idata[16]; + char *pIndexStr=NULL; + + for (i=0; i<activeUniforms; ++i) + { + bool fPrintBraketsWithName = false; + pRec->pDispatch->GetActiveUniform(hwid, i, maxUniformLen, NULL, &size, &type, pszName); + + if (size>1) + { + pIndexStr = crStrchr(pszName, '['); + if (!pIndexStr) + { + pIndexStr = pszName+crStrlen(pszName); + fPrintBraketsWithName = true; + } + } + + if (fPrintBraketsWithName) + { + crDmpStrF(pRec->pDumper, "%s %s[%d];", crRecDumpVarTypeString(type, pRec->pDumper), pszName, size); + Assert(size > 1); + } + else + crDmpStrF(pRec->pDumper, "%s %s;", crRecDumpVarTypeString(type, pRec->pDumper), pszName); + + GLint uniformTypeSize = crStateGetUniformSize(type); + Assert(uniformTypeSize >= 1); + + for (j=0; j<size; ++j) + { + if (size>1) + { + sprintf(pIndexStr, "[%i]", j); + } + location = pRec->pDispatch->GetUniformLocation(hwid, pszName); + + if (crStateIsIntUniform(type)) + { + pRec->pDispatch->GetUniformiv(hwid, location, &idata[0]); + switch (uniformTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %d; //location %d", pszName, idata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%d, %d}; //location %d", pszName, idata[0], idata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], idata[3], location); + break; + default: + for (GLint k = 0; k < uniformTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %d; //location %d", pszName, k, idata[k], location); + } + break; + } + } + else + { + pRec->pDispatch->GetUniformfv(hwid, location, &fdata[0]); + switch (uniformTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %f; //location %d", pszName, fdata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%f, %f}; //location %d", pszName, fdata[0], fdata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], fdata[3], location); + break; + default: + for (GLint k = 0; k < uniformTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %f; //location %d", pszName, k, fdata[k], location); + } + break; + } + } + } + } + + crFree(pszName); + } +} + +void crRecDumpProgramAttribs(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + GLint maxAttribLen = 0, activeAttrib = 0, i, j, attribCount = 0; + GLenum type; + GLint size, location; + GLchar *pszName = NULL; + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLen); + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_ATTRIBUTES, &activeAttrib); + + if (!maxAttribLen) + { + if (activeAttrib) + { + crWarning("activeAttrib (%d), while maxAttribLen is zero", activeAttrib); + activeAttrib = 0; + } + } + + if (activeAttrib>0) + { + pszName = (GLchar *) crAlloc((maxAttribLen+8)*sizeof(GLchar)); + + if (!pszName) + { + crWarning("crRecDumpProgramAttrib: out of memory"); + return; + } + } + + for (i=0; i<activeAttrib; ++i) + { + pRec->pDispatch->GetActiveAttrib(hwid, i, maxAttribLen, NULL, &size, &type, pszName); + attribCount += size; + } + Assert(attribCount>=activeAttrib); + + if (activeAttrib>0) + { + GLfloat fdata[16]; + GLint idata[16]; + char *pIndexStr=NULL; + + for (i=0; i<activeAttrib; ++i) + { + bool fPrintBraketsWithName = false; + pRec->pDispatch->GetActiveAttrib(hwid, i, maxAttribLen, NULL, &size, &type, pszName); + GLint arrayBufferBind = 0, arrayEnabled = 0, arraySize = 0, arrayStride = 0, arrayType = 0, arrayNormalized = 0, arrayInteger = 0/*, arrayDivisor = 0*/; + + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &arrayBufferBind); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &arrayEnabled); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &arraySize); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &arrayStride); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &arrayType); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &arrayNormalized); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_INTEGER, &arrayInteger); +// pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &arrayDivisor); + + if (size>1) + { + pIndexStr = crStrchr(pszName, '['); + if (!pIndexStr) + { + pIndexStr = pszName+crStrlen(pszName); + fPrintBraketsWithName = true; + } + } + + if (fPrintBraketsWithName) + { + crDmpStrF(pRec->pDumper, "%s %s[%d];", crRecDumpVarTypeString(type, pRec->pDumper), pszName, size); + Assert(size > 1); + } + else + crDmpStrF(pRec->pDumper, "%s %s;", crRecDumpVarTypeString(type, pRec->pDumper), pszName); + + crDmpStrF(pRec->pDumper, "Array buff(%d), enabled(%d) size(%d), stride(%d), type(%s), normalized(%d), integer(%d)", arrayBufferBind, arrayEnabled, arraySize, arrayStride, crRecDumpVarTypeString(arrayType, pRec->pDumper), arrayNormalized, arrayInteger); + + GLint attribTypeSize = crStateGetUniformSize(type); + Assert(attribTypeSize >= 1); + + for (j=0; j<size; ++j) + { + if (size>1) + { + sprintf(pIndexStr, "[%i]", j); + } + location = pRec->pDispatch->GetAttribLocation(hwid, pszName); + + if (crStateIsIntUniform(type)) + { + pRec->pDispatch->GetVertexAttribivARB(location, GL_CURRENT_VERTEX_ATTRIB, &idata[0]); + switch (attribTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %d; //location %d", pszName, idata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%d, %d}; //location %d", pszName, idata[0], idata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], idata[3], location); + break; + default: + for (GLint k = 0; k < attribTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %d; //location %d", pszName, k, idata[k], location); + } + break; + } + } + else + { + pRec->pDispatch->GetVertexAttribfvARB(location, GL_CURRENT_VERTEX_ATTRIB, &fdata[0]); + switch (attribTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %f; //location %d", pszName, fdata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%f, %f}; //location %d", pszName, fdata[0], fdata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], fdata[3], location); + break; + default: + for (GLint k = 0; k < attribTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %f; //location %d", pszName, k, fdata[k], location); + } + break; + } + } + } + } + + crFree(pszName); + } +} + +VBOXDUMPDECL(void) crRecDumpCurrentProgramUniforms(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecDumpProgramUniforms(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +VBOXDUMPDECL(void) crRecDumpCurrentProgramAttribs(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecDumpProgramAttribs(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +VBOXDUMPDECL(void) crRecRecompileCurrentProgram(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecRecompileProgram(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +int crRecAlphaImgCreate(const CR_BLITTER_IMG *pImg, CR_BLITTER_IMG *pAlphaImg) +{ + if (pImg->enmFormat != GL_RGBA + && pImg->enmFormat != GL_BGRA) + { + crWarning("unsupported format 0x%x", pImg->enmFormat); + return VERR_NOT_IMPLEMENTED; + } + + pAlphaImg->bpp = 32; + pAlphaImg->pitch = pImg->width * 4; + pAlphaImg->cbData = pAlphaImg->pitch * pImg->height; + pAlphaImg->enmFormat = GL_BGRA; + pAlphaImg->width = pImg->width; + pAlphaImg->height = pImg->height; + + pAlphaImg->pvData = RTMemAlloc(pAlphaImg->cbData); + if (!pAlphaImg->pvData) + { + crWarning("RTMemAlloc failed"); + return VERR_NO_MEMORY; + } + + uint8_t *pu8SrcBuf = (uint8_t*)pImg->pvData; + uint8_t *pu8DstBuf = (uint8_t*)pAlphaImg->pvData; + for (uint32_t ih = 0; ih < pAlphaImg->height; ++ih) + { + uint32_t *pu32SrcBuf = (uint32_t*)pu8SrcBuf; + uint32_t *pu32DstBuf = (uint32_t*)pu8DstBuf; + for (uint32_t iw = 0; iw < pAlphaImg->width; ++iw) + { + uint8_t alpha = (((*pu32SrcBuf) >> 24) & 0xff); + *pu32DstBuf = (0xff << 24) || (alpha << 16) || (alpha << 8) || alpha; + ++pu32SrcBuf; + ++pu32DstBuf; + } + pu8SrcBuf += pImg->pitch; + pu8DstBuf += pAlphaImg->pitch; + } + + return VINF_SUCCESS; +} + +void crRecAlphaImgDestroy(CR_BLITTER_IMG *pImg) +{ + RTMemFree(pImg->pvData); + pImg->pvData = NULL; +} + +void crRecDumpTextureV(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, const char *pszStr, va_list pArgList) +{ + CR_BLITTER_IMG Img = {0}; + int rc = CrBltEnter(pRec->pBlitter); + if (RT_SUCCESS(rc)) + { + rc = CrBltImgGetTex(pRec->pBlitter, pTex, GL_BGRA, &Img); + if (RT_SUCCESS(rc)) + { + crDmpImgV(pRec->pDumper, &Img, pszStr, pArgList); + if (g_CrDbgDumpAlphaData) + { + CR_BLITTER_IMG AlphaImg = {0}; + rc = crRecAlphaImgCreate(&Img, &AlphaImg); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &AlphaImg, "Texture ALPHA Data"); + crRecAlphaImgDestroy(&AlphaImg); + } + else + { + crWarning("crRecAlphaImgCreate failed rc %d", rc); + } + } + CrBltImgFree(pRec->pBlitter, &Img); + } + else + { + crWarning("CrBltImgGetTex failed, rc %d", rc); + } + CrBltLeave(pRec->pBlitter); + } + else + { + crWarning("CrBltEnter failed, rc %d", rc); + } +} + +void crRecDumpTextureF(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, const char *pszStr, ...) +{ + va_list pArgList; + va_start(pArgList, pszStr); + crRecDumpTextureV(pRec, pTex, pszStr, pArgList); + va_end(pArgList); +} + +void crRecDumpTextureByIdV(CR_RECORDER *pRec, CRContext *ctx, GLint id, const char *pszStr, va_list pArgList) +{ + CRTextureObj *pTobj = (CRTextureObj *)crHashtableSearch(ctx->shared->textureTable, id); + if (!pTobj) + { + crWarning("no texture of id %d", id); + return; + } + + CRTextureLevel *pTl = &pTobj->level[0][0 /* level */]; + VBOXVR_TEXTURE Tex; + Tex.width = pTl->width; + Tex.height = pTl->height; + Tex.target = pTobj->target; + Assert(Tex.target == GL_TEXTURE_2D); + Tex.hwid = pTobj->hwid; + if (!Tex.hwid) + { + crWarning("no texture hwid of id %d", id); + return; + } + + crRecDumpTextureV(pRec, &Tex, pszStr, pArgList); +} + +void crRecDumpTextureByIdF(CR_RECORDER *pRec, CRContext *ctx, GLint id, const char *pszStr, ...) +{ + va_list pArgList; + va_start(pArgList, pszStr); + crRecDumpTextureByIdV(pRec, ctx, id, pszStr, pArgList); + va_end(pArgList); +} + +void crRecDumpTextures(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint maxUnits = 0; + GLint curTexUnit = 0; + GLint restoreTexUnit = 0; + GLint curProgram = 0; + int i; + + pRec->pDispatch->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits); + maxUnits = RT_MIN(CR_MAX_TEXTURE_UNITS, maxUnits); + + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + Assert(curProgram); + Assert(ctx->glsl.activeProgram && ctx->glsl.activeProgram->hwid == curProgram); + + Assert(maxUnits); + pRec->pDispatch->GetIntegerv(GL_ACTIVE_TEXTURE, &curTexUnit); + restoreTexUnit = curTexUnit; + Assert(curTexUnit >= GL_TEXTURE0); + Assert(curTexUnit < GL_TEXTURE0 + maxUnits); + + Assert(ctx->texture.curTextureUnit == restoreTexUnit - GL_TEXTURE0); + + for (i = 0; i < maxUnits; ++i) + { + GLboolean enabled1D; + GLboolean enabled2D; + GLboolean enabled3D; + GLboolean enabledCubeMap; + GLboolean enabledRect; + CRTextureUnit *tu = &ctx->texture.unit[i]; + + if (i > 1) + break; + + if (curTexUnit != i + GL_TEXTURE0) + { + pRec->pDispatch->ActiveTextureARB(i + GL_TEXTURE0); + curTexUnit = i + GL_TEXTURE0; + } + + enabled1D = pRec->pDispatch->IsEnabled(GL_TEXTURE_1D); + enabled2D = pRec->pDispatch->IsEnabled(GL_TEXTURE_2D); + enabled3D = pRec->pDispatch->IsEnabled(GL_TEXTURE_3D); + enabledCubeMap = pRec->pDispatch->IsEnabled(GL_TEXTURE_CUBE_MAP_ARB); + enabledRect = pRec->pDispatch->IsEnabled(GL_TEXTURE_RECTANGLE_NV); + + Assert(enabled1D == tu->enabled1D); + Assert(enabled2D == tu->enabled2D); + Assert(enabled3D == tu->enabled3D); + Assert(enabledCubeMap == tu->enabledCubeMap); + Assert(enabledRect == tu->enabledRect); + + if (enabled1D) + { + crWarning("GL_TEXTURE_1D: unsupported"); + } + +// if (enabled2D) + { + GLint hwTex = 0; + VBOXVR_TEXTURE Tex; + + GLint width = 0, height = 0, depth = 0; + CRTextureObj *pTobj = tu->currentTexture2D; + + pRec->pDispatch->GetIntegerv(GL_TEXTURE_BINDING_2D, &hwTex); + if (hwTex) + { + CRTextureLevel *pTl = &pTobj->level[0][0 /* level */]; + Assert(pTobj + && pTobj->hwid == hwTex); + + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pTl->width); + Assert(height == pTl->height); + Assert(depth == pTl->depth); + + Tex.width = width; + Tex.height = height; + Tex.target = GL_TEXTURE_2D; + Tex.hwid = hwTex; + + if (g_CrDbgDumpRecTexInfo) + { + crRecDumpTexParam(pRec, ctx, GL_TEXTURE_2D); + crRecDumpTexEnv(pRec, ctx); + crRecDumpTexGen(pRec, ctx); + } + + crRecDumpTextureF(pRec, &Tex, "ctx(%d), Unit %d: TEXTURE_2D id(%d) hwid(%d), width(%d), height(%d)", ctx, i, pTobj->id, pTobj->hwid, width, height); + } +// else +// { +// Assert(!pTobj || pTobj->hwid == 0); +// crWarning("no TEXTURE_2D bound!"); +// } + } +#if 0 + if (enabled3D) + { + crWarning("GL_TEXTURE_3D: unsupported"); + } + + if (enabledCubeMap) + { + crWarning("GL_TEXTURE_CUBE_MAP_ARB: unsupported"); + } + +// if (enabledRect) + { + GLint hwTex = 0; + CR_BLITTER_IMG Img = {0}; + VBOXVR_TEXTURE Tex; + + GLint width = 0, height = 0, depth = 0; + CRTextureObj *pTobj = tu->currentTextureRect; + + pRec->pDispatch->GetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_NV, &hwTex); + if (hwTex) + { + CRTextureLevel *pTl = &pTobj->level[0][0 /* level */]; + Assert(pTobj + && pTobj->hwid == hwTex); + + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_WIDTH, &width); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_HEIGHT, &height); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pTl->width); + Assert(height == pTl->height); + Assert(depth == pTl->depth); + + Tex.width = width; + Tex.height = height; + Tex.target = GL_TEXTURE_RECTANGLE_NV; + Tex.hwid = hwTex; + + rc = CrBltEnter(pRec->pBlitter); + if (RT_SUCCESS(rc)) + { + rc = CrBltImgGetTex(pRec->pBlitter, &Tex, GL_BGRA, &Img); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &Img, "Unit %d: TEXTURE_RECTANGLE data", i); + CrBltImgFree(pRec->pBlitter, &Img); + } + else + { + crWarning("CrBltImgGetTex failed, rc %d", rc); + } + CrBltLeave(pRec->pBlitter); + } + else + { + crWarning("CrBltEnter failed, rc %d", rc); + } + } +// else +// { +// Assert(!pTobj || pTobj->hwid == 0); +// crWarning("no TEXTURE_RECTANGLE bound!"); +// } + } +#endif + } + + if (curTexUnit != restoreTexUnit) + { + pRec->pDispatch->ActiveTextureARB(restoreTexUnit); + curTexUnit = restoreTexUnit; + } +} + +#ifdef RT_OS_WINDOWS +static void crDmpPrint(const char* szString, ...) +{ + char szBuffer[4096] = {0}; + va_list pArgList; + va_start(pArgList, szString); + RTStrPrintfV(szBuffer, sizeof (szBuffer), szString, pArgList); + va_end(pArgList); + + OutputDebugStringA(szBuffer); +} + +static void crDmpPrintDmlCmd(const char* pszDesc, const char* pszCmd) +{ + crDmpPrint("<?dml?><exec cmd=\"%s\">%s</exec>, ( %s )\n", pszCmd, pszDesc, pszCmd); +} + +void crDmpPrintDumpDmlCmd(const char* pszDesc, const void *pvData, uint32_t width, uint32_t height, uint32_t bpp, uint32_t pitch) +{ + char Cmd[1024]; + sprintf(Cmd, "!vbvdbg.ms 0x%p 0n%d 0n%d 0n%d 0n%d", pvData, width, height, bpp, pitch); + crDmpPrintDmlCmd(pszDesc, Cmd); +} + +DECLCALLBACK(void) crDmpDumpImgDmlBreak(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc) +{ + crDmpPrintDumpDmlCmd(pszEntryDesc, pImg->pvData, pImg->width, pImg->height, pImg->bpp, pImg->pitch); + RT_BREAKPOINT(); +} + +DECLCALLBACK(void) crDmpDumpStrDbgPrint(struct CR_DUMPER * pDumper, const char*pszStr) +{ + crDmpPrint("%s\n", pszStr); +} +#endif + +static void crDmpHtmlDumpStrExact(struct CR_HTML_DUMPER * pDumper, const char *pszStr) +{ + fprintf(pDumper->pFile, "%s", pszStr); + fflush(pDumper->pFile); +} + +static DECLCALLBACK(void) crDmpHtmlDumpStr(struct CR_DUMPER * pDumper, const char*pszStr) +{ + CR_HTML_DUMPER * pHtmlDumper = (CR_HTML_DUMPER*)pDumper; + fprintf(pHtmlDumper->pFile, "<pre>%s</pre>\n", pszStr); + fflush(pHtmlDumper->pFile); +} + +static DECLCALLBACK(void) crDmpHtmlDumpImg(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc) +{ + CR_HTML_DUMPER * pHtmlDumper = (CR_HTML_DUMPER*)pDumper; + char szBuffer[4096] = {0}; + size_t cbWritten = RTStrPrintf(szBuffer, sizeof(szBuffer), "%s/", pHtmlDumper->pszDir); + char *pszFileName = szBuffer + cbWritten; + RTStrPrintf(pszFileName, sizeof(szBuffer) - cbWritten, "img%d.bmp", ++pHtmlDumper->cImg); + crDmpImgBmp(pImg, szBuffer); + fprintf(pHtmlDumper->pFile, "<a href=\"%s\"><pre>%s</pre><img src=\"%s\" alt=\"%s\" width=\"150\" height=\"100\" /></a><br>\n", + pszFileName, pszEntryDesc, pszFileName, pszEntryDesc); + fflush(pHtmlDumper->pFile); +} + +static void crDmpHtmlPrintHeader(struct CR_HTML_DUMPER * pDumper) +{ + fprintf(pDumper->pFile, "<html><body>\n"); + fflush(pDumper->pFile); +} + +static void crDmpHtmlPrintFooter(struct CR_HTML_DUMPER * pDumper) +{ + fprintf(pDumper->pFile, "</body></html>\n"); + fflush(pDumper->pFile); +} + +DECLEXPORT(bool) crDmpHtmlIsInited(struct CR_HTML_DUMPER * pDumper) +{ + return !!pDumper->pFile; +} + +DECLEXPORT(void) crDmpHtmlTerm(struct CR_HTML_DUMPER * pDumper) +{ + crDmpHtmlPrintFooter(pDumper); + fclose (pDumper->pFile); + pDumper->pFile = NULL; +} + +DECLEXPORT(int) crDmpHtmlInit(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile) +{ + int rc = VERR_NO_MEMORY; + pDumper->Base.pfnDumpImg = crDmpHtmlDumpImg; + pDumper->Base.pfnDumpStr = crDmpHtmlDumpStr; + pDumper->cImg = 0; + pDumper->pszDir = crStrdup(pszDir); + if (pDumper->pszDir) + { + pDumper->pszFile = crStrdup(pszFile); + if (pDumper->pszFile) + { + char szBuffer[4096] = {0}; + RTStrPrintf(szBuffer, sizeof(szBuffer), "%s/%s", pszDir, pszFile); + + pDumper->pszFile = crStrdup(pszFile); + pDumper->pFile = fopen(szBuffer, "w"); + if (pDumper->pFile) + { + crDmpHtmlPrintHeader(pDumper); + return VINF_SUCCESS; + } + else + { + crWarning("open failed"); + rc = VERR_OPEN_FAILED; + } + crFree((void*)pDumper->pszFile); + } + else + { + crWarning("open failed"); + } + crFree((void*)pDumper->pszDir); + } + else + { + crWarning("open failed"); + } + return rc; +} + +DECLEXPORT(int) crDmpHtmlInitV(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, va_list pArgList) +{ + char szBuffer[4096] = {0}; + vsprintf_s(szBuffer, sizeof (szBuffer), pszFile, pArgList); + return crDmpHtmlInit(pDumper, pszDir, szBuffer); +} + +DECLEXPORT(int) crDmpHtmlInitF(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, ...) +{ + int rc; + va_list pArgList; + va_start(pArgList, pszFile); + rc = crDmpHtmlInitV(pDumper, pszDir, pszFile, pArgList); + va_end(pArgList); + return rc; +} + +#endif diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/dump_gen.py b/src/VBox/GuestHost/OpenGL/state_tracker/dump_gen.py new file mode 100644 index 00000000..7103ed4e --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/dump_gen.py @@ -0,0 +1,257 @@ +import sys + +import apiutil + +import sys, re, string + + +line_re = re.compile(r'^(\S+)\s+(GL_\S+)\s+(.*)\s*$') +extensions_line_re = re.compile(r'^(\S+)\s+(GL_\S+)\s(\S+)\s+(.*)\s*$') + +params = {} +extended_params = {} + +input = open( sys.argv[2]+"/state_isenabled.txt", 'r' ) +for line in input.readlines(): + match = line_re.match( line ) + if match: + type = match.group(1) + pname = match.group(2) + fields = string.split( match.group(3) ) + params[pname] = ( type, fields ) + +input = open( sys.argv[2]+"/state_extensions_isenabled.txt", 'r' ) +for line in input.readlines(): + match = extensions_line_re.match( line ) + if match: + type = match.group(1) + pname = match.group(2) + ifdef = match.group(3) + fields = string.split( match.group(4) ) + extended_params[pname] = ( type, ifdef, fields ) + + +apiutil.CopyrightC() + +print """#include "cr_blitter.h" +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "cr_mem.h" +#include "cr_string.h" +#include <cr_dump.h> +#include "cr_pixeldata.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/mem.h> + +#include <stdio.h> + +#ifdef VBOX_WITH_CRDUMPER +""" + +from get_sizes import *; + +getprops = apiutil.ParamProps("GetDoublev") +enableprops = apiutil.ParamProps("Enable") + +#print "//missing get props:" +#for prop in getprops: +# try: +# tmp = num_get_values[prop] +# except KeyError: +# try: +# keyvalues = extensions_num_get_values[prop] +# except KeyError: +# print "//%s" % prop +# +print """ +static void crRecDumpPrintVal(CR_DUMPER *pDumper, struct nv_struct *pDesc, float *pfData) +{ + char aBuf[4096]; + crDmpFormatArray(aBuf, sizeof (aBuf), "%f", sizeof (float), pfData, pDesc->num_values); + crDmpStrF(pDumper, "%s = %s;", pDesc->pszName, aBuf); +} + + +void crRecDumpGlGetState(CR_RECORDER *pRec, CRContext *ctx) +{ + float afData[CR_MAX_GET_VALUES]; + struct nv_struct *pDesc; + + for (pDesc = num_values_array; pDesc->num_values != 0 ; pDesc++) + { + memset(afData, 0, sizeof(afData)); + pRec->pDispatch->GetFloatv(pDesc->pname, afData); + crRecDumpPrintVal(pRec->pDumper, pDesc, afData); + } +} + +void crRecDumpGlEnableState(CR_RECORDER *pRec, CRContext *ctx) +{ + GLboolean fEnabled; +""" +keys = params.keys() +keys.sort(); + +for pname in keys: + print "\tfEnabled = pRec->pDispatch->IsEnabled(%s);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%d;\", fEnabled);" % pname + +keys = extended_params.keys(); +keys.sort() + +for pname in keys: + (srctype,ifdef,fields) = extended_params[pname] + ext = ifdef[3:] # the extension name with the "GL_" prefix removed + ext = ifdef + print '#ifdef CR_%s' % ext + print "\tfEnabled = pRec->pDispatch->IsEnabled(%s);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%d;\", fEnabled);" % pname + print '#endif /* CR_%s */' % ext + +#print "//missing enable props:" +#for prop in enableprops: +# try: +# keyvalues = params[prop] +# except KeyError: +# try: +# keyvalues = extended_params[prop] +# except KeyError: +# print "//%s" % prop +# +print """ +} +#endif +""" + +texenv_mappings = { + 'GL_TEXTURE_ENV' : [ + 'GL_TEXTURE_ENV_MODE', + 'GL_TEXTURE_ENV_COLOR', + 'GL_COMBINE_RGB', + 'GL_COMBINE_ALPHA', + 'GL_RGB_SCALE', + 'GL_ALPHA_SCALE', + 'GL_SRC0_RGB', + 'GL_SRC1_RGB', + 'GL_SRC2_RGB', + 'GL_SRC0_ALPHA', + 'GL_SRC1_ALPHA', + 'GL_SRC2_ALPHA' + ], + 'GL_TEXTURE_FILTER_CONTROL' : [ + 'GL_TEXTURE_LOD_BIAS' + ], + 'GL_POINT_SPRITE' : [ + 'GL_COORD_REPLACE' + ] +} + +texgen_coords = [ + 'GL_S', + 'GL_T', + 'GL_R', + 'GL_Q' +] + +texgen_names = [ + 'GL_TEXTURE_GEN_MODE', + 'GL_OBJECT_PLANE', + 'GL_EYE_PLANE' +] + +texparam_names = [ + 'GL_TEXTURE_MAG_FILTER', + 'GL_TEXTURE_MIN_FILTER', + 'GL_TEXTURE_MIN_LOD', + 'GL_TEXTURE_MAX_LOD', + 'GL_TEXTURE_BASE_LEVEL', + 'GL_TEXTURE_MAX_LEVEL', + 'GL_TEXTURE_WRAP_S', + 'GL_TEXTURE_WRAP_T', + 'GL_TEXTURE_WRAP_R', + 'GL_TEXTURE_BORDER_COLOR', + 'GL_TEXTURE_PRIORITY', + 'GL_TEXTURE_RESIDENT', + 'GL_TEXTURE_COMPARE_MODE', + 'GL_TEXTURE_COMPARE_FUNC', + 'GL_DEPTH_TEXTURE_MODE', + 'GL_GENERATE_MIPMAP' +] + +print """ +void crRecDumpTexParam(CR_RECORDER *pRec, CRContext *ctx, GLenum enmTarget) +{ + GLfloat afBuf[4]; + char acBuf[1024]; + unsigned int cComponents; + crDmpStrF(pRec->pDumper, "==TEX_PARAM for target(0x%x)==", enmTarget); +""" +for pname in texparam_names: + print "\tcComponents = crStateHlpComponentsCount(%s);" % pname + print "\tAssert(cComponents <= RT_ELEMENTS(afBuf));" + print "\tmemset(afBuf, 0, sizeof (afBuf));" + print "\tpRec->pDispatch->GetTexParameterfv(enmTarget, %s, afBuf);" % pname + print "\tcrDmpFormatArray(acBuf, sizeof (acBuf), \"%f\", sizeof (afBuf[0]), afBuf, cComponents);" + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%s;\", acBuf);" % pname +print """ + crDmpStrF(pRec->pDumper, "==Done TEX_PARAM for target(0x%x)==", enmTarget); +} +""" + +print """ +void crRecDumpTexEnv(CR_RECORDER *pRec, CRContext *ctx) +{ + GLfloat afBuf[4]; + char acBuf[1024]; + unsigned int cComponents; + crDmpStrF(pRec->pDumper, "==TEX_ENV=="); +""" + +keys = texenv_mappings.keys() +keys.sort(); + +for target in keys: + print "\tcrDmpStrF(pRec->pDumper, \"===%s===\");" % target + values = texenv_mappings[target] + for pname in values: + print "\tcComponents = crStateHlpComponentsCount(%s);" % pname + print "\tAssert(cComponents <= RT_ELEMENTS(afBuf));" + print "\tmemset(afBuf, 0, sizeof (afBuf));" + print "\tpRec->pDispatch->GetTexEnvfv(%s, %s, afBuf);" % (target, pname) + print "\tcrDmpFormatArray(acBuf, sizeof (acBuf), \"%f\", sizeof (afBuf[0]), afBuf, cComponents);" + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%s;\", acBuf);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"===Done %s===\");" % target +print """ + crDmpStrF(pRec->pDumper, "==Done TEX_ENV=="); +} +""" + + +print """ +void crRecDumpTexGen(CR_RECORDER *pRec, CRContext *ctx) +{ + GLdouble afBuf[4]; + char acBuf[1024]; + unsigned int cComponents; + crDmpStrF(pRec->pDumper, "==TEX_GEN=="); +""" + +for coord in texgen_coords: + print "\tcrDmpStrF(pRec->pDumper, \"===%s===\");" % coord + for pname in texgen_names: + print "\tcComponents = crStateHlpComponentsCount(%s);" % pname + print "\tAssert(cComponents <= RT_ELEMENTS(afBuf));" + print "\tmemset(afBuf, 0, sizeof (afBuf));" + print "\tpRec->pDispatch->GetTexGendv(%s, %s, afBuf);" % (coord, pname) + print "\tcrDmpFormatArray(acBuf, sizeof (acBuf), \"%f\", sizeof (afBuf[0]), afBuf, cComponents);" + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%s;\", acBuf);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"===Done %s===\");" % coord +print """ + crDmpStrF(pRec->pDumper, "==Done TEX_GEN=="); +} +""" diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/get_components.py b/src/VBox/GuestHost/OpenGL/state_tracker/get_components.py new file mode 100644 index 00000000..c9a32452 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/get_components.py @@ -0,0 +1,144 @@ +# Copyright (c) 2001, Stanford University +# All rights reserved. +# +# See the file LICENSE.txt for information on redistributing this software. + +num_components = { + 'GL_AMBIENT' : 4, + 'GL_DIFFUSE' : 4, + 'GL_SPECULAR' : 4, + 'GL_POSITION' : 4, + 'GL_SPOT_DIRECTION' : 3, + 'GL_SPOT_EXPONENT' : 1, + 'GL_SPOT_CUTOFF' : 1, + 'GL_CONSTANT_ATTENUATION' : 1, + 'GL_LINEAR_ATTENUATION' : 1, + 'GL_QUADRATIC_ATTENUATION' : 1, + 'GL_EMISSION' : 4, + 'GL_SHININESS' : 1, + 'GL_COLOR_INDEXES' : 3, + 'GL_TEXTURE_ENV_MODE' : 1, + 'GL_TEXTURE_ENV_COLOR' : 4, + 'GL_TEXTURE_GEN_MODE' : 1, + 'GL_OBJECT_PLANE' : 4, + 'GL_EYE_PLANE' : 4, + 'GL_TEXTURE_MAG_FILTER' : 1, + 'GL_TEXTURE_MIN_FILTER' : 1, + 'GL_TEXTURE_WRAP_S' : 1, + 'GL_TEXTURE_WRAP_T' : 1, + 'GL_TEXTURE_BORDER_COLOR' : 4, + 'GL_TEXTURE_WIDTH': 1, + 'GL_TEXTURE_HEIGHT': 1, + 'GL_TEXTURE_DEPTH': 1, + # 'GL_TEXTURE_INTERNAL_FORMAT': 1, THIS CONFLICTS WITH GL_TEXTURE_COMPONENTS! + 'GL_TEXTURE_BORDER': 1, + 'GL_TEXTURE_RED_SIZE': 1, + 'GL_TEXTURE_GREEN_SIZE': 1, + 'GL_TEXTURE_BLUE_SIZE': 1, + 'GL_TEXTURE_ALPHA_SIZE': 1, + 'GL_TEXTURE_LUMINANCE_SIZE': 1, + 'GL_TEXTURE_INTENSITY_SIZE': 1, + 'GL_TEXTURE_COMPONENTS': 1, + 'GL_TEXTURE_RESIDENT': 1 +} + +num_extended_components = { + 'GL_TEXTURE_MAX_ANISOTROPY_EXT': ( 1, 'CR_EXT_texture_filter_anisotropic' ), + 'GL_TEXTURE_WRAP_R': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_PRIORITY': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_MIN_LOD': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_MAX_LOD': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_BASE_LEVEL': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_MAX_LEVEL': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_COMBINER_INPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_MAPPING_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_COMPONENT_USAGE_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_AB_DOT_PRODUCT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_CD_DOT_PRODUCT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_MUX_SUM_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_SCALE_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_BIAS_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_AB_OUTPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_CD_OUTPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_SUM_OUTPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_INPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_INPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_MAPPING_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_COMPONENT_USAGE_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_COMBINE_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_COMBINE_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE0_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE1_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE2_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE0_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE1_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE2_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND0_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND1_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND2_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND0_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND1_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND2_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_RGB_SCALE_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_ALPHA_SCALE': (1, 'CR_ARB_texture_env_combine'), + 'GL_DEPTH_TEXTURE_MODE_ARB': (1, 'CR_ARB_depth_texture'), + 'GL_TEXTURE_DEPTH_SIZE_ARB': (1, 'CR_ARB_depth_texture'), + 'GL_TEXTURE_COMPARE_MODE_ARB': (1, 'CR_ARB_shadow'), + 'GL_TEXTURE_COMPARE_FUNC_ARB': (1, 'CR_ARB_shadow'), + 'GL_TEXTURE_COMPARE_FAIL_VALUE_ARB': (1, 'CR_ARB_shadow_ambient'), + 'GL_GENERATE_MIPMAP_SGIS': (1, 'CR_SGIS_generate_mipmap'), + 'GL_TEXTURE_LOD_BIAS_EXT': (1, 'CR_EXT_texture_lod_bias'), + 'GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB': (1, 'CR_any_vertex_program'), + 'GL_CURRENT_VERTEX_ATTRIB_ARB': (4, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB': (1, 'CR_any_vertex_program'), + 'GL_TRACK_MATRIX_NV': (24, 'CR_any_vertex_program'), + 'GL_TRACK_MATRIX_TRANSFORM_NV': (24, 'CR_any_vertex_program'), + 'GL_BUFFER_SIZE_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_BUFFER_USAGE_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_BUFFER_ACCESS_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_BUFFER_MAPPED_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_QUERY_COUNTER_BITS_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_QUERY_RESULT_AVAILABLE_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_QUERY_RESULT_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_CURRENT_QUERY_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_TEXTURE_COMPRESSED_IMAGE_SIZE': (1, 'CR_ARB_texture_compression'), + 'GL_TEXTURE_COMPRESSED': (1, 'CR_ARB_texture_compression'), + 'GL_COORD_REPLACE_ARB': (1, 'CR_ARB_point_sprite'), +} + +print """unsigned int crStateHlpComponentsCount( GLenum pname ) +{ + switch( pname ) + { +""" +comps = num_components.keys(); +comps.sort(); +for comp in comps: + print '\t\t\tcase %s: return %d;' % (comp,num_components[comp]) + +comps = num_extended_components.keys(); +comps.sort(); +for comp in comps: + (nc, ifdef) = num_extended_components[comp] + print '#ifdef %s' % ifdef + print '\t\t\tcase %s: return %d;' % (comp,nc) + print '#endif /* %s */' % ifdef + +print """ + default: + crError( "Unknown parameter name in crStateHlpComponentsCount: %d", (int) pname ); + break; + } + /* NOTREACHED */ + return 0; +} +""" + + diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state.h b/src/VBox/GuestHost/OpenGL/state_tracker/state.h index c94525a1..07429aa9 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state.h +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state.h @@ -9,6 +9,16 @@ #include "cr_glstate.h" +#define CRSTATE_CHECKERR_RET(expr, result, message, ret) \ + if (expr) { \ + crStateError(__LINE__, __FILE__, result, message); \ + return ret; \ + } + +#define CRSTATE_NO_RETURN + +#define CRSTATE_CHECKERR(expr, result, message) CRSTATE_CHECKERR_RET(expr, result, message, CRSTATE_NO_RETURN) + typedef struct _crCheckIDHWID { GLuint id, hwid; } crCheckIDHWID_t; @@ -33,6 +43,11 @@ extern CRContext *__currentContext; #define GetCurrentContext() __currentContext #endif +extern GLboolean g_bVBoxEnableDiffOnMakeCurrent; + +extern CRContext *g_pAvailableContexts[CR_MAX_CONTEXTS]; +extern uint32_t g_cContexts; + extern void crStateTextureInitTextureObj (CRContext *ctx, CRTextureObj *tobj, GLuint name, GLenum target); extern void crStateTextureInitTextureFormat( CRTextureLevel *tl, GLenum internalFormat ); @@ -55,10 +70,10 @@ void crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, CRContext *from, CRC void crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, CRContext *from, CRContext *to); -void crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, - CRTextureObj **obj, CRTextureLevel **img); - void crStateFreeBufferObject(void *data); void crStateFreeFBO(void *data); void crStateFreeRBO(void *data); + +void crStateGenNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names); +void crStateRegNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names); #endif diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c index 836c2221..68cbdb62 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c @@ -439,14 +439,17 @@ void STATE_APIENTRY crStatePushAttrib(GLbitfield mask) if (mask & GL_STENCIL_BUFFER_BIT) { a->stencilBufferStack[a->stencilBufferStackDepth].stencilTest = g->stencil.stencilTest; - a->stencilBufferStack[a->stencilBufferStackDepth].func = g->stencil.func; - a->stencilBufferStack[a->stencilBufferStackDepth].mask = g->stencil.mask; - a->stencilBufferStack[a->stencilBufferStackDepth].ref = g->stencil.ref; - a->stencilBufferStack[a->stencilBufferStackDepth].fail = g->stencil.fail; - a->stencilBufferStack[a->stencilBufferStackDepth].passDepthFail = g->stencil.passDepthFail; - a->stencilBufferStack[a->stencilBufferStackDepth].passDepthPass = g->stencil.passDepthPass; a->stencilBufferStack[a->stencilBufferStackDepth].clearValue = g->stencil.clearValue; a->stencilBufferStack[a->stencilBufferStackDepth].writeMask = g->stencil.writeMask; + for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i) + { + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].func = g->stencil.buffers[i].func; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].mask = g->stencil.buffers[i].mask; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].ref = g->stencil.buffers[i].ref; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].fail = g->stencil.buffers[i].fail; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthFail = g->stencil.buffers[i].passDepthFail; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthPass = g->stencil.buffers[i].passDepthPass; + } a->stencilBufferStackDepth++; } if (mask & GL_TEXTURE_BIT) @@ -1033,20 +1036,28 @@ void STATE_APIENTRY crStatePopAttrib(void) } a->stencilBufferStackDepth--; g->stencil.stencilTest = a->stencilBufferStack[a->stencilBufferStackDepth].stencilTest; - g->stencil.func = a->stencilBufferStack[a->stencilBufferStackDepth].func; - g->stencil.mask = a->stencilBufferStack[a->stencilBufferStackDepth].mask; - g->stencil.ref = a->stencilBufferStack[a->stencilBufferStackDepth].ref; - g->stencil.fail = a->stencilBufferStack[a->stencilBufferStackDepth].fail; - g->stencil.passDepthFail = a->stencilBufferStack[a->stencilBufferStackDepth].passDepthFail; - g->stencil.passDepthPass = a->stencilBufferStack[a->stencilBufferStackDepth].passDepthPass; g->stencil.clearValue = a->stencilBufferStack[a->stencilBufferStackDepth].clearValue; g->stencil.writeMask = a->stencilBufferStack[a->stencilBufferStackDepth].writeMask; + for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i) + { + g->stencil.buffers[i].func = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].func; + g->stencil.buffers[i].mask = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].mask; + g->stencil.buffers[i].ref = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].ref; + g->stencil.buffers[i].fail = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].fail; + g->stencil.buffers[i].passDepthFail = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthFail; + g->stencil.buffers[i].passDepthPass = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthPass; + } + DIRTY(sb->stencil.dirty, g->neg_bitid); DIRTY(sb->stencil.enable, g->neg_bitid); - DIRTY(sb->stencil.func, g->neg_bitid); - DIRTY(sb->stencil.op, g->neg_bitid); DIRTY(sb->stencil.clearValue, g->neg_bitid); DIRTY(sb->stencil.writeMask, g->neg_bitid); + + for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) + { + DIRTY(sb->stencil.bufferRefs[i].func, g->neg_bitid); + DIRTY(sb->stencil.bufferRefs[i].op, g->neg_bitid); + } } if (mask & GL_TEXTURE_BIT) { diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_bits_globalop.h b/src/VBox/GuestHost/OpenGL/state_tracker/state_bits_globalop.h new file mode 100644 index 00000000..351a85a3 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_bits_globalop.h @@ -0,0 +1,338 @@ +/* $Id: state_bits_globalop.h $ */ + +/** @file + * Global State bits operation + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include <iprt/cdefs.h> + +#include <cr_version.h> + +#ifndef CRSTATE_BITS_OP +# error "CRSTATE_BITS_OP must be defined!" +#endif + +#define _CRSTATE_BITS_OP_SIZEOF(_val) CRSTATE_BITS_OP(_val, RT_SIZEOFMEMB(CRStateBits, _val)) + +#ifndef CRSTATE_BITS_OP_VERSION +# define CRSTATE_BITS_OP_VERSION SHCROGL_SSM_VERSION +#endif + +do { +int i; +#ifdef _CRSTATE_BITS_OP_STENCIL_V_33 +# error "_CRSTATE_BITS_OP_STENCIL_V_33 must no be defined!" +#endif +#if CRSTATE_BITS_OP_VERSION < SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL +# define _CRSTATE_BITS_OP_STENCIL_V_33 +#endif + +#ifdef _CRSTATE_BITS_OP_STENCIL_V_33 +# ifndef CRSTATE_BITS_OP_STENCIL_OP_V_33 +# error "CRSTATE_BITS_OP_STENCIL_OP_V_33 undefined!" +# endif +# ifndef CRSTATE_BITS_OP_STENCIL_FUNC_V_33 +# error "CRSTATE_BITS_OP_STENCIL_FUNC_V_33 undefined!" +# endif +#endif + +_CRSTATE_BITS_OP_SIZEOF(attrib.dirty); + +_CRSTATE_BITS_OP_SIZEOF(buffer.dirty); +_CRSTATE_BITS_OP_SIZEOF(buffer.enable); +_CRSTATE_BITS_OP_SIZEOF(buffer.alphaFunc); +_CRSTATE_BITS_OP_SIZEOF(buffer.depthFunc); +_CRSTATE_BITS_OP_SIZEOF(buffer.blendFunc); +_CRSTATE_BITS_OP_SIZEOF(buffer.logicOp); +_CRSTATE_BITS_OP_SIZEOF(buffer.indexLogicOp); +_CRSTATE_BITS_OP_SIZEOF(buffer.drawBuffer); +_CRSTATE_BITS_OP_SIZEOF(buffer.readBuffer); +_CRSTATE_BITS_OP_SIZEOF(buffer.indexMask); +_CRSTATE_BITS_OP_SIZEOF(buffer.colorWriteMask); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearColor); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearIndex); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearDepth); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearAccum); +_CRSTATE_BITS_OP_SIZEOF(buffer.depthMask); +#ifdef CR_EXT_blend_color +_CRSTATE_BITS_OP_SIZEOF(buffer.blendColor); +#endif +#if defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op) +_CRSTATE_BITS_OP_SIZEOF(buffer.blendEquation); +#endif +#if defined(CR_EXT_blend_func_separate) +_CRSTATE_BITS_OP_SIZEOF(buffer.blendFuncSeparate); +#endif + +#ifdef CR_ARB_vertex_buffer_object +_CRSTATE_BITS_OP_SIZEOF(bufferobject.dirty); +_CRSTATE_BITS_OP_SIZEOF(bufferobject.arrayBinding); +_CRSTATE_BITS_OP_SIZEOF(bufferobject.elementsBinding); +# ifdef CR_ARB_pixel_buffer_object +_CRSTATE_BITS_OP_SIZEOF(bufferobject.packBinding); +_CRSTATE_BITS_OP_SIZEOF(bufferobject.unpackBinding); +# endif +#endif + +_CRSTATE_BITS_OP_SIZEOF(client.dirty); +_CRSTATE_BITS_OP_SIZEOF(client.pack); +_CRSTATE_BITS_OP_SIZEOF(client.unpack); +_CRSTATE_BITS_OP_SIZEOF(client.enableClientState); +_CRSTATE_BITS_OP_SIZEOF(client.clientPointer); +CRSTATE_BITS_OP(client.v, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.n, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.c, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.i, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.e, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.s, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.f, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) +{ + CRSTATE_BITS_OP(client.t[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +} +#ifdef CR_NV_vertex_program +for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) +{ + CRSTATE_BITS_OP(client.a[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +} +#endif + +_CRSTATE_BITS_OP_SIZEOF(current.dirty); +for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) +{ + _CRSTATE_BITS_OP_SIZEOF(current.vertexAttrib[i]); +} +_CRSTATE_BITS_OP_SIZEOF(current.edgeFlag); +_CRSTATE_BITS_OP_SIZEOF(current.colorIndex); +_CRSTATE_BITS_OP_SIZEOF(current.rasterPos); + + +_CRSTATE_BITS_OP_SIZEOF(eval.dirty); +for (i=0; i<GLEVAL_TOT; i++) +{ + _CRSTATE_BITS_OP_SIZEOF(eval.eval1D[i]); + _CRSTATE_BITS_OP_SIZEOF(eval.eval2D[i]); + _CRSTATE_BITS_OP_SIZEOF(eval.enable1D[i]); + _CRSTATE_BITS_OP_SIZEOF(eval.enable2D[i]); +} +_CRSTATE_BITS_OP_SIZEOF(eval.enable); +_CRSTATE_BITS_OP_SIZEOF(eval.grid1D); +_CRSTATE_BITS_OP_SIZEOF(eval.grid2D); +#ifdef CR_NV_vertex_program + /*@todo Those seems to be unused? +_CRSTATE_BITS_OP_SIZEOF(eval.enableAttrib1D); +_CRSTATE_BITS_OP_SIZEOF(eval.enableAttrib2D); + */ +#endif + +_CRSTATE_BITS_OP_SIZEOF(feedback.dirty); +_CRSTATE_BITS_OP_SIZEOF(selection.dirty); + +_CRSTATE_BITS_OP_SIZEOF(fog.dirty); +_CRSTATE_BITS_OP_SIZEOF(fog.color); +_CRSTATE_BITS_OP_SIZEOF(fog.index); +_CRSTATE_BITS_OP_SIZEOF(fog.density); +_CRSTATE_BITS_OP_SIZEOF(fog.start); +_CRSTATE_BITS_OP_SIZEOF(fog.end); +_CRSTATE_BITS_OP_SIZEOF(fog.mode); +_CRSTATE_BITS_OP_SIZEOF(fog.enable); +#ifdef CR_NV_fog_distance +_CRSTATE_BITS_OP_SIZEOF(fog.fogDistanceMode); +#endif +#ifdef CR_EXT_fog_coord +_CRSTATE_BITS_OP_SIZEOF(fog.fogCoordinateSource); +#endif + +_CRSTATE_BITS_OP_SIZEOF(hint.dirty); +_CRSTATE_BITS_OP_SIZEOF(hint.perspectiveCorrection); +_CRSTATE_BITS_OP_SIZEOF(hint.pointSmooth); +_CRSTATE_BITS_OP_SIZEOF(hint.lineSmooth); +_CRSTATE_BITS_OP_SIZEOF(hint.polygonSmooth); +_CRSTATE_BITS_OP_SIZEOF(hint.fog); +#ifdef CR_EXT_clip_volume_hint +_CRSTATE_BITS_OP_SIZEOF(hint.clipVolumeClipping); + +#endif +#ifdef CR_ARB_texture_compression +_CRSTATE_BITS_OP_SIZEOF(hint.textureCompression); +#endif +#ifdef CR_SGIS_generate_mipmap +_CRSTATE_BITS_OP_SIZEOF(hint.generateMipmap); +#endif + +_CRSTATE_BITS_OP_SIZEOF(lighting.dirty); +_CRSTATE_BITS_OP_SIZEOF(lighting.shadeModel); +_CRSTATE_BITS_OP_SIZEOF(lighting.colorMaterial); +_CRSTATE_BITS_OP_SIZEOF(lighting.lightModel); +_CRSTATE_BITS_OP_SIZEOF(lighting.material); +_CRSTATE_BITS_OP_SIZEOF(lighting.enable); +for (i=0; i<CR_MAX_LIGHTS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].dirty); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].enable); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].ambient); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].diffuse); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].specular); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].position); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].attenuation); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].spot); +} + +_CRSTATE_BITS_OP_SIZEOF(line.dirty); +_CRSTATE_BITS_OP_SIZEOF(line.enable); +_CRSTATE_BITS_OP_SIZEOF(line.width); +_CRSTATE_BITS_OP_SIZEOF(line.stipple); + +_CRSTATE_BITS_OP_SIZEOF(lists.dirty); +_CRSTATE_BITS_OP_SIZEOF(lists.base); + +_CRSTATE_BITS_OP_SIZEOF(multisample.dirty); +_CRSTATE_BITS_OP_SIZEOF(multisample.enable); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleAlphaToCoverage); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleAlphaToOne); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleCoverage); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleCoverageValue); + +#if CR_ARB_occlusion_query +_CRSTATE_BITS_OP_SIZEOF(occlusion.dirty); +#endif + +_CRSTATE_BITS_OP_SIZEOF(pixel.dirty); +_CRSTATE_BITS_OP_SIZEOF(pixel.transfer); +_CRSTATE_BITS_OP_SIZEOF(pixel.zoom); +_CRSTATE_BITS_OP_SIZEOF(pixel.maps); + +_CRSTATE_BITS_OP_SIZEOF(point.dirty); +_CRSTATE_BITS_OP_SIZEOF(point.enableSmooth); +_CRSTATE_BITS_OP_SIZEOF(point.size); +#ifdef CR_ARB_point_parameters +_CRSTATE_BITS_OP_SIZEOF(point.minSize); +_CRSTATE_BITS_OP_SIZEOF(point.maxSize); +_CRSTATE_BITS_OP_SIZEOF(point.fadeThresholdSize); +_CRSTATE_BITS_OP_SIZEOF(point.distanceAttenuation); +#endif +#ifdef CR_ARB_point_sprite +_CRSTATE_BITS_OP_SIZEOF(point.enableSprite); +for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(point.coordReplacement[i]); +} +#endif +#if CRSTATE_BITS_OP_VERSION >= SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN +_CRSTATE_BITS_OP_SIZEOF(point.spriteCoordOrigin); +#endif + +_CRSTATE_BITS_OP_SIZEOF(polygon.dirty); +_CRSTATE_BITS_OP_SIZEOF(polygon.enable); +_CRSTATE_BITS_OP_SIZEOF(polygon.offset); +_CRSTATE_BITS_OP_SIZEOF(polygon.mode); +_CRSTATE_BITS_OP_SIZEOF(polygon.stipple); + +_CRSTATE_BITS_OP_SIZEOF(program.dirty); +_CRSTATE_BITS_OP_SIZEOF(program.vpEnable); +_CRSTATE_BITS_OP_SIZEOF(program.fpEnable); +_CRSTATE_BITS_OP_SIZEOF(program.vpBinding); +_CRSTATE_BITS_OP_SIZEOF(program.fpBinding); +for (i=0; i<CR_MAX_VERTEX_ATTRIBS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.vertexAttribArrayEnable[i]); + _CRSTATE_BITS_OP_SIZEOF(program.map1AttribArrayEnable[i]); + _CRSTATE_BITS_OP_SIZEOF(program.map2AttribArrayEnable[i]); +} +for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.vertexEnvParameter[i]); +} +for (i=0; i<CR_MAX_FRAGMENT_PROGRAM_ENV_PARAMS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.fragmentEnvParameter[i]); +} +_CRSTATE_BITS_OP_SIZEOF(program.vertexEnvParameters); +_CRSTATE_BITS_OP_SIZEOF(program.fragmentEnvParameters); +for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS/4; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.trackMatrix[i]); +} + +_CRSTATE_BITS_OP_SIZEOF(regcombiner.dirty); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.enable); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerVars); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerColor0); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerColor1); +for (i=0; i<CR_MAX_GENERAL_COMBINERS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerStageColor0[i]); + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerStageColor1[i]); + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerInput[i]); + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerOutput[i]); +} +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerFinalInput); + +_CRSTATE_BITS_OP_SIZEOF(stencil.dirty); +_CRSTATE_BITS_OP_SIZEOF(stencil.enable); +#ifdef _CRSTATE_BITS_OP_STENCIL_V_33 +_CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func); +_CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op); +for (i = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK + 1; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) +{ + CRSTATE_BITS_OP_STENCIL_FUNC_V_33(i, stencil.bufferRefs[i].func); + CRSTATE_BITS_OP_STENCIL_OP_V_33(i, stencil.bufferRefs[i].op); +} +_CRSTATE_BITS_OP_SIZEOF(stencil.clearValue); +_CRSTATE_BITS_OP_SIZEOF(stencil.writeMask); +#else +_CRSTATE_BITS_OP_SIZEOF(stencil.enableTwoSideEXT); +_CRSTATE_BITS_OP_SIZEOF(stencil.activeStencilFace); +_CRSTATE_BITS_OP_SIZEOF(stencil.clearValue); +_CRSTATE_BITS_OP_SIZEOF(stencil.writeMask); +for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[i].func); + _CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[i].op); +} +#endif + +_CRSTATE_BITS_OP_SIZEOF(texture.dirty); +for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(texture.enable[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.current[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.objGen[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.eyeGen[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.genMode[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.envBit[i]); +} + +_CRSTATE_BITS_OP_SIZEOF(transform.dirty); +_CRSTATE_BITS_OP_SIZEOF(transform.matrixMode); +_CRSTATE_BITS_OP_SIZEOF(transform.modelviewMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.projectionMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.colorMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.textureMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.programMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.clipPlane); +_CRSTATE_BITS_OP_SIZEOF(transform.enable); +_CRSTATE_BITS_OP_SIZEOF(transform.base); + +_CRSTATE_BITS_OP_SIZEOF(viewport.dirty); +_CRSTATE_BITS_OP_SIZEOF(viewport.v_dims); +_CRSTATE_BITS_OP_SIZEOF(viewport.s_dims); +_CRSTATE_BITS_OP_SIZEOF(viewport.enable); +_CRSTATE_BITS_OP_SIZEOF(viewport.depth); + +} while (0); + +#undef CRSTATE_BITS_OP_VERSION +#undef _CRSTATE_BITS_OP_STENCIL_V_33 diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c index 6214e889..90917ab5 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c @@ -483,6 +483,7 @@ void STATE_APIENTRY crStateDrawBuffer (GLenum mode) switch (mode) { case GL_NONE: + break; case GL_FRONT_LEFT: case GL_FRONT_RIGHT: case GL_BACK_LEFT: @@ -548,6 +549,7 @@ void STATE_APIENTRY crStateReadBuffer (GLenum mode) switch (mode) { case GL_NONE: + break; case GL_FRONT_LEFT: case GL_FRONT_RIGHT: case GL_BACK_LEFT: diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c index 5a3d2e49..bd6a1e20 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c @@ -22,16 +22,25 @@ static CRBufferObject *AllocBufferObject(GLuint name) b->usage = GL_STATIC_DRAW_ARB; b->access = GL_READ_WRITE_ARB; b->bResyncOnRead = GL_FALSE; -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_INIT(b); -#endif } return b; } -GLboolean crStateIsBufferBound(GLenum target) +void STATE_APIENTRY crStateGenBuffersARB(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->buffersTable, n, buffers); +} + +void crStateRegBuffers(GLsizei n, GLuint *buffers) { CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->buffersTable, n, buffers); +} + +GLboolean crStateIsBufferBoundForCtx(CRContext *g, GLenum target) +{ CRBufferObjectState *b = &(g->bufferobject); switch (target) @@ -51,6 +60,12 @@ GLboolean crStateIsBufferBound(GLenum target) } } +GLboolean crStateIsBufferBound(GLenum target) +{ + CRContext *g = GetCurrentContext(); + return crStateIsBufferBoundForCtx(g, target); +} + CRBufferObject *crStateGetBoundBufferObject(GLenum target, CRBufferObjectState *b) { switch (target) @@ -70,6 +85,21 @@ CRBufferObject *crStateGetBoundBufferObject(GLenum target, CRBufferObjectState * } } +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsBufferARB( GLuint buffer ) +{ + CRContext *g = GetCurrentContext(); + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsBufferARB called in begin/end"); + return GL_FALSE; + } + + return buffer ? crHashtableIsKeyUsed(g->shared->buffersTable, buffer) : GL_FALSE; +} + void crStateBufferObjectInit (CRContext *ctx) { CRStateBits *sb = GetCurrentBits(); @@ -93,7 +123,7 @@ void crStateBufferObjectInit (CRContext *ctx) b->nullBuffer = AllocBufferObject(0); b->arrayBuffer = b->nullBuffer; b->elementsBuffer = b->nullBuffer; - b->nullBuffer->refCount = 3; + b->nullBuffer->refCount += 2; #ifdef CR_ARB_pixel_buffer_object b->packBuffer = b->nullBuffer; b->unpackBuffer = b->nullBuffer; @@ -184,17 +214,22 @@ crStateBindBufferARB (GLenum target, GLuint buffer) else { newObj = (CRBufferObject *) crHashtableSearch(g->shared->buffersTable, buffer); if (!newObj) { + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->buffersTable, buffer), GL_INVALID_OPERATION, "name is not a buffer object"); newObj = AllocBufferObject(buffer); - if (!newObj) { - crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glBindBuffer"); + CRSTATE_CHECKERR(!newObj, GL_OUT_OF_MEMORY, "glBindBuffer"); +#ifndef IN_GUEST + diff_api.GenBuffersARB(1, &newObj->hwid); + if (!newObj->hwid) + { + crWarning("GenBuffersARB failed!"); + crFree(newObj); return; } +#endif crHashtableAdd( g->shared->buffersTable, buffer, newObj ); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(newObj, g); -#endif } newObj->refCount++; @@ -243,127 +278,124 @@ crStateBindBufferARB (GLenum target, GLuint buffer) #endif } -void STATE_APIENTRY -crStateDeleteBuffersARB(GLsizei n, const GLuint *buffers) +static void ctStateBuffersRefsCleanup(CRContext *ctx, CRBufferObject *obj, CRbitvalue *neg_bitid) { - CRContext *g = GetCurrentContext(); - CRBufferObjectState *b = &(g->bufferobject); + CRBufferObjectState *b = &(ctx->bufferobject); CRStateBits *sb = GetCurrentBits(); CRBufferObjectBits *bb = &(sb->bufferobject); - int i; + int j, k; - FLUSH(); - - if (g->current.inBeginEnd) { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glDeleteBuffersARB called in Begin/End"); - return; + if (obj == b->arrayBuffer) + { + b->arrayBuffer = b->nullBuffer; + b->arrayBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->arrayBinding, neg_bitid); } - - if (n < 0) { - crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, - "glDeleteBuffersARB(n < 0)"); - return; + if (obj == b->elementsBuffer) + { + b->elementsBuffer = b->nullBuffer; + b->elementsBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->elementsBinding, neg_bitid); } - - for (i = 0; i < n; i++) { - if (buffers[i]) { - CRBufferObject *obj = (CRBufferObject *) - crHashtableSearch(g->shared->buffersTable, buffers[i]); - if (obj) { - if (obj == b->arrayBuffer) - { - b->arrayBuffer = b->nullBuffer; - b->arrayBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->arrayBinding, g->neg_bitid); - } - else if (obj == b->elementsBuffer) - { - b->elementsBuffer = b->nullBuffer; - b->elementsBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->elementsBinding, g->neg_bitid); - } #ifdef CR_ARB_pixel_buffer_object - else if (obj == b->packBuffer) - { - b->packBuffer = b->nullBuffer; - b->packBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->packBinding, g->neg_bitid); - } - else if (obj == b->unpackBuffer) - { - b->unpackBuffer = b->nullBuffer; - b->unpackBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->unpackBinding, g->neg_bitid); - } + if (obj == b->packBuffer) + { + b->packBuffer = b->nullBuffer; + b->packBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->packBinding, neg_bitid); + } + if (obj == b->unpackBuffer) + { + b->unpackBuffer = b->nullBuffer; + b->unpackBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->unpackBinding, neg_bitid); + } #endif - /* @todo check bindings with the vertex arrays */ - crHashtableDelete(g->shared->buffersTable, buffers[i], crStateFreeBufferObject); +#ifdef CR_ARB_vertex_buffer_object + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) + { + CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array); + if (obj == cp->buffer) + { + cp->buffer = b->nullBuffer; + ++b->nullBuffer->refCount; + } + } + + for (k=0; k<ctx->client.vertexArrayStackDepth; ++k) + { + CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k]; + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) + { + CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray); + if (obj == cp->buffer) + { + cp->buffer = b->nullBuffer; + ++b->nullBuffer->refCount; } } } -} +#endif + CR_STATE_SHAREDOBJ_USAGE_CLEAR(obj, ctx); +} void STATE_APIENTRY -crStateGenBuffersARB(GLsizei n, GLuint * buffers) +crStateDeleteBuffersARB(GLsizei n, const GLuint *buffers) { CRContext *g = GetCurrentContext(); - CRBufferObjectState *b = &(g->bufferobject); - GLint start; + int i; FLUSH(); if (g->current.inBeginEnd) { crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glGenBuffersARB called in Begin/End"); + "glDeleteBuffersARB called in Begin/End"); return; } if (n < 0) { crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, - "glGenBuffersARB(n < 0)"); + "glDeleteBuffersARB(n < 0)"); return; } - start = crHashtableAllocKeys(g->shared->buffersTable, n); - if (start) { - GLint i; - for (i = 0; i < n; i++) - buffers[i] = (GLuint) (start + i); - } - else { - crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glGenBuffersARB"); - } -} - + for (i = 0; i < n; i++) { + if (buffers[i]) { + CRBufferObject *obj = (CRBufferObject *) + crHashtableSearch(g->shared->buffersTable, buffers[i]); + if (obj) { + int j; -GLboolean STATE_APIENTRY -crStateIsBufferARB(GLuint buffer) -{ - CRContext *g = GetCurrentContext(); - CRBufferObjectState *b = &g->bufferobject; + ctStateBuffersRefsCleanup(g, obj, g->neg_bitid); - FLUSH(); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(obj, j) + { + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + ctStateBuffersRefsCleanup(ctx, obj, g->neg_bitid); /* <- yes, use g->neg_bitid, i.e. neg_bitid of the current context to ensure others bits get dirtified, + * but not the current context ones*/ + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(obj, j); + } - if (g->current.inBeginEnd) { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glIsBufferARB called in begin/end"); - return GL_FALSE; + crHashtableDelete(g->shared->buffersTable, buffers[i], crStateFreeBufferObject); + } + } } - - if (buffer && crHashtableSearch(g->shared->buffersTable, buffer)) - return GL_TRUE; - else - return GL_FALSE; } - void STATE_APIENTRY crStateBufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage) { diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c index f0405c64..e02f3abe 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c @@ -83,8 +83,9 @@ static void crStateUnlockClientPointer(CRClientPointer* cp) } } -void crStateClientDestroy(CRClientState *c) +void crStateClientDestroy(CRContext *g) { + CRClientState *c = &(g->client); #ifdef CR_EXT_compiled_vertex_array if (c->array.locked) { @@ -109,9 +110,9 @@ void crStateClientDestroy(CRClientState *c) #endif } -void crStateClientInit(CRClientState *c) +void crStateClientInit(CRContext *ctx) { - CRContext *g = GetCurrentContext(); + CRClientState *c = &(ctx->client); unsigned int i; /* pixel pack/unpack */ @@ -151,7 +152,9 @@ void crStateClientInit(CRClientState *c) c->array.v.stride = 0; c->array.v.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.v.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.v.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.v.buffer) + ++c->array.v.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.v.locked = GL_FALSE; @@ -166,7 +169,9 @@ void crStateClientInit(CRClientState *c) c->array.c.stride = 0; c->array.c.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.c.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.c.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.c.buffer) + ++c->array.c.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.c.locked = GL_FALSE; @@ -181,7 +186,9 @@ void crStateClientInit(CRClientState *c) c->array.f.stride = 0; c->array.f.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.f.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.f.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.f.buffer) + ++c->array.f.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.f.locked = GL_FALSE; @@ -196,7 +203,9 @@ void crStateClientInit(CRClientState *c) c->array.s.stride = 0; c->array.s.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.s.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.s.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.s.buffer) + ++c->array.s.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.s.locked = GL_FALSE; @@ -211,7 +220,9 @@ void crStateClientInit(CRClientState *c) c->array.e.stride = 0; c->array.e.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.e.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.e.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.e.buffer) + ++c->array.e.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.e.locked = GL_FALSE; @@ -226,7 +237,9 @@ void crStateClientInit(CRClientState *c) c->array.i.stride = 0; c->array.i.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.i.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.i.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.i.buffer) + ++c->array.i.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.i.locked = GL_FALSE; @@ -241,7 +254,9 @@ void crStateClientInit(CRClientState *c) c->array.n.stride = 0; c->array.n.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.n.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.n.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.n.buffer) + ++c->array.n.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.n.locked = GL_FALSE; @@ -258,7 +273,9 @@ void crStateClientInit(CRClientState *c) c->array.t[i].stride = 0; c->array.t[i].enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.t[i].buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.t[i].buffer = ctx->bufferobject.arrayBuffer; + if (c->array.t[i].buffer) + ++c->array.t[i].buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.t[i].locked = GL_FALSE; @@ -275,7 +292,9 @@ void crStateClientInit(CRClientState *c) c->array.a[i].size = 4; c->array.a[i].stride = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.a[i].buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.a[i].buffer = ctx->bufferobject.arrayBuffer; + if (c->array.a[i].buffer) + ++c->array.a[i].buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.a[i].locked = GL_FALSE; @@ -622,7 +641,14 @@ crStateClientSetPointer(CRClientPointer *cp, GLint size, cp->stride = cp->bytesPerIndex; #ifdef CR_ARB_vertex_buffer_object + if (cp->buffer) + { + --cp->buffer->refCount; + CRASSERT(cp->buffer->refCount && cp->buffer->refCount < UINT32_MAX/2); + } cp->buffer = g->bufferobject.arrayBuffer; + if (cp->buffer) + ++cp->buffer->refCount; #endif } @@ -1622,6 +1648,7 @@ crStateUseServerArrayElements(void) #endif } +#define CR_BUFFER_HWID(_p) ((_p) ? (_p)->hwid : 0) void crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, @@ -1631,6 +1658,17 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, const CRClientState *to = &(toCtx->client); GLint curClientTextureUnit = from->curClientTextureUnit; int i; + GLint idHwArrayBuffer = CR_BUFFER_HWID(toCtx->bufferobject.arrayBuffer); + const GLint idHwInitialBuffer = idHwArrayBuffer; + +#ifdef DEBUG_misha + { + GLint tstHwBuffer = -1; + diff_api.GetIntegerv(GL_ARRAY_BUFFER_BINDING, &tstHwBuffer); + CRASSERT(idHwInitialBuffer == tstHwBuffer); + } +#endif + if (CHECKDIRTY(cb->clientPointer, bitID)) { /* one or more vertex pointers is dirty */ @@ -1638,7 +1676,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.v.size != to->array.v.size || from->array.v.type != to->array.v.type || from->array.v.stride != to->array.v.stride || + from->array.v.p != to->array.v.p || from->array.v.buffer != to->array.v.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.v.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexPointer(to->array.v.size, to->array.v.type, to->array.v.stride, to->array.v.p); from->array.v.size = to->array.v.size; @@ -1653,7 +1698,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->n, bitID)) { if (from->array.n.type != to->array.n.type || from->array.n.stride != to->array.n.stride || + from->array.n.p != to->array.n.p || from->array.n.buffer != to->array.n.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.n.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.NormalPointer(to->array.n.type, to->array.n.stride, to->array.n.p); from->array.n.type = to->array.n.type; @@ -1668,7 +1720,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.c.size != to->array.c.size || from->array.c.type != to->array.c.type || from->array.c.stride != to->array.c.stride || + from->array.c.p != to->array.c.p || from->array.c.buffer != to->array.c.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.c.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ColorPointer(to->array.c.size, to->array.c.type, to->array.c.stride, to->array.c.p); from->array.c.size = to->array.c.size; @@ -1683,7 +1742,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->i, bitID)) { if (from->array.i.type != to->array.i.type || from->array.i.stride != to->array.i.stride || + from->array.i.p != to->array.i.p || from->array.i.buffer != to->array.i.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.i.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.IndexPointer(to->array.i.type, to->array.i.stride, to->array.i.p); from->array.i.type = to->array.i.type; @@ -1699,7 +1765,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.t[i].size != to->array.t[i].size || from->array.t[i].type != to->array.t[i].type || from->array.t[i].stride != to->array.t[i].stride || + from->array.t[i].p != to->array.t[i].p || from->array.t[i].buffer != to->array.t[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.t[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ClientActiveTextureARB(GL_TEXTURE0_ARB + i); curClientTextureUnit = i; diff_api.TexCoordPointer(to->array.t[i].size, to->array.t[i].type, @@ -1716,7 +1789,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, /* edge flag */ if (CHECKDIRTY(cb->e, bitID)) { if (from->array.e.stride != to->array.e.stride || + from->array.e.p != to->array.e.p || from->array.e.buffer != to->array.e.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.e.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.EdgeFlagPointer(to->array.e.stride, to->array.e.p); from->array.e.stride = to->array.e.stride; from->array.e.p = to->array.e.p; @@ -1729,7 +1809,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.s.size != to->array.s.size || from->array.s.type != to->array.s.type || from->array.s.stride != to->array.s.stride || + from->array.s.p != to->array.s.p || from->array.s.buffer != to->array.s.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.s.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.SecondaryColorPointerEXT(to->array.s.size, to->array.s.type, to->array.s.stride, to->array.s.p); from->array.s.size = to->array.s.size; @@ -1744,7 +1831,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->f, bitID)) { if (from->array.f.type != to->array.f.type || from->array.f.stride != to->array.f.stride || + from->array.f.p != to->array.f.p || from->array.f.buffer != to->array.f.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.f.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.FogCoordPointerEXT(to->array.f.type, to->array.f.stride, to->array.f.p); from->array.f.type = to->array.f.type; @@ -1762,7 +1856,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, from->array.a[i].type != to->array.a[i].type || from->array.a[i].stride != to->array.a[i].stride || from->array.a[i].normalized != to->array.a[i].normalized || + from->array.a[i].p != to->array.a[i].p || from->array.a[i].buffer != to->array.a[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.a[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexAttribPointerARB(i, to->array.a[i].size, to->array.a[i].type, to->array.a[i].normalized, @@ -1781,11 +1882,16 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, #endif } + if (idHwArrayBuffer != idHwInitialBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwInitialBuffer); + } + if (CHECKDIRTY(cb->enableClientState, bitID)) { /* update vertex array enable/disable flags */ glAble able[2]; - able[0] = diff_api.Disable; - able[1] = diff_api.Enable; + able[0] = diff_api.DisableClientState; + able[1] = diff_api.EnableClientState; if (from->array.v.enabled != to->array.v.enabled) { able[to->array.v.enabled](GL_VERTEX_ARRAY); from->array.v.enabled = to->array.v.enabled; @@ -1849,6 +1955,16 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, const CRClientState *to = &(toCtx->client); GLint curClientTextureUnit = from->curClientTextureUnit; int i; + GLint idHwArrayBuffer = CR_BUFFER_HWID(toCtx->bufferobject.arrayBuffer); + const GLint idHwInitialBuffer = idHwArrayBuffer; + +#ifdef DEBUG_misha + { + GLint tstHwBuffer = -1; + diff_api.GetIntegerv(GL_ARRAY_BUFFER_BINDING, &tstHwBuffer); + CRASSERT(idHwInitialBuffer == tstHwBuffer); + } +#endif if (CHECKDIRTY(cb->clientPointer, bitID)) { /* one or more vertex pointers is dirty */ @@ -1856,7 +1972,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.v.size != to->array.v.size || from->array.v.type != to->array.v.type || from->array.v.stride != to->array.v.stride || + from->array.v.p != to->array.v.p || from->array.v.buffer != to->array.v.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.v.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexPointer(to->array.v.size, to->array.v.type, to->array.v.stride, to->array.v.p); FILLDIRTY(cb->v); @@ -1869,7 +1992,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->n, bitID)) { if (from->array.n.type != to->array.n.type || from->array.n.stride != to->array.n.stride || + from->array.n.p != to->array.n.p || from->array.n.buffer != to->array.n.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.n.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.NormalPointer(to->array.n.type, to->array.n.stride, to->array.n.p); FILLDIRTY(cb->n); @@ -1883,7 +2013,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.c.size != to->array.c.size || from->array.c.type != to->array.c.type || from->array.c.stride != to->array.c.stride || + from->array.c.p != to->array.c.p || from->array.c.buffer != to->array.c.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.c.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ColorPointer(to->array.c.size, to->array.c.type, to->array.c.stride, to->array.c.p); FILLDIRTY(cb->c); @@ -1896,7 +2033,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->i, bitID)) { if (from->array.i.type != to->array.i.type || from->array.i.stride != to->array.i.stride || + from->array.i.p != to->array.i.p || from->array.i.buffer != to->array.i.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.i.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.IndexPointer(to->array.i.type, to->array.i.stride, to->array.i.p); FILLDIRTY(cb->i); @@ -1911,7 +2055,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.t[i].size != to->array.t[i].size || from->array.t[i].type != to->array.t[i].type || from->array.t[i].stride != to->array.t[i].stride || + from->array.t[i].p != to->array.t[i].p || from->array.t[i].buffer != to->array.t[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.t[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ClientActiveTextureARB(GL_TEXTURE0_ARB + i); curClientTextureUnit = i; diff_api.TexCoordPointer(to->array.t[i].size, to->array.t[i].type, @@ -1926,7 +2077,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, /* edge flag */ if (CHECKDIRTY(cb->e, bitID)) { if (from->array.e.stride != to->array.e.stride || + from->array.e.p != to->array.e.p || from->array.e.buffer != to->array.e.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.e.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.EdgeFlagPointer(to->array.e.stride, to->array.e.p); FILLDIRTY(cb->e); FILLDIRTY(cb->clientPointer); @@ -1939,7 +2097,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.s.size != to->array.s.size || from->array.s.type != to->array.s.type || from->array.s.stride != to->array.s.stride || + from->array.s.p != to->array.s.p || from->array.s.buffer != to->array.s.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.s.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.SecondaryColorPointerEXT(to->array.s.size, to->array.s.type, to->array.s.stride, to->array.s.p); FILLDIRTY(cb->s); @@ -1952,7 +2117,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->f, bitID)) { if (from->array.f.type != to->array.f.type || from->array.f.stride != to->array.f.stride || + from->array.f.p != to->array.f.p || from->array.f.buffer != to->array.f.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.f.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.FogCoordPointerEXT(to->array.f.type, to->array.f.stride, to->array.f.p); FILLDIRTY(cb->f); @@ -1969,7 +2141,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, from->array.a[i].type != to->array.a[i].type || from->array.a[i].stride != to->array.a[i].stride || from->array.a[i].normalized != to->array.a[i].normalized || + from->array.a[i].p != to->array.a[i].p || from->array.a[i].buffer != to->array.a[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.a[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexAttribPointerARB(i, to->array.a[i].size, to->array.a[i].type, to->array.a[i].normalized, @@ -1985,11 +2164,16 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, #endif } + if (idHwArrayBuffer != idHwInitialBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwInitialBuffer); + } + if (CHECKDIRTY(cb->enableClientState, bitID)) { /* update vertex array enable/disable flags */ glAble able[2]; - able[0] = diff_api.Disable; - able[1] = diff_api.Enable; + able[0] = diff_api.DisableClientState; + able[1] = diff_api.EnableClientState; if (from->array.v.enabled != to->array.v.enabled) { able[to->array.v.enabled](GL_VERTEX_ARRAY); FILLDIRTY(cb->enableClientState); @@ -2038,7 +2222,7 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.a[i].enabled != to->array.a[i].enabled) { if (to->array.a[i].enabled) diff_api.EnableVertexAttribArrayARB(i); - else + else diff_api.DisableVertexAttribArrayARB(i); FILLDIRTY(cb->enableClientState); FILLDIRTY(cb->dirty); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c index d46a9561..c8e616d2 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c @@ -8,6 +8,8 @@ #include "cr_error.h" #include "cr_mem.h" #include "cr_pixeldata.h" +#include <iprt/err.h> +#include <stdio.h> void crStateDiffContext( CRContext *from, CRContext *to ) { @@ -121,12 +123,165 @@ void crStateDiffContext( CRContext *from, CRContext *to ) } } -void crStateApplyFBImage(CRContext *to) +void crStateFreeFBImageLegacy(CRContext *to) +{ + if (to->buffer.pFrontImg) + { + crFree(to->buffer.pFrontImg); + to->buffer.pFrontImg = NULL; + } + if (to->buffer.pBackImg) + { + crFree(to->buffer.pBackImg); + to->buffer.pBackImg = NULL; + } + + to->buffer.storedWidth = 0; + to->buffer.storedHeight = 0; +} + +int crStateAcquireFBImage(CRContext *to, CRFBData *data) +{ + CRBufferState *pBuf = &to->buffer; + CRPixelPackState packing = to->client.pack; + uint32_t i; + + diff_api.PixelStorei(GL_PACK_SKIP_ROWS, 0); + diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, 0); + diff_api.PixelStorei(GL_PACK_ALIGNMENT, 1); + diff_api.PixelStorei(GL_PACK_ROW_LENGTH, 0); + diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, 0); + diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, 0); + diff_api.PixelStorei(GL_PACK_SWAP_BYTES, 0); + diff_api.PixelStorei(GL_PACK_LSB_FIRST, 0); + + if (to->bufferobject.packBuffer->hwid>0) + { + diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } + + for (i = 0; i < data->cElements; ++i) + { + CRFBDataElement *el = &data->aElements[i]; + + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + if (!to->buffer.depthTest) + { + diff_api.Enable(GL_DEPTH_TEST); + } + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, 1.0f); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, 0.0f); + } + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + if (!to->stencil.stencilTest) + { + diff_api.Enable(GL_STENCIL_TEST); + } + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_FALSE); + } + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, 0); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, 0); + } + } + + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, el->idFBO); + + if (el->enmBuffer) + diff_api.ReadBuffer(el->enmBuffer); + + diff_api.ReadPixels(el->posX, el->posY, el->width, el->height, el->enmFormat, el->enmType, el->pvData); + crDebug("Acquired %d;%d;%d;%d;%d;0x%p fb image", el->enmBuffer, el->width, el->height, el->enmFormat, el->enmType, el->pvData); + + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, to->pixel.depthScale); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, to->pixel.depthBias); + } + if (!to->buffer.depthTest) + { + diff_api.Disable(GL_DEPTH_TEST); + } + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, to->pixel.indexOffset); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, to->pixel.indexShift); + } + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_TRUE); + } + if (!to->stencil.stencilTest) + { + diff_api.Disable(GL_STENCIL_TEST); + } + } + } + + if (to->bufferobject.packBuffer->hwid>0) + { + diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, to->bufferobject.packBuffer->hwid); + } + if (to->framebufferobject.readFB) + { + CRASSERT(to->framebufferobject.readFB->hwid); + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, to->framebufferobject.readFB->hwid); + diff_api.ReadBuffer(to->framebufferobject.readFB->readbuffer); + + } + else if (data->idOverrrideFBO) + { + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, data->idOverrrideFBO); + diff_api.ReadBuffer(GL_COLOR_ATTACHMENT0); + } + else + { + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); + diff_api.ReadBuffer(to->buffer.readBuffer); + } + + diff_api.PixelStorei(GL_PACK_SKIP_ROWS, packing.skipRows); + diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, packing.skipPixels); + diff_api.PixelStorei(GL_PACK_ALIGNMENT, packing.alignment); + diff_api.PixelStorei(GL_PACK_ROW_LENGTH, packing.rowLength); + diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, packing.imageHeight); + diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, packing.skipImages); + diff_api.PixelStorei(GL_PACK_SWAP_BYTES, packing.swapBytes); + diff_api.PixelStorei(GL_PACK_LSB_FIRST, packing.psLSBFirst); + return VINF_SUCCESS; +} + +void crStateApplyFBImage(CRContext *to, CRFBData *data) { - if (to->buffer.pFrontImg || to->buffer.pBackImg) { CRBufferState *pBuf = &to->buffer; CRPixelPackState unpack = to->client.unpack; + uint32_t i; diff_api.PixelStorei(GL_UNPACK_SKIP_ROWS, 0); diff_api.PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); @@ -137,11 +292,6 @@ void crStateApplyFBImage(CRContext *to) diff_api.PixelStorei(GL_UNPACK_SWAP_BYTES, 0); diff_api.PixelStorei(GL_UNPACK_LSB_FIRST, 0); - if (to->framebufferobject.drawFB) - { - diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - } - if (to->bufferobject.unpackBuffer->hwid>0) { diff_api.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); @@ -151,25 +301,84 @@ void crStateApplyFBImage(CRContext *to) diff_api.Disable(GL_SCISSOR_TEST); diff_api.Disable(GL_BLEND); diff_api.Disable(GL_COLOR_LOGIC_OP); + diff_api.Disable(GL_DEPTH_TEST); + diff_api.Disable(GL_STENCIL_TEST); - if (pBuf->pFrontImg) + for (i = 0; i < data->cElements; ++i) { - diff_api.DrawBuffer(GL_FRONT); - diff_api.WindowPos2iARB(0, 0); - diff_api.DrawPixels(pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pBuf->pFrontImg); - crDebug("Applied %ix%i fb image", pBuf->storedWidth, pBuf->storedHeight); - crFree(pBuf->pFrontImg); - pBuf->pFrontImg = NULL; - } + CRFBDataElement *el = &data->aElements[i]; +#if 0 + char fname[200]; + sprintf(fname, "./img_apply_%p_%d_%d.tga", to, i, el->enmFormat); + crDumpNamedTGA(fname, el->width, el->height, el->pvData); +#endif - if (pBuf->pBackImg) - { - diff_api.DrawBuffer(GL_BACK); - diff_api.WindowPos2iARB(0, 0); - diff_api.DrawPixels(pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pBuf->pBackImg); - crDebug("Applied %ix%i bb image", pBuf->storedWidth, pBuf->storedHeight); - crFree(pBuf->pBackImg); - pBuf->pBackImg = NULL; + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + diff_api.Enable(GL_DEPTH_TEST); + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, 1.0f); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, 0.0f); + } + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + diff_api.Enable(GL_STENCIL_TEST); + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_FALSE); + } + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, 0); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, 0); + } + } + + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, el->idFBO); + + if (el->enmBuffer) + diff_api.DrawBuffer(el->enmBuffer); + + diff_api.WindowPos2iARB(el->posX, el->posY); + diff_api.DrawPixels(el->width, el->height, el->enmFormat, el->enmType, el->pvData); + crDebug("Applied %d;%d;%d;%d;%d;0x%p fb image", el->enmBuffer, el->width, el->height, el->enmFormat, el->enmType, el->pvData); + + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, to->pixel.depthScale); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, to->pixel.depthBias); + } + diff_api.Disable(GL_DEPTH_TEST); + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, to->pixel.indexOffset); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, to->pixel.indexShift); + } + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_TRUE); + } + diff_api.Disable(GL_STENCIL_TEST); + } } diff_api.WindowPos3fvARB(to->current.rasterAttrib[VERT_ATTRIB_POS]); @@ -179,10 +388,20 @@ void crStateApplyFBImage(CRContext *to) } if (to->framebufferobject.drawFB) { + CRASSERT(to->framebufferobject.drawFB->hwid); diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, to->framebufferobject.drawFB->hwid); + diff_api.DrawBuffer(to->framebufferobject.drawFB->drawbuffer[0]); + } + else if (data->idOverrrideFBO) + { + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, data->idOverrrideFBO); + diff_api.DrawBuffer(GL_COLOR_ATTACHMENT0); + } + else + { + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); + diff_api.DrawBuffer(to->buffer.drawBuffer); } - diff_api.DrawBuffer(to->framebufferobject.drawFB ? - to->framebufferobject.drawFB->drawbuffer[0] : to->buffer.drawBuffer); if (to->buffer.alphaTest) { diff_api.Enable(GL_ALPHA_TEST); @@ -199,6 +418,14 @@ void crStateApplyFBImage(CRContext *to) { diff_api.Enable(GL_COLOR_LOGIC_OP); } + if (to->buffer.depthTest) + { + diff_api.Enable(GL_DEPTH_TEST); + } + if (to->stencil.stencilTest) + { + diff_api.Enable(GL_STENCIL_TEST); + } diff_api.PixelStorei(GL_UNPACK_SKIP_ROWS, unpack.skipRows); diff_api.PixelStorei(GL_UNPACK_SKIP_PIXELS, unpack.skipPixels); @@ -341,34 +568,59 @@ void crStateSwitchContext( CRContext *from, CRContext *to ) } #ifdef WINDOWS - crStateApplyFBImage(to); + if (to->buffer.pFrontImg) + { + CRFBData *pLazyData = (CRFBData *)to->buffer.pFrontImg; + crStateApplyFBImage(to, pLazyData); + crStateFreeFBImageLegacy(to); + } #endif } -CRContext * crStateSwichPrepare(CRContext *toCtx, GLboolean fMultipleContexts, GLuint idFBO) +void crStateSyncHWErrorState(CRContext *ctx) { - CRContext *fromCtx = GetCurrentContext(); - - if (!fMultipleContexts) + GLenum err; + while ((err = diff_api.GetError()) != GL_NO_ERROR) { + if (ctx->error != GL_NO_ERROR) + ctx->error = err; + } +} + +void crStateSwitchPrepare(CRContext *toCtx, CRContext *fromCtx, GLuint idDrawFBO, GLuint idReadFBO) +{ + if (!fromCtx) + return; + + if (g_bVBoxEnableDiffOnMakeCurrent && toCtx && toCtx != fromCtx) + crStateSyncHWErrorState(fromCtx); + #ifdef CR_EXT_framebuffer_object - if (fromCtx) - crStateFramebufferObjectDisableHW(fromCtx, idFBO); + crStateFramebufferObjectDisableHW(fromCtx, idDrawFBO, idReadFBO); #endif - } - return fromCtx; } -void crStateSwichPostprocess(CRContext *fromCtx, GLboolean fMultipleContexts, GLuint idFBO) +void crStateSwitchPostprocess(CRContext *toCtx, CRContext *fromCtx, GLuint idDrawFBO, GLuint idReadFBO) { - CRContext *toCtx = GetCurrentContext();; - if (!fromCtx || !toCtx) + if (!toCtx) return; - if (!fMultipleContexts) + if (g_bVBoxEnableDiffOnMakeCurrent && fromCtx && toCtx != fromCtx) { -#ifdef CR_EXT_framebuffer_object - crStateFramebufferObjectReenableHW(fromCtx, toCtx, idFBO); + GLenum err; + while ((err = diff_api.GetError()) != GL_NO_ERROR) + { + static int cErrPrints = 0; +#ifndef DEBUG_misha + if (cErrPrints < 5) #endif + { + ++cErrPrints; + crWarning("gl error (0x%x) after context switch, ignoring.. (%d out of 5) ..", err, cErrPrints); + } + } } +#ifdef CR_EXT_framebuffer_object + crStateFramebufferObjectReenableHW(fromCtx, toCtx, idDrawFBO, idReadFBO); +#endif } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c index 75a1534d..185de9eb 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c @@ -496,6 +496,13 @@ static void __enableSet (CRContext *g, CRStateBits *sb, CRbitvalue *neg_bitid, else crStateDisableClientState(cap); break; +#ifdef CR_EXT_stencil_two_side + case GL_STENCIL_TEST_TWO_SIDE_EXT: + g->stencil.stencilTwoSideEXT= val; + DIRTY(sb->stencil.enableTwoSideEXT, neg_bitid); + DIRTY(sb->stencil.dirty, neg_bitid); + break; +#endif default: crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glEnable/glDisable called with bogus cap: 0x%x", cap); return; diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c index 60eaa457..07a7b494 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c @@ -18,9 +18,14 @@ void crStateError( int line, const char *file, GLenum error, const char *format, char errstr[8096]; va_list args; - g->error = error; + CRASSERT(error != GL_NO_ERROR); + if (g->error == GL_NO_ERROR) + g->error = error; + +#ifndef DEBUG_misha if (crGetenv("CR_DEBUG")) +#endif { char *glerr; va_start( args, format ); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c index cdd3cecd..2f150361 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,12 +22,6 @@ #include "state_internals.h" #include "cr_mem.h" -#define CRSTATE_FBO_CHECKERR(expr, result, message) \ - if (expr) { \ - crStateError(__LINE__, __FILE__, result, message); \ - return; \ - } - DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectInit(CRContext *ctx) { @@ -39,6 +33,82 @@ crStateFramebufferObjectInit(CRContext *ctx) ctx->shared->bFBOResyncNeeded = GL_FALSE; } +void STATE_APIENTRY crStateGenFramebuffersEXT(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->fbTable, n, buffers); +} + +void STATE_APIENTRY crStateGenRenderbuffersEXT(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->rbTable, n, buffers); +} + +void crStateRegFramebuffers(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->fbTable, n, buffers); +} + +void crStateRegRenderbuffers(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->rbTable, n, buffers); +} + +static void crStateInitFrameBuffer(CRFramebufferObject *fbo); + +static CRFramebufferObject * +crStateFramebufferAllocate(CRContext *ctx, GLuint name) +{ + CRFramebufferObject *buffer = (CRFramebufferObject*) crCalloc(sizeof(CRFramebufferObject)); + CRSTATE_CHECKERR_RET(!buffer, GL_OUT_OF_MEMORY, "crStateFramebufferAllocate", NULL); + buffer->id = name; +#ifndef IN_GUEST + diff_api.GenFramebuffersEXT(1, &buffer->hwid); + if (!buffer->hwid) + { + crWarning("GenFramebuffersEXT failed!"); + crFree(buffer); + return NULL; + } +#else + buffer->hwid = name; +#endif + + crStateInitFrameBuffer(buffer); + crHashtableAdd(ctx->shared->fbTable, name, buffer); + CR_STATE_SHAREDOBJ_USAGE_INIT(buffer); + + return buffer; +} + +static CRRenderbufferObject * +crStateRenderbufferAllocate(CRContext *ctx, GLuint name) +{ + CRRenderbufferObject *buffer = (CRRenderbufferObject*) crCalloc(sizeof(CRRenderbufferObject)); + CRSTATE_CHECKERR_RET(!buffer, GL_OUT_OF_MEMORY, "crStateRenderbufferAllocate", NULL); + buffer->id = name; +#ifndef IN_GUEST + diff_api.GenRenderbuffersEXT(1, &buffer->hwid); + if (!buffer->hwid) + { + crWarning("GenRenderbuffersEXT failed!"); + crFree(buffer); + return NULL; + } +#else + buffer->hwid = name; +#endif + + buffer->internalformat = GL_RGBA; + crHashtableAdd(ctx->shared->rbTable, name, buffer); + CR_STATE_SHAREDOBJ_USAGE_INIT(buffer); + + return buffer; +} + void crStateFreeFBO(void *data) { CRFramebufferObject *pObj = (CRFramebufferObject *)data; @@ -83,28 +153,18 @@ crStateBindRenderbufferEXT(GLenum target, GLuint renderbuffer) CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); if (renderbuffer) { fbo->renderbuffer = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer); if (!fbo->renderbuffer) { - fbo->renderbuffer = (CRRenderbufferObject*) crCalloc(sizeof(CRRenderbufferObject)); - CRSTATE_FBO_CHECKERR(!fbo->renderbuffer, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); - fbo->renderbuffer->id = renderbuffer; - fbo->renderbuffer->hwid = renderbuffer; - fbo->renderbuffer->internalformat = GL_RGBA; - crHashtableAdd(g->shared->rbTable, renderbuffer, fbo->renderbuffer); -#ifndef IN_GUEST - CR_STATE_SHAREDOBJ_USAGE_INIT(fbo->renderbuffer); -#endif + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "name is not a renderbuffer"); + fbo->renderbuffer = crStateRenderbufferAllocate(g, renderbuffer); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(fbo->renderbuffer, g); -#endif - } else fbo->renderbuffer = NULL; } @@ -147,6 +207,22 @@ static void crStateCheckFBOAttachments(CRFramebufferObject *pFBO, GLuint rbo, GL } } +static void ctStateRenderbufferRefsCleanup(CRContext *g, GLuint fboId, CRRenderbufferObject *rbo) +{ + CRFramebufferObjectState *fbo = &g->framebufferobject; + + if (fbo->renderbuffer==rbo) + { + fbo->renderbuffer = NULL; + } + + /* check the attachments of current framebuffers */ + crStateCheckFBOAttachments(fbo->readFB, fboId, GL_READ_FRAMEBUFFER); + crStateCheckFBOAttachments(fbo->drawFB, fboId, GL_DRAW_FRAMEBUFFER); + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(rbo, g); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) { @@ -154,8 +230,8 @@ crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) CRFramebufferObjectState *fbo = &g->framebufferobject; int i; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); for (i = 0; i < n; i++) { @@ -165,15 +241,29 @@ crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) rbo = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffers[i]); if (rbo) { - if (fbo->renderbuffer==rbo) + int j; + + ctStateRenderbufferRefsCleanup(g, renderbuffers[i], rbo); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(rbo, j) { - fbo->renderbuffer = NULL; + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + CRFramebufferObjectState *ctxFbo; + CRASSERT(ctx); + ctxFbo = &ctx->framebufferobject; + if (ctxFbo->renderbuffer==rbo) + crWarning("deleting RBO being used by another context %d", ctx->id); + + ctStateRenderbufferRefsCleanup(ctx, renderbuffers[i], rbo); + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(rbo, j); } - - /* check the attachments of current framebuffers */ - crStateCheckFBOAttachments(fbo->readFB, renderbuffers[i], GL_READ_FRAMEBUFFER); - crStateCheckFBOAttachments(fbo->drawFB, renderbuffers[i], GL_DRAW_FRAMEBUFFER); - crHashtableDelete(g->shared->rbTable, renderbuffers[i], crStateFreeRBO); } } @@ -187,9 +277,9 @@ crStateRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei widt CRFramebufferObjectState *fbo = &g->framebufferobject; CRRenderbufferObject *rb = fbo->renderbuffer; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); rb->width = width; rb->height = height; @@ -203,9 +293,9 @@ crStateGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) CRFramebufferObjectState *fbo = &g->framebufferobject; CRRenderbufferObject *rb = fbo->renderbuffer; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); switch (pname) { @@ -224,10 +314,10 @@ crStateGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) case GL_RENDERBUFFER_ALPHA_SIZE_EXT: case GL_RENDERBUFFER_DEPTH_SIZE_EXT: case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "unimplemented"); + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "unimplemented"); break; default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); } } @@ -286,8 +376,8 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) CRFramebufferObjectState *fbo = &g->framebufferobject; CRFramebufferObject *pFBO=NULL; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); if (framebuffer) @@ -295,20 +385,12 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) pFBO = (CRFramebufferObject*) crHashtableSearch(g->shared->fbTable, framebuffer); if (!pFBO) { - pFBO = (CRFramebufferObject*) crCalloc(sizeof(CRFramebufferObject)); - CRSTATE_FBO_CHECKERR(!pFBO, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); - pFBO->id = framebuffer; - pFBO->hwid = framebuffer; - crStateInitFrameBuffer(pFBO); - crHashtableAdd(g->shared->fbTable, framebuffer, pFBO); -#ifndef IN_GUEST - CR_STATE_SHAREDOBJ_USAGE_INIT(pFBO); -#endif + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->fbTable, framebuffer), GL_INVALID_OPERATION, "name is not a framebuffer"); + pFBO = crStateFramebufferAllocate(g, framebuffer); } -#ifndef IN_GUEST + CR_STATE_SHAREDOBJ_USAGE_SET(pFBO, g); -#endif } /* @todo: http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt @@ -331,15 +413,29 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) } } +static void ctStateFramebufferRefsCleanup(CRContext *g, CRFramebufferObject *fb) +{ + CRFramebufferObjectState *fbo = &g->framebufferobject; + if (fbo->readFB==fb) + { + fbo->readFB = NULL; + } + if (fbo->drawFB==fb) + { + fbo->drawFB = NULL; + } + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(fb, g); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) { CRContext *g = GetCurrentContext(); - CRFramebufferObjectState *fbo = &g->framebufferobject; int i; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); for (i = 0; i < n; i++) { @@ -349,13 +445,32 @@ crStateDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) fb = (CRFramebufferObject*) crHashtableSearch(g->shared->fbTable, framebuffers[i]); if (fb) { - if (fbo->readFB==fb) - { - fbo->readFB = NULL; - } - if (fbo->drawFB==fb) + int j; + + ctStateFramebufferRefsCleanup(g, fb); + + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(fb, j) { - fbo->drawFB = NULL; + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + CRFramebufferObjectState *ctxFbo; + CRASSERT(ctx); + ctxFbo = &ctx->framebufferobject; + if (ctxFbo->readFB==fb) + crWarning("deleting FBO being used as read buffer by another context %d", ctx->id); + + if (ctxFbo->drawFB==fb) + crWarning("deleting FBO being used as draw buffer by another context %d", ctx->id); + + ctStateFramebufferRefsCleanup(ctx, fb); + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(fb, j); } crHashtableDelete(g->shared->fbTable, framebuffers[i], crStateFreeFBO); } @@ -380,27 +495,72 @@ unsigned int crLog2Floor(unsigned int x) return (x & 0x0000003f) - 1; } -static void crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, - GLboolean *failed, CRFBOAttachmentPoint **ap, CRTextureObj **tobj) +static GLuint crStateFramebufferGet(CRFramebufferObjectState *fbo, GLenum target, CRFramebufferObject **apFBOs) +{ + GLuint cPBOs = 0; + switch (target) + { + case GL_READ_FRAMEBUFFER: + cPBOs = 1; + apFBOs[0] = fbo->readFB; + break; + case GL_DRAW_FRAMEBUFFER: + cPBOs = 1; + apFBOs[0] = fbo->drawFB; + break; + case GL_FRAMEBUFFER: + if (fbo->readFB == fbo->drawFB) + { + cPBOs = 1; + apFBOs[0] = fbo->readFB; + } + else + { + cPBOs = 2; + apFBOs[0] = fbo->readFB; + apFBOs[1] = fbo->drawFB; + } + break; + default: + crWarning("unexpected target value: 0x%x", target); + cPBOs = 0; + break; + } + + return cPBOs; +} + +static GLuint crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, + CRFBOAttachmentPoint **aap, CRTextureObj **tobj) { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; + CRFramebufferObject *apFBOs[2]; + GLuint cFBOs = 0, i; GLuint maxtexsizelog2; - *failed = GL_TRUE; + CRSTATE_CHECKERR_RET(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end", 0); + CRSTATE_CHECKERR_RET(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + GL_INVALID_ENUM, "invalid target", 0); - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), - GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, ap), GL_INVALID_ENUM, "invalid attachment"); + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + CRSTATE_CHECKERR_RET(!cFBOs, GL_INVALID_ENUM, "unexpected target", 0); + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR_RET(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound", 0); + } + + Assert(cFBOs); + Assert(cFBOs <= 2); + + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR_RET(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &aap[i]), GL_INVALID_ENUM, "invalid attachment", 0); + } if (!texture) { - *failed = GL_FALSE; - return; + return cFBOs; } switch (textarget) @@ -428,27 +588,33 @@ static void crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLe *tobj = crStateTextureGet(textarget, texture); break; default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "invalid textarget"); + CRSTATE_CHECKERR_RET(GL_TRUE, GL_INVALID_OPERATION, "invalid textarget", 0); } - CRSTATE_FBO_CHECKERR(!*tobj, GL_INVALID_OPERATION, "invalid textarget/texture combo"); + CRSTATE_CHECKERR_RET(!*tobj, GL_INVALID_OPERATION, "invalid textarget/texture combo", 0); if (GL_TEXTURE_RECTANGLE_ARB==textarget) { - CRSTATE_FBO_CHECKERR(level!=0, GL_INVALID_VALUE, "non zero mipmap level"); + CRSTATE_CHECKERR_RET(level!=0, GL_INVALID_VALUE, "non zero mipmap level", 0); } - CRSTATE_FBO_CHECKERR(level<0, GL_INVALID_VALUE, "level<0"); - CRSTATE_FBO_CHECKERR(level>maxtexsizelog2, GL_INVALID_VALUE, "level too big"); - - *failed = GL_FALSE; + CRSTATE_CHECKERR_RET(level<0, GL_INVALID_VALUE, "level<0", 0); + CRSTATE_CHECKERR_RET(level>maxtexsizelog2, GL_INVALID_VALUE, "level too big", 0); #ifdef IN_GUEST - if ((*ap)->type!=GL_TEXTURE || (*ap)->name!=texture || (*ap)->level!=level) + for (i = 0; i < cFBOs; ++i) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; + if ((aap[i])->type!=GL_TEXTURE || (aap[i])->name!=texture || (aap[i])->level!=level) + { + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; + } } #endif + + Assert(cFBOs); + Assert(cFBOs <= 2); + + return cFBOs; } DECLEXPORT(void) STATE_APIENTRY @@ -456,29 +622,33 @@ crStateFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(textarget!=GL_TEXTURE_1D, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(textarget!=GL_TEXTURE_1D, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + } } DECLEXPORT(void) STATE_APIENTRY @@ -486,32 +656,36 @@ crStateFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(GL_TEXTURE_1D==textarget || GL_TEXTURE_3D==textarget, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(GL_TEXTURE_1D==textarget || GL_TEXTURE_3D==textarget, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; - if (textarget!=GL_TEXTURE_2D && textarget!=GL_TEXTURE_RECTANGLE_ARB) + for (i = 0; i < cap; ++i) { - ap->face = textarget; + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + if (textarget!=GL_TEXTURE_2D && textarget!=GL_TEXTURE_RECTANGLE_ARB) + { + aap[i]->face = textarget; + } } } @@ -520,31 +694,35 @@ crStateFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(zoffset>(g->limits.max3DTextureSize-1), GL_INVALID_VALUE, "zoffset too big"); - CRSTATE_FBO_CHECKERR(textarget!=GL_TEXTURE_3D, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(zoffset>(g->limits.max3DTextureSize-1), GL_INVALID_VALUE, "zoffset too big"); + CRSTATE_CHECKERR(textarget!=GL_TEXTURE_3D, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; - ap->zoffset = zoffset; + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + aap[i]->zoffset = zoffset; + } } DECLEXPORT(void) STATE_APIENTRY @@ -552,41 +730,62 @@ crStateFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum rende { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; - CRFBOAttachmentPoint *ap; + CRFramebufferObject *apFBOs[2]; + GLuint cFBOs, i; + CRFBOAttachmentPoint *aap[2]; CRRenderbufferObject *rb; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + CRSTATE_CHECKERR(!cFBOs, GL_INVALID_OPERATION, "no fbo bound"); + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound"); + } + + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &aap[i]), GL_INVALID_ENUM, "invalid attachment"); + } if (!renderbuffer) { -#ifdef IN_GUEST - if (ap->type!=GL_NONE) + for (i = 0; i < cFBOs; ++i) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; - } +#ifdef IN_GUEST + if (&aap[i]->type!=GL_NONE) + { + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; + } #endif - crStateInitFBOAttachmentPoint(ap); + crStateInitFBOAttachmentPoint(aap[i]); + } return; } rb = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "rb doesn't exist"); + if (!rb) + { + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "rb doesn't exist"); + rb = crStateRenderbufferAllocate(g, renderbuffer); + } + CR_STATE_SHAREDOBJ_USAGE_SET(rb, g); + + for (i = 0; i < cFBOs; ++i) + { #ifdef IN_GUEST - if (ap->type!=GL_RENDERBUFFER_EXT || ap->name!=renderbuffer) + if (aap[i]->type!=GL_RENDERBUFFER_EXT || aap[i]->name!=renderbuffer) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; } #endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_RENDERBUFFER_EXT; - ap->name = renderbuffer; + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_RENDERBUFFER_EXT; + aap[i]->name = renderbuffer; + } } DECLEXPORT(void) STATE_APIENTRY @@ -594,40 +793,87 @@ crStateGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; + CRFramebufferObject *apFBOs[2]; + GLint cFBOs = 0, i; CRFBOAttachmentPoint *ap; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); - switch (pname) + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + + CRSTATE_CHECKERR(!cFBOs, GL_INVALID_OPERATION, "no fbo bound"); + for (i = 0; i < cFBOs; ++i) { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = ap->type; - break; - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_RENDERBUFFER_EXT && ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "can't query object name when it's not bound") - *params = ap->name; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->level; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->face; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->zoffset; - break; - default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + CRSTATE_CHECKERR(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound"); + } + + if(cFBOs != 1) + { + crWarning("different FBPs attached to draw and read buffers, returning info for the read buffer"); + } + + for (i = 0; i < 1; ++i) + { + CRSTATE_CHECKERR(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: + *params = ap->type; + break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: + CRSTATE_CHECKERR(ap->type!=GL_RENDERBUFFER_EXT && ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "can't query object name when it's not bound") + *params = ap->name; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->level; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->face; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->zoffset; + break; + default: + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + } + } +} + +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsFramebufferEXT( GLuint framebuffer ) +{ + CRContext *g = GetCurrentContext(); + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsFramebufferEXT called in begin/end"); + return GL_FALSE; } + + return framebuffer ? crHashtableIsKeyUsed(g->shared->fbTable, framebuffer) : GL_FALSE; +} + +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsRenderbufferEXT( GLuint renderbuffer ) +{ + CRContext *g = GetCurrentContext(); + + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsRenderbufferEXT called in begin/end"); + return GL_FALSE; + } + + return renderbuffer ? crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer) : GL_FALSE; } DECLEXPORT(void) STATE_APIENTRY @@ -642,8 +888,11 @@ static void crStateSyncRenderbuffersCB(unsigned long key, void *data1, void *dat diff_api.GenRenderbuffersEXT(1, &pRBO->hwid); - diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, pRBO->hwid); - diff_api.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, pRBO->internalformat, pRBO->width, pRBO->height); + if (pRBO->width && pRBO->height) + { + diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, pRBO->hwid); + diff_api.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, pRBO->internalformat, pRBO->width, pRBO->height); + } } static void crStateSyncAP(CRFBOAttachmentPoint *pAP, GLenum ap, CRContext *ctx) @@ -774,36 +1023,37 @@ crStateFramebufferObjectSwitch(CRContext *from, CRContext *to) } DECLEXPORT(void) STATE_APIENTRY -crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idFBO) +crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idDrawFBO, GLuint idReadFBO) { - GLboolean fAdjustDrawReadBuffers = GL_FALSE; + GLenum idDrawBuffer = 0, idReadBuffer = 0; - if (ctx->framebufferobject.drawFB || idFBO) + if (ctx->framebufferobject.drawFB || idDrawFBO) { diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - fAdjustDrawReadBuffers = GL_TRUE; + idDrawBuffer = ctx->buffer.drawBuffer; } - if (ctx->framebufferobject.readFB ||idFBO) + if (ctx->framebufferobject.readFB || idReadFBO) { diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - fAdjustDrawReadBuffers = GL_TRUE; + idReadBuffer = ctx->buffer.readBuffer; } - if (fAdjustDrawReadBuffers) - { - diff_api.DrawBuffer(GL_BACK); - diff_api.ReadBuffer(GL_BACK); - } + if (idDrawBuffer) + diff_api.DrawBuffer(idDrawBuffer); + if (idReadBuffer) + diff_api.ReadBuffer(idReadBuffer); if (ctx->framebufferobject.renderbuffer) diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } DECLEXPORT(void) STATE_APIENTRY -crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idFBO) +crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idDrawFBO, GLuint idReadFBO) { GLuint idReadBuffer = 0, idDrawBuffer = 0; + if (!fromCtx) + fromCtx = toCtx; /* <- in case fromCtx is zero, set it to toCtx to ensure framebuffer state gets re-enabled correctly */ if ((fromCtx->framebufferobject.drawFB) /* <- the FBO state was reset in crStateFramebufferObjectDisableHW */ && fromCtx->framebufferobject.drawFB == toCtx->framebufferobject.drawFB) /* .. and it was NOT restored properly in crStateFramebufferObjectSwitch */ @@ -811,9 +1061,9 @@ crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, toCtx->framebufferobject.drawFB->hwid); idDrawBuffer = toCtx->framebufferobject.drawFB->drawbuffer[0]; } - else if (idFBO && !toCtx->framebufferobject.drawFB) + else if (idDrawFBO && !toCtx->framebufferobject.drawFB) { - diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idFBO); + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO); idDrawBuffer = GL_COLOR_ATTACHMENT0; } @@ -823,9 +1073,9 @@ crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, toCtx->framebufferobject.readFB->hwid); idReadBuffer = toCtx->framebufferobject.readFB->readbuffer; } - else if (idFBO && !toCtx->framebufferobject.readFB) + else if (idReadFBO && !toCtx->framebufferobject.readFB) { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idFBO); + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO); idReadBuffer = GL_COLOR_ATTACHMENT0; } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py index 674eb6b6..759c30d9 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py @@ -233,3 +233,5 @@ for rettype in types: print '\t\t\treturn;' print '\t}' print '}' + +from get_components import *
\ No newline at end of file diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt index 01974573..150d350b 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt @@ -80,6 +80,7 @@ GLfloat GL_POINT_SIZE g->point.pointSize GLfloat GL_POINT_SIZE_MIN_ARB g->point.minSize GLfloat GL_POINT_SIZE_MAX_ARB g->point.maxSize GLfloat GL_POINT_FADE_THRESHOLD_SIZE_ARB g->point.fadeThresholdSize +GLfloat GL_POINT_SPRITE_COORD_ORIGIN g->point.spriteCoordOrigin GLfloat GL_POINT_DISTANCE_ATTENUATION_ARB g->point.distanceAttenuation[0] g->point.distanceAttenuation[1] g->point.distanceAttenuation[2] GLboolean GL_NORMALIZE g->transform.normalize @@ -233,13 +234,19 @@ GLint GL_LIST_INDEX g->lists.currentIndex GLenum GL_LIST_MODE g->lists.mode GLint GL_STENCIL_CLEAR_VALUE g->stencil.clearValue -GLint GL_STENCIL_FAIL g->stencil.fail -GLint GL_STENCIL_FUNC g->stencil.func -GLint GL_STENCIL_PASS_DEPTH_FAIL g->stencil.passDepthFail -GLint GL_STENCIL_PASS_DEPTH_PASS g->stencil.passDepthPass -GLint GL_STENCIL_REF g->stencil.ref +GLint GL_STENCIL_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail +GLint GL_STENCIL_BACK_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail +GLint GL_STENCIL_FUNC g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func +GLint GL_STENCIL_BACK_FUNC g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func +GLint GL_STENCIL_PASS_DEPTH_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail +GLint GL_STENCIL_BACK_PASS_DEPTH_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail +GLint GL_STENCIL_PASS_DEPTH_PASS g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass +GLint GL_STENCIL_BACK_PASS_DEPTH_PASS g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass +GLint GL_STENCIL_REF g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref +GLint GL_STENCIL_BACK_REF g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref GLboolean GL_STENCIL_TEST g->stencil.stencilTest -GLint GL_STENCIL_VALUE_MASK g->stencil.mask +GLint GL_STENCIL_VALUE_MASK g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask +GLint GL_STENCIL_BACK_VALUE_MASK g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask GLint GL_STENCIL_WRITEMASK g->stencil.writeMask GLfloat GL_CURRENT_INDEX g->current.colorIndex @@ -308,3 +315,5 @@ GLint GL_RENDERBUFFER_BINDING_EXT (g->framebufferobject.renderbuffer?g->framebuf #CVA GLint GL_ARRAY_ELEMENT_LOCK_FIRST_EXT g->client.array.lockFirst GLint GL_ARRAY_ELEMENT_LOCK_COUNT_EXT g->client.array.lockCount + +GLint GL_ACTIVE_STENCIL_FACE_EXT g->stencil.activeStencilFace
\ No newline at end of file diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c index 7741007b..48d5a7e8 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -258,6 +258,21 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateGLSLProgramHWIDtoID(GLuint hwid) return parms.id; } +DECLEXPORT(GLuint) STATE_APIENTRY crStateDeleteObjectARB( VBoxGLhandleARB obj ) +{ + GLuint hwId = crStateGetProgramHWID(obj); + if (hwId) + { + crStateDeleteProgram(obj); + } + else + { + hwId = crStateGetShaderHWID(obj); + crStateDeleteShader(obj); + } + return hwId; +} + DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateShader(GLuint hwid, GLenum type) { CRGLSLShader *pShader; @@ -267,13 +282,17 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateShader(GLuint hwid, GLenum type) #ifdef IN_GUEST CRASSERT(!crStateGetShaderObj(stateId)); #else - /* the id may not necesserily be hwid after save state restoration */ - while ((pShader = crStateGetShaderObj(stateId)) != NULL) + /* the proogram and shader names must not intersect because DeleteObjectARB must distinguish between them + * see crStateDeleteObjectARB + * this is why use programs table for shader keys allocation */ + stateId = crHashtableAllocKeys(g->glsl.programs, 1); + if (!stateId) { - GLuint newStateId = stateId + 7; - crDebug("Shader object %d already exists, generating a new one, %d", stateId, newStateId); - stateId = newStateId; + crWarning("failed to allocate program key"); + return 0; } + + Assert((pShader = crStateGetShaderObj(stateId)) == NULL); #endif pShader = (CRGLSLShader *) crAlloc(sizeof(*pShader)); @@ -311,19 +330,18 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateProgram(GLuint hwid) CRASSERT(!crStateGetProgramObj(stateId)); } #else - /* the id may not necesserily be hwid after save state restoration */ - while ((pProgram = crStateGetProgramObj(stateId)) != NULL) + stateId = crHashtableAllocKeys(g->glsl.programs, 1); + if (!stateId) { - GLuint newStateId = stateId + 7; - crDebug("Program object %d already exists, generating a new one, %d", stateId, newStateId); - stateId = newStateId; + crWarning("failed to allocate program key"); + return 0; } #endif pProgram = (CRGLSLProgram *) crAlloc(sizeof(*pProgram)); if (!pProgram) { - crWarning("crStateCreateShader: Out of memory!"); + crWarning("crStateCreateProgram: Out of memory!"); return 0; } @@ -363,6 +381,11 @@ DECLEXPORT(void) STATE_APIENTRY crStateCompileShader(GLuint shader) pShader->compiled = GL_TRUE; } +static void crStateDbgCheckNoProgramOfId(void *data) +{ + crError("Unexpected Program id"); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteShader(GLuint shader) { CRGLSLShader *pShader = crStateGetShaderObj(shader); @@ -378,6 +401,10 @@ DECLEXPORT(void) STATE_APIENTRY crStateDeleteShader(GLuint shader) { CRContext *g = GetCurrentContext(); crHashtableDelete(g->glsl.shaders, shader, crStateFreeGLSLShader); + /* since we use programs table for key allocation key allocation, we need to + * free the key in the programs table. + * See comment in crStateCreateShader */ + crHashtableDelete(g->glsl.programs, shader, crStateDbgCheckNoProgramOfId); } } @@ -598,8 +625,7 @@ DECLEXPORT(void) STATE_APIENTRY crStateBindAttribLocation(GLuint program, GLuint { if (!crStrcmp(pProgram->currentState.pAttribs[i].name, name)) { - crFree(pProgram->currentState.pAttribs[i].name); - pProgram->currentState.pAttribs[i].name = crStrdup(name); + pProgram->currentState.pAttribs[i].index = index; return; } } @@ -1186,6 +1212,7 @@ static void crStateGLSLCreateProgramCB(unsigned long key, void *data1, void *dat DECLEXPORT(void) STATE_APIENTRY crStateGLSLSwitch(CRContext *from, CRContext *to) { + GLboolean fForceUseProgramSet = GL_FALSE; if (to->glsl.bResyncNeeded) { to->glsl.bResyncNeeded = GL_FALSE; @@ -1194,10 +1221,13 @@ DECLEXPORT(void) STATE_APIENTRY crStateGLSLSwitch(CRContext *from, CRContext *to crHashtableWalk(to->glsl.programs, crStateGLSLCreateProgramCB, to); + /* crStateGLSLCreateProgramCB changes the current program, ensure we have the proper program re-sored */ + fForceUseProgramSet = GL_TRUE; + crHashtableWalk(to->glsl.shaders, crStateGLSLSyncShadersCB, NULL); } - if (to->glsl.activeProgram != from->glsl.activeProgram) + if (to->glsl.activeProgram != from->glsl.activeProgram || fForceUseProgramSet) { diff_api.UseProgram(to->glsl.activeProgram ? to->glsl.activeProgram->hwid : 0); } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c index f8ac1f5a..49bcd38b 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c @@ -17,13 +17,14 @@ CRContext *__currentContext = NULL; #endif CRStateBits *__currentBits = NULL; -GLboolean g_availableContexts[CR_MAX_CONTEXTS]; +CRContext *g_pAvailableContexts[CR_MAX_CONTEXTS]; +uint32_t g_cContexts = 0; static CRSharedState *gSharedState=NULL; static CRContext *defaultContext = NULL; -static GLboolean g_bVBoxEnableDiffOnMakeCurrent = GL_TRUE; +GLboolean g_bVBoxEnableDiffOnMakeCurrent = GL_TRUE; /** @@ -60,7 +61,6 @@ crStateDeleteTextureCallback(void *texObj) crStateDeleteTextureObject((CRTextureObj *) texObj); } -#ifndef IN_GUEST typedef struct CR_STATE_RELEASEOBJ { CRContext *pCtx; @@ -102,7 +102,7 @@ static void ReleaseRBOCallback(unsigned long key, void *data1, void *data2) if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pObj)) crHashtableDelete(pData->s->rbTable, key, crStateFreeRBO); } -#endif + /** * Decrement shared state's refcount and delete when it hits zero. */ @@ -110,6 +110,7 @@ DECLEXPORT(void) crStateFreeShared(CRContext *pContext, CRSharedState *s) { s->refCount--; + Assert(s->refCount >= 0); if (s->refCount <= 0) { if (s==gSharedState) { @@ -122,8 +123,7 @@ crStateFreeShared(CRContext *pContext, CRSharedState *s) crFreeHashtable(s->rbTable, crStateFreeRBO); crFree(s); } -#ifndef IN_GUEST - else + else if (pContext) { /* evaluate usage bits*/ CR_STATE_RELEASEOBJ CbData; @@ -134,7 +134,22 @@ crStateFreeShared(CRContext *pContext, CRSharedState *s) crHashtableWalk(s->fbTable, ReleaseFBOCallback, &CbData); crHashtableWalk(s->rbTable, ReleaseRBOCallback, &CbData); } -#endif +} + +DECLEXPORT(CRSharedState *) crStateGlobalSharedAcquire() +{ + if (!gSharedState) + { + crWarning("No Global Shared State!"); + return NULL; + } + gSharedState->refCount++; + return gSharedState; +} + +DECLEXPORT(void) crStateGlobalSharedRelease() +{ + crStateFreeShared(NULL, gSharedState); } DECLEXPORT(void) STATE_APIENTRY @@ -218,11 +233,26 @@ static CRContext * crStateCreateContextId(int i, const CRLimitsState *limits, GLint visBits, CRContext *shareCtx) { - CRContext *ctx = (CRContext *) crCalloc( sizeof( *ctx ) ); + CRContext *ctx; int j; int node32 = i >> 5; int node = i & 0x1f; + if (g_pAvailableContexts[i] != NULL) + { + crWarning("trying to create context with used id"); + return NULL; + } + + ctx = (CRContext *) crCalloc( sizeof( *ctx ) ); + if (!ctx) + { + crWarning("failed to allocate context"); + return NULL; + } + g_pAvailableContexts[i] = ctx; + ++g_cContexts; + CRASSERT(g_cContexts < RT_ELEMENTS(g_pAvailableContexts)); ctx->id = i; #ifdef CHROMIUM_THREADSAFE VBoxTlsRefInit(ctx, crStateContextDtor); @@ -252,7 +282,7 @@ crStateCreateContextId(int i, const CRLimitsState *limits, crStateExtensionsInit( &(ctx->limits), &(ctx->extensions) ); crStateBufferObjectInit( ctx ); /* must precede client state init! */ - crStateClientInit( &(ctx->client) ); + crStateClientInit( ctx ); crStateBufferInit( ctx ); crStateCurrentInit( ctx ); @@ -330,7 +360,23 @@ crStateCreateContextId(int i, const CRLimitsState *limits, static void crStateFreeContext(CRContext *ctx) { - crStateClientDestroy( &(ctx->client) ); +#ifndef DEBUG_misha + CRASSERT(g_pAvailableContexts[ctx->id] == ctx); +#endif + if (g_pAvailableContexts[ctx->id] == ctx) + { + g_pAvailableContexts[ctx->id] = NULL; + --g_cContexts; + CRASSERT(g_cContexts < RT_ELEMENTS(g_pAvailableContexts)); + } + else + { +#ifndef DEBUG_misha + crWarning("freeing context %p, id(%d) not being in the context list", ctx, ctx->id); +#endif + } + + crStateClientDestroy( ctx ); crStateLimitsDestroy( &(ctx->limits) ); crStateBufferObjectDestroy( ctx ); crStateEvaluatorDestroy( ctx ); @@ -377,10 +423,15 @@ void crStateInit(void) crStateClientInitBits( &(__currentBits->client) ); crStateLightingInitBits( &(__currentBits->lighting) ); } else + { +#ifndef DEBUG_misha crWarning("State tracker is being re-initialized..\n"); +#endif + } for (i=0;i<CR_MAX_CONTEXTS;i++) - g_availableContexts[i] = 0; + g_pAvailableContexts[i] = NULL; + g_cContexts = 0; #ifdef CHROMIUM_THREADSAFE if (!__isContextTLSInited) @@ -411,11 +462,14 @@ void crStateInit(void) /* Reset diff_api */ crMemZero(&diff_api, sizeof(SPUDispatchTable)); + Assert(!gSharedState); + gSharedState = NULL; + /* Allocate the default/NULL context */ + CRASSERT(g_pAvailableContexts[0] == NULL); defaultContext = crStateCreateContextId(0, NULL, CR_RGB_BIT, NULL); - CRASSERT(g_availableContexts[0] == 0); - g_availableContexts[0] = 1; /* in use forever */ - + CRASSERT(g_pAvailableContexts[0] == defaultContext); + CRASSERT(g_cContexts == 1); #ifdef CHROMIUM_THREADSAFE SetCurrentContext(defaultContext); #else @@ -425,6 +479,7 @@ void crStateInit(void) void crStateDestroy(void) { + int i; if (__currentBits) { crStateClientDestroyBits(&(__currentBits->client)); @@ -433,6 +488,25 @@ void crStateDestroy(void) __currentBits = NULL; } + SetCurrentContext(NULL); + + for (i = CR_MAX_CONTEXTS-1; i >= 0; i--) + { + if (g_pAvailableContexts[i]) + { +#ifdef CHROMIUM_THREADSAFE + if (VBoxTlsRefIsFunctional(g_pAvailableContexts[i])) + VBoxTlsRefRelease(g_pAvailableContexts[i]); +#else + crStateFreeContext(g_pAvailableContexts[i]); +#endif + } + } + + /* default context was stored in g_pAvailableContexts[0], so it was destroyed already */ + defaultContext = NULL; + + #ifdef CHROMIUM_THREADSAFE crFreeTSD(&__contextTSD); __isContextTLSInited = 0; @@ -452,7 +526,7 @@ void crStateDestroy(void) * (i.e. the old context to the new context). The transformation * is accomplished by calling GL functions through the 'diff_api' * so that the downstream GL machine (represented by the __currentContext - * structure) is updated to reflect the new context state. Finally, + * structure) is updated to reflect the new context state. Finally, * we point __currentContext to the new context. * * A subtle problem we have to deal with is context destruction. @@ -485,35 +559,46 @@ void crStateDestroy(void) CRContext * crStateCreateContext(const CRLimitsState *limits, GLint visBits, CRContext *share) { - int i; + return crStateCreateContextEx(limits, visBits, share, -1); +} +CRContext * +crStateCreateContextEx(const CRLimitsState *limits, GLint visBits, CRContext *share, GLint presetID) +{ /* Must have created the default context via crStateInit() first */ CRASSERT(defaultContext); - for (i = 1 ; i < CR_MAX_CONTEXTS ; i++) + if (presetID>0) { - if (!g_availableContexts[i]) + if(g_pAvailableContexts[presetID]) { - g_availableContexts[i] = 1; /* it's no longer available */ - return crStateCreateContextId( i, limits, visBits, share ); + crWarning("requesting to create context with already allocated id"); + return NULL; } } - crError( "Out of available contexts in crStateCreateContexts (max %d)", - CR_MAX_CONTEXTS ); - /* never get here */ - return NULL; -} - -CRContext * -crStateCreateContextEx(const CRLimitsState *limits, GLint visBits, CRContext *share, GLint presetID) -{ - if (presetID>0) + else { - CRASSERT(!g_availableContexts[presetID]); - g_availableContexts[presetID] = 1; - return crStateCreateContextId(presetID, limits, visBits, share); + int i; + + for (i = 1 ; i < CR_MAX_CONTEXTS ; i++) + { + if (!g_pAvailableContexts[i]) + { + presetID = i; + break; + } + } + + if (presetID<=0) + { + crError( "Out of available contexts in crStateCreateContexts (max %d)", + CR_MAX_CONTEXTS ); + /* never get here */ + return NULL; + } } - else return crStateCreateContext(limits, visBits, share); + + return crStateCreateContextId(presetID, limits, visBits, share); } void crStateDestroyContext( CRContext *ctx ) @@ -535,9 +620,17 @@ void crStateDestroyContext( CRContext *ctx ) /* ensure matrix state is also current */ crStateMatrixMode(defaultContext->transform.matrixMode); } - g_availableContexts[ctx->id] = 0; #ifdef CHROMIUM_THREADSAFE + VBoxTlsRefMarkDestroy(ctx); +# ifdef IN_GUEST + if (VBoxTlsRefCountGet(ctx) > 1 && ctx->shared == gSharedState) + { + /* we always need to free the global shared state to prevent the situation when guest thinks the shared objects are still valid, while host destroys them */ + crStateFreeShared(ctx, ctx->shared); + ctx->shared = crStateAllocShared(); + } +# endif VBoxTlsRefRelease(ctx); #else crStateFreeContext(ctx); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c index 09831311..005f9462 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c @@ -30,7 +30,7 @@ void crStateListsInit(CRContext *ctx) RESET(lb->dirty, ctx->bitid); } -/*#define CRSTATE_DEBUG_QUERY_HW_STATE*/ +//#define CRSTATE_DEBUG_QUERY_HW_STATE #ifndef CRSTATE_DEBUG_QUERY_HW_STATE # define CRSTATE_SET_CAP(state, value, format) g->state=value @@ -168,7 +168,7 @@ void crStateListsInit(CRContext *ctx) } \ } -void STATE_APIENTRY crStateQueryHWState() +void STATE_APIENTRY crStateQueryHWState(GLuint fbFbo, GLuint bbFbo) { CRContext *g = GetCurrentContext(); CRStateBits *sb = GetCurrentBits(); @@ -217,12 +217,68 @@ void STATE_APIENTRY crStateQueryHWState() if (CHECKDIRTY(sb->buffer.drawBuffer, negbitID)) { - CRSTATE_SET_ENUM(buffer.drawBuffer, GL_DRAW_BUFFER); + GLuint buf = 0; + diff_api.GetIntegerv(GL_DRAW_BUFFER, &buf); + + if (buf == GL_COLOR_ATTACHMENT0_EXT && (bbFbo || fbFbo)) + { + GLuint binding = 0; + diff_api.GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &binding); + if (!binding) + { + crWarning("HW state synch: GL_DRAW_FRAMEBUFFER_BINDING is NULL"); + } + + if (bbFbo && binding == bbFbo) + { + g->buffer.drawBuffer = GL_BACK; + } + else if (fbFbo && binding == fbFbo) + { + g->buffer.drawBuffer = GL_FRONT; + } + else + { + g->buffer.drawBuffer = buf; + } + } + else + { + g->buffer.drawBuffer = buf; + } } if (CHECKDIRTY(sb->buffer.readBuffer, negbitID)) { - CRSTATE_SET_ENUM(buffer.readBuffer, GL_READ_BUFFER); + GLuint buf = 0; + diff_api.GetIntegerv(GL_READ_BUFFER, &buf); + + if (buf == GL_COLOR_ATTACHMENT0_EXT && (bbFbo || fbFbo)) + { + GLuint binding = 0; + diff_api.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &binding); + if (!binding) + { + crWarning("HW state synch: GL_READ_FRAMEBUFFER_BINDING is NULL"); + } + + if (bbFbo && binding == bbFbo) + { + g->buffer.readBuffer = GL_BACK; + } + else if (fbFbo && binding == fbFbo) + { + g->buffer.readBuffer = GL_FRONT; + } + else + { + g->buffer.readBuffer = buf; + } + } + else + { + g->buffer.readBuffer = buf; + } } if (CHECKDIRTY(sb->buffer.indexMask, negbitID)) @@ -295,23 +351,122 @@ void STATE_APIENTRY crStateQueryHWState() if (CHECKDIRTY(sb->stencil.dirty, negbitID)) { + GLenum activeFace; + GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + if (CHECKDIRTY(sb->stencil.enable, negbitID)) { CRSTATE_SET_ENABLED(stencil.stencilTest, GL_STENCIL_TEST); } - if (CHECKDIRTY(sb->stencil.func, negbitID)) + if (CHECKDIRTY(sb->stencil.enableTwoSideEXT, negbitID)) { - CRSTATE_SET_ENUM(stencil.func, GL_STENCIL_FUNC); - CRSTATE_SET_INT(stencil.ref, GL_STENCIL_REF); - CRSTATE_SET_INT(stencil.mask, GL_STENCIL_VALUE_MASK); + CRSTATE_SET_ENABLED(stencil.stencilTwoSideEXT, GL_STENCIL_TEST_TWO_SIDE_EXT); } - if (CHECKDIRTY(sb->stencil.op, negbitID)) + if (CHECKDIRTY(sb->stencil.activeStencilFace, negbitID)) { - CRSTATE_SET_ENUM(stencil.fail, GL_STENCIL_FAIL); - CRSTATE_SET_ENUM(stencil.passDepthFail, GL_STENCIL_PASS_DEPTH_FAIL); - CRSTATE_SET_ENUM(stencil.passDepthPass, GL_STENCIL_PASS_DEPTH_PASS); + CRSTATE_SET_ENUM(stencil.activeStencilFace, GL_ACTIVE_STENCIL_FACE_EXT); + } + + activeFace = g->stencil.activeStencilFace; + + +#define CRSTATE_SET_STENCIL_FUNC(_idx, _suff) do { \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].func, GL_STENCIL##_suff##FUNC); \ + CRSTATE_SET_INT(stencil.buffers[(_idx)].ref, GL_STENCIL##_suff##REF); \ + CRSTATE_SET_INT(stencil.buffers[(_idx)].mask, GL_STENCIL##_suff##VALUE_MASK); \ + } while (0) + +#define CRSTATE_SET_STENCIL_OP(_idx, _suff) do { \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].fail, GL_STENCIL##_suff##FAIL); \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].passDepthFail, GL_STENCIL##_suff##PASS_DEPTH_FAIL); \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].passDepthPass, GL_STENCIL##_suff##PASS_DEPTH_PASS); \ + } while (0) + + /* func */ + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, negbitID)) + { + /* this if branch is not needed here actually, just in case ogl drivers misbehave */ + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_SET_STENCIL_FUNC(CRSTATE_STENCIL_BUFFER_ID_BACK, _BACK_); + backIsSet = GL_TRUE; + } + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_FUNC(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + frontIsSet = GL_TRUE; + } + + if ((!frontIsSet || !backIsSet) && CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_FUNC(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + if (!backIsSet) + { + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask; + } + } + + /* op */ + backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, negbitID)) + { + /* this if branch is not needed here actually, just in case ogl drivers misbehave */ + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_SET_STENCIL_OP(CRSTATE_STENCIL_BUFFER_ID_BACK, _BACK_); + backIsSet = GL_TRUE; + } + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_OP(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + frontIsSet = GL_TRUE; + } + + if ((!frontIsSet || !backIsSet) && CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_OP(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + if (!backIsSet) + { + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass; + } } if (CHECKDIRTY(sb->stencil.clearValue, negbitID)) @@ -499,12 +654,12 @@ void STATE_APIENTRY crStateQueryHWState() { CRSTATE_SET_MATERIAL_COLOR(lighting.ambient[0], GL_FRONT, GL_AMBIENT); CRSTATE_SET_MATERIAL_COLOR(lighting.ambient[1], GL_BACK, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[0], GL_FRONT, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[1], GL_BACK, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.specular[0], GL_FRONT, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.specular[1], GL_BACK, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.emission[0], GL_FRONT, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.emission[1], GL_BACK, GL_AMBIENT); + CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[0], GL_FRONT, GL_DIFFUSE); + CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[1], GL_BACK, GL_DIFFUSE); + CRSTATE_SET_MATERIAL_COLOR(lighting.specular[0], GL_FRONT, GL_SPECULAR); + CRSTATE_SET_MATERIAL_COLOR(lighting.specular[1], GL_BACK, GL_SPECULAR); + CRSTATE_SET_MATERIAL_COLOR(lighting.emission[0], GL_FRONT, GL_EMISSION); + CRSTATE_SET_MATERIAL_COLOR(lighting.emission[1], GL_BACK, GL_EMISSION); CRSTATE_SET_MATERIAL_F(lighting.shininess[0], GL_FRONT, GL_SHININESS); CRSTATE_SET_MATERIAL_F(lighting.shininess[1], GL_BACK, GL_SHININESS); } @@ -1093,7 +1248,7 @@ void STATE_APIENTRY crStateNewList (GLuint list, GLenum mode) l->mode = mode; } -void STATE_APIENTRY crStateEndList (void) +void STATE_APIENTRY crStateEndList (void) { CRContext *g = GetCurrentContext(); CRListsState *l = &(g->lists); @@ -1110,13 +1265,6 @@ void STATE_APIENTRY crStateEndList (void) return; } -#ifndef IN_GUEST - if (l->mode==GL_COMPILE) - { - crStateQueryHWState(); - } -#endif - l->currentIndex = 0; l->mode = 0; } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c index fbaac24d..de40c089 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c @@ -40,6 +40,9 @@ void crStatePointInit (CRContext *ctx) } #endif + p->spriteCoordOrigin = (GLfloat)GL_UPPER_LEFT; + RESET(pb->spriteCoordOrigin, ctx->bitid); + RESET(pb->dirty, ctx->bitid); /* @@ -167,6 +170,17 @@ void STATE_APIENTRY crStatePointParameterfvARB(GLenum pname, const GLfloat *para return; } break; + case GL_POINT_SPRITE_COORD_ORIGIN: + { + GLenum enmVal = (GLenum)params[0]; + if (enmVal != GL_LOWER_LEFT && enmVal != GL_UPPER_LEFT) { + crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, "glPointParameterfvARB invalid GL_POINT_SPRITE_COORD_ORIGIN value: %f", params[0]); + return; + } + p->spriteCoordOrigin = params[0]; + DIRTY(pb->spriteCoordOrigin, g->neg_bitid); + break; + } default: crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glPointParameterfvARB invalid enum: %f", pname); return; @@ -186,3 +200,248 @@ void STATE_APIENTRY crStatePointParameteriv(GLenum pname, const GLint *params) GLfloat f_param = (GLfloat) (*params); crStatePointParameterfvARB( pname, &f_param ); } + +void crStatePointDiff(CRPointBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRPointState *from = &(fromCtx->point); + CRPointState *to = &(toCtx->point); + unsigned int j, i; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + Assert(0); + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + if (CHECKDIRTY(b->enableSmooth, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->pointSmooth != to->pointSmooth) + { + able[to->pointSmooth](GL_POINT_SMOOTH); + from->pointSmooth = to->pointSmooth; + } + CLEARDIRTY(b->enableSmooth, nbitID); + } + if (CHECKDIRTY(b->size, bitID)) + { + if (from->pointSize != to->pointSize) + { + diff_api.PointSize (to->pointSize); + from->pointSize = to->pointSize; + } + CLEARDIRTY(b->size, nbitID); + } + if (CHECKDIRTY(b->minSize, bitID)) + { + if (from->minSize != to->minSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MIN_ARB, to->minSize); + from->minSize = to->minSize; + } + CLEARDIRTY(b->minSize, nbitID); + } + if (CHECKDIRTY(b->maxSize, bitID)) + { + if (from->maxSize != to->maxSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MAX_ARB, to->maxSize); + from->maxSize = to->maxSize; + } + CLEARDIRTY(b->maxSize, nbitID); + } + if (CHECKDIRTY(b->fadeThresholdSize, bitID)) + { + if (from->fadeThresholdSize != to->fadeThresholdSize) + { + diff_api.PointParameterfARB (GL_POINT_FADE_THRESHOLD_SIZE_ARB, to->fadeThresholdSize); + from->fadeThresholdSize = to->fadeThresholdSize; + } + CLEARDIRTY(b->fadeThresholdSize, nbitID); + } + if (CHECKDIRTY(b->spriteCoordOrigin, bitID)) + { + if (from->spriteCoordOrigin != to->spriteCoordOrigin) + { + diff_api.PointParameterfARB (GL_POINT_SPRITE_COORD_ORIGIN, to->spriteCoordOrigin); + from->spriteCoordOrigin = to->spriteCoordOrigin; + } + CLEARDIRTY(b->spriteCoordOrigin, nbitID); + } + if (CHECKDIRTY(b->distanceAttenuation, bitID)) + { + if (from->distanceAttenuation[0] != to->distanceAttenuation[0] || from->distanceAttenuation[1] != to->distanceAttenuation[1] || from->distanceAttenuation[2] != to->distanceAttenuation[2]) { + diff_api.PointParameterfvARB (GL_POINT_DISTANCE_ATTENUATION_ARB, to->distanceAttenuation); + from->distanceAttenuation[0] = to->distanceAttenuation[0]; + from->distanceAttenuation[1] = to->distanceAttenuation[1]; + from->distanceAttenuation[2] = to->distanceAttenuation[2]; + } + CLEARDIRTY(b->distanceAttenuation, nbitID); + } + if (CHECKDIRTY(b->enableSprite, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->pointSprite != to->pointSprite) + { + able[to->pointSprite](GL_POINT_SPRITE_ARB); + from->pointSprite = to->pointSprite; + } + CLEARDIRTY(b->enableSprite, nbitID); + } + { + unsigned int activeUnit = (unsigned int) -1; + for (i = 0; i < CR_MAX_TEXTURE_UNITS; i++) { + if (CHECKDIRTY(b->coordReplacement[i], bitID)) + { + GLint replacement = to->coordReplacement[i]; + if (activeUnit != i) { + diff_api.ActiveTextureARB(i + GL_TEXTURE0_ARB ); + activeUnit = i; + } + diff_api.TexEnviv(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, &replacement); + from->coordReplacement[i] = to->coordReplacement[i]; + CLEARDIRTY(b->coordReplacement[i], nbitID); + } + } + if (activeUnit != toCtx->texture.curTextureUnit) + diff_api.ActiveTextureARB(GL_TEXTURE0 + toCtx->texture.curTextureUnit); + } + CLEARDIRTY(b->dirty, nbitID); +} + +void crStatePointSwitch(CRPointBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRPointState *from = &(fromCtx->point); + CRPointState *to = &(toCtx->point); + unsigned int j, i; + GLboolean fEnabled; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + if (CHECKDIRTY(b->enableSmooth, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->pointSmooth != to->pointSmooth) + { + able[to->pointSmooth](GL_POINT_SMOOTH); + FILLDIRTY(b->enableSmooth); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enableSmooth, nbitID); + } + if (CHECKDIRTY(b->size, bitID)) + { + if (from->pointSize != to->pointSize) + { + diff_api.PointSize (to->pointSize); + FILLDIRTY(b->size); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->size, nbitID); + } + if (CHECKDIRTY(b->minSize, bitID)) + { + if (from->minSize != to->minSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MIN_ARB, to->minSize); + FILLDIRTY(b->minSize); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->minSize, nbitID); + } + if (CHECKDIRTY(b->maxSize, bitID)) + { + if (from->maxSize != to->maxSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MAX_ARB, to->maxSize); + FILLDIRTY(b->maxSize); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->maxSize, nbitID); + } + if (CHECKDIRTY(b->fadeThresholdSize, bitID)) + { + if (from->fadeThresholdSize != to->fadeThresholdSize) + { + diff_api.PointParameterfARB (GL_POINT_FADE_THRESHOLD_SIZE_ARB, to->fadeThresholdSize); + FILLDIRTY(b->fadeThresholdSize); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->fadeThresholdSize, nbitID); + } + if (CHECKDIRTY(b->spriteCoordOrigin, bitID)) + { + if (from->spriteCoordOrigin != to->spriteCoordOrigin) + { + diff_api.PointParameterfARB (GL_POINT_SPRITE_COORD_ORIGIN, to->spriteCoordOrigin); + FILLDIRTY(b->spriteCoordOrigin); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->spriteCoordOrigin, nbitID); + } + if (CHECKDIRTY(b->distanceAttenuation, bitID)) + { + if (from->distanceAttenuation[0] != to->distanceAttenuation[0] || from->distanceAttenuation[1] != to->distanceAttenuation[1] || from->distanceAttenuation[2] != to->distanceAttenuation[2]) { + diff_api.PointParameterfvARB (GL_POINT_DISTANCE_ATTENUATION_ARB, to->distanceAttenuation); + FILLDIRTY(b->distanceAttenuation); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->distanceAttenuation, nbitID); + } + fEnabled = from->pointSprite; + { + unsigned int activeUnit = (unsigned int) -1; + for (i = 0; i < CR_MAX_TEXTURE_UNITS; i++) { + if (CHECKDIRTY(b->coordReplacement[i], bitID)) + { + if (!fEnabled) + { + diff_api.Enable(GL_POINT_SPRITE_ARB); + fEnabled = GL_TRUE; + } +#if 0 + /*don't set coord replacement, it will be set just before drawing points when necessary, + * to work around gpu driver bugs + * See crServerDispatch[Begin|End|Draw*] */ + GLint replacement = to->coordReplacement[i]; + if (activeUnit != i) { + diff_api.ActiveTextureARB(i + GL_TEXTURE0_ARB ); + activeUnit = i; + } + diff_api.TexEnviv(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, &replacement); +#endif + CLEARDIRTY(b->coordReplacement[i], nbitID); + } + } + if (activeUnit != toCtx->texture.curTextureUnit) + diff_api.ActiveTextureARB(GL_TEXTURE0 + toCtx->texture.curTextureUnit); + } + if (CHECKDIRTY(b->enableSprite, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (fEnabled != to->pointSprite) + { + able[to->pointSprite](GL_POINT_SPRITE_ARB); + FILLDIRTY(b->enableSprite); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enableSprite, nbitID); + } + else if (fEnabled != to->pointSprite) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + able[to->pointSprite](GL_POINT_SPRITE_ARB); + } + CLEARDIRTY(b->dirty, nbitID); +} diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt index 69ab8a70..ba92c153 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt @@ -7,6 +7,7 @@ :minSize:minSize:PointParameterfARB,GL_POINT_SIZE_MIN_ARB :maxSize:maxSize:PointParameterfARB,GL_POINT_SIZE_MAX_ARB :fadeThresholdSize:fadeThresholdSize:PointParameterfARB,GL_POINT_FADE_THRESHOLD_SIZE_ARB +:spriteCoordOrigin:spriteCoordOrigin:PointParameterfARB,GL_POINT_SPRITE_COORD_ORIGIN #:distanceAttenuation:distanceAttenuation:PointParameterfvARB,GL_POINT_DISTANCE_ATTENUATION_ARB -:distanceAttenuation:*if (from->distanceAttenuation[0] != to->distanceAttenuation[0] || from->distanceAttenuation[1] != to->distanceAttenuation[1] || from->distanceAttenuation[2] != to->distanceAttenuation[2]) { -:distanceAttenuation:* diff_api.PointParameterfvARB (GL_POINT_DISTANCE_ATTENUATION_ARB, to->distanceAttenuation); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c index 31410bed..611e2f18 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c @@ -180,8 +180,7 @@ void STATE_APIENTRY crStatePolygonStipple (const GLubyte *p) if (!p && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) { - crStateError(__LINE__, __FILE__, GL_NO_ERROR, - "Void pointer passed to PolygonStipple"); + crDebug("Void pointer passed to PolygonStipple"); return; } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c index 2b0940bb..e8dd5971 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c @@ -267,25 +267,10 @@ void STATE_APIENTRY crStateGenProgramsNV(GLsizei n, GLuint *ids) { CRContext *g = GetCurrentContext(); CRProgramState *p = &(g->program); - GLint start, i; - if (g->current.inBeginEnd) { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glGenProgramsNV called in Begin/End"); - return; - } - - if (n < 0) { - crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, "glGenProgramsNV(n)"); - return; - } - - start = crHashtableAllocKeys(p->programHash , n); - for (i = 0; i < n; i++) - ids[i] = (GLuint) (start + i); + crStateGenNames(g, p->programHash, n, ids); } - void STATE_APIENTRY crStateGenProgramsARB(GLsizei n, GLuint *ids) { crStateGenProgramsNV(n, ids); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c index eadc228a..6b2a5baa 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -85,6 +85,18 @@ static int32_t crStateAllocAndSSMR3GetMem(PSSMHANDLE pSSM, void **pBuffer, size_ } \ } while (0) +#define SHCROGL_ROUNDBOUND(_v, _b) (((_v) + ((_b) - 1)) & ~((_b) - 1)) +#define SHCROGL_ALIGNTAILSIZE(_v, _b) (SHCROGL_ROUNDBOUND((_v),(_b)) - (_v)) +#define SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT_SIZE(_type, _field, _oldFieldType, _nextFieldAllignment) (SHCROGL_ALIGNTAILSIZE(((RT_OFFSETOF(_type, _field) + sizeof (_oldFieldType))), (_nextFieldAllignment))) +#define SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(_type, _field, _oldFieldType, _nextFieldAllignment) do { \ + const int32_t cbAlignment = SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT_SIZE(_type, _field, _oldFieldType, _nextFieldAllignment); \ + /*AssertCompile(SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField) >= 0 && SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField) < sizeof (void*));*/ \ + if (cbAlignment) { \ + rc = SSMR3Skip(pSSM, cbAlignment); \ + } \ + } while (0) + + #define SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField) (sizeof (_type) - RT_OFFSETOF(_type, _lastField) - RT_SIZEOFMEMB(_type, _lastField)) #define SHCROGL_CUT_TAIL_ALIGNMENT(_type, _lastField) do { \ const int32_t cbAlignment = SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField); \ @@ -139,6 +151,35 @@ static int32_t crStateLoadTextureUnit_v_BEFORE_CTXUSAGE_BITS(CRTextureUnit *t, P return rc; } +static int crStateLoadStencilPoint_v_37(CRPointState *pPoint, PSSMHANDLE pSSM) +{ + int rc = VINF_SUCCESS; + SHCROGL_GET_STRUCT_HEAD(pPoint, CRPointState, spriteCoordOrigin); + pPoint->spriteCoordOrigin = (GLfloat)GL_UPPER_LEFT; + return rc; +} + +static int32_t crStateLoadStencilState_v_33(CRStencilState *s, PSSMHANDLE pSSM) +{ + CRStencilState_v_33 stencilV33; + int32_t rc = SSMR3GetMem(pSSM, &stencilV33, sizeof (stencilV33)); + AssertRCReturn(rc, rc); + s->stencilTest = stencilV33.stencilTest; + s->stencilTwoSideEXT = GL_FALSE; + s->activeStencilFace = GL_FRONT; + s->clearValue = stencilV33.clearValue; + s->writeMask = stencilV33.writeMask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func = stencilV33.func; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask = stencilV33.mask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref = stencilV33.ref; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail = stencilV33.fail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail = stencilV33.passDepthFail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass = stencilV33.passDepthPass; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK] = s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT]; + crStateStencilBufferInit(&s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK]); + return VINF_SUCCESS; +} + static int32_t crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(CRTextureState *t, PSSMHANDLE pSSM) { GLint i; @@ -202,6 +243,47 @@ static int32_t crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(CRTextureState *t, SHCROGL_CUT_TAIL_ALIGNMENT(CRTextureState, unit); + return VINF_SUCCESS; +} + +static int32_t crStateStencilBufferStack_v_33(CRStencilBufferStack *s, PSSMHANDLE pSSM) +{ + CRStencilBufferStack_v_33 stackV33; + int32_t rc = SSMR3GetMem(pSSM, &stackV33, sizeof (stackV33)); + + s->stencilTest = stackV33.stencilTest; + s->stencilTwoSideEXT = GL_FALSE; + s->activeStencilFace = GL_FRONT; + s->clearValue = stackV33.clearValue; + s->writeMask = stackV33.writeMask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func = stackV33.func; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask = stackV33.mask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref = stackV33.ref; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail = stackV33.fail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail = stackV33.passDepthFail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass = stackV33.passDepthPass; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK] = s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT]; + + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func = GL_ALWAYS; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask = 0xFFFFFFFF; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref = 0; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail = GL_KEEP; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail = GL_KEEP; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass = GL_KEEP; + + return VINF_SUCCESS; +} + +static int32_t crStateLoadAttribState_v_33(CRAttribState *t, PSSMHANDLE pSSM) +{ + int32_t i, rc; + SHCROGL_GET_STRUCT_HEAD(t, CRAttribState, stencilBufferStack); + for (i = 0; i < CR_MAX_ATTRIB_STACK_DEPTH; ++i) + { + rc = crStateStencilBufferStack_v_33(&t->stencilBufferStack[i], pSSM); + AssertRCReturn(rc, rc); + } + SHCROGL_GET_STRUCT_TAIL(t, CRAttribState, textureStackDepth); return rc; } @@ -221,7 +303,14 @@ static int32_t crStateLoadTextureStack_v_BEFORE_CTXUSAGE_BITS(CRTextureStack *t, static int32_t crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(CRAttribState *t, PSSMHANDLE pSSM) { int32_t i, rc; - SHCROGL_GET_STRUCT_HEAD(t, CRAttribState, textureStack); + + SHCROGL_GET_STRUCT_HEAD(t, CRAttribState, stencilBufferStack); + for (i = 0; i < CR_MAX_ATTRIB_STACK_DEPTH; ++i) + { + rc = crStateStencilBufferStack_v_33(&t->stencilBufferStack[i], pSSM); + AssertRCReturn(rc, rc); + } + SHCROGL_GET_STRUCT_PART(t, CRAttribState, textureStackDepth, textureStack); for (i = 0; i < CR_MAX_ATTRIB_STACK_DEPTH; ++i) { rc = crStateLoadTextureStack_v_BEFORE_CTXUSAGE_BITS(&t->textureStack[i], pSSM); @@ -1069,6 +1158,15 @@ static void crStateSaveGLSLProgramCB(unsigned long key, void *data1, void *data2 diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen); diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORMS, &activeUniforms); + if (!maxUniformLen) + { + if (activeUniforms) + { + crWarning("activeUniforms (%d), while maxUniformLen is zero", activeUniforms); + activeUniforms = 0; + } + } + if (activeUniforms>0) { name = (GLchar *) crAlloc((maxUniformLen+8)*sizeof(GLchar)); @@ -1148,7 +1246,11 @@ static int32_t crStateSaveClientPointer(CRVertexArrays *pArrays, int32_t index, cp = crStateGetClientPointerByIndex(index, pArrays); - rc = SSMR3PutU32(pSSM, cp->buffer->id); + if (cp->buffer) + rc = SSMR3PutU32(pSSM, cp->buffer->id); + else + rc = SSMR3PutU32(pSSM, 0); + AssertRCReturn(rc, rc); #ifdef CR_EXT_compiled_vertex_array @@ -1304,6 +1406,59 @@ static int32_t crStateLoadCurrentBits(CRStateBits *pBits, PSSMHANDLE pSSM) return VINF_SUCCESS; } +static void crStateSaveKeysCB(unsigned long firstKey, unsigned long count, void *data) +{ + PSSMHANDLE pSSM = (PSSMHANDLE)data; + int rc; + CRASSERT(firstKey); + CRASSERT(count); + rc = SSMR3PutU32(pSSM, firstKey); + CRASSERT(RT_SUCCESS(rc)); + rc = SSMR3PutU32(pSSM, count); + CRASSERT(RT_SUCCESS(rc)); +} + +static int32_t crStateSaveKeys(CRHashTable *pHash, PSSMHANDLE pSSM) +{ + crHashtableWalkKeys(pHash, crStateSaveKeysCB , pSSM); + /* use null terminator */ + SSMR3PutU32(pSSM, 0); + return VINF_SUCCESS; +} + +static int32_t crStateLoadKeys(CRHashTable *pHash, PSSMHANDLE pSSM, uint32_t u32Version) +{ + uint32_t u32Key, u32Count, i; + int rc; + for(;;) + { + rc = SSMR3GetU32(pSSM, &u32Key); + AssertRCReturn(rc, rc); + + if (!u32Key) + return rc; + + rc = SSMR3GetU32(pSSM, &u32Count); + AssertRCReturn(rc, rc); + + CRASSERT(u32Count); + + if (u32Version > SHCROGL_SSM_VERSION_WITH_BUGGY_KEYS) + { + for (i = u32Key; i < u32Count + u32Key; ++i) + { + GLboolean fIsNew = crHashtableAllocRegisterKey(pHash, i); +#if 0 //def DEBUG_misha + CRASSERT(fIsNew); +#endif + } + } + } + + return rc; +} + + int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) { int32_t rc, i; @@ -1312,30 +1467,18 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) CRASSERT(pContext && pSSM); - pContext->buffer.storedWidth = pContext->buffer.width; - pContext->buffer.storedHeight = pContext->buffer.height; + CRASSERT(pContext->client.attribStackDepth == 0); - CRASSERT(VBoxTlsRefIsFunctional(pContext)); + /* this stuff is not used anymore, zero it up for sanity */ + pContext->buffer.storedWidth = 0; + pContext->buffer.storedHeight = 0; - /* do not increment the saved state version due to VBOXTLSREFDATA addition to CRContext */ - rc = SSMR3PutMem(pSSM, pContext, VBOXTLSREFDATA_OFFSET(CRContext)); - AssertRCReturn(rc, rc); - - /* now store bitid & neg_bitid */ - rc = SSMR3PutMem(pSSM, pContext->bitid, sizeof (pContext->bitid) + sizeof (pContext->neg_bitid)); - AssertRCReturn(rc, rc); + CRASSERT(VBoxTlsRefIsFunctional(pContext)); - /* the pre-VBOXTLSREFDATA CRContext structure might have additional allignment bits before the CRContext::shared */ - ui32 = VBOXTLSREFDATA_OFFSET(CRContext) + sizeof (pContext->bitid) + sizeof (pContext->neg_bitid); - ui32 &= (sizeof (void*) - 1); - if (ui32) - { - void* pTmp = NULL; - rc = SSMR3PutMem(pSSM, &pTmp, ui32); - AssertRCReturn(rc, rc); - } + /* make sure the gl error state is captured by our state mechanism to store the correct gl error value */ + crStateSyncHWErrorState(pContext); - rc = SSMR3PutMem(pSSM, &pContext->shared, sizeof (CRContext) - RT_OFFSETOF(CRContext, shared)); + rc = SSMR3PutMem(pSSM, pContext, sizeof (*pContext)); AssertRCReturn(rc, rc); if (crHashtableNumElements(pContext->shared->dlistTable)>0) @@ -1412,6 +1555,8 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) if (bSaveShared) { CRASSERT(pContext->shared && pContext->shared->textureTable); + rc = crStateSaveKeys(pContext->shared->textureTable, pSSM); + AssertRCReturn(rc, rc); ui32 = crHashtableNumElements(pContext->shared->textureTable); rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); @@ -1509,6 +1654,11 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) #ifdef CR_ARB_vertex_buffer_object /* Save buffer objects */ + if (bSaveShared) + { + rc = crStateSaveKeys(pContext->shared->buffersTable, pSSM); + AssertRCReturn(rc, rc); + } ui32 = bSaveShared? crHashtableNumElements(pContext->shared->buffersTable):0; rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); @@ -1576,10 +1726,15 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) /* Save FBOs */ if (bSaveShared) { + rc = crStateSaveKeys(pContext->shared->fbTable, pSSM); + AssertRCReturn(rc, rc); ui32 = crHashtableNumElements(pContext->shared->fbTable); rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); crHashtableWalk(pContext->shared->fbTable, crStateSaveFramebuffersCB, pSSM); + + rc = crStateSaveKeys(pContext->shared->rbTable, pSSM); + AssertRCReturn(rc, rc); ui32 = crHashtableNumElements(pContext->shared->rbTable); rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); @@ -1607,72 +1762,6 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) AssertRCReturn(rc, rc); #endif - if (pContext->buffer.storedWidth && pContext->buffer.storedHeight) - { - CRBufferState *pBuf = &pContext->buffer; - CRPixelPackState packing = pContext->client.pack; - GLint cbData; - void *pData; - - cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * pBuf->storedWidth * pBuf->storedHeight; - pData = crAlloc(cbData); - - if (!pData) - { - return VERR_NO_MEMORY; - } - - diff_api.PixelStorei(GL_PACK_SKIP_ROWS, 0); - diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, 0); - diff_api.PixelStorei(GL_PACK_ALIGNMENT, 1); - diff_api.PixelStorei(GL_PACK_ROW_LENGTH, 0); - diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, 0); - diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, 0); - diff_api.PixelStorei(GL_PACK_SWAP_BYTES, 0); - diff_api.PixelStorei(GL_PACK_LSB_FIRST, 0); - - if (pContext->framebufferobject.readFB) - { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - } - if (pContext->bufferobject.packBuffer->hwid>0) - { - diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); - } - - diff_api.ReadBuffer(GL_FRONT); - diff_api.ReadPixels(0, 0, pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData); - rc = SSMR3PutMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - diff_api.ReadBuffer(GL_BACK); - diff_api.ReadPixels(0, 0, pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData); - rc = SSMR3PutMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - if (pContext->bufferobject.packBuffer->hwid>0) - { - diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pContext->bufferobject.packBuffer->hwid); - } - if (pContext->framebufferobject.readFB) - { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, pContext->framebufferobject.readFB->hwid); - } - diff_api.ReadBuffer(pContext->framebufferobject.readFB ? - pContext->framebufferobject.readFB->readbuffer : pContext->buffer.readBuffer); - - diff_api.PixelStorei(GL_PACK_SKIP_ROWS, packing.skipRows); - diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, packing.skipPixels); - diff_api.PixelStorei(GL_PACK_ALIGNMENT, packing.alignment); - diff_api.PixelStorei(GL_PACK_ROW_LENGTH, packing.rowLength); - diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, packing.imageHeight); - diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, packing.skipImages); - diff_api.PixelStorei(GL_PACK_SWAP_BYTES, packing.swapBytes); - diff_api.PixelStorei(GL_PACK_LSB_FIRST, packing.psLSBFirst); - - crFree(pData); - } - return VINF_SUCCESS; } @@ -1693,6 +1782,77 @@ static void crStateFindSharedCB(unsigned long key, void *data1, void *data2) } } +int32_t crStateSaveGlobals(PSSMHANDLE pSSM) +{ + /* don't need that for now */ +#if 0 + CRStateBits *pBits; + int rc; + + CRASSERT(g_cContexts >= 1); + if (g_cContexts <= 1) + return VINF_SUCCESS; + + pBits = GetCurrentBits(); +#define CRSTATE_BITS_OP(_var, _size) \ + rc = SSMR3PutMem(pSSM, (pBits->_var), _size); \ + AssertRCReturn(rc, rc); +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP +#endif + return VINF_SUCCESS; +} + +int32_t crStateLoadGlobals(PSSMHANDLE pSSM, uint32_t u32Version) +{ + CRStateBits *pBits; + int rc; + CRASSERT(g_cContexts >= 1); + if (g_cContexts <= 1) + return VINF_SUCCESS; + + pBits = GetCurrentBits(); + + if (u32Version >= SHCROGL_SSM_VERSION_WITH_STATE_BITS) + { +#define CRSTATE_BITS_OP(_var, _size) \ + rc = SSMR3GetMem(pSSM, (pBits->_var), _size); \ + AssertRCReturn(rc, rc); + + if (u32Version < SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL) + { +#define CRSTATE_BITS_OP_VERSION (SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL - 1) +#define CRSTATE_BITS_OP_STENCIL_FUNC_V_33(_i, _var) do {} while (0) +#define CRSTATE_BITS_OP_STENCIL_OP_V_33(_i, _var) do {} while (0) +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP_VERSION +#undef CRSTATE_BITS_OP_STENCIL_FUNC_V_33 +#undef CRSTATE_BITS_OP_STENCIL_OP_V_33 + } + else if (u32Version < SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN) + { +#define CRSTATE_BITS_OP_VERSION (SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN - 1) +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP_VERSION + } + else + { + /* we do not put dirty bits to state anymore, + * nop */ +//#include "state_bits_globalop.h" + } +#undef CRSTATE_BITS_OP + /* always dirty all bits */ + /* return VINF_SUCCESS; */ + } + +#define CRSTATE_BITS_OP(_var, _size) FILLDIRTY(pBits->_var); +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP + return VINF_SUCCESS; +} + + #define SLC_COPYPTR(ptr) pTmpContext->ptr = pContext->ptr #define SLC_ASSSERT_NULL_PTR(ptr) CRASSERT(!pContext->ptr) @@ -1707,12 +1867,7 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST uint32_t uiNumElems, ui, k; unsigned long key; GLboolean bLoadShared = GL_TRUE; - union { - CRbitvalue bitid[CR_MAX_BITARRAY]; - struct { - VBOXTLSREFDATA - } tlsRef; - } bitid; + GLenum err; CRASSERT(pContext && pSSM); @@ -1723,70 +1878,130 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST CRASSERT(VBoxTlsRefIsFunctional(pContext)); - /* do not increment the saved state version due to VBOXTLSREFDATA addition to CRContext */ - rc = SSMR3GetMem(pSSM, pTmpContext, VBOXTLSREFDATA_OFFSET(CRContext)); - AssertRCReturn(rc, rc); - - /* VBox 4.1.8 had a bug that VBOXTLSREFDATA was also stored in the snapshot, - * thus the saved state data format was changed w/o changing the saved state version. - * here we determine whether the saved state contains VBOXTLSREFDATA, and if so, treat it accordingly */ - rc = SSMR3GetMem(pSSM, &bitid, sizeof (bitid)); - AssertRCReturn(rc, rc); - - /* the bitid array has one bit set only. this is why if bitid.tlsRef has both cTlsRefs - * and enmTlsRefState non-zero - this is definitely NOT a bit id and is a VBOXTLSREFDATA */ - if (bitid.tlsRef.enmTlsRefState == VBOXTLSREFDATA_STATE_INITIALIZED - && bitid.tlsRef.cTlsRefs) + if (u32Version <= SHCROGL_SSM_VERSION_WITH_INVALID_ERROR_STATE) { - /* VBOXTLSREFDATA is stored, skip it */ - crMemcpy(&pTmpContext->bitid, ((uint8_t*)&bitid) + VBOXTLSREFDATA_SIZE(), sizeof (bitid) - VBOXTLSREFDATA_SIZE()); - rc = SSMR3GetMem(pSSM, ((uint8_t*)&pTmpContext->bitid) + sizeof (pTmpContext->bitid) - VBOXTLSREFDATA_SIZE(), sizeof (pTmpContext->neg_bitid) + VBOXTLSREFDATA_SIZE()); + union { + CRbitvalue bitid[CR_MAX_BITARRAY]; + struct { + VBOXTLSREFDATA + } tlsRef; + } bitid; + + /* do not increment the saved state version due to VBOXTLSREFDATA addition to CRContext */ + rc = SSMR3GetMem(pSSM, pTmpContext, VBOXTLSREFDATA_OFFSET(CRContext)); AssertRCReturn(rc, rc); - ui = VBOXTLSREFDATA_OFFSET(CRContext) + VBOXTLSREFDATA_SIZE() + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); - ui = RT_OFFSETOF(CRContext, shared) - ui; - } - else - { - /* VBOXTLSREFDATA is NOT stored */ - crMemcpy(&pTmpContext->bitid, &bitid, sizeof (bitid)); - rc = SSMR3GetMem(pSSM, &pTmpContext->neg_bitid, sizeof (pTmpContext->neg_bitid)); + /* VBox 4.1.8 had a bug that VBOXTLSREFDATA was also stored in the snapshot, + * thus the saved state data format was changed w/o changing the saved state version. + * here we determine whether the saved state contains VBOXTLSREFDATA, and if so, treat it accordingly */ + rc = SSMR3GetMem(pSSM, &bitid, sizeof (bitid)); AssertRCReturn(rc, rc); - /* the pre-VBOXTLSREFDATA CRContext structure might have additional allignment bits before the CRContext::shared */ - ui = VBOXTLSREFDATA_OFFSET(CRContext) + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); + /* the bitid array has one bit set only. this is why if bitid.tlsRef has both cTlsRefs + * and enmTlsRefState non-zero - this is definitely NOT a bit id and is a VBOXTLSREFDATA */ + if (bitid.tlsRef.enmTlsRefState == VBOXTLSREFDATA_STATE_INITIALIZED + && bitid.tlsRef.cTlsRefs) + { + /* VBOXTLSREFDATA is stored, skip it */ + crMemcpy(&pTmpContext->bitid, ((uint8_t*)&bitid) + VBOXTLSREFDATA_SIZE(), sizeof (bitid) - VBOXTLSREFDATA_SIZE()); + rc = SSMR3GetMem(pSSM, ((uint8_t*)&pTmpContext->bitid) + sizeof (pTmpContext->bitid) - VBOXTLSREFDATA_SIZE(), sizeof (pTmpContext->neg_bitid) + VBOXTLSREFDATA_SIZE()); + AssertRCReturn(rc, rc); - ui &= (sizeof (void*) - 1); - } + ui = VBOXTLSREFDATA_OFFSET(CRContext) + VBOXTLSREFDATA_SIZE() + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); + ui = RT_OFFSETOF(CRContext, shared) - ui; + } + else + { + /* VBOXTLSREFDATA is NOT stored */ + crMemcpy(&pTmpContext->bitid, &bitid, sizeof (bitid)); + rc = SSMR3GetMem(pSSM, &pTmpContext->neg_bitid, sizeof (pTmpContext->neg_bitid)); + AssertRCReturn(rc, rc); - if (ui) - { - void* pTmp = NULL; - rc = SSMR3GetMem(pSSM, &pTmp, ui); - AssertRCReturn(rc, rc); - } + /* the pre-VBOXTLSREFDATA CRContext structure might have additional allignment bits before the CRContext::shared */ + ui = VBOXTLSREFDATA_OFFSET(CRContext) + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); - /* we will later do crMemcpy from entire pTmpContext to pContext, - * for simplicity store the VBOXTLSREFDATA from the pContext to pTmpContext */ - VBOXTLSREFDATA_COPY(pTmpContext, pContext); + ui &= (sizeof (void*) - 1); + } - if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + if (ui) + { + void* pTmp = NULL; + rc = SSMR3GetMem(pSSM, &pTmp, ui); + AssertRCReturn(rc, rc); + } + + if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + { + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, shared, attrib); + rc = crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->attrib, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, attrib, buffer); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, point); + rc = crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, polygon, stencil); + rc = crStateLoadStencilState_v_33(&pTmpContext->stencil, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(CRContext, stencil, CRStencilState_v_33, sizeof (void*)); + rc = crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->texture, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, texture, transform); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, transform); + } + else + { + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, shared, attrib); + rc = crStateLoadAttribState_v_33(&pTmpContext->attrib, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, attrib, buffer); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, point); + rc = crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, polygon, stencil); + rc = crStateLoadStencilState_v_33(&pTmpContext->stencil, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(CRContext, stencil, CRStencilState_v_33, sizeof (void*)); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, texture); + } + + pTmpContext->error = GL_NO_ERROR; /* <- the error state contained some random error data here + * treat as no error */ + } + else if (u32Version < SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL) { - SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, shared, attrib); - rc = crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->attrib, pSSM); + SHCROGL_GET_STRUCT_HEAD(pTmpContext, CRContext, attrib); + rc = crStateLoadAttribState_v_33(&pTmpContext->attrib, pSSM); AssertRCReturn(rc, rc); SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, attrib, buffer); - SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, texture); - rc = crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->texture, pSSM); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, point); + rc = crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); AssertRCReturn(rc, rc); - SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, texture, transform); - SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, transform); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, polygon, stencil); + rc = crStateLoadStencilState_v_33(&pTmpContext->stencil, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(CRContext, stencil, CRStencilState_v_33, sizeof (void*)); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, texture); + } + else if (u32Version < SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN) + { + SHCROGL_GET_STRUCT_HEAD(pTmpContext, CRContext, point); + crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, polygon); } else { - SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, shared); + rc = SSMR3GetMem(pSSM, pTmpContext, sizeof (*pTmpContext)); + AssertRCReturn(rc, rc); } + /* preserve the error to restore it at the end of context creation, + * it should not normally change, but just in case it it changed */ + err = pTmpContext->error; + + /* we will later do crMemcpy from entire pTmpContext to pContext, + * for simplicity store the VBOXTLSREFDATA from the pContext to pTmpContext */ + VBOXTLSREFDATA_COPY(pTmpContext, pContext); + /* Deal with shared state */ { crFindSharedCtxParms_t parms; @@ -2018,6 +2233,13 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST { /* Load shared textures */ CRASSERT(pContext->shared && pContext->shared->textureTable); + + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->buffersTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<uiNumElems; ++ui) @@ -2120,6 +2342,15 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST /* Load buffer objects */ #ifdef CR_ARB_vertex_buffer_object + if (bLoadShared) + { + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->textureTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<=uiNumElems; ++ui) /*ui<=uiNumElems to load nullBuffer in same loop*/ @@ -2242,6 +2473,12 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST /* Load FBOs */ if (bLoadShared) { + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->fbTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<uiNumElems; ++ui) @@ -2256,9 +2493,17 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST rc = crStateLoadFramebufferObject(pFBO, pSSM, u32Version); AssertRCReturn(rc, rc); + Assert(key == pFBO->id); + crHashtableAdd(pContext->shared->fbTable, key, pFBO); } + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->rbTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<uiNumElems; ++ui) @@ -2304,7 +2549,10 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST for (ui=0; ui<uiNumElems; ++ui) { CRGLSLShader *pShader = crStateLoadGLSLShader(pSSM); + GLboolean fNewKeyCheck; if (!pShader) return VERR_SSM_UNEXPECTED_DATA; + fNewKeyCheck = crHashtableAllocRegisterKey(pContext->glsl.programs, pShader->id); + CRASSERT(fNewKeyCheck); crHashtableAdd(pContext->glsl.shaders, pShader->id, pShader); } @@ -2416,310 +2664,11 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST pContext->glsl.bResyncNeeded = GL_TRUE; #endif - - /*Restore front/back buffer images*/ - if (pContext->buffer.storedWidth && pContext->buffer.storedHeight) - { - CRBufferState *pBuf = &pContext->buffer; - GLint cbData; - void *pData; - - cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * pBuf->storedWidth * pBuf->storedHeight; - - pData = crAlloc(cbData); - if (!pData) - { - pBuf->pFrontImg = NULL; - pBuf->pBackImg = NULL; - return VERR_NO_MEMORY; - } - - rc = SSMR3GetMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - pBuf->pFrontImg = pData; - - pData = crAlloc(cbData); - if (!pData) - { - pBuf->pBackImg = NULL; - return VERR_NO_MEMORY; - } - - rc = SSMR3GetMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - pBuf->pBackImg = pData; - } - - - /*Mark all as dirty to make sure we'd restore correct context state*/ + if (pContext->error != err) { - CRStateBits *pBits = GetCurrentBits(); - - FILLDIRTY(pBits->attrib.dirty); - - FILLDIRTY(pBits->buffer.dirty); - FILLDIRTY(pBits->buffer.enable); - FILLDIRTY(pBits->buffer.alphaFunc); - FILLDIRTY(pBits->buffer.depthFunc); - FILLDIRTY(pBits->buffer.blendFunc); - FILLDIRTY(pBits->buffer.logicOp); - FILLDIRTY(pBits->buffer.indexLogicOp); - FILLDIRTY(pBits->buffer.drawBuffer); - FILLDIRTY(pBits->buffer.readBuffer); - FILLDIRTY(pBits->buffer.indexMask); - FILLDIRTY(pBits->buffer.colorWriteMask); - FILLDIRTY(pBits->buffer.clearColor); - FILLDIRTY(pBits->buffer.clearIndex); - FILLDIRTY(pBits->buffer.clearDepth); - FILLDIRTY(pBits->buffer.clearAccum); - FILLDIRTY(pBits->buffer.depthMask); -#ifdef CR_EXT_blend_color - FILLDIRTY(pBits->buffer.blendColor); -#endif -#if defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op) - FILLDIRTY(pBits->buffer.blendEquation); -#endif -#if defined(CR_EXT_blend_func_separate) - FILLDIRTY(pBits->buffer.blendFuncSeparate); -#endif - -#ifdef CR_ARB_vertex_buffer_object - FILLDIRTY(pBits->bufferobject.dirty); - FILLDIRTY(pBits->bufferobject.arrayBinding); - FILLDIRTY(pBits->bufferobject.elementsBinding); -# ifdef CR_ARB_pixel_buffer_object - FILLDIRTY(pBits->bufferobject.packBinding); - FILLDIRTY(pBits->bufferobject.unpackBinding); -# endif -#endif - - FILLDIRTY(pBits->client.dirty); - FILLDIRTY(pBits->client.pack); - FILLDIRTY(pBits->client.unpack); - FILLDIRTY(pBits->client.enableClientState); - FILLDIRTY(pBits->client.clientPointer); - FILLDIRTY(pBits->client.v); - FILLDIRTY(pBits->client.n); - FILLDIRTY(pBits->client.c); - FILLDIRTY(pBits->client.i); - FILLDIRTY(pBits->client.e); - FILLDIRTY(pBits->client.s); - FILLDIRTY(pBits->client.f); - for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) - { - FILLDIRTY(pBits->client.t[i]); - } -#ifdef CR_NV_vertex_program - for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) - { - FILLDIRTY(pBits->client.a[i]); - } -#endif - - FILLDIRTY(pBits->current.dirty); - for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) - { - FILLDIRTY(pBits->current.vertexAttrib[i]); - } - FILLDIRTY(pBits->current.edgeFlag); - FILLDIRTY(pBits->current.colorIndex); - FILLDIRTY(pBits->current.rasterPos); - - - FILLDIRTY(pBits->eval.dirty); - for (i=0; i<GLEVAL_TOT; i++) - { - FILLDIRTY(pBits->eval.eval1D[i]); - FILLDIRTY(pBits->eval.eval2D[i]); - FILLDIRTY(pBits->eval.enable1D[i]); - FILLDIRTY(pBits->eval.enable2D[i]); - } - FILLDIRTY(pBits->eval.enable); - FILLDIRTY(pBits->eval.grid1D); - FILLDIRTY(pBits->eval.grid2D); -#ifdef CR_NV_vertex_program - /*@todo Those seems to be unused? - FILLDIRTY(pBits->eval.enableAttrib1D); - FILLDIRTY(pBits->eval.enableAttrib2D); - */ -#endif - - FILLDIRTY(pBits->feedback.dirty); - FILLDIRTY(pBits->selection.dirty); - - FILLDIRTY(pBits->fog.dirty); - FILLDIRTY(pBits->fog.color); - FILLDIRTY(pBits->fog.index); - FILLDIRTY(pBits->fog.density); - FILLDIRTY(pBits->fog.start); - FILLDIRTY(pBits->fog.end); - FILLDIRTY(pBits->fog.mode); - FILLDIRTY(pBits->fog.enable); -#ifdef CR_NV_fog_distance - FILLDIRTY(pBits->fog.fogDistanceMode); -#endif -#ifdef CR_EXT_fog_coord - FILLDIRTY(pBits->fog.fogCoordinateSource); -#endif - - FILLDIRTY(pBits->hint.dirty); - FILLDIRTY(pBits->hint.perspectiveCorrection); - FILLDIRTY(pBits->hint.pointSmooth); - FILLDIRTY(pBits->hint.lineSmooth); - FILLDIRTY(pBits->hint.polygonSmooth); - FILLDIRTY(pBits->hint.fog); -#ifdef CR_EXT_clip_volume_hint - FILLDIRTY(pBits->hint.clipVolumeClipping); - -#endif -#ifdef CR_ARB_texture_compression - FILLDIRTY(pBits->hint.textureCompression); -#endif -#ifdef CR_SGIS_generate_mipmap - FILLDIRTY(pBits->hint.generateMipmap); -#endif - - FILLDIRTY(pBits->lighting.dirty); - FILLDIRTY(pBits->lighting.shadeModel); - FILLDIRTY(pBits->lighting.colorMaterial); - FILLDIRTY(pBits->lighting.lightModel); - FILLDIRTY(pBits->lighting.material); - FILLDIRTY(pBits->lighting.enable); - for (i=0; i<CR_MAX_LIGHTS; ++i) - { - FILLDIRTY(pBits->lighting.light[i].dirty); - FILLDIRTY(pBits->lighting.light[i].enable); - FILLDIRTY(pBits->lighting.light[i].ambient); - FILLDIRTY(pBits->lighting.light[i].diffuse); - FILLDIRTY(pBits->lighting.light[i].specular); - FILLDIRTY(pBits->lighting.light[i].position); - FILLDIRTY(pBits->lighting.light[i].attenuation); - FILLDIRTY(pBits->lighting.light[i].spot); - } - - FILLDIRTY(pBits->line.dirty); - FILLDIRTY(pBits->line.enable); - FILLDIRTY(pBits->line.width); - FILLDIRTY(pBits->line.stipple); - - FILLDIRTY(pBits->lists.dirty); - FILLDIRTY(pBits->lists.base); - - FILLDIRTY(pBits->multisample.dirty); - FILLDIRTY(pBits->multisample.enable); - FILLDIRTY(pBits->multisample.sampleAlphaToCoverage); - FILLDIRTY(pBits->multisample.sampleAlphaToOne); - FILLDIRTY(pBits->multisample.sampleCoverage); - FILLDIRTY(pBits->multisample.sampleCoverageValue); - -#if CR_ARB_occlusion_query - FILLDIRTY(pBits->occlusion.dirty); -#endif - - FILLDIRTY(pBits->pixel.dirty); - FILLDIRTY(pBits->pixel.transfer); - FILLDIRTY(pBits->pixel.zoom); - FILLDIRTY(pBits->pixel.maps); - - FILLDIRTY(pBits->point.dirty); - FILLDIRTY(pBits->point.enableSmooth); - FILLDIRTY(pBits->point.size); -#ifdef CR_ARB_point_parameters - FILLDIRTY(pBits->point.minSize); - FILLDIRTY(pBits->point.maxSize); - FILLDIRTY(pBits->point.fadeThresholdSize); - FILLDIRTY(pBits->point.distanceAttenuation); -#endif -#ifdef CR_ARB_point_sprite - FILLDIRTY(pBits->point.enableSprite); - for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) - { - FILLDIRTY(pBits->point.coordReplacement[i]); - } -#endif - - FILLDIRTY(pBits->polygon.dirty); - FILLDIRTY(pBits->polygon.enable); - FILLDIRTY(pBits->polygon.offset); - FILLDIRTY(pBits->polygon.mode); - FILLDIRTY(pBits->polygon.stipple); - - FILLDIRTY(pBits->program.dirty); - FILLDIRTY(pBits->program.vpEnable); - FILLDIRTY(pBits->program.fpEnable); - FILLDIRTY(pBits->program.vpBinding); - FILLDIRTY(pBits->program.fpBinding); - for (i=0; i<CR_MAX_VERTEX_ATTRIBS; ++i) - { - FILLDIRTY(pBits->program.vertexAttribArrayEnable[i]); - FILLDIRTY(pBits->program.map1AttribArrayEnable[i]); - FILLDIRTY(pBits->program.map2AttribArrayEnable[i]); - } - for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS; ++i) - { - FILLDIRTY(pBits->program.vertexEnvParameter[i]); - } - for (i=0; i<CR_MAX_FRAGMENT_PROGRAM_ENV_PARAMS; ++i) - { - FILLDIRTY(pBits->program.fragmentEnvParameter[i]); - } - FILLDIRTY(pBits->program.vertexEnvParameters); - FILLDIRTY(pBits->program.fragmentEnvParameters); - for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS/4; ++i) - { - FILLDIRTY(pBits->program.trackMatrix[i]); - } - - FILLDIRTY(pBits->regcombiner.dirty); - FILLDIRTY(pBits->regcombiner.enable); - FILLDIRTY(pBits->regcombiner.regCombinerVars); - FILLDIRTY(pBits->regcombiner.regCombinerColor0); - FILLDIRTY(pBits->regcombiner.regCombinerColor1); - for (i=0; i<CR_MAX_GENERAL_COMBINERS; ++i) - { - FILLDIRTY(pBits->regcombiner.regCombinerStageColor0[i]); - FILLDIRTY(pBits->regcombiner.regCombinerStageColor1[i]); - FILLDIRTY(pBits->regcombiner.regCombinerInput[i]); - FILLDIRTY(pBits->regcombiner.regCombinerOutput[i]); - } - FILLDIRTY(pBits->regcombiner.regCombinerFinalInput); - - FILLDIRTY(pBits->stencil.dirty); - FILLDIRTY(pBits->stencil.enable); - FILLDIRTY(pBits->stencil.func); - FILLDIRTY(pBits->stencil.op); - FILLDIRTY(pBits->stencil.clearValue); - FILLDIRTY(pBits->stencil.writeMask); - - FILLDIRTY(pBits->texture.dirty); - for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) - { - FILLDIRTY(pBits->texture.enable[i]); - FILLDIRTY(pBits->texture.current[i]); - FILLDIRTY(pBits->texture.objGen[i]); - FILLDIRTY(pBits->texture.eyeGen[i]); - FILLDIRTY(pBits->texture.genMode[i]); - FILLDIRTY(pBits->texture.envBit[i]); - } - - FILLDIRTY(pBits->transform.dirty); - FILLDIRTY(pBits->transform.matrixMode); - FILLDIRTY(pBits->transform.modelviewMatrix); - FILLDIRTY(pBits->transform.projectionMatrix); - FILLDIRTY(pBits->transform.colorMatrix); - FILLDIRTY(pBits->transform.textureMatrix); - FILLDIRTY(pBits->transform.programMatrix); - FILLDIRTY(pBits->transform.clipPlane); - FILLDIRTY(pBits->transform.enable); - FILLDIRTY(pBits->transform.base); - - FILLDIRTY(pBits->viewport.dirty); - FILLDIRTY(pBits->viewport.v_dims); - FILLDIRTY(pBits->viewport.s_dims); - FILLDIRTY(pBits->viewport.enable); - FILLDIRTY(pBits->viewport.depth); + crWarning("context error state changed on context restore, was 0x%x, but became 0x%x, resetting to its original value", + err, pContext->error); + pContext->error = err; } return VINF_SUCCESS; diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_special b/src/VBox/GuestHost/OpenGL/state_tracker/state_special index e0bcc305..dfdca2f1 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_special +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_special @@ -157,6 +157,9 @@ GetIntegerv GetError StencilFunc StencilOp +StencilFuncSeparate +StencilOpSeparate +ActiveStencilFaceEXT ClearStencil StencilMask Viewport @@ -375,3 +378,7 @@ ValidateProgram BindAttribLocation GetUniformLocation CopyTexImage2D +GenFramebuffersEXT +GenRenderbuffersEXT +IsRenderbufferEXT +IsFramebufferEXT diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c index e284b31a..d543e301 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c @@ -9,24 +9,74 @@ #include "state/cr_statetypes.h" #include "state_internals.h" + +static GLint crStateStencilBufferGetIdxAndCount(CRStencilState *s, GLenum face, GLint *pIdx, GLint *pBitsIdx) +{ + switch (face) + { + case GL_FRONT_AND_BACK: + *pIdx = 0; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK; + return 2; + case GL_FRONT: + *pIdx = CRSTATE_STENCIL_BUFFER_ID_FRONT; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT; + return 1; + case GL_BACK: + *pIdx = CRSTATE_STENCIL_BUFFER_ID_BACK; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_BACK; + return 1; + case 0: + if (!s->stencilTwoSideEXT || s->activeStencilFace == GL_FRONT) + { + /* both front and back */ + *pIdx = 0; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK; + return 2; + } + *pIdx = CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK; + return 1; + default: + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilBufferGetIdxAndCount"); + return 0; + } + crError("should never be here!"); + return 0; +} + +void crStateStencilBufferInit(CRStencilBufferState *s) +{ + s->func = GL_ALWAYS; + s->mask = 0xFFFFFFFF; + s->ref = 0; + + s->fail = GL_KEEP; + s->passDepthFail = GL_KEEP; + s->passDepthPass = GL_KEEP; +} + +static void crStateStencilBufferRefBitsInit(CRContext *ctx, CRStencilBufferRefBits *sb) +{ + RESET(sb->func, ctx->bitid); + RESET(sb->op, ctx->bitid); +} + void crStateStencilInit(CRContext *ctx) { CRStencilState *s = &ctx->stencil; CRStateBits *stateb = GetCurrentBits(); CRStencilBits *sb = &(stateb->stencil); + int i; s->stencilTest = GL_FALSE; RESET(sb->enable, ctx->bitid); - s->func = GL_ALWAYS; - s->mask = 0xFFFFFFFF; - s->ref = 0; - RESET(sb->func, ctx->bitid); + s->stencilTwoSideEXT = GL_FALSE; + RESET(sb->enableTwoSideEXT, ctx->bitid); - s->fail = GL_KEEP; - s->passDepthFail = GL_KEEP; - s->passDepthPass = GL_KEEP; - RESET(sb->op, ctx->bitid); + s->activeStencilFace = GL_FRONT; + RESET(sb->activeStencilFace, ctx->bitid); s->clearValue = 0; RESET(sb->clearValue, ctx->bitid); @@ -35,53 +85,101 @@ void crStateStencilInit(CRContext *ctx) RESET(sb->writeMask, ctx->bitid); RESET(sb->dirty, ctx->bitid); + + for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i) + { + crStateStencilBufferInit(&s->buffers[i]); + } + + for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) + { + crStateStencilBufferRefBitsInit(ctx, &sb->bufferRefs[i]); + } } -void STATE_APIENTRY crStateStencilFunc(GLenum func, GLint ref, GLuint mask) +static void crStateStencilBufferFunc(CRContext *g, CRStencilBufferState *s, GLenum func, GLint ref, GLuint mask) { - CRContext *g = GetCurrentContext(); - CRStencilState *s = &(g->stencil); - CRStateBits *stateb = GetCurrentBits(); - CRStencilBits *sb = &(stateb->stencil); + s->func = func; + s->ref = ref; + s->mask = mask; +} +static void crStateStencilFuncPerform(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + CRContext *g = GetCurrentContext(); + CRStencilState *s = &(g->stencil); + CRStateBits *stateb = GetCurrentBits(); + CRStencilBits *sb = &(stateb->stencil); + GLint idx, bitsIdx, count, i; - if (g->current.inBeginEnd) - { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glStencilFunc called in begin/end"); - return; - } - FLUSH(); + if (g->current.inBeginEnd) + { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glStencilFunc called in begin/end"); + return; + } - if (func != GL_NEVER && - func != GL_LESS && - func != GL_LEQUAL && - func != GL_GREATER && - func != GL_GEQUAL && - func != GL_EQUAL && - func != GL_NOTEQUAL && - func != GL_ALWAYS) - { - crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, - "glStencilFunc called with bogu func: %d", func); - return; - } + FLUSH(); - s->func = func; - s->ref = ref; - s->mask = mask; + if (func != GL_NEVER && + func != GL_LESS && + func != GL_LEQUAL && + func != GL_GREATER && + func != GL_GEQUAL && + func != GL_EQUAL && + func != GL_NOTEQUAL && + func != GL_ALWAYS) + { + crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, + "glStencilFunc called with bogu func: %d", func); + return; + } - DIRTY(sb->func, g->neg_bitid); - DIRTY(sb->dirty, g->neg_bitid); + count = crStateStencilBufferGetIdxAndCount(s, face, &idx, &bitsIdx); + if (count) + { + for (i = idx; i < idx + count; ++i) + { + crStateStencilBufferFunc(g, &s->buffers[i], func, ref, mask); + } + DIRTY(sb->bufferRefs[bitsIdx].func, g->neg_bitid); + + DIRTY(sb->dirty, g->neg_bitid); + } +} + +void STATE_APIENTRY crStateStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + if (!face) + { + /* crStateStencilFuncPerform accepts 0 value, while glStencilFuncSeparate does not, + * filter it out here */ + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilFuncSeparate"); + return; + } + crStateStencilFuncPerform(face, func, ref, mask); } -void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass) +void STATE_APIENTRY crStateStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + crStateStencilFuncPerform(0, func, ref, mask); +} + +static void STATE_APIENTRY crStateStencilBufferOp (CRContext *g, CRStencilBufferState *s, GLenum fail, GLenum zfail, GLenum zpass) +{ + s->fail = fail; + s->passDepthFail = zfail; + s->passDepthPass = zpass; +} + +static void crStateStencilOpPerform (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { CRContext *g = GetCurrentContext(); CRStencilState *s = &(g->stencil); CRStateBits *stateb = GetCurrentBits(); CRStencilBits *sb = &(stateb->stencil); + GLint idx, bitsIdx, count, i; if (g->current.inBeginEnd) { @@ -146,14 +244,36 @@ void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass) return; } - s->fail = fail; - s->passDepthFail = zfail; - s->passDepthPass = zpass; + count = crStateStencilBufferGetIdxAndCount(s, face, &idx, &bitsIdx); + if (count) + { + for (i = idx; i < idx + count; ++i) + { + crStateStencilBufferOp(g, &s->buffers[i], fail, zfail, zpass); + } - DIRTY(sb->op, g->neg_bitid); - DIRTY(sb->dirty, g->neg_bitid); + DIRTY(sb->bufferRefs[bitsIdx].op, g->neg_bitid); + + DIRTY(sb->dirty, g->neg_bitid); + } } +void STATE_APIENTRY crStateStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (!face) + { + /* crStateStencilOpPerform accepts 0 value, while glStencilOpSeparate does not, + * filter it out here */ + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilOpSeparate"); + return; + } + crStateStencilOpPerform (0, fail, zfail, zpass); +} + +void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass) +{ + crStateStencilOpPerform (0, fail, zfail, zpass); +} void STATE_APIENTRY crStateClearStencil (GLint c) { @@ -171,7 +291,6 @@ void STATE_APIENTRY crStateClearStencil (GLint c) FLUSH(); - s->clearValue = c; DIRTY(sb->clearValue, g->neg_bitid); @@ -199,3 +318,1129 @@ void STATE_APIENTRY crStateStencilMask (GLuint mask) DIRTY(sb->writeMask, g->neg_bitid); DIRTY(sb->dirty, g->neg_bitid); } + +void STATE_APIENTRY crStateActiveStencilFaceEXT (GLenum face) +{ + CRContext *g = GetCurrentContext(); + CRStencilState *s = &(g->stencil); + CRStateBits *stateb = GetCurrentBits(); + CRStencilBits *sb = &(stateb->stencil); + + switch (face) + { + case GL_FRONT: + case GL_BACK: + s->activeStencilFace = face; + break; + default: + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateActiveStencilFaceEXT"); + return; + } + + DIRTY(sb->activeStencilFace, g->neg_bitid); + DIRTY(sb->dirty, g->neg_bitid); +} + +#ifdef CRSTATE_DEBUG_STENCIL_ERR +#define CRSTATE_CLEARERR() do { \ + while (diff_api.GetError() != GL_NO_ERROR) {} \ + } while (0) + +#define CRSTATE_CHECKGLERR(_op) do {\ + GLenum _glErr; \ + CRSTATE_CLEARERR(); \ + _op; \ + while ((_glErr = diff_api.GetError()) != GL_NO_ERROR) { Assert(0);} \ + }while (0) +#else +#define CRSTATE_CHECKGLERR(_op) do { _op; } while (0) +#endif + +#define CR_STATE_STENCIL_FUNC_MATCH(_s1, _i1, _s2, _i2) (\ + (_s1)->buffers[(_i1)].func == (_s2)->buffers[(_i2)].func && \ + (_s1)->buffers[(_i1)].ref == (_s2)->buffers[(_i2)].ref && \ + (_s1)->buffers[(_i1)].mask == (_s2)->buffers[(_i2)].mask) + +#define CR_STATE_STENCIL_FUNC_COPY(_s1, _i1, _s2, _i2) do { \ + (_s1)->buffers[(_i1)].func = (_s2)->buffers[(_i2)].func; \ + (_s1)->buffers[(_i1)].ref = (_s2)->buffers[(_i2)].ref; \ + (_s1)->buffers[(_i1)].mask = (_s2)->buffers[(_i2)].mask; \ + } while (0) + + +#define CR_STATE_STENCIL_OP_MATCH(_s1, _i1, _s2, _i2) (\ + (_s1)->buffers[(_i1)].fail == (_s2)->buffers[(_i2)].fail && \ + (_s1)->buffers[(_i1)].passDepthFail == (_s2)->buffers[(_i2)].passDepthFail && \ + (_s1)->buffers[(_i1)].passDepthPass == (_s2)->buffers[(_i2)].passDepthPass) + +#define CR_STATE_STENCIL_OP_COPY(_s1, _i1, _s2, _i2) do { \ + (_s1)->buffers[(_i1)].fail = (_s2)->buffers[(_i2)].fail; \ + (_s1)->buffers[(_i1)].passDepthFail = (_s2)->buffers[(_i2)].passDepthFail; \ + (_s1)->buffers[(_i1)].passDepthPass = (_s2)->buffers[(_i2)].passDepthPass; \ + } while (0) + + +void crStateStencilDiff(CRStencilBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRStencilState *from = &(fromCtx->stencil); + CRStencilState *to = &(toCtx->stencil); + unsigned int j, i; + GLenum activeFace; + GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE, frontBackDirty, frontDirty, backDirty; + GLchar frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + + if (CHECKDIRTY(b->enable, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTest != to->stencilTest) + { + able[to->stencilTest](GL_STENCIL_TEST); + from->stencilTest = to->stencilTest; + } + CLEARDIRTY(b->enable, nbitID); + } + + if (CHECKDIRTY(b->enableTwoSideEXT, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTwoSideEXT != to->stencilTwoSideEXT) + { + able[to->stencilTwoSideEXT](GL_STENCIL_TEST_TWO_SIDE_EXT); + from->stencilTwoSideEXT = to->stencilTwoSideEXT; + } + CLEARDIRTY(b->enableTwoSideEXT, nbitID); + } + + if (CHECKDIRTY(b->clearValue, bitID)) + { + if (from->clearValue != to->clearValue) + { + diff_api.ClearStencil (to->clearValue); + from->clearValue = to->clearValue; + } + CLEARDIRTY(b->clearValue, nbitID); + } + + activeFace = to->activeStencilFace; + + + /* func */ + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, bitID); +#define CR_STATE_STENCIL_FUNC_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_FUNC_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_FUNC_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH() + || !CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + + backIsSet = GL_TRUE; + } + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, bitID)) + { + if (!CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + diff_api.ActiveStencilFaceEXT(GL_BACK); + activeFace = GL_BACK; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, nbitID); + } + +#undef CR_STATE_STENCIL_FUNC_FRONT_MATCH +#undef CR_STATE_STENCIL_FUNC_BACK_MATCH +#undef CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH + + /* op */ + backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, bitID); + +#define CR_STATE_STENCIL_OP_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_OP_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_OP_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH() + || !CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, bitID)) + { + if (!CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + diff_api.ActiveStencilFaceEXT(GL_BACK); + activeFace = GL_BACK; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, nbitID); + } + +#undef CR_STATE_STENCIL_OP_FRONT_MATCH +#undef CR_STATE_STENCIL_OP_BACK_MATCH +#undef CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH + + + if (activeFace != to->activeStencilFace) + { + diff_api.ActiveStencilFaceEXT(activeFace); + } + + if (CHECKDIRTY(b->activeStencilFace, bitID)) + { + if (from->activeStencilFace != to->activeStencilFace) + { + /* we already did it ( see above )*/ + /* diff_api.ActiveStencilFaceEXT(to->activeStencilFace); */ + from->activeStencilFace = to->activeStencilFace; + } + CLEARDIRTY(b->activeStencilFace, nbitID); + } + + if (CHECKDIRTY(b->writeMask, bitID)) + { + if (from->writeMask != to->writeMask) + { + diff_api.StencilMask (to->writeMask); + from->writeMask = to->writeMask; + } + CLEARDIRTY(b->writeMask, nbitID); + } + CLEARDIRTY(b->dirty, nbitID); +} + +void crStateStencilSwitch(CRStencilBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRStencilState *from = &(fromCtx->stencil); + CRStencilState *to = &(toCtx->stencil); + unsigned int j, i; + GLenum activeFace; + GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE, frontBackDirty, frontDirty, backDirty; + GLchar frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + + if (CHECKDIRTY(b->enable, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTest != to->stencilTest) + { + CRSTATE_CHECKGLERR(able[to->stencilTest](GL_STENCIL_TEST)); + FILLDIRTY(b->enable); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enable, nbitID); + } + if (CHECKDIRTY(b->enableTwoSideEXT, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTwoSideEXT != to->stencilTwoSideEXT) + { + CRSTATE_CHECKGLERR(able[to->stencilTwoSideEXT](GL_STENCIL_TEST_TWO_SIDE_EXT)); + FILLDIRTY(b->enableTwoSideEXT); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enableTwoSideEXT, nbitID); + } + if (CHECKDIRTY(b->clearValue, bitID)) + { + if (from->clearValue != to->clearValue) + { + CRSTATE_CHECKGLERR(diff_api.ClearStencil (to->clearValue)); + FILLDIRTY(b->clearValue); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->clearValue, nbitID); + } + + activeFace = from->activeStencilFace; + + /* func */ + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, bitID); +#define CR_STATE_STENCIL_FUNC_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_FUNC_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_FUNC_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH() + || !CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask)); + backIsSet = GL_TRUE; + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func); + FILLDIRTY(b->dirty); + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask)); + backIsSet = GL_TRUE; + } + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask)); + backIsSet = GL_TRUE; + } + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, bitID)) + { + if (!CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_BACK)); + activeFace = GL_BACK; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask)); + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, nbitID); + } + +#undef CR_STATE_STENCIL_FUNC_FRONT_MATCH +#undef CR_STATE_STENCIL_FUNC_BACK_MATCH +#undef CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH + + /* op */ + backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, bitID); + +#define CR_STATE_STENCIL_OP_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_OP_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_OP_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH() + || !CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass)); + backIsSet = GL_TRUE; + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op); + FILLDIRTY(b->dirty); + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass)); + backIsSet = GL_TRUE; + } + } + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass)); + backIsSet = GL_TRUE; + } + } + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, bitID)) + { + if (!CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_BACK)); + activeFace = GL_BACK; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass)); + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, nbitID); + } + +#undef CR_STATE_STENCIL_OP_FRONT_MATCH +#undef CR_STATE_STENCIL_OP_BACK_MATCH +#undef CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH + + if (activeFace != to->activeStencilFace) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(activeFace)); + } + + if (CHECKDIRTY(b->activeStencilFace, bitID)) + { + if (from->activeStencilFace != to->activeStencilFace) + { + /* we already did it ( see above )*/ + /* diff_api.ActiveStencilFaceEXT(to->activeStencilFace); */ + FILLDIRTY(b->activeStencilFace); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->activeStencilFace, nbitID); + } + + if (CHECKDIRTY(b->writeMask, bitID)) + { + if (from->writeMask != to->writeMask) + { + CRSTATE_CHECKGLERR(diff_api.StencilMask (to->writeMask)); + FILLDIRTY(b->writeMask); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->writeMask, nbitID); + } + + CLEARDIRTY(b->dirty, nbitID); +} + diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c index 00adbfff..5ac9028a 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c @@ -603,6 +603,10 @@ crStateTextureObjectDiff(CRContext *fromCtx, CRTextureState *from = &(fromCtx->texture); glAble able[2]; int u = 0; /* always use texture unit 0 for diff'ing */ + GLuint hwid = crStateGetTextureObjHWID(tobj); + + if (!hwid) + return; able[0] = diff_api.Disable; able[1] = diff_api.Enable; @@ -619,7 +623,7 @@ crStateTextureObjectDiff(CRContext *fromCtx, } #endif - diff_api.BindTexture(tobj->target, crStateGetTextureObjHWID(tobj)); + diff_api.BindTexture(tobj->target, hwid); if (alwaysDirty || CHECKDIRTY(tobj->paramsBit[u], bitID)) { @@ -1448,7 +1452,7 @@ crStateDiffAllTextureObjects( CRContext *g, CRbitvalue *bitID, GLboolean bForceU #endif /* restore bindings */ - diff_api.ActiveTextureARB(GL_TEXTURE0_ARB + origUnit); + /* first restore unit 0 bindings the unit 0 is active currently */ diff_api.BindTexture(GL_TEXTURE_1D, orig1D); diff_api.BindTexture(GL_TEXTURE_2D, orig2D); diff_api.BindTexture(GL_TEXTURE_3D, orig3D); @@ -1458,4 +1462,6 @@ crStateDiffAllTextureObjects( CRContext *g, CRbitvalue *bitID, GLboolean bForceU #ifdef CR_NV_texture_rectangle diff_api.BindTexture(GL_TEXTURE_RECTANGLE_NV, origRect); #endif + /* now restore the proper active unit */ + diff_api.ActiveTextureARB(GL_TEXTURE0_ARB + origUnit); } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c index 6917197b..41d96125 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c @@ -245,7 +245,7 @@ crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, return; default: /* fall-through */ - ; + ; } #ifdef CR_NV_texture_rectangle @@ -308,6 +308,7 @@ crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, } #endif + crWarning("unexpected texTarget 0x%x", texTarget); *obj = NULL; *img = NULL; } @@ -971,6 +972,13 @@ crStateTexSubImage1D(GLenum target, GLint level, GLint xoffset, return; /* GL error state already set */ } +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; @@ -1024,6 +1032,13 @@ crStateTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, CRASSERT(tobj); CRASSERT(tl); +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; yoffset += tl->border; @@ -1109,6 +1124,14 @@ crStateTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, return; /* GL error state already set */ } +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_3D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; yoffset += tl->border; @@ -1416,6 +1439,14 @@ crStateCompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, return; /* GL error state already set */ } +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_1D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; @@ -1456,11 +1487,19 @@ crStateCompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, CRStateBits *sb = GetCurrentBits(); CRTextureBits *tb = &(sb->texture); CRTextureUnit *unit = t->unit + t->curTextureUnit; - CRTextureObj *tobj = unit->currentTexture1D; + CRTextureObj *tobj = unit->currentTexture2D; CRTextureLevel *tl = tobj->level[0] + level; FLUSH(); +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_2D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + if (ErrorCheckTexSubImage(2, target, level, xoffset, yoffset, 0, width, height, 1)) { return; /* GL error state already set */ @@ -1510,11 +1549,19 @@ crStateCompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, CRStateBits *sb = GetCurrentBits(); CRTextureBits *tb = &(sb->texture); CRTextureUnit *unit = t->unit + t->curTextureUnit; - CRTextureObj *tobj = unit->currentTexture1D; + CRTextureObj *tobj = unit->currentTexture3D; CRTextureLevel *tl = tobj->level[0] + level; FLUSH(); +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_3D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + if (ErrorCheckTexSubImage(3, target, level, xoffset, yoffset, zoffset, width, height, depth)) { return; /* GL error state already set */ @@ -1580,6 +1627,13 @@ crStateGetCompressedTexImageARB(GLenum target, GLint level, GLvoid * img) return; } +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE crMemcpy(img, tl->img, tl->bytes); #else @@ -1616,6 +1670,13 @@ crStateGetTexImage(GLenum target, GLint level, GLenum format, return; } +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + switch (format) { case GL_RED: diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c index 951a0e55..5da27393 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c @@ -250,10 +250,8 @@ crStateTextureInitTextureObj(CRContext *ctx, CRTextureObj *tobj, RESET(tobj->paramsBit[i], ctx->bitid); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_INIT(tobj); CR_STATE_SHAREDOBJ_USAGE_SET(tobj, ctx); -#endif } @@ -620,9 +618,29 @@ crStateDeleteTextureObject(CRTextureObj *tobj) crFree(tobj); } -void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) +void crStateRegNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names) +{ + GLint i; + for (i = 0; i < n; i++) + { + if (names[i]) + { + GLboolean isNewKey = crHashtableAllocRegisterKey(table, names[i]); + CRASSERT(isNewKey); + } + else + crWarning("RegNames: requested to register a null name"); + } +} + +void crStateRegTextures(GLsizei n, GLuint *names) { CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->textureTable, n, names); +} + +void crStateGenNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names) +{ GLint start; FLUSH(); @@ -630,23 +648,23 @@ void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) if (g->current.inBeginEnd) { crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glGenTextures called in Begin/End"); + "crStateGenNames called in Begin/End"); return; } if (n < 0) { crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, - "Negative n passed to glGenTextures: %d", n); + "Negative n passed to crStateGenNames: %d", n); return; } - start = crHashtableAllocKeys(g->shared->textureTable, n); + start = crHashtableAllocKeys(table, n); if (start) { GLint i; for (i = 0; i < n; i++) - textures[i] = (GLuint) (start + i); + names[i] = (GLuint) (start + i); } else { @@ -654,6 +672,12 @@ void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) } } +void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->textureTable, n, textures); +} + static void crStateTextureCheckFBOAPs(GLenum target, GLuint texture) { GLuint u; @@ -730,6 +754,7 @@ static void crStateCleanupTextureRefs(CRContext *g, CRTextureObj *tObj) #endif } + CR_STATE_SHAREDOBJ_USAGE_CLEAR(tObj, g); } void STATE_APIENTRY crStateDeleteTextures(GLsizei n, const GLuint *textures) @@ -760,15 +785,39 @@ void STATE_APIENTRY crStateDeleteTextures(GLsizei n, const GLuint *textures) { GLuint name = textures[i]; CRTextureObj *tObj; + if (!name) + continue; + GET_TOBJ(tObj, g, name); - if (name && tObj) + if (tObj) { + GLuint j; + crStateCleanupTextureRefs(g, tObj); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(tObj, j) + { + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + crStateCleanupTextureRefs(ctx, tObj); + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(tObj, j); + } + /* on the host side, ogl texture object is deleted by a separate cr_server.head_spu->dispatch_table.DeleteTextures(n, newTextures); * in crServerDispatchDeleteTextures, we just delete a state object here, which crStateDeleteTextureObject does */ crHashtableDelete(g->shared->textureTable, name, (CRHashtableCallback)crStateDeleteTextureObject); } + else + { + /* call crHashtableDelete in any way, to ensure the allocated key is freed */ + Assert(crHashtableIsKeyUsed(g->shared->textureTable, name)); + crHashtableDelete(g->shared->textureTable, name, NULL); + } } DIRTY(tb->dirty, g->neg_bitid); @@ -858,8 +907,17 @@ DECLEXPORT(void) crStateSetTextureUsed(GLuint texture, GLboolean used) GET_TOBJ(tobj, g, texture); if (!tobj) { - crWarning("crStateSetTextureUsed: failed to fined a HW name for texture(%d)!", texture); - return; +#ifdef IN_GUEST + if (used) + { + tobj = crStateTextureAllocate_t(g, texture); + } + else +#endif + { + crWarning("crStateSetTextureUsed: failed to fined a HW name for texture(%d)!", texture); + return; + } } if (used) @@ -870,8 +928,6 @@ DECLEXPORT(void) crStateSetTextureUsed(GLuint texture, GLboolean used) CRTextureBits *tb = &(sb->texture); CRTextureState *t = &(g->texture); - CR_STATE_SHAREDOBJ_USAGE_CLEAR(tobj, g); - crStateCleanupTextureRefs(g, tobj); if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(tobj)) @@ -953,12 +1009,11 @@ void STATE_APIENTRY crStateBindTexture(GLenum target, GLuint texture) GET_TOBJ(tobj, g, texture); if (!tobj) { + Assert(crHashtableIsKeyUsed(g->shared->textureTable, texture)); tobj = crStateTextureAllocate_t(g, texture); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif /* Check the targets */ if (tobj->target == GL_NONE) @@ -3204,10 +3259,28 @@ void STATE_APIENTRY crStatePrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities) { - UNUSED(n); - UNUSED(textures); + CRContext *g = GetCurrentContext(); + CRTextureObj *tobj; + GLsizei i; UNUSED(priorities); - /* TODO: */ + + for (i = 0; i < n; ++i) + { + GLuint tex = textures[i]; + GET_TOBJ(tobj, g, tex); + if (!tobj) + { + Assert(crHashtableIsKeyUsed(g->shared->textureTable, tex)); + tobj = crStateTextureAllocate_t(g, tex); + } + + /* so far the code just ensures the tex object is created to make + * the crserverlib code be able to pass it to host ogl */ + + /* TODO: store texture priorities in the state data to be able to restore it properly + * on save state load */ + } + return; } @@ -3259,7 +3332,9 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateTextureHWIDtoID(GLuint hwid) DECLEXPORT(GLuint) STATE_APIENTRY crStateGetTextureHWID(GLuint id) { CRContext *g = GetCurrentContext(); - CRTextureObj *tobj = GET_TOBJ(tobj, g, id); + CRTextureObj *tobj; + + GET_TOBJ(tobj, g, id); #ifdef DEBUG_misha if (id) diff --git a/src/VBox/GuestHost/OpenGL/util/blitter.cpp b/src/VBox/GuestHost/OpenGL/util/blitter.cpp new file mode 100644 index 00000000..a14c0916 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/blitter.cpp @@ -0,0 +1,1751 @@ +/* $Id$ */ + +/** @file + * Blitter API implementation + */ +/* + * Copyright (C) 2013 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_blitter.h" +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "cr_mem.h" +#include "cr_string.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/mem.h> + +/* @param pCtxBase - contains the blitter context info. Its value is treated differently depending on the fCreateNewCtx value + * @param fCreateNewCtx - if true - the pCtxBase must NOT be NULL. its visualBits is used as a visual bits info for the new context, + * its id field is used to specified the shared context id to be used for blitter context. + * The id can be null to specify no shared context is needed + * if false - if pCtxBase is NOT null AND its id field is NOT null - + * specified the blitter context to be used + * blitter treats it as if it has default ogl state. + * otherwise - + * the blitter works in a "no-context" mode, i.e. a caller is responsible + * to making a proper context current before calling the blitter. + * Note that BltEnter/Leave MUST still be called, but the proper context + * must be set before doing BltEnter, and ResoreContext info is ignored in that case. + * Also note that blitter caches the current window info, and assumes the current context's values are preserved + * wrt that window before the calls, so if one uses different contexts for one blitter, + * the blitter current window values must be explicitly reset by doing CrBltMuralSetCurrentInfo(pBlitter, NULL) + * @param fForceDrawBlt - if true - forces the blitter to always use glDrawXxx-based blits even if GL_EXT_framebuffer_blit. + * This is needed because BlitFramebufferEXT is known to be often buggy, and glDrawXxx-based blits appear to be more reliable + */ +VBOXBLITTERDECL(int) CrBltInit(PCR_BLITTER pBlitter, const CR_BLITTER_CONTEXT *pCtxBase, bool fCreateNewCtx, bool fForceDrawBlt, const CR_GLSL_CACHE *pShaders, SPUDispatchTable *pDispatch) +{ + if (pCtxBase && pCtxBase->Base.id < 0) + { + crWarning("Default share context not initialized!"); + return VERR_INVALID_PARAMETER; + } + + if (!pCtxBase && fCreateNewCtx) + { + crWarning("pCtxBase is zero while fCreateNewCtx is set!"); + return VERR_INVALID_PARAMETER; + } + + memset(pBlitter, 0, sizeof (*pBlitter)); + + pBlitter->pDispatch = pDispatch; + if (pCtxBase) + pBlitter->CtxInfo = *pCtxBase; + + pBlitter->Flags.ForceDrawBlit = fForceDrawBlt; + + if (fCreateNewCtx) + { + pBlitter->CtxInfo.Base.id = pDispatch->CreateContext("", pCtxBase->Base.visualBits, pCtxBase->Base.id); + if (!pBlitter->CtxInfo.Base.id) + { + memset(pBlitter, 0, sizeof (*pBlitter)); + crWarning("CreateContext failed!"); + return VERR_GENERAL_FAILURE; + } + pBlitter->Flags.CtxCreated = 1; + } + + if (pShaders) + { + pBlitter->pGlslCache = pShaders; + pBlitter->Flags.ShadersGloal = 1; + } + else + { + CrGlslInit(&pBlitter->LocalGlslCache, pDispatch); + pBlitter->pGlslCache = &pBlitter->LocalGlslCache; + } + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrBltCleanup(PCR_BLITTER pBlitter) +{ + if (CrBltIsEntered(pBlitter)) + { + WARN(("CrBltBlitTexTex: blitter is entered")); + return VERR_INVALID_STATE; + } + + if (pBlitter->Flags.ShadersGloal || !CrGlslNeedsCleanup(&pBlitter->LocalGlslCache)) + return VINF_SUCCESS; + + int rc = CrBltEnter(pBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed, rc %d", rc)); + return rc; + } + + CrGlslCleanup(&pBlitter->LocalGlslCache); + + CrBltLeave(pBlitter); + + return VINF_SUCCESS; +} + +void CrBltTerm(PCR_BLITTER pBlitter) +{ + if (pBlitter->Flags.CtxCreated) + pBlitter->pDispatch->DestroyContext(pBlitter->CtxInfo.Base.id); + memset(pBlitter, 0, sizeof (*pBlitter)); +} + +int CrBltMuralSetCurrentInfo(PCR_BLITTER pBlitter, const CR_BLITTER_WINDOW *pMural) +{ + if (pMural) + { + if (!memcmp(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural))) + return VINF_SUCCESS; + memcpy(&pBlitter->CurrentMural, pMural, sizeof (pBlitter->CurrentMural)); + } + else + { + if (CrBltIsEntered(pBlitter)) + { + WARN(("can not set null mural for entered bleater")); + return VERR_INVALID_STATE; + } + if (!pBlitter->CurrentMural.Base.id) + return VINF_SUCCESS; + pBlitter->CurrentMural.Base.id = 0; + } + + pBlitter->Flags.CurrentMuralChanged = 1; + + if (!CrBltIsEntered(pBlitter)) + return VINF_SUCCESS; + else if (!pBlitter->CtxInfo.Base.id) + { + WARN(("setting current mural for entered no-context blitter")); + return VERR_INVALID_STATE; + } + + WARN(("changing mural for entered blitter, is is somewhat expected?")); + + pBlitter->pDispatch->Flush(); + + pBlitter->pDispatch->MakeCurrent(pMural->Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id); + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) crBltBlitTexBufImplFbo(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags) +{ + GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags); + pBlitter->pDispatch->BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO); + pBlitter->pDispatch->FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0); + pBlitter->pDispatch->ReadBuffer(GL_COLOR_ATTACHMENT0); + + for (uint32_t i = 0; i < cRects; ++i) + { + const RTRECT * pSrcRect = &paSrcRect[i]; + const RTRECT * pDstRect = &paDstRect[i]; + int32_t srcY1; + int32_t srcY2; + int32_t dstY1; + int32_t dstY2; + int32_t srcX1 = pSrcRect->xLeft; + int32_t srcX2 = pSrcRect->xRight; + int32_t dstX1 = pDstRect->xLeft; + int32_t dstX2 = pDstRect->xRight; + + if (CRBLT_F_INVERT_SRC_YCOORDS & fFlags) + { + srcY1 = pSrc->height - pSrcRect->yTop; + srcY2 = pSrc->height - pSrcRect->yBottom; + } + else + { + srcY1 = pSrcRect->yTop; + srcY2 = pSrcRect->yBottom; + } + + if (CRBLT_F_INVERT_DST_YCOORDS & fFlags) + { + dstY1 = pDstSize->cy - pDstRect->yTop; + dstY2 = pDstSize->cy - pDstRect->yBottom; + } + else + { + dstY1 = pDstRect->yTop; + dstY2 = pDstRect->yBottom; + } + + if (srcY1 > srcY2) + { + if (dstY1 > dstY2) + { + /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */ + int32_t tmp = srcY1; + srcY1 = srcY2; + srcY2 = tmp; + tmp = dstY1; + dstY1 = dstY2; + dstY2 = tmp; + } + } + + if (srcX1 > srcX2) + { + if (dstX1 > dstX2) + { + /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */ + int32_t tmp = srcX1; + srcX1 = srcX2; + srcX2 = tmp; + tmp = dstX1; + dstX1 = dstX2; + dstX2 = tmp; + } + } + + pBlitter->pDispatch->BlitFramebufferEXT(srcX1, srcY1, srcX2, srcY2, + dstX1, dstY1, dstX2, dstY2, + GL_COLOR_BUFFER_BIT, filter); + } + + return VINF_SUCCESS; +} + +/* GL_TRIANGLE_FAN */ +DECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height) +{ + /* going ccw: + * 1. (left;top) 4. (right;top) + * | ^ + * > | + * 2. (left;bottom) -> 3. (right;bottom) */ + /* xLeft yTop */ + pBuff[0] = ((float)pRect->xLeft)/((float)normalX); + pBuff[1] = ((float)(height ? height - pRect->yTop : pRect->yTop))/((float)normalY); + + /* xLeft yBottom */ + pBuff[2] = pBuff[0]; + pBuff[3] = ((float)(height ? height - pRect->yBottom : pRect->yBottom))/((float)normalY); + + /* xRight yBottom */ + pBuff[4] = ((float)pRect->xRight)/((float)normalX); + pBuff[5] = pBuff[3]; + + /* xRight yTop */ + pBuff[6] = pBuff[4]; + pBuff[7] = pBuff[1]; + return &pBuff[8]; +} + +DECLINLINE(GLfloat*) crBltVtRectsTFNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height) +{ + for (uint32_t i = 0; i < cRects; ++i) + { + pBuff = crBltVtRectTFNormalized(&paRects[i], normalX, normalY, pBuff, height); + } + return pBuff; +} + +DECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, uint32_t height) +{ + /* xLeft yTop */ + pBuff[0] = pRect->xLeft; + pBuff[1] = height ? height - pRect->yTop : pRect->yTop; + + /* xLeft yBottom */ + pBuff[2] = pBuff[0]; + pBuff[3] = height ? height - pRect->yBottom : pRect->yBottom; + + /* xRight yBottom */ + pBuff[4] = pRect->xRight; + pBuff[5] = pBuff[3]; + + /* xRight yTop */ + pBuff[6] = pBuff[4]; + pBuff[7] = pBuff[1]; + return &pBuff[8]; +} + +DECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase) +{ + GLubyte iBase = *piBase; + /* triangle 1 */ + pIndex[0] = iBase; + pIndex[1] = iBase + 1; + pIndex[2] = iBase + 2; + + /* triangle 2 */ + pIndex[3] = iBase; + pIndex[4] = iBase + 2; + pIndex[5] = iBase + 3; + *piBase = iBase + 4; + return pIndex + 6; +} + +/* Indexed GL_TRIANGLES */ +DECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, uint32_t height) +{ + GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff, height); + return ret; +} + +DECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height) +{ + GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff, height); + + if (ppIndex) + *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase); + + return ret; +} + +DECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects) +{ + return cRects * 4; +} + +#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF + +DECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects) +{ + return 6 * cRects; +} + + +static GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase, uint32_t height) +{ + uint32_t i; + for (i = 0; i < cRects; ++i) + { + pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, height); + } + + + if (ppIndex) + { + GLubyte *pIndex = (GLubyte*)pBuff; + *ppIndex = pIndex; + for (i = 0; i < cRects; ++i) + { + pIndex = crBltVtFillRectIndicies(pIndex, piBase); + } + pBuff = (GLfloat*)pIndex; + } + + return pBuff; +} + +static void* crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer) +{ + if (pBuffer->cbBuffer < cbBuffer) + { + if (pBuffer->pvBuffer) + { + RTMemFree(pBuffer->pvBuffer); + } + +#ifndef DEBUG_misha + /* debugging: ensure we calculate proper buffer size */ + cbBuffer += 16; +#endif + + pBuffer->pvBuffer = RTMemAlloc(cbBuffer); + if (pBuffer->pvBuffer) + pBuffer->cbBuffer = cbBuffer; + else + { + crWarning("failed to allocate buffer of size %d", cbBuffer); + pBuffer->cbBuffer = 0; + } + } + return pBuffer->pvBuffer; +} + +static void crBltCheckSetupViewport(PCR_BLITTER pBlitter, const RTRECTSIZE *pDstSize, bool fFBODraw) +{ + bool fUpdateViewport = pBlitter->Flags.CurrentMuralChanged; + if (pBlitter->CurrentSetSize.cx != pDstSize->cx + || pBlitter->CurrentSetSize.cy != pDstSize->cy) + { + pBlitter->CurrentSetSize = *pDstSize; + pBlitter->pDispatch->MatrixMode(GL_PROJECTION); + pBlitter->pDispatch->LoadIdentity(); + pBlitter->pDispatch->Ortho(0, pDstSize->cx, 0, pDstSize->cy, -1, 1); + fUpdateViewport = true; + } + + if (fUpdateViewport) + { + pBlitter->pDispatch->Viewport(0, 0, pBlitter->CurrentSetSize.cx, pBlitter->CurrentSetSize.cy); + pBlitter->Flags.CurrentMuralChanged = 0; + } + + pBlitter->Flags.LastWasFBODraw = fFBODraw; +} + +static DECLCALLBACK(int) crBltBlitTexBufImplDraw2D(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const RTRECTSIZE *pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags) +{ + GLuint normalX, normalY; + uint32_t srcHeight = (fFlags & CRBLT_F_INVERT_SRC_YCOORDS) ? pSrc->height : 0; + uint32_t dstHeight = (fFlags & CRBLT_F_INVERT_DST_YCOORDS) ? pDstSize->cy : 0; + + switch (pSrc->target) + { + case GL_TEXTURE_2D: + { + normalX = pSrc->width; + normalY = pSrc->height; + break; + } + + case GL_TEXTURE_RECTANGLE_ARB: + { + normalX = 1; + normalY = 1; + break; + } + + default: + { + crWarning("Unsupported texture target 0x%x", pSrc->target); + return VERR_INVALID_PARAMETER; + } + } + + Assert(pSrc->hwid); + + pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid); + + if (cRects == 1) + { + /* just optimization to draw a single rect with GL_TRIANGLE_FAN */ + GLfloat *pVerticies; + GLfloat *pTexCoords; + GLuint cElements = crBltVtGetNumVerticiesTF(cRects); + + pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies)); + pTexCoords = crBltVtRectsTFNormalized(paDstRect, cRects, 1, 1, pVerticies, dstHeight); + crBltVtRectsTFNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, srcHeight); + + pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY); + pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies); + + pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY); + pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords); + + pBlitter->pDispatch->Enable(pSrc->target); + + pBlitter->pDispatch->DrawArrays(GL_TRIANGLE_FAN, 0, cElements); + + pBlitter->pDispatch->Disable(pSrc->target); + + pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY); + pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY); + } + else + { + GLfloat *pVerticies; + GLfloat *pTexCoords; + GLubyte *pIndicies; + GLuint cElements = crBltVtGetNumVerticiesIT(cRects); + GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects); + GLubyte iIdxBase = 0; + + pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies) + cIndicies * sizeof (*pIndicies)); + pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, 1, 1, pVerticies, &pIndicies, &iIdxBase, dstHeight); + crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL, srcHeight); + + pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY); + pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies); + + pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY); + pBlitter->pDispatch->TexCoordPointer(2, GL_FLOAT, 0, pTexCoords); + + pBlitter->pDispatch->Enable(pSrc->target); + + pBlitter->pDispatch->DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies); + + pBlitter->pDispatch->Disable(pSrc->target); + + pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY); + pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY); + } + + pBlitter->pDispatch->BindTexture(pSrc->target, 0); + + return VINF_SUCCESS; +} + +static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter) +{ + const char * pszExtension = (const char*)pBlitter->pDispatch->GetString(GL_EXTENSIONS); + if (crStrstr(pszExtension, "GL_EXT_framebuffer_object")) + { + pBlitter->Flags.SupportsFBO = 1; + pBlitter->pDispatch->GenFramebuffersEXT(1, &pBlitter->idFBO); + Assert(pBlitter->idFBO); + } + else + crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window"); + + if (crStrstr(pszExtension, "GL_ARB_pixel_buffer_object")) + pBlitter->Flags.SupportsPBO = 1; + else + crWarning("GL_ARB_pixel_buffer_object not supported"); + + /* BlitFramebuffer seems to be buggy on Intel, + * try always glDrawXxx for now */ + if (!pBlitter->Flags.ForceDrawBlit && crStrstr(pszExtension, "GL_EXT_framebuffer_blit")) + { + pBlitter->pfnBlt = crBltBlitTexBufImplFbo; + } + else + { +// crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient"); + pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D; + } + + /* defaults. but just in case */ + pBlitter->pDispatch->MatrixMode(GL_TEXTURE); + pBlitter->pDispatch->LoadIdentity(); + pBlitter->pDispatch->MatrixMode(GL_MODELVIEW); + pBlitter->pDispatch->LoadIdentity(); + + return VINF_SUCCESS; +} + +void CrBltLeave(PCR_BLITTER pBlitter) +{ + if (!pBlitter->cEnters) + { + WARN(("blitter not entered!")); + return; + } + + if (--pBlitter->cEnters) + return; + + if (pBlitter->Flags.SupportsFBO) + { + pBlitter->pDispatch->BindFramebufferEXT(GL_FRAMEBUFFER, 0); + pBlitter->pDispatch->DrawBuffer(GL_BACK); + pBlitter->pDispatch->ReadBuffer(GL_BACK); + } + + pBlitter->pDispatch->Flush(); + + if (pBlitter->CtxInfo.Base.id) + pBlitter->pDispatch->MakeCurrent(0, 0, 0); +} + +int CrBltEnter(PCR_BLITTER pBlitter) +{ + if (!pBlitter->CurrentMural.Base.id && pBlitter->CtxInfo.Base.id) + { + WARN(("current mural not initialized!")); + return VERR_INVALID_STATE; + } + + if (pBlitter->cEnters++) + return VINF_SUCCESS; + + if (pBlitter->CurrentMural.Base.id) /* <- pBlitter->CurrentMural.Base.id can be null if the blitter is in a "no-context" mode (see comments to BltInit for detail)*/ + { + pBlitter->pDispatch->MakeCurrent(pBlitter->CurrentMural.Base.id, pBlitter->i32MakeCurrentUserData, pBlitter->CtxInfo.Base.id); + } + + if (pBlitter->Flags.Initialized) + return VINF_SUCCESS; + + int rc = crBltInitOnMakeCurent(pBlitter); + if (RT_SUCCESS(rc)) + { + pBlitter->Flags.Initialized = 1; + return VINF_SUCCESS; + } + + WARN(("crBltInitOnMakeCurent failed, rc %d", rc)); + CrBltLeave(pBlitter); + return rc; +} + +static void crBltBlitTexBuf(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, GLenum enmDstBuff, const RTRECTSIZE *pDstSize, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags) +{ + pBlitter->pDispatch->DrawBuffer(enmDstBuff); + + crBltCheckSetupViewport(pBlitter, pDstSize, enmDstBuff == GL_DRAW_FRAMEBUFFER); + + if (!(fFlags & CRBLT_F_NOALPHA)) + pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags); + else + { + int rc = pBlitter->Flags.ShadersGloal ? + CrGlslProgUseNoAlpha(pBlitter->pGlslCache, pSrc->target) + : + CrGlslProgUseGenNoAlpha(&pBlitter->LocalGlslCache, pSrc->target); + + if (!RT_SUCCESS(rc)) + { + crWarning("Failed to use no-alpha program rc %d!, falling back to default blit", rc); + pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags); + return; + } + + /* since we use shaders, we need to use draw commands rather than framebuffer blits. + * force using draw-based blitting */ + crBltBlitTexBufImplDraw2D(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags); + + Assert(pBlitter->Flags.ShadersGloal || &pBlitter->LocalGlslCache == pBlitter->pGlslCache); + + CrGlslProgClear(pBlitter->pGlslCache); + } +} + +void CrBltCheckUpdateViewport(PCR_BLITTER pBlitter) +{ + RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height}; + crBltCheckSetupViewport(pBlitter, &DstSize, false); +} + +void CrBltBlitTexMural(PCR_BLITTER pBlitter, bool fBb, const VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags) +{ + if (!CrBltIsEntered(pBlitter)) + { + WARN(("CrBltBlitTexMural: blitter not entered")); + return; + } + + RTRECTSIZE DstSize = {pBlitter->CurrentMural.width, pBlitter->CurrentMural.height}; + + pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); + + crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, fBb ? GL_BACK : GL_FRONT, &DstSize, paDstRects, cRects, fFlags); +} + +void CrBltBlitTexTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, const VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags) +{ + if (!CrBltIsEntered(pBlitter)) + { + WARN(("CrBltBlitTexTex: blitter not entered")); + return; + } + + RTRECTSIZE DstSize = {(uint32_t)pDst->width, (uint32_t)pDst->height}; + + pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO); + + /* TODO: mag/min filters ? */ + + pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0); + +// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); +// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + + crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags); + + pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, 0, 0); +} + +void CrBltPresent(PCR_BLITTER pBlitter) +{ + if (!CrBltIsEntered(pBlitter)) + { + WARN(("CrBltPresent: blitter not entered")); + return; + } + + if (pBlitter->CtxInfo.Base.visualBits & CR_DOUBLE_BIT) + pBlitter->pDispatch->SwapBuffers(pBlitter->CurrentMural.Base.id, 0); + else + pBlitter->pDispatch->Flush(); +} + +static int crBltImgInitBaseForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat) +{ + memset(pDst, 0, sizeof (*pDst)); + if (enmFormat != GL_RGBA + && enmFormat != GL_BGRA) + { + WARN(("unsupported format 0x%x", enmFormat)); + return VERR_NOT_IMPLEMENTED; + } + + uint32_t bpp = 32; + + uint32_t pitch = ((bpp * pSrc->width) + 7) >> 3; + uint32_t cbData = pitch * pSrc->height; + pDst->cbData = cbData; + pDst->enmFormat = enmFormat; + pDst->width = pSrc->width; + pDst->height = pSrc->height; + pDst->bpp = bpp; + pDst->pitch = pitch; + return VINF_SUCCESS; +} + +static int crBltImgCreateForTex(const VBOXVR_TEXTURE *pSrc, CR_BLITTER_IMG *pDst, GLenum enmFormat) +{ + int rc = crBltImgInitBaseForTex(pSrc, pDst, enmFormat); + if (!RT_SUCCESS(rc)) + { + crWarning("crBltImgInitBaseForTex failed rc %d", rc); + return rc; + } + + uint32_t cbData = pDst->cbData; + pDst->pvData = RTMemAllocZ(cbData); + if (!pDst->pvData) + { + crWarning("RTMemAlloc failed"); + return VERR_NO_MEMORY; + } + +#ifdef DEBUG_misha + { + char *pTmp = (char*)pDst->pvData; + for (uint32_t i = 0; i < cbData; ++i) + { + pTmp[i] = (char)((1 << i) % 255); + } + } +#endif + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrBltImgGetTex(PCR_BLITTER pBlitter, const VBOXVR_TEXTURE *pSrc, GLenum enmFormat, CR_BLITTER_IMG *pDst) +{ + if (!CrBltIsEntered(pBlitter)) + { + WARN(("CrBltImgGetTex: blitter not entered")); + return VERR_INVALID_STATE; + } + + int rc = crBltImgCreateForTex(pSrc, pDst, enmFormat); + if (!RT_SUCCESS(rc)) + { + crWarning("crBltImgCreateForTex failed, rc %d", rc); + return rc; + } + pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid); + +#ifdef DEBUG_misha + { + GLint width = 0, height = 0, depth = 0; + pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_WIDTH, &width); + pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_HEIGHT, &height); + pBlitter->pDispatch->GetTexLevelParameteriv(pSrc->target, 0, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pSrc->width); + Assert(height == pSrc->height); +// Assert(depth == pSrc->depth); + } +#endif + + pBlitter->pDispatch->GetTexImage(pSrc->target, 0, enmFormat, GL_UNSIGNED_BYTE, pDst->pvData); + + pBlitter->pDispatch->BindTexture(pSrc->target, 0); + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrBltImgGetMural(PCR_BLITTER pBlitter, bool fBb, CR_BLITTER_IMG *pDst) +{ + if (!CrBltIsEntered(pBlitter)) + { + WARN(("CrBltImgGetMural: blitter not entered")); + return VERR_INVALID_STATE; + } + + crWarning("NOT IMPLEMENTED"); + return VERR_NOT_IMPLEMENTED; +} + +VBOXBLITTERDECL(void) CrBltImgFree(PCR_BLITTER pBlitter, CR_BLITTER_IMG *pDst) +{ + if (!CrBltIsEntered(pBlitter)) + { + WARN(("CrBltImgFree: blitter not entered")); + return; + } + + if (pDst->pvData) + { + RTMemFree(pDst->pvData); + pDst->pvData = NULL; + } +} + + +VBOXBLITTERDECL(bool) CrGlslIsSupported(CR_GLSL_CACHE *pCache) +{ + if (pCache->iGlVersion == 0) + { + const char * pszStr = (const char*)pCache->pDispatch->GetString(GL_VERSION); + pCache->iGlVersion = crStrParseGlVersion(pszStr); + if (pCache->iGlVersion <= 0) + { + crWarning("crStrParseGlVersion returned %d", pCache->iGlVersion); + pCache->iGlVersion = -1; + } + } + + if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0)) + return true; + + crWarning("GLSL unsuported, gl version %d", pCache->iGlVersion); + + /* @todo: we could also check for GL_ARB_shader_objects and GL_ARB_fragment_shader, + * but seems like chromium does not support properly gl*Object versions of shader functions used with those extensions */ + return false; +} + +#define CR_GLSL_STR_V_120 "#version 120\n" +#define CR_GLSL_STR_EXT_TR "#extension GL_ARB_texture_rectangle : enable\n" +#define CR_GLSL_STR_2D "2D" +#define CR_GLSL_STR_2DRECT "2DRect" + +#define CR_GLSL_PATTERN_FS_NOALPHA(_ver, _ext, _tex) \ + _ver \ + _ext \ + "uniform sampler" _tex " sampler0;\n" \ + "void main()\n" \ + "{\n" \ + "vec2 srcCoord = vec2(gl_TexCoord[0]);\n" \ + "gl_FragData[0].xyz = (texture" _tex "(sampler0, srcCoord).xyz);\n" \ + "gl_FragData[0].w = 1.0;\n" \ + "}\n" + +static const char* crGlslGetFsStringNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget) +{ + if (!CrGlslIsSupported(pCache)) + { + crWarning("CrGlslIsSupported is false"); + return NULL; + } + + if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 1, 0)) + { + if (enmTexTarget == GL_TEXTURE_2D) + return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, "", CR_GLSL_STR_2D); + else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB) + return CR_GLSL_PATTERN_FS_NOALPHA(CR_GLSL_STR_V_120, CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT); + + crWarning("invalid enmTexTarget %#x", enmTexTarget); + return NULL; + } + else if (pCache->iGlVersion >= CR_GLVERSION_COMPOSE(2, 0, 0)) + { + if (enmTexTarget == GL_TEXTURE_2D) + return CR_GLSL_PATTERN_FS_NOALPHA("", "", CR_GLSL_STR_2D); + else if (enmTexTarget == GL_TEXTURE_RECTANGLE_ARB) + return CR_GLSL_PATTERN_FS_NOALPHA("", CR_GLSL_STR_EXT_TR, CR_GLSL_STR_2DRECT); + + crWarning("invalid enmTexTarget %#x", enmTexTarget); + return NULL; + } + + crError("crGlslGetFsStringNoAlpha: we should not be here!"); + return NULL; +} + +static int crGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget, GLuint *puiProgram) +{ + *puiProgram = 0; + + const char*pStrFsShader = crGlslGetFsStringNoAlpha(pCache, enmTexTarget); + if (!pStrFsShader) + { + crWarning("crGlslGetFsStringNoAlpha failed"); + return VERR_NOT_SUPPORTED; + } + + int rc = VINF_SUCCESS; + GLchar * pBuf = NULL; + GLuint uiProgram = 0; + GLint iUniform = -1; + GLuint uiShader = pCache->pDispatch->CreateShader(GL_FRAGMENT_SHADER); + if (!uiShader) + { + crWarning("CreateShader failed"); + return VERR_NOT_SUPPORTED; + } + + pCache->pDispatch->ShaderSource(uiShader, 1, &pStrFsShader, NULL); + + pCache->pDispatch->CompileShader(uiShader); + + GLint compiled = 0; + pCache->pDispatch->GetShaderiv(uiShader, GL_COMPILE_STATUS, &compiled); + +#ifndef DEBUG_misha + if(!compiled) +#endif + { + if (!pBuf) + pBuf = (GLchar *)RTMemAlloc(16300); + pCache->pDispatch->GetShaderInfoLog(uiShader, 16300, NULL, pBuf); +#ifdef DEBUG_misha + if (compiled) + crDebug("compile success:\n-------------------\n%s\n--------\n", pBuf); + else +#endif + { + crWarning("compile FAILURE:\n-------------------\n%s\n--------\n", pBuf); + rc = VERR_NOT_SUPPORTED; + goto end; + } + } + + Assert(compiled); + + uiProgram = pCache->pDispatch->CreateProgram(); + if (!uiProgram) + { + rc = VERR_NOT_SUPPORTED; + goto end; + } + + pCache->pDispatch->AttachShader(uiProgram, uiShader); + + pCache->pDispatch->LinkProgram(uiProgram); + + GLint linked; + pCache->pDispatch->GetProgramiv(uiProgram, GL_LINK_STATUS, &linked); +#ifndef DEBUG_misha + if(!linked) +#endif + { + if (!pBuf) + pBuf = (GLchar *)RTMemAlloc(16300); + pCache->pDispatch->GetProgramInfoLog(uiProgram, 16300, NULL, pBuf); +#ifdef DEBUG_misha + if (linked) + crDebug("link success:\n-------------------\n%s\n--------\n", pBuf); + else +#endif + { + crWarning("link FAILURE:\n-------------------\n%s\n--------\n", pBuf); + rc = VERR_NOT_SUPPORTED; + goto end; + } + } + + Assert(linked); + + iUniform = pCache->pDispatch->GetUniformLocation(uiProgram, "sampler0"); + if (iUniform == -1) + { + crWarning("GetUniformLocation failed for sampler0"); + } + else + { + pCache->pDispatch->Uniform1i(iUniform, 0); + } + + *puiProgram = uiProgram; + + /* avoid end finalizer from cleaning it */ + uiProgram = 0; + + end: + if (uiShader) + pCache->pDispatch->DeleteShader(uiShader); + if (uiProgram) + pCache->pDispatch->DeleteProgram(uiProgram); + if (pBuf) + RTMemFree(pBuf); + return rc; +} + +DECLINLINE(GLuint) crGlslProgGetNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget) +{ + switch (enmTexTarget) + { + case GL_TEXTURE_2D: + return pCache->uNoAlpha2DProg; + case GL_TEXTURE_RECTANGLE_ARB: + return pCache->uNoAlpha2DRectProg; + default: + crWarning("invalid tex enmTexTarget %#x", enmTexTarget); + return 0; + } +} + +DECLINLINE(GLuint*) crGlslProgGetNoAlphaPtr(CR_GLSL_CACHE *pCache, GLenum enmTexTarget) +{ + switch (enmTexTarget) + { + case GL_TEXTURE_2D: + return &pCache->uNoAlpha2DProg; + case GL_TEXTURE_RECTANGLE_ARB: + return &pCache->uNoAlpha2DRectProg; + default: + crWarning("invalid tex enmTexTarget %#x", enmTexTarget); + return NULL; + } +} + +VBOXBLITTERDECL(int) CrGlslProgGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget) +{ + GLuint*puiProgram = crGlslProgGetNoAlphaPtr(pCache, enmTexTarget); + if (!puiProgram) + return VERR_INVALID_PARAMETER; + + if (*puiProgram) + return VINF_SUCCESS; + + return crGlslProgGenNoAlpha(pCache, enmTexTarget, puiProgram); +} + +VBOXBLITTERDECL(int) CrGlslProgGenAllNoAlpha(CR_GLSL_CACHE *pCache) +{ + int rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_2D); + if (!RT_SUCCESS(rc)) + { + crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_2D failed rc %d", rc); + return rc; + } + + rc = CrGlslProgGenNoAlpha(pCache, GL_TEXTURE_RECTANGLE_ARB); + if (!RT_SUCCESS(rc)) + { + crWarning("CrGlslProgGenNoAlpha GL_TEXTURE_RECTANGLE failed rc %d", rc); + return rc; + } + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(void) CrGlslProgClear(const CR_GLSL_CACHE *pCache) +{ + pCache->pDispatch->UseProgram(0); +} + +VBOXBLITTERDECL(int) CrGlslProgUseNoAlpha(const CR_GLSL_CACHE *pCache, GLenum enmTexTarget) +{ + GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget); + if (!uiProg) + { + crWarning("request to use inexistent program!"); + return VERR_INVALID_STATE; + } + + Assert(uiProg); + + pCache->pDispatch->UseProgram(uiProg); + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrGlslProgUseGenNoAlpha(CR_GLSL_CACHE *pCache, GLenum enmTexTarget) +{ + GLuint uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget); + if (!uiProg) + { + int rc = CrGlslProgGenNoAlpha(pCache, enmTexTarget); + if (!RT_SUCCESS(rc)) + { + crWarning("CrGlslProgGenNoAlpha failed, rc %d", rc); + return rc; + } + + uiProg = crGlslProgGetNoAlpha(pCache, enmTexTarget); + CRASSERT(uiProg); + } + + Assert(uiProg); + + pCache->pDispatch->UseProgram(uiProg); + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(bool) CrGlslNeedsCleanup(const CR_GLSL_CACHE *pCache) +{ + return pCache->uNoAlpha2DProg || pCache->uNoAlpha2DRectProg; +} + +VBOXBLITTERDECL(void) CrGlslCleanup(CR_GLSL_CACHE *pCache) +{ + if (pCache->uNoAlpha2DProg) + { + pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DProg); + pCache->uNoAlpha2DProg = 0; + } + + if (pCache->uNoAlpha2DRectProg) + { + pCache->pDispatch->DeleteProgram(pCache->uNoAlpha2DRectProg); + pCache->uNoAlpha2DRectProg = 0; + } +} + +VBOXBLITTERDECL(void) CrGlslTerm(CR_GLSL_CACHE *pCache) +{ + CRASSERT(!CrGlslNeedsCleanup(pCache)); + + CrGlslCleanup(pCache); + + /* sanity */ + memset(pCache, 0, sizeof (*pCache)); +} + + +/*TdBlt*/ +static void crTdBltCheckPBO(PCR_TEXDATA pTex) +{ + if (pTex->idPBO) + return; + + PCR_BLITTER pBlitter = pTex->pBlitter; + + if (!pBlitter->Flags.SupportsPBO) + return; + + pBlitter->pDispatch->GenBuffersARB(1, &pTex->idPBO); + if (!pTex->idPBO) + { + crWarning("PBO create failed"); + return; + } + + pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO); + pBlitter->pDispatch->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, + pTex->Tex.width*pTex->Tex.height*4, + 0, GL_STREAM_READ_ARB); + pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); +} + +static uint32_t crTdBltTexCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget) +{ + uint32_t tex = 0; + pBlitter->pDispatch->GenTextures(1, &tex); + if (!tex) + { + crWarning("Tex create failed"); + return 0; + } + + pBlitter->pDispatch->BindTexture(enmTarget, tex); + pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_S, GL_CLAMP); + pBlitter->pDispatch->TexParameteri(enmTarget, GL_TEXTURE_WRAP_T, GL_CLAMP); + pBlitter->pDispatch->TexImage2D(enmTarget, 0, GL_RGBA8, + width, height, + 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + + + /*Restore gl state*/ + pBlitter->pDispatch->BindTexture(enmTarget, 0); + + return tex; +} + +int crTdBltCheckInvertTex(PCR_TEXDATA pTex) +{ + if (pTex->idInvertTex) + return VINF_SUCCESS; + + pTex->idInvertTex = crTdBltTexCreate(pTex->pBlitter, pTex->Tex.width, pTex->Tex.height, pTex->Tex.target); + if (!pTex->idInvertTex) + { + crWarning("Invert Tex create failed"); + return VERR_GENERAL_FAILURE; + } + return VINF_SUCCESS; +} + +void crTdBltImgRelease(PCR_TEXDATA pTex) +{ + pTex->Flags.DataValid = 0; +} + +void crTdBltImgFree(PCR_TEXDATA pTex) +{ + if (!pTex->Img.pvData) + { + Assert(!pTex->Flags.DataValid); + return; + } + + crTdBltImgRelease(pTex); + + Assert(!pTex->Flags.DataValid); + + + if (pTex->idPBO) + { + PCR_BLITTER pBlitter = pTex->pBlitter; + + Assert(CrBltIsEntered(pBlitter)); + pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO); + pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } + else + { + Assert(pTex->Img.pvData); + RTMemFree(pTex->Img.pvData); + } + + pTex->Img.pvData = NULL; +} + +int crTdBltImgAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted) +{ + void *pvData = pTex->Img.pvData; + Assert(!pTex->Flags.DataValid); + int rc = crBltImgInitBaseForTex(&pTex->Tex, &pTex->Img, enmFormat); + if (!RT_SUCCESS(rc)) + { + WARN(("crBltImgInitBaseForTex failed rc %d", rc)); + return rc; + } + + PCR_BLITTER pBlitter = pTex->pBlitter; + Assert(CrBltIsEntered(pBlitter)); + pBlitter->pDispatch->BindTexture(pTex->Tex.target, fInverted ? pTex->idInvertTex : pTex->Tex.hwid); + + pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pTex->idPBO); + + if (pvData) + { + if (pTex->idPBO) + { + pBlitter->pDispatch->UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + pvData = NULL; + + } + } + else + { + if (!pTex->idPBO) + { + pvData = RTMemAlloc(4*pTex->Tex.width*pTex->Tex.height); + if (!pvData) + { + WARN(("Out of memory in crTdBltImgAcquire")); + pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0); + return VERR_NO_MEMORY; + } + } + } + + Assert(!pvData == !!pTex->idPBO); + + /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ + pBlitter->pDispatch->GetTexImage(GL_TEXTURE_2D, 0, enmFormat, GL_UNSIGNED_BYTE, pvData); + + /*restore gl state*/ + pBlitter->pDispatch->BindTexture(pTex->Tex.target, 0); + + if (pTex->idPBO) + { + pvData = pBlitter->pDispatch->MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + if (!pvData) + { + WARN(("Failed to MapBuffer in CrHlpGetTexImage")); + return VERR_GENERAL_FAILURE; + } + + pBlitter->pDispatch->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } + + Assert(pvData); + pTex->Img.pvData = pvData; + pTex->Flags.DataValid = 1; + pTex->Flags.DataInverted = fInverted; + return VINF_SUCCESS; +} + +/* release the texture data, the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataInvalidateNe or CrTdBltDataCleanup */ +VBOXBLITTERDECL(int) CrTdBltDataRelease(PCR_TEXDATA pTex) +{ + if (!pTex->Flags.Entered) + { + WARN(("tex not entered")); + return VERR_INVALID_STATE; + } + + if (!pTex->Flags.DataAcquired) + { + WARN(("Data NOT acquired")); + return VERR_INVALID_STATE; + } + + Assert(pTex->Img.pvData); + Assert(pTex->Flags.DataValid); + + pTex->Flags.DataAcquired = 0; + + return VINF_SUCCESS; +} + +static void crTdBltDataFree(PCR_TEXDATA pTex) +{ + crTdBltImgFree(pTex); + + if (pTex->pScaledCache) + CrTdBltDataFreeNe(pTex->pScaledCache); +} + +/* discard the texture data cached with previous CrTdBltDataAcquire. + * Must be called wit data released (CrTdBltDataRelease) */ +VBOXBLITTERDECL(int) CrTdBltDataFree(PCR_TEXDATA pTex) +{ + if (!pTex->Flags.Entered) + { + WARN(("tex not entered")); + return VERR_INVALID_STATE; + } + + crTdBltDataFree(pTex); + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(void) CrTdBltDataInvalidateNe(PCR_TEXDATA pTex) +{ + crTdBltImgRelease(pTex); + + if (pTex->pScaledCache) + CrTdBltDataInvalidateNe(pTex->pScaledCache); +} + +VBOXBLITTERDECL(int) CrTdBltDataFreeNe(PCR_TEXDATA pTex) +{ + if (!pTex->Img.pvData) + return VINF_SUCCESS; + + bool fEntered = false; + if (pTex->idPBO) + { + int rc = CrTdBltEnter(pTex); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + fEntered = true; + } + + crTdBltDataFree(pTex); + + if (fEntered) + CrTdBltLeave(pTex); + + return VINF_SUCCESS; +} + +static void crTdBltSdCleanupCacheNe(PCR_TEXDATA pTex) +{ + if (pTex->pScaledCache) + { + CrTdBltDataCleanupNe(pTex->pScaledCache); + CrTdRelease(pTex->pScaledCache); + pTex->pScaledCache = NULL; + } +} + +static void crTdBltDataCleanup(PCR_TEXDATA pTex) +{ + crTdBltImgFree(pTex); + + PCR_BLITTER pBlitter = pTex->pBlitter; + + if (pTex->idPBO) + { + Assert(CrBltIsEntered(pBlitter)); + pBlitter->pDispatch->DeleteBuffersARB(1, &pTex->idPBO); + pTex->idPBO = 0; + } + + if (pTex->idInvertTex) + { + Assert(CrBltIsEntered(pBlitter)); + pBlitter->pDispatch->DeleteTextures(1, &pTex->idInvertTex); + pTex->idInvertTex = 0; + } + + crTdBltSdCleanupCacheNe(pTex); +} + +/* does same as CrTdBltDataFree, and in addition cleans up */ +VBOXBLITTERDECL(int) CrTdBltDataCleanup(PCR_TEXDATA pTex) +{ + if (!pTex->Flags.Entered) + { + WARN(("tex not entered")); + return VERR_INVALID_STATE; + } + + crTdBltDataCleanup(pTex); + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrTdBltDataCleanupNe(PCR_TEXDATA pTex) +{ + bool fEntered = false; + if (pTex->idPBO || pTex->idInvertTex) + { + int rc = CrTdBltEnter(pTex); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + fEntered = true; + } + + crTdBltDataCleanup(pTex); + + if (fEntered) + CrTdBltLeave(pTex); + + return VINF_SUCCESS; +} + +/* acquire the texture data, returns the cached data in case it is cached. + * the data remains cached in the CR_TEXDATA object until it is discarded with CrTdBltDataFree or CrTdBltDataCleanup. + * */ +VBOXBLITTERDECL(int) CrTdBltDataAcquire(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, const CR_BLITTER_IMG**ppImg) +{ + if (!pTex->Flags.Entered) + { + WARN(("tex not entered")); + return VERR_INVALID_STATE; + } + + if (pTex->Flags.DataAcquired) + { + WARN(("Data acquired already")); + return VERR_INVALID_STATE; + } + + if (pTex->Flags.DataValid && pTex->Img.enmFormat == enmFormat && !pTex->Flags.DataInverted == !fInverted) + { + Assert(pTex->Img.pvData); + *ppImg = &pTex->Img; + pTex->Flags.DataAcquired = 1; + return VINF_SUCCESS; + } + + crTdBltImgRelease(pTex); + + crTdBltCheckPBO(pTex); + + int rc; + + if (fInverted) + { + rc = crTdBltCheckInvertTex(pTex); + if (!RT_SUCCESS(rc)) + { + WARN(("crTdBltCheckInvertTex failed rc %d", rc)); + return rc; + } + + RTRECT SrcRect, DstRect; + VBOXVR_TEXTURE InvertTex; + + InvertTex = pTex->Tex; + InvertTex.hwid = pTex->idInvertTex; + + SrcRect.xLeft = 0; + SrcRect.yTop = InvertTex.height; + SrcRect.xRight = InvertTex.width; + SrcRect.yBottom = 0; + + DstRect.xLeft = 0; + DstRect.yTop = 0; + DstRect.xRight = InvertTex.width; + DstRect.yBottom = InvertTex.height; + + CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &InvertTex, &DstRect, 1, 0); + } + + rc = crTdBltImgAcquire(pTex, enmFormat, fInverted); + if (!RT_SUCCESS(rc)) + { + WARN(("crTdBltImgAcquire failed rc %d", rc)); + return rc; + } + + Assert(pTex->Img.pvData); + *ppImg = &pTex->Img; + pTex->Flags.DataAcquired = 1; + + return VINF_SUCCESS; +} + +DECLINLINE(void) crTdResize(PCR_TEXDATA pTex, const VBOXVR_TEXTURE *pVrTex) +{ + crTdBltDataCleanup(pTex); + + pTex->Tex = *pVrTex; +} + +static DECLCALLBACK(void) ctTdBltSdReleased(struct CR_TEXDATA *pTexture) +{ + PCR_BLITTER pBlitter = pTexture->pBlitter; + + int rc = CrBltEnter(pBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed, rc %d", rc)); + return; + } + + CrTdBltDataCleanupNe(pTexture); + + pBlitter->pDispatch->DeleteTextures(1, &pTexture->Tex.hwid); + + CrBltLeave(pBlitter); + + RTMemFree(pTexture); +} + +static int ctTdBltSdCreate(PCR_BLITTER pBlitter, uint32_t width, uint32_t height, GLenum enmTarget, PCR_TEXDATA *ppScaledCache) +{ + PCR_TEXDATA pScaledCache; + + Assert(CrBltIsEntered(pBlitter)); + + *ppScaledCache = NULL; + + pScaledCache = (PCR_TEXDATA)RTMemAlloc(sizeof (*pScaledCache)); + if (!pScaledCache) + { + WARN(("RTMemAlloc failed")); + return VERR_NO_MEMORY; + } + + VBOXVR_TEXTURE Tex; + Tex.width = width; + Tex.height = height; + Tex.target = enmTarget; + Tex.hwid = crTdBltTexCreate(pBlitter, width, height, enmTarget); + if (!Tex.hwid) + { + WARN(("Tex create failed")); + RTMemFree(pScaledCache); + return VERR_GENERAL_FAILURE; + } + + CrTdInit(pScaledCache, &Tex, pBlitter, ctTdBltSdReleased); + + *ppScaledCache = pScaledCache; + + return VINF_SUCCESS; +} + +static int ctTdBltSdGet(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppScaledCache) +{ + Assert(CrBltIsEntered(pTex->pBlitter)); + + PCR_TEXDATA pScaledCache; + + *ppScaledCache = NULL; + + if (!pTex->pScaledCache) + { + int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("ctTdBltSdCreate failed %d", rc)); + return rc; + } + + pTex->pScaledCache = pScaledCache; + } + else + { + int cmp = pTex->pScaledCache->Tex.width - width; + if (cmp <= 0) + cmp = pTex->pScaledCache->Tex.height - height; + + if (!cmp) + pScaledCache = pTex->pScaledCache; + else if (cmp < 0) /* current cache is "less" than the requested */ + { + int rc = ctTdBltSdCreate(pTex->pBlitter, width, height, pTex->Tex.target, &pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("ctTdBltSdCreate failed %d", rc)); + return rc; + } + + pScaledCache->pScaledCache = pTex->pScaledCache; + pTex->pScaledCache = pScaledCache; + } + else /* cmp > 0 */ + { + int rc = ctTdBltSdGet(pTex->pScaledCache, width, height, &pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("ctTdBltSdGet failed %d", rc)); + return rc; + } + } + } + + Assert(pScaledCache); + +#if 0 + { + VBOXVR_TEXTURE Tex; + Tex.width = width; + Tex.height = height; + Tex.target = pTex->Tex.target; + Tex.hwid = crTdBltTexCreate(pTex, width, height); + if (!Tex.hwid) + { + WARN(("Tex create failed")); + return VERR_GENERAL_FAILURE; + } + + pTex->pBlitter->pDispatch->DeleteTextures(1, &pTex->pScaledCache->Tex.hwid); + + crTdResize(pTex->pScaledCache, &Tex); + } +#endif + + *ppScaledCache = pScaledCache; + return VINF_SUCCESS; +} + +static int ctTdBltSdGetUpdated(PCR_TEXDATA pTex, uint32_t width, uint32_t height, PCR_TEXDATA *ppScaledCache) +{ + PCR_TEXDATA pScaledCache; + + *ppScaledCache = NULL; + int rc = ctTdBltSdGet(pTex, width, height, &pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("ctTdBltSdGet failed %d", rc)); + return rc; + } + + Assert(width == pScaledCache->Tex.width); + Assert(height == pScaledCache->Tex.height); + + if (!pScaledCache->Flags.DataValid) + { + RTRECT SrcRect, DstRect; + + SrcRect.xLeft = 0; + SrcRect.yTop = 0; + SrcRect.xRight = pTex->Tex.width; + SrcRect.yBottom = pTex->Tex.height; + + DstRect.xLeft = 0; + DstRect.yTop = 0; + DstRect.xRight = width; + DstRect.yBottom = height; + + CrBltBlitTexTex(pTex->pBlitter, &pTex->Tex, &SrcRect, &pScaledCache->Tex, &DstRect, 1, 0); + } + + *ppScaledCache = pScaledCache; + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrTdBltDataAcquireScaled(PCR_TEXDATA pTex, GLenum enmFormat, bool fInverted, uint32_t width, uint32_t height, const CR_BLITTER_IMG**ppImg) +{ + if (pTex->Tex.width == width && pTex->Tex.height == height) + return CrTdBltDataAcquire(pTex, enmFormat, fInverted, ppImg); + + if (!pTex->Flags.Entered) + { + WARN(("tex not entered")); + return VERR_INVALID_STATE; + } + + PCR_TEXDATA pScaledCache; + + int rc = ctTdBltSdGetUpdated(pTex, width, height, &pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("ctTdBltSdGetUpdated failed rc %d", rc)); + return rc; + } + + rc = CrTdBltEnter(pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltEnter failed rc %d", rc)); + return rc; + } + + rc = CrTdBltDataAcquire(pScaledCache, enmFormat, fInverted, ppImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + CrTdBltLeave(pTex->pScaledCache); + return rc; + } + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(int) CrTdBltDataReleaseScaled(PCR_TEXDATA pTex, const CR_BLITTER_IMG *pImg) +{ + PCR_TEXDATA pScaledCache = RT_FROM_MEMBER(pImg, CR_TEXDATA, Img); + int rc = CrTdBltDataRelease(pScaledCache); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataRelease failed rc %d", rc)); + return rc; + } + + if (pScaledCache != pTex) + CrTdBltLeave(pScaledCache); + + return VINF_SUCCESS; +} + +VBOXBLITTERDECL(void) CrTdBltScaleCacheMoveTo(PCR_TEXDATA pTex, PCR_TEXDATA pDstTex) +{ + if (!pTex->pScaledCache) + return; + + crTdBltSdCleanupCacheNe(pDstTex); + + pDstTex->pScaledCache = pTex->pScaledCache; + pTex->pScaledCache = NULL; +} diff --git a/src/VBox/GuestHost/OpenGL/util/bmpscale.cpp b/src/VBox/GuestHost/OpenGL/util/bmpscale.cpp new file mode 100644 index 00000000..1b32487b --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/bmpscale.cpp @@ -0,0 +1,319 @@ +/** @file + * Image resampling code, used for snapshot thumbnails. + */ + +/* + * Copyright (C) 2009-2011 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. + */ + +/* + * Based on gdImageCopyResampled from libgd. + * Original copyright notice follows: + + Portions copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Pierre-Alain Joye (pierre@libgd.org). + + Permission has been granted to copy, distribute and modify gd in + any context without fee, including a commercial application, + provided that this notice is present in user-accessible supporting + documentation. + + This does not affect your ownership of the derived work itself, and + the intent is to assure proper credit for the authors of gd, not to + interfere with your productive use of gd. If you have questions, + ask. "Derived works" includes all programs that utilize the + library. Credit must be given in user-accessible documentation. + + This software is provided "AS IS." The copyright holders disclaim + all warranties, either express or implied, including but not + limited to implied warranties of merchantability and fitness for a + particular purpose, with respect to this code and accompanying + documentation. + */ + +/* + * + * @todo Simplify: Offsets of images are 0,0 => no dstX, dstY, srcX, srcY; + * Screenshot has no alpha channel => no processing of alpha byte. + */ + +#include <cr_bmpscale.h> + +/* 2.0.10: cast instead of floor() yields 35% performance improvement. + Thanks to John Buckman. */ + +#define floor2(exp) ((long) exp) +/*#define floor2(exp) floor(exp)*/ + +typedef uint8_t *gdImagePtr; + +DECLINLINE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y, int w) +{ + return *(int32_t *)(im + y * w * 4 + x * 4); +} + +DECLINLINE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color, int cbLine) +{ + *(int32_t *)(im + y * cbLine + x * 4) = color; +} + +#define gdAlphaMax 127 +#define gdAlphaOpaque 0 +#define gdAlphaTransparent 127 +#define gdRedMax 255 +#define gdGreenMax 255 +#define gdBlueMax 255 +#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24) +#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16) +#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8) +#define gdTrueColorGetBlue(c) ((c) & 0x0000FF) +#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \ + ((r) << 16) + \ + ((g) << 8) + \ + (b)) + +void gdImageCopyResampled (uint8_t *dst, + uint8_t *src, + int dstX, int dstY, + int srcX, int srcY, + int dstW, int dstH, int srcW, int srcH) +{ + int x, y; + double sy1, sy2, sx1, sx2; + for (y = dstY; (y < dstY + dstH); y++) + { + sy1 = ((double) y - (double) dstY) * (double) srcH / (double) dstH; + sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / + (double) dstH; + for (x = dstX; (x < dstX + dstW); x++) + { + double sx, sy; + double spixels = 0; + double red = 0.0, green = 0.0, blue = 0.0, alpha = 0.0; + sx1 = ((double) x - (double) dstX) * (double) srcW / dstW; + sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / dstW; + sy = sy1; + do + { + double yportion; + if (floor2 (sy) == floor2 (sy1)) + { + yportion = 1.0 - (sy - floor2 (sy)); + if (yportion > sy2 - sy1) + { + yportion = sy2 - sy1; + } + sy = floor2 (sy); + } + else if (sy == floor2 (sy2)) + { + yportion = sy2 - floor2 (sy2); + } + else + { + yportion = 1.0; + } + sx = sx1; + do + { + double xportion; + double pcontribution; + int p; + if (floor2 (sx) == floor2 (sx1)) + { + xportion = 1.0 - (sx - floor2 (sx)); + if (xportion > sx2 - sx1) + { + xportion = sx2 - sx1; + } + sx = floor2 (sx); + } + else if (sx == floor2 (sx2)) + { + xportion = sx2 - floor2 (sx2); + } + else + { + xportion = 1.0; + } + pcontribution = xportion * yportion; + /* 2.08: previously srcX and srcY were ignored. + Andrew Pattison */ + p = gdImageGetTrueColorPixel (src, + (int) sx + srcX, + (int) sy + srcY, srcW); + red += gdTrueColorGetRed (p) * pcontribution; + green += gdTrueColorGetGreen (p) * pcontribution; + blue += gdTrueColorGetBlue (p) * pcontribution; + alpha += gdTrueColorGetAlpha (p) * pcontribution; + spixels += xportion * yportion; + sx += 1.0; + } + while (sx < sx2); + sy += 1.0; + } + while (sy < sy2); + if (spixels != 0.0) + { + red /= spixels; + green /= spixels; + blue /= spixels; + alpha /= spixels; + } + /* Clamping to allow for rounding errors above */ + if (red > 255.0) + { + red = 255.0; + } + if (green > 255.0) + { + green = 255.0; + } + if (blue > 255.0) + { + blue = 255.0; + } + if (alpha > gdAlphaMax) + { + alpha = gdAlphaMax; + } + gdImageSetPixel (dst, + x, y, + gdTrueColorAlpha ((int) red, + (int) green, + (int) blue, (int) alpha), dstW * 4); + } + } +} + +/* Fast integer implementation for 32 bpp bitmap scaling. + * Use fixed point values * 16. + */ +typedef int32_t FIXEDPOINT; +#define INT_TO_FIXEDPOINT(i) (FIXEDPOINT)((i) << 4) +#define FIXEDPOINT_TO_INT(v) (int)((v) >> 4) +#define FIXEDPOINT_FLOOR(v) ((v) & ~0xF) +#define FIXEDPOINT_FRACTION(v) ((v) & 0xF) + +/* For 32 bit source only. */ +VBOXBMPSCALEDECL(void) CrBmpScale32 (uint8_t *dst, + int iDstDeltaLine, + int dstW, int dstH, + const uint8_t *src, + int iSrcDeltaLine, + int srcW, int srcH) +{ + int x, y; + + for (y = 0; y < dstH; y++) + { + FIXEDPOINT sy1 = INT_TO_FIXEDPOINT(y * srcH) / dstH; + FIXEDPOINT sy2 = INT_TO_FIXEDPOINT((y + 1) * srcH) / dstH; + + for (x = 0; x < dstW; x++) + { + FIXEDPOINT red = 0, green = 0, blue = 0; + + FIXEDPOINT sx1 = INT_TO_FIXEDPOINT(x * srcW) / dstW; + FIXEDPOINT sx2 = INT_TO_FIXEDPOINT((x + 1) * srcW) / dstW; + + FIXEDPOINT spixels = (sx2 - sx1) * (sy2 - sy1); + + FIXEDPOINT sy = sy1; + + do + { + FIXEDPOINT yportion; + if (FIXEDPOINT_FLOOR (sy) == FIXEDPOINT_FLOOR (sy1)) + { + yportion = INT_TO_FIXEDPOINT(1) - FIXEDPOINT_FRACTION(sy); + if (yportion > sy2 - sy1) + { + yportion = sy2 - sy1; + } + sy = FIXEDPOINT_FLOOR (sy); + } + else if (sy == FIXEDPOINT_FLOOR (sy2)) + { + yportion = FIXEDPOINT_FRACTION(sy2); + } + else + { + yportion = INT_TO_FIXEDPOINT(1); + } + + const uint8_t *pu8SrcLine = src + iSrcDeltaLine * FIXEDPOINT_TO_INT(sy); + FIXEDPOINT sx = sx1; + do + { + FIXEDPOINT xportion; + FIXEDPOINT pcontribution; + int p; + if (FIXEDPOINT_FLOOR (sx) == FIXEDPOINT_FLOOR (sx1)) + { + xportion = INT_TO_FIXEDPOINT(1) - FIXEDPOINT_FRACTION(sx); + if (xportion > sx2 - sx1) + { + xportion = sx2 - sx1; + } + pcontribution = xportion * yportion; + sx = FIXEDPOINT_FLOOR (sx); + } + else if (sx == FIXEDPOINT_FLOOR (sx2)) + { + xportion = FIXEDPOINT_FRACTION(sx2); + pcontribution = xportion * yportion; + } + else + { + xportion = INT_TO_FIXEDPOINT(1); + pcontribution = xportion * yportion; + } + /* Color depth specific code begin */ + p = *(uint32_t *)(pu8SrcLine + FIXEDPOINT_TO_INT(sx) * 4); + /* Color depth specific code end */ + red += gdTrueColorGetRed (p) * pcontribution; + green += gdTrueColorGetGreen (p) * pcontribution; + blue += gdTrueColorGetBlue (p) * pcontribution; + + sx += INT_TO_FIXEDPOINT(1); + } while (sx < sx2); + + sy += INT_TO_FIXEDPOINT(1); + } while (sy < sy2); + + if (spixels != 0) + { + red /= spixels; + green /= spixels; + blue /= spixels; + } + /* Clamping to allow for rounding errors above */ + if (red > 255) + { + red = 255; + } + if (green > 255) + { + green = 255; + } + if (blue > 255) + { + blue = 255; + } + gdImageSetPixel (dst, + x, y, + ( ((int) red) << 16) + (((int) green) << 8) + ((int) blue), + iDstDeltaLine); + } + } +} + diff --git a/src/VBox/GuestHost/OpenGL/util/compositor.cpp b/src/VBox/GuestHost/OpenGL/util/compositor.cpp new file mode 100644 index 00000000..f7c50bcd --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/compositor.cpp @@ -0,0 +1,1015 @@ +/* $Id: compositor.cpp $ */ + +/** @file + * Compositor impl + */ + +/* + * Copyright (C) 2013 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_compositor.h> + +#define VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED UINT32_MAX + + +static int crVrScrCompositorRectsAssignBuffer(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRects) +{ + Assert(cRects); + + if (pCompositor->cRectsBuffer >= cRects) + { + pCompositor->cRects = cRects; + return VINF_SUCCESS; + } + + if (pCompositor->cRectsBuffer) + { + Assert(pCompositor->paSrcRects); + RTMemFree(pCompositor->paSrcRects); + pCompositor->paSrcRects = NULL; + Assert(pCompositor->paDstRects); + RTMemFree(pCompositor->paDstRects); + pCompositor->paDstRects = NULL; + Assert(pCompositor->paDstUnstretchedRects); + RTMemFree(pCompositor->paDstUnstretchedRects); + pCompositor->paDstUnstretchedRects = NULL; + } + else + { + Assert(!pCompositor->paSrcRects); + Assert(!pCompositor->paDstRects); + Assert(!pCompositor->paDstUnstretchedRects); + } + + pCompositor->paSrcRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paSrcRects) * cRects); + if (pCompositor->paSrcRects) + { + pCompositor->paDstRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstRects) * cRects); + if (pCompositor->paDstRects) + { + pCompositor->paDstUnstretchedRects = (PRTRECT)RTMemAlloc(sizeof (*pCompositor->paDstUnstretchedRects) * cRects); + if (pCompositor->paDstUnstretchedRects) + { + pCompositor->cRects = cRects; + pCompositor->cRectsBuffer = cRects; + return VINF_SUCCESS; + } + + RTMemFree(pCompositor->paDstRects); + pCompositor->paDstRects = NULL; + } + else + { + WARN(("RTMemAlloc failed!")); + } + RTMemFree(pCompositor->paSrcRects); + pCompositor->paSrcRects = NULL; + } + else + { + WARN(("RTMemAlloc failed!")); + } + + pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED; + pCompositor->cRectsBuffer = 0; + + return VERR_NO_MEMORY; +} + +static void crVrScrCompositorRectsInvalidate(PVBOXVR_SCR_COMPOSITOR pCompositor) +{ + pCompositor->cRects = VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED; +} + +static DECLCALLBACK(bool) crVrScrCompositorRectsCounterCb(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, void *pvVisitor) +{ + uint32_t* pCounter = (uint32_t*)pvVisitor; + Assert(VBoxVrListRectsCount(&pEntry->Vr)); + *pCounter += VBoxVrListRectsCount(&pEntry->Vr); + return true; +} + +typedef struct VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER +{ + PRTRECT paSrcRects; + PRTRECT paDstRects; + PRTRECT paDstUnstretchedRects; + uint32_t cRects; +} VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER, *PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER; + +static DECLCALLBACK(bool) crVrScrCompositorRectsAssignerCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor) +{ + PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER pData = (PVBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER)pvVisitor; + PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry); + pEntry->paSrcRects = pData->paSrcRects; + pEntry->paDstRects = pData->paDstRects; + pEntry->paDstUnstretchedRects = pData->paDstUnstretchedRects; + uint32_t cRects = VBoxVrListRectsCount(&pCEntry->Vr); + Assert(cRects); + Assert(cRects <= pData->cRects); + int rc = VBoxVrListRectsGet(&pCEntry->Vr, cRects, pEntry->paDstUnstretchedRects); + AssertRC(rc); + + if (!pEntry->Rect.xLeft && !pEntry->Rect.yTop) + { + memcpy(pEntry->paSrcRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paSrcRects)); + } + else + { + for (uint32_t i = 0; i < cRects; ++i) + { + pEntry->paSrcRects[i].xLeft = (int32_t)((pEntry->paDstUnstretchedRects[i].xLeft - pEntry->Rect.xLeft)); + pEntry->paSrcRects[i].yTop = (int32_t)((pEntry->paDstUnstretchedRects[i].yTop - pEntry->Rect.yTop)); + pEntry->paSrcRects[i].xRight = (int32_t)((pEntry->paDstUnstretchedRects[i].xRight - pEntry->Rect.xLeft)); + pEntry->paSrcRects[i].yBottom = (int32_t)((pEntry->paDstUnstretchedRects[i].yBottom - pEntry->Rect.yTop)); + } + } + +#ifndef IN_RING0 + if (pCompositor->StretchX != 1. || pCompositor->StretchY != 1.) + { + for (uint32_t i = 0; i < cRects; ++i) + { + if (pCompositor->StretchX != 1.) + { + pEntry->paDstRects[i].xLeft = (int32_t)(pEntry->paDstUnstretchedRects[i].xLeft * pCompositor->StretchX); + pEntry->paDstRects[i].xRight = (int32_t)(pEntry->paDstUnstretchedRects[i].xRight * pCompositor->StretchX); + } + if (pCompositor->StretchY != 1.) + { + pEntry->paDstRects[i].yTop = (int32_t)(pEntry->paDstUnstretchedRects[i].yTop * pCompositor->StretchY); + pEntry->paDstRects[i].yBottom = (int32_t)(pEntry->paDstUnstretchedRects[i].yBottom * pCompositor->StretchY); + } + } + } + else +#endif + { + memcpy(pEntry->paDstRects, pEntry->paDstUnstretchedRects, cRects * sizeof (*pEntry->paDstUnstretchedRects)); + } + +#if 0//ndef IN_RING0 + bool canZeroX = (pCompositor->StretchX < 1.); + bool canZeroY = (pCompositor->StretchY < 1.); + if (canZeroX && canZeroY) + { + /* filter out zero rectangles*/ + uint32_t iOrig, iNew; + for (iOrig = 0, iNew = 0; iOrig < cRects; ++iOrig) + { + PRTRECT pOrigRect = &pEntry->paDstRects[iOrig]; + if (pOrigRect->xLeft != pOrigRect->xRight + && pOrigRect->yTop != pOrigRect->yBottom) + continue; + + if (iNew != iOrig) + { + PRTRECT pNewRect = &pEntry->paSrcRects[iNew]; + *pNewRect = *pOrigRect; + } + + ++iNew; + } + + Assert(iNew <= iOrig); + + uint32_t cDiff = iOrig - iNew; + + if (cDiff) + { + pCompositor->cRects -= cDiff; + cRects -= cDiff; + } + } +#endif + + pEntry->cRects = cRects; + pData->paDstRects += cRects; + pData->paSrcRects += cRects; + pData->paDstUnstretchedRects += cRects; + pData->cRects -= cRects; + return true; +} + +static int crVrScrCompositorRectsCheckInit(const VBOXVR_SCR_COMPOSITOR *pcCompositor) +{ + VBOXVR_SCR_COMPOSITOR *pCompositor = const_cast<VBOXVR_SCR_COMPOSITOR*>(pcCompositor); + + if (pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED) + return VINF_SUCCESS; + + uint32_t cRects = 0; + VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsCounterCb, &cRects); + + if (!cRects) + { + pCompositor->cRects = 0; + return VINF_SUCCESS; + } + + int rc = crVrScrCompositorRectsAssignBuffer(pCompositor, cRects); + if (!RT_SUCCESS(rc)) + return rc; + + VBOXVR_SCR_COMPOSITOR_RECTS_ASSIGNER AssignerData; + AssignerData.paSrcRects = pCompositor->paSrcRects; + AssignerData.paDstRects = pCompositor->paDstRects; + AssignerData.paDstUnstretchedRects = pCompositor->paDstUnstretchedRects; + AssignerData.cRects = pCompositor->cRects; + VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorRectsAssignerCb, &AssignerData); + Assert(!AssignerData.cRects); + return VINF_SUCCESS; +} + + +static int crVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangedFlags) +{ + uint32_t fChangedFlags = 0; + PVBOXVR_COMPOSITOR_ENTRY pReplacedEntry; + int rc = VBoxVrCompositorEntryRegionsAdd(&pCompositor->Compositor, pEntry ? &pEntry->Ce : NULL, cRegions, paRegions, &pReplacedEntry, &fChangedFlags); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc)); + return rc; + } + + VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacedEntry); + + if (fChangedFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED) + { + crVrScrCompositorRectsInvalidate(pCompositor); + } + else if (fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + { + Assert(pReplacedScrEntry); + } + + if (fChangedFlags & VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED) + { + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); + } + else if ((fChangedFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED) && pEntry) + { + CrVrScrCompositorEntrySetChanged(pEntry, true); + } + + if (pfChangedFlags) + *pfChangedFlags = fChangedFlags; + + if (ppReplacedScrEntry) + *ppReplacedScrEntry = pReplacedScrEntry; + + return VINF_SUCCESS; +} + +static int crVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + bool fChanged; + int rc = VBoxVrCompositorEntryRegionsSet(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrCompositorEntryRegionsSet failed, rc %d", rc)); + return rc; + } + + if (fChanged) + { + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); + if (!CrVrScrCompositorEntryIsInList(pEntry)) + { + pEntry->cRects = 0; + pEntry->paSrcRects = NULL; + pEntry->paDstRects = NULL; + pEntry->paDstUnstretchedRects = NULL; + } + crVrScrCompositorRectsInvalidate(pCompositor); + } + + + if (pfChanged) + *pfChanged = fChanged; + return VINF_SUCCESS; +} + +static int crVrScrCompositorEntryPositionSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, bool *pfChanged) +{ + if (pfChanged) + *pfChanged = false; + if (pEntry && (pEntry->Rect.xLeft != pPos->x || pEntry->Rect.yTop != pPos->y)) + { + if (VBoxVrCompositorEntryIsInList(&pEntry->Ce)) + { + int rc = VBoxVrCompositorEntryRegionsTranslate(&pCompositor->Compositor, &pEntry->Ce, pPos->x - pEntry->Rect.xLeft, pPos->y - pEntry->Rect.yTop, pfChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrCompositorEntryRegionsTranslate failed rc %d", rc)); + return rc; + } + + crVrScrCompositorRectsInvalidate(pCompositor); + } + + VBoxRectMove(&pEntry->Rect, pPos->x, pPos->y); + CrVrScrCompositorEntrySetChanged(pEntry, true); + + if (pfChanged) + *pfChanged = true; + } + return VINF_SUCCESS; +} + +static int crVrScrCompositorEntryEnsureRegionsBounds(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, bool *pfChanged) +{ + RTRECT Rect; + Rect.xLeft = RT_MAX(pCompositor->Rect.xLeft, pEntry->Rect.xLeft); + Rect.yTop = RT_MAX(pCompositor->Rect.yTop, pEntry->Rect.yTop); + Rect.xRight = RT_MIN(pCompositor->Rect.xRight, pEntry->Rect.xRight); + Rect.yBottom = RT_MIN(pCompositor->Rect.yBottom, pEntry->Rect.yBottom); + bool fChanged = false; + + if (pfChanged) + *pfChanged = false; + + int rc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, 1, &Rect, &fChanged); + if (!RT_SUCCESS(rc)) + WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", rc)); + + if (pfChanged) + *pfChanged = fChanged; + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsAdd(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, VBOXVR_SCR_COMPOSITOR_ENTRY **ppReplacedScrEntry, uint32_t *pfChangeFlags) +{ + int rc; + uint32_t fChangeFlags = 0; + bool fPosChanged = false; + RTRECT *paTranslatedRects = NULL; + if (pPos) + { + rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsAdd: crVrScrCompositorEntryPositionSet failed rc %d", rc)); + return rc; + } + } + + if (fPosRelated) + { + if (!pEntry) + { + WARN(("Entry is expected to be specified for pos-related regions")); + return VERR_INVALID_PARAMETER; + } + + if (cRegions && (pEntry->Rect.xLeft || pEntry->Rect.yTop)) + { + paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions); + if (!paTranslatedRects) + { + WARN(("RTMemAlloc failed")); + return VERR_NO_MEMORY; + } + memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions); + for (uint32_t i = 0; i < cRegions; ++i) + { + VBoxRectTranslate(&paTranslatedRects[i], pEntry->Rect.xLeft, pEntry->Rect.yTop); + paRegions = paTranslatedRects; + } + } + } + + rc = crVrScrCompositorEntryRegionsAdd(pCompositor, pEntry, cRegions, paRegions, ppReplacedScrEntry, &fChangeFlags); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryRegionsAdd failed, rc %d", rc)); + goto done; + } + + if ((fPosChanged || (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED)) && pEntry) + { + bool fAdjusted = false; + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, &fAdjusted); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + goto done; + } + + if (fAdjusted) + { + if (CrVrScrCompositorEntryIsUsed(pEntry)) + { + fChangeFlags &= ~VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED; + fChangeFlags |= VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED; + } + else + { + fChangeFlags = 0; + } + } + } + + if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + fPosChanged = false; + else if (ppReplacedScrEntry) + *ppReplacedScrEntry = NULL; + + if (pfChangeFlags) + { + if (fPosChanged) + { + /* means entry was in list and was moved, so regions changed */ + *pfChangeFlags = VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED; + } + else + *pfChangeFlags = fChangeFlags; + } + +done: + + if (paTranslatedRects) + RTMemFree(paTranslatedRects); + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTRECT *pRect) +{ + if (!memcmp(&pEntry->Rect, pRect, sizeof (*pRect))) + { + return VINF_SUCCESS; + } + RTPOINT Point = {pRect->xLeft, pRect->yTop}; + bool fChanged = false; + int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, &Point, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryPositionSet failed %d", rc)); + return rc; + } + + pEntry->Rect = *pRect; + + if (!CrVrScrCompositorEntryIsUsed(pEntry)) + return VINF_SUCCESS; + + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryTexAssign(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, CR_TEXDATA *pTex) +{ + if (pEntry->pTex == pTex) + return VINF_SUCCESS; + + if (pEntry->pTex) + CrTdRelease(pEntry->pTex); + if (pTex) + CrTdAddRef(pTex); + pEntry->pTex = pTex; + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated, bool *pfChanged) +{ + /* @todo: the fChanged sate calculation is really rough now, this is enough for now though */ + bool fChanged = false, fPosChanged = false; + bool fWasInList = CrVrScrCompositorEntryIsInList(pEntry); + RTRECT *paTranslatedRects = NULL; + int rc = CrVrScrCompositorEntryRemove(pCompositor, pEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: CrVrScrCompositorEntryRemove failed rc %d", rc)); + return rc; + } + + if (pPos) + { + rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, &fPosChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc)); + return rc; + } + } + + if (fPosRelated) + { + if (!pEntry) + { + WARN(("Entry is expected to be specified for pos-related regions")); + return VERR_INVALID_PARAMETER; + } + + if (cRegions && (pEntry->Rect.xLeft || pEntry->Rect.yTop)) + { + paTranslatedRects = (RTRECT*)RTMemAlloc(sizeof (RTRECT) * cRegions); + if (!paTranslatedRects) + { + WARN(("RTMemAlloc failed")); + return VERR_NO_MEMORY; + } + memcpy (paTranslatedRects, paRegions, sizeof (RTRECT) * cRegions); + for (uint32_t i = 0; i < cRegions; ++i) + { + VBoxRectTranslate(&paTranslatedRects[i], pEntry->Rect.xLeft, pEntry->Rect.yTop); + paRegions = paTranslatedRects; + } + } + } + + rc = crVrScrCompositorEntryRegionsSet(pCompositor, pEntry, cRegions, paRegions, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + return rc; + } + + if (fChanged && CrVrScrCompositorEntryIsUsed(pEntry)) + { + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + return rc; + } + } + + if (pfChanged) + *pfChanged = fPosChanged || fChanged || fWasInList; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + bool fChanged = false; + int rc = VBoxVrCompositorEntryListIntersect(&pCompositor->Compositor, &pEntry->Ce, pList2, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc)); + return rc; + } + + if (fChanged) + { + CrVrScrCompositorEntrySetChanged(pEntry, true); + crVrScrCompositorRectsInvalidate(pCompositor); + } + + if (pfChanged) + *pfChanged = fChanged; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersect(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + bool fChanged = false; + int rc = VBoxVrCompositorEntryRegionsIntersect(&pCompositor->Compositor, &pEntry->Ce, cRegions, paRegions, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsIntersect: VBoxVrCompositorEntryRegionsIntersect failed rc %d", rc)); + return rc; + } + + if (fChanged) + crVrScrCompositorRectsInvalidate(pCompositor); + + if (pfChanged) + *pfChanged = fChanged; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryListIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; + CrVrScrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + { + bool fTmpChanged = false; + int tmpRc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged); + if (RT_SUCCESS(tmpRc)) + { + fChanged |= fTmpChanged; + } + else + { + WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc)); + rc = tmpRc; + } + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsIntersectAll(PVBOXVR_SCR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; + CrVrScrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + { + bool fTmpChanged = false; + int tmpRc = CrVrScrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged); + if (RT_SUCCESS(tmpRc)) + { + fChanged |= fTmpChanged; + } + else + { + WARN(("CrVrScrCompositorEntryRegionsIntersect failed, rc %d", tmpRc)); + rc = tmpRc; + } + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryPosSet(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, const RTPOINT *pPos) +{ + int rc = crVrScrCompositorEntryPositionSet(pCompositor, pEntry, pPos, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: crVrScrCompositorEntryPositionSet failed rc %d", rc)); + return rc; + } + + rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("RegionsSet: crVrScrCompositorEntryEnsureRegionsBounds failed rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; +} + +/* regions are valid until the next CrVrScrCompositor call */ +VBOXVREGDECL(int) CrVrScrCompositorEntryRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects) +{ + if (CrVrScrCompositorEntryIsUsed(pEntry)) + { + int rc = crVrScrCompositorRectsCheckInit(pCompositor); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc)); + return rc; + } + } + + Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED); + + *pcRegions = pEntry->cRects; + if (ppaSrcRegions) + *ppaSrcRegions = pEntry->paSrcRects; + if (ppaDstRegions) + *ppaDstRegions = pEntry->paDstRects; + if (ppaDstUnstretchedRects) + *ppaDstUnstretchedRects = pEntry->paDstUnstretchedRects; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(uint32_t) CrVrScrCompositorEntryFlagsCombinedGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry) +{ + return CRBLT_FOP_COMBINE(pCompositor->fFlags, pEntry->fFlags); +} + +VBOXVREGDECL(void) CrVrScrCompositorEntryFlagsSet(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, uint32_t fFlags) +{ + if (pEntry->fFlags == fFlags) + return; + + pEntry->fFlags = fFlags; + CrVrScrCompositorEntrySetChanged(pEntry, true); +} + +static void crVrScrCompositorEntryDataCleanup(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry) +{ + pEntry->cRects = 0; + pEntry->paSrcRects = NULL; + pEntry->paDstRects = NULL; + pEntry->paDstUnstretchedRects = NULL; +} + +static void crVrScrCompositorEntryDataCopy(PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pToEntry) +{ + pToEntry->cRects = pEntry->cRects; + pToEntry->paSrcRects = pEntry->paSrcRects; + pToEntry->paDstRects = pEntry->paDstRects; + pToEntry->paDstUnstretchedRects = pEntry->paDstUnstretchedRects; + crVrScrCompositorEntryDataCleanup(pEntry); +} + +VBOXVREGDECL(int) CrVrScrCompositorEntryRemove(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry) +{ + if (!VBoxVrCompositorEntryRemove(&pCompositor->Compositor, &pEntry->Ce)) + return VINF_SUCCESS; + + CrVrScrCompositorEntrySetChanged(pEntry, true); + crVrScrCompositorEntryDataCleanup(pEntry); + + crVrScrCompositorRectsInvalidate(pCompositor); + return VINF_SUCCESS; +} + +VBOXVREGDECL(bool) CrVrScrCompositorEntryReplace(PVBOXVR_SCR_COMPOSITOR pCompositor, PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry, PVBOXVR_SCR_COMPOSITOR_ENTRY pNewEntry) +{ + Assert(!CrVrScrCompositorEntryIsUsed(pNewEntry)); + + if (!VBoxVrCompositorEntryReplace(&pCompositor->Compositor, &pEntry->Ce, &pNewEntry->Ce)) + return false; + + CrVrScrCompositorEntrySetChanged(pEntry, true); + crVrScrCompositorEntryDataCopy(pEntry, pNewEntry); + CrVrScrCompositorEntrySetChanged(pNewEntry, true); + + return true; +} + +static DECLCALLBACK(void) crVrScrCompositorEntryReleasedCB(const struct VBOXVR_COMPOSITOR *pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry) +{ + PVBOXVR_SCR_COMPOSITOR_ENTRY pCEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pEntry); + + CrVrScrCompositorEntrySetChanged(pCEntry, true); + + Assert(!CrVrScrCompositorEntryIsInList(pCEntry)); + + if (pReplacingEntry) + { + PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry); + Assert(CrVrScrCompositorEntryIsInList(pCReplacingEntry)); + pCReplacingEntry->cRects = pCEntry->cRects; + pCReplacingEntry->paSrcRects = pCEntry->paSrcRects; + pCReplacingEntry->paDstRects = pCEntry->paDstRects; + pCReplacingEntry->paDstUnstretchedRects = pCEntry->paDstUnstretchedRects; + } + + if (pCEntry->pfnEntryReleased) + { + PVBOXVR_SCR_COMPOSITOR_ENTRY pCReplacingEntry = pReplacingEntry ? VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pReplacingEntry) : NULL; + PVBOXVR_SCR_COMPOSITOR pCConpositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCompositor); + pCEntry->pfnEntryReleased(pCConpositor, pCEntry, pCReplacingEntry); + } +} + +VBOXVREGDECL(int) CrVrScrCompositorRectSet(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect, bool *pfChanged) +{ + if (!memcmp(&pCompositor->Rect, pRect, sizeof (pCompositor->Rect))) + { + if (pfChanged) + *pfChanged = false; + return VINF_SUCCESS; + } + + pCompositor->Rect = *pRect; + + VBOXVR_SCR_COMPOSITOR_ITERATOR Iter; + CrVrScrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + while ((pEntry = CrVrScrCompositorIterNext(&Iter)) != NULL) + { + int rc = crVrScrCompositorEntryEnsureRegionsBounds(pCompositor, pEntry, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorEntryEnsureRegionsBounds failed, rc %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; +} + +VBOXVREGDECL(void) CrVrScrCompositorInit(PVBOXVR_SCR_COMPOSITOR pCompositor, const RTRECT *pRect) +{ + memset(pCompositor, 0, sizeof (*pCompositor)); + VBoxVrCompositorInit(&pCompositor->Compositor, crVrScrCompositorEntryReleasedCB); + pCompositor->fFlags = CRBLT_F_LINEAR | CRBLT_F_INVERT_YCOORDS; + if (pRect) + pCompositor->Rect = *pRect; +#ifndef IN_RING0 + pCompositor->StretchX = 1.0; + pCompositor->StretchY = 1.0; +#endif +} + +VBOXVREGDECL(void) CrVrScrCompositorRegionsClear(PVBOXVR_SCR_COMPOSITOR pCompositor, bool *pfChanged) +{ + /* set changed flag first, while entries are in the list and we have them */ + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); + VBoxVrCompositorRegionsClear(&pCompositor->Compositor, pfChanged); + crVrScrCompositorRectsInvalidate(pCompositor); +} + +VBOXVREGDECL(void) CrVrScrCompositorClear(PVBOXVR_SCR_COMPOSITOR pCompositor) +{ + CrVrScrCompositorRegionsClear(pCompositor, NULL); + if (pCompositor->paDstRects) + { + RTMemFree(pCompositor->paDstRects); + pCompositor->paDstRects = NULL; + } + if (pCompositor->paSrcRects) + { + RTMemFree(pCompositor->paSrcRects); + pCompositor->paSrcRects = NULL; + } + if (pCompositor->paDstUnstretchedRects) + { + RTMemFree(pCompositor->paDstUnstretchedRects); + pCompositor->paDstUnstretchedRects = NULL; + } + + pCompositor->cRects = 0; + pCompositor->cRectsBuffer = 0; +} + +VBOXVREGDECL(void) CrVrScrCompositorEntrySetAllChanged(PVBOXVR_SCR_COMPOSITOR pCompositor, bool fChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR CIter; + PVBOXVR_SCR_COMPOSITOR_ENTRY pCurEntry; + CrVrScrCompositorIterInit(pCompositor, &CIter); + + while ((pCurEntry = CrVrScrCompositorIterNext(&CIter)) != NULL) + { + CrVrScrCompositorEntrySetChanged(pCurEntry, fChanged); + } +} + +#ifndef IN_RING0 +VBOXVREGDECL(void) CrVrScrCompositorSetStretching(PVBOXVR_SCR_COMPOSITOR pCompositor, float StretchX, float StretchY) +{ + if (pCompositor->StretchX == StretchX && pCompositor->StretchY == StretchY) + return; + + pCompositor->StretchX = StretchX; + pCompositor->StretchY = StretchY; + crVrScrCompositorRectsInvalidate(pCompositor); + CrVrScrCompositorEntrySetAllChanged(pCompositor, true); +} +#endif + +/* regions are valid until the next CrVrScrCompositor call */ +VBOXVREGDECL(int) CrVrScrCompositorRegionsGet(const VBOXVR_SCR_COMPOSITOR *pCompositor, uint32_t *pcRegions, const RTRECT **ppaSrcRegions, const RTRECT **ppaDstRegions, const RTRECT **ppaDstUnstretchedRects) +{ + int rc = crVrScrCompositorRectsCheckInit(pCompositor); + if (!RT_SUCCESS(rc)) + { + WARN(("crVrScrCompositorRectsCheckInit failed, rc %d", rc)); + return rc; + } + + Assert(pCompositor->cRects != VBOXVR_SCR_COMPOSITOR_RECTS_UNDEFINED); + + *pcRegions = pCompositor->cRects; + if (ppaSrcRegions) + *ppaSrcRegions = pCompositor->paSrcRects; + if (ppaDstRegions) + *ppaDstRegions = pCompositor->paDstRects; + if (ppaDstUnstretchedRects) + *ppaDstUnstretchedRects = pCompositor->paDstUnstretchedRects; + + return VINF_SUCCESS; +} + +typedef struct VBOXVR_SCR_COMPOSITOR_VISITOR_CB +{ + PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor; + void *pvVisitor; +} VBOXVR_SCR_COMPOSITOR_VISITOR_CB, *PVBOXVR_SCR_COMPOSITOR_VISITOR_CB; + +static DECLCALLBACK(bool) crVrScrCompositorVisitCb(PVBOXVR_COMPOSITOR pCCompositor, PVBOXVR_COMPOSITOR_ENTRY pCEntry, void *pvVisitor) +{ + PVBOXVR_SCR_COMPOSITOR_VISITOR_CB pData = (PVBOXVR_SCR_COMPOSITOR_VISITOR_CB)pvVisitor; + PVBOXVR_SCR_COMPOSITOR pCompositor = VBOXVR_SCR_COMPOSITOR_FROM_COMPOSITOR(pCCompositor); + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry = VBOXVR_SCR_COMPOSITOR_ENTRY_FROM_ENTRY(pCEntry); + return pData->pfnVisitor(pCompositor, pEntry, pData->pvVisitor); +} + +VBOXVREGDECL(void) CrVrScrCompositorVisit(PVBOXVR_SCR_COMPOSITOR pCompositor, PFNVBOXVRSCRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor) +{ + VBOXVR_SCR_COMPOSITOR_VISITOR_CB Data; + Data.pfnVisitor = pfnVisitor; + Data.pvVisitor = pvVisitor; + VBoxVrCompositorVisit(&pCompositor->Compositor, crVrScrCompositorVisitCb, &Data); +} + +VBOXVREGDECL(int) CrVrScrCompositorClone(const VBOXVR_SCR_COMPOSITOR *pCompositor, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor) +{ + /* for simplicity just copy from one to another */ + CrVrScrCompositorInit(pDstCompositor, CrVrScrCompositorRectGet(pCompositor)); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR CIter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + CrVrScrCompositorConstIterInit(pCompositor, &CIter); + int rc = VINF_SUCCESS; + uint32_t cRects; + const RTRECT *pRects; + + while ((pEntry = CrVrScrCompositorConstIterNext(&CIter)) != NULL) + { + /* get source rects, that will be non-stretched and entry pos - pased */ + rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, NULL, NULL, &pRects); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc)); + return rc; + } + + PVBOXVR_SCR_COMPOSITOR_ENTRY pDstEntry = pfnEntryFor(pEntry, pvEntryFor); + if (!pDstEntry) + { + WARN(("pfnEntryFor failed")); + return VERR_INVALID_STATE; + } + + rc = CrVrScrCompositorEntryRegionsSet(pDstCompositor, pDstEntry, NULL, cRects, pRects, false, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + return rc; + } + } + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorIntersectList(PVBOXVR_SCR_COMPOSITOR pCompositor, const VBOXVR_LIST *pVr, bool *pfChanged) +{ + VBOXVR_SCR_COMPOSITOR_ITERATOR CIter; + PVBOXVR_SCR_COMPOSITOR_ENTRY pEntry; + CrVrScrCompositorIterInit(pCompositor, &CIter); + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = CrVrScrCompositorIterNext(&CIter)) != NULL) + { + bool fCurChanged = false; + + rc = CrVrScrCompositorEntryListIntersect(pCompositor, pEntry, pVr, &fCurChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + break; + } + + fChanged |= fCurChanged; + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) CrVrScrCompositorIntersectedList(const VBOXVR_SCR_COMPOSITOR *pCompositor, const VBOXVR_LIST *pVr, PVBOXVR_SCR_COMPOSITOR pDstCompositor, PFNVBOXVR_SCR_COMPOSITOR_ENTRY_FOR pfnEntryFor, void* pvEntryFor, bool *pfChanged) +{ + int rc = CrVrScrCompositorClone(pCompositor, pDstCompositor, pfnEntryFor, pvEntryFor); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorClone failed, rc %d", rc)); + return rc; + } + + rc = CrVrScrCompositorIntersectList(pDstCompositor, pVr, pfChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorIntersectList failed, rc %d", rc)); + CrVrScrCompositorClear(pDstCompositor); + return rc; + } + + return VINF_SUCCESS; +} + diff --git a/src/VBox/GuestHost/OpenGL/util/dll.c b/src/VBox/GuestHost/OpenGL/util/dll.c index a3245a36..dbc61759 100644 --- a/src/VBox/GuestHost/OpenGL/util/dll.c +++ b/src/VBox/GuestHost/OpenGL/util/dll.c @@ -18,6 +18,10 @@ #include <dlfcn.h> #endif +#ifdef WINDOWS +#include <Shlwapi.h> +#endif + #ifdef DARWIN #include <Carbon/Carbon.h> @@ -147,7 +151,6 @@ int get_dll_type( const char *name ) { #endif - /* * Open the named shared library. * If resolveGlobal is non-zero, unresolved symbols can be satisfied by @@ -162,14 +165,77 @@ CRDLL *crDLLOpen( const char *dllname, int resolveGlobal ) { CRDLL *dll; char *dll_err; +#if defined(WINDOWS) + WCHAR szwPath[MAX_PATH]; + UINT cwcPath = 0; + + (void) resolveGlobal; + +# ifndef CR_NO_GL_SYSTEM_PATH + if (PathIsRelative(dllname)) + { + size_t cName = strlen(dllname) + 1; +# ifdef IN_GUEST + cwcPath = GetSystemDirectoryW(szwPath, RT_ELEMENTS(szwPath)); + if (!cwcPath || cwcPath >= MAX_PATH) + { + DWORD winEr = GetLastError(); + crError("GetSystemDirectoryW failed err %d", winEr); + SetLastError(winEr); + return NULL; + } +# else + WCHAR * pszwSlashFile; + cwcPath = GetModuleFileNameW(NULL, szwPath, RT_ELEMENTS(szwPath)); + if (!cwcPath || cwcPath >= MAX_PATH) + { + DWORD winEr = GetLastError(); + crError("GetModuleFileNameW failed err %d", winEr); + SetLastError(winEr); + return NULL; + } + + pszwSlashFile = wcsrchr(szwPath, L'\\'); + if (!pszwSlashFile) + { + crError("failed to match file name"); + SetLastError(ERROR_PATH_NOT_FOUND); + return NULL; + } + + cwcPath = pszwSlashFile - szwPath; +# endif + + if (cwcPath + 1 + cName > MAX_PATH) + { + crError("invalid path specified"); + SetLastError(ERROR_FILENAME_EXCED_RANGE); + return NULL; + } + szwPath[cwcPath] = '\\'; + ++cwcPath; + } + + if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dllname, -1, &szwPath[cwcPath], MAX_PATH - cwcPath)) + { + DWORD winEr = GetLastError(); + crError("MultiByteToWideChar failed err %d", winEr); + SetLastError(winEr); + return NULL; + } +# endif // CR_NO_GL_SYSTEM_PATH +#endif dll = (CRDLL *) crAlloc( sizeof( CRDLL ) ); dll->name = crStrdup( dllname ); #if defined(WINDOWS) - (void) resolveGlobal; - dll->hinstLib = LoadLibrary( dllname ); - dll_err = NULL; + dll->hinstLib = LoadLibraryW( szwPath ); + if (!dll->hinstLib) + { + crError("failed to load dll %s", dllname); + } + dll_err = NULL; #elif defined(DARWIN) /* XXX \todo Get better error handling in here */ dll->type = get_dll_type( dllname ); diff --git a/src/VBox/GuestHost/OpenGL/util/error.c b/src/VBox/GuestHost/OpenGL/util/error.c index 4a8254b3..48fbc577 100644 --- a/src/VBox/GuestHost/OpenGL/util/error.c +++ b/src/VBox/GuestHost/OpenGL/util/error.c @@ -125,7 +125,7 @@ static void __crCheckAustralia(void) static void outputChromiumMessage( FILE *output, char *str ) { - fprintf( output, "%s%s%s%s\n", str, + fprintf( output, "%s%s%s%s\n", str, swedish_chef ? " BORK BORK BORK!" : "", canada ? ", eh?" : "", australia ? ", mate!" : "" @@ -219,7 +219,7 @@ DECLEXPORT(void) crError(const char *format, ... ) MessageBox( NULL, txt, "Chromium Error", MB_OK ); } else - { + { #endif va_end( args ); #ifdef WINDOWS @@ -241,10 +241,13 @@ DECLEXPORT(void) crError(const char *format, ... ) } void crEnableWarnings(int onOff) -{ +{ warnings_enabled = onOff; } +#ifdef DEBUG_misha +# undef crWarning +#endif DECLEXPORT(void) crWarning(const char *format, ... ) { if (warnings_enabled) { @@ -268,7 +271,7 @@ DECLEXPORT(void) crWarning(const char *format, ... ) #endif va_end( args ); -#if defined(WINDOWS) && defined(DEBUG) && !defined(IN_GUEST) +#if defined(WINDOWS) && defined(DEBUG) && !defined(IN_GUEST) && defined(DEBUG_misha) DebugBreak(); #endif } @@ -373,13 +376,13 @@ DECLEXPORT(void) crDebug(const char *format, ... ) if (crStrlen(fnamePrefix) < sizeof (str) - sizeof (pname) - 20) { crGetProcName(pname, 1024); - sprintf(str, "%s_%s_%u.txt", fnamePrefix, pname, + sprintf(str, #ifdef RT_OS_WINDOWS - GetCurrentProcessId() + "%s_%s_%u.txt", fnamePrefix, pname, GetCurrentProcessId() #else - crGetPID() + "%s_%s_%lu.txt", fnamePrefix, pname, crGetPID() #endif - ); + ); fname = &str[0]; } } @@ -399,7 +402,7 @@ DECLEXPORT(void) crDebug(const char *format, ... ) output = fopen( fname, "w" ); if (!output) { - crError( "Couldn't open debug log %s", fname ); + crError( "Couldn't open debug log %s", fname ); } } else @@ -495,18 +498,16 @@ DECLEXPORT(void) crDebug(const char *format, ... ) outputChromiumMessage( output, txt ); #else if (!output -# ifndef DEBUG_misha +#ifndef DEBUG_misha || output==stderr -# endif +#endif ) { LogRel(("%s\n", txt)); } else { -# ifndef DEBUG_misha LogRel(("%s\n", txt)); -# endif outputChromiumMessage(output, txt); } #endif diff --git a/src/VBox/GuestHost/OpenGL/util/hash.c b/src/VBox/GuestHost/OpenGL/util/hash.c index c91c4ad0..95f3ab65 100644 --- a/src/VBox/GuestHost/OpenGL/util/hash.c +++ b/src/VBox/GuestHost/OpenGL/util/hash.c @@ -9,20 +9,25 @@ #include "cr_mem.h" #include "cr_error.h" +#include <iprt/list.h> + #define CR_MAXUINT ((GLuint) 0xFFFFFFFF) +#define CR_HASH_ID_MIN ((GLuint)1) +#define CR_HASH_ID_MAX CR_MAXUINT #define CR_NUM_BUCKETS 1047 typedef struct FreeElemRec { + RTLISTNODE Node; GLuint min; GLuint max; - struct FreeElemRec *next; - struct FreeElemRec *prev; } FreeElem; -typedef struct CRHashIdPoolRec { - FreeElem *freeList; -} CRHashIdPool; +struct CRHashIdPool { + RTLISTNODE freeList; + GLuint min; + GLuint max; +}; typedef struct CRHashNode { unsigned long key; @@ -40,86 +45,124 @@ struct CRHashTable { }; -static CRHashIdPool *crAllocHashIdPool( void ) +CRHashIdPool *crAllocHashIdPoolEx( GLuint min, GLuint max ) { - CRHashIdPool *pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool)); - pool->freeList = (FreeElem *) crCalloc(sizeof(FreeElem)); - pool->freeList->min = 1; - pool->freeList->max = CR_MAXUINT; - pool->freeList->next = NULL; - pool->freeList->prev = NULL; + CRHashIdPool *pool; + FreeElem *elem; + if (min < CR_HASH_ID_MIN || max > CR_HASH_ID_MAX || min >= max) + { + crWarning("invalid min man vals"); + return NULL; + } + pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool)); + elem = (FreeElem *) crCalloc(sizeof(FreeElem)); + RTListInit(&pool->freeList); + elem->min = min; + elem->max = max; + RTListAppend(&pool->freeList, &elem->Node); + pool->min = min; + pool->max = max; return pool; } -static void crFreeHashIdPool( CRHashIdPool *pool ) +CRHashIdPool *crAllocHashIdPool( void ) +{ + return crAllocHashIdPoolEx( CR_HASH_ID_MIN, CR_HASH_ID_MAX ); +} + +void crFreeHashIdPool( CRHashIdPool *pool ) { FreeElem *i, *next; - for (i = pool->freeList; i; i = next) + RTListForEachSafe(&pool->freeList, i, next, FreeElem, Node) { - next = i->next; crFree(i); } + crFree(pool); } +#ifdef DEBUG_misha +static void crHashIdPoolDbgCheckConsistency(CRHashIdPool *pool) +{ + FreeElem *i; + GLuint min = 0; + + /* null is a special case, it is always treated as allocated */ + Assert(!crHashIdPoolIsIdFree(pool, 0)); + + /* first ensure entries have correct values */ + RTListForEach(&pool->freeList, i, FreeElem, Node) + { + Assert(i->min >= pool->min); + Assert(i->max <= pool->max); + Assert(i->min < i->max); + } + + /* now ensure entries do not intersect */ + /* and that they are sorted */ + RTListForEach(&pool->freeList, i, FreeElem, Node) + { + Assert(min < i->min); + min = i->max; + } +} + +static void crHashIdPoolDbgCheckUsed( const CRHashIdPool *pool, GLuint start, GLuint count, GLboolean fUsed ) +{ + GLuint i; + CRASSERT(count); + CRASSERT(start >= pool->min); + CRASSERT(start + count <= pool->max); + CRASSERT(start + count > start); + for (i = 0; i < count; ++i) + { + Assert(!fUsed == !!crHashIdPoolIsIdFree( pool, start + i )); + } +} + +# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { \ + crHashIdPoolDbgCheckConsistency((_p)); \ + crHashIdPoolDbgCheckUsed( (_p), (_start), (_count), (_used) ); \ + } while (0) + +# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { crHashIdPoolDbgCheckConsistency((_p)); } while (0) +#else +# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { } while (0) +# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { } while (0) +#endif + /* * Allocate a block of <count> IDs. Return index of first one. * Return 0 if we fail. */ -static GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count ) +GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count ) { - FreeElem *f; + FreeElem *f, *next; GLuint ret; CRASSERT(count > 0); - - f = pool->freeList; - while (f) + RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node) { - if (f->max - f->min + 1 >= (GLuint) count) + Assert(f->max > f->min); + if (f->max - f->min >= (GLuint) count) { /* found a sufficiently large enough block */ ret = f->min; f->min += count; - if (f->min == f->max) { - /* remove this block from linked list */ - if (f == pool->freeList) - { - /* remove from head */ - pool->freeList = pool->freeList->next; - pool->freeList->prev = NULL; - } - else - { - /* remove from elsewhere */ - f->prev->next = f->next; - f->next->prev = f->prev; - } + RTListNodeRemove(&f->Node); crFree(f); } -#ifdef DEBUG - /* make sure the IDs really are allocated */ - { - GLuint i; - for (i = 0; i < count; i++) - { - //CRASSERT(crHashIdPoolIsIdUsed(pool, ret + i)); - } - } -#endif - + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, ret, count, GL_TRUE); return ret; } - else { - f = f->next; - } } /* failed to find free block */ - crDebug("crHashIdPoolAllocBlock failed"); + crWarning("crHashIdPoolAllocBlock failed"); + CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(pool); return 0; } @@ -127,107 +170,91 @@ static GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count ) /* * Free a block of <count> IDs starting at <first>. */ -static void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count ) +void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count ) { - FreeElem *i; - FreeElem *newelem; - - /*********************************/ - /* Add the name to the freeList */ - /* Find the bracketing sequences */ + FreeElem *f; + GLuint last; + GLuint newMax; + FreeElem *cur, *curNext; - for (i = pool->freeList; i && i->next && i->next->min < first; i = i->next) + /* null is a special case, it is always treated as allocated */ + if (!first) { - /* EMPTY BODY */ + Assert(!crHashIdPoolIsIdFree(pool, 0)); + ++first; + --count; + if (!count) + return; } - /* j will always be valid */ - if (!i) { - return; - } - if (!i->next && i->max == first) { - return; - } + last = first + count; + CRASSERT(count > 0); + CRASSERT(last > first); + CRASSERT(first >= pool->min); + CRASSERT(last <= pool->max); - /* Case: j:(~,first-1) */ - if (i->max + 1 == first) + /* the id list is sorted, first find a place to insert */ + RTListForEach(&pool->freeList, f, FreeElem, Node) { - i->max += count; - if (i->next && i->max+1 >= i->next->min) + Assert(f->max > f->min); + + if (f->max < first) + continue; + + if (f->min > last) { - /* Collapse */ - i->next->min = i->min; - i->next->prev = i->prev; - if (i->prev) - { - i->prev->next = i->next; - } - if (i == pool->freeList) - { - pool->freeList = i->next; - } - crFree(i); + /* we are here because first is > than prevEntry->max + * otherwise the previous loop iterations should handle that */ + FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem)); + elem->min = first; + elem->max = last; + RTListNodeInsertBefore(&f->Node, &elem->Node); + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE); + return; } - return; - } - /* Case: j->next: (first+1, ~) */ - if (i->next && i->next->min - count == first) - { - i->next->min -= count; - if (i->max + 1 >= i->next->min) + /* now we have f->min <= last and f->max >= first, + * so we have either intersection */ + + if (f->min > first) + f->min = first; /* first is guaranteed not to touch any prev regions */ + + newMax = last; + + if (f->max >= last) { - /* Collapse */ - i->next->min = i->min; - i->next->prev = i->prev; - if (i->prev) - { - i->prev->next = i->next; - } - if (i == pool->freeList) - { - pool->freeList = i->next; - } - crFree(i); + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE); + return; } - return; - } - /* Case: j: (first+1, ~) j->next: null */ - if (!i->next && i->min - count == first) - { - i->min -= count; - return; - } + for (cur = RTListNodeGetNext(&f->Node, FreeElem, Node), + curNext = RT_FROM_MEMBER(cur->Node.pNext, FreeElem, Node); + !RTListNodeIsDummy(&pool->freeList, cur, FreeElem, Node); + cur = curNext, + curNext = RT_FROM_MEMBER((cur)->Node.pNext, FreeElem, Node) ) + { + if (cur->min > last) + break; - /* allocate a new FreeElem node */ - newelem = (FreeElem *) crCalloc(sizeof(FreeElem)); - newelem->min = first; - newelem->max = first + count - 1; + newMax = cur->max; + RTListNodeRemove(&cur->Node); + crFree(cur); - /* Case: j: (~,first-(2+)) j->next: (first+(2+), ~) or null */ - if (first > i->max) - { - newelem->prev = i; - newelem->next = i->next; - if (i->next) - { - i->next->prev = newelem; + if (newMax >= last) + break; } - i->next = newelem; - return; - } - /* Case: j: (first+(2+), ~) */ - /* Can only happen if j = t->freeList! */ - if (i == pool->freeList && i->min > first) - { - newelem->next = i; - newelem->prev = i->prev; - i->prev = newelem; - pool->freeList = newelem; + f->max = newMax; + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE); return; } + + /* we are here because either the list is empty or because all list rande elements have smaller values */ + f = (FreeElem *) crCalloc(sizeof(FreeElem)); + f->min = first; + f->max = last; + RTListAppend(&pool->freeList, &f->Node); + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE); } @@ -235,68 +262,116 @@ static void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint coun /* * Mark the given Id as being allocated. */ -static void crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id ) +GLboolean crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id ) { - FreeElem *f; + FreeElem *f, *next; + + if (!id) + { + /* null is a special case, it is always treated as allocated */ + Assert(!crHashIdPoolIsIdFree(pool, 0)); + return GL_FALSE; + } + +// Assert(id != 2); - f = pool->freeList; - while (f) + RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node) { - if (id >= f->min && id <= f->max) + if (f->max <= id) + continue; + if (f->min > id) { - /* found the block */ - if (id == f->min) + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE); + return GL_FALSE; + } + + /* f->min <= id && f->max > id */ + if (id > f->min) + { + if (id + 1 < f->max) { - f->min++; + FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem)); + elem->min = id + 1; + elem->max = f->max; + RTListNodeInsertAfter(&f->Node, &elem->Node); } - else if (id == f->max) + f->max = id; + + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE); + } + else + { + Assert(id == f->min); + if (id + 1 < f->max) { - f->max--; + f->min = id + 1; + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE); } else { - /* somewhere in the middle - split the block */ - FreeElem *newelem = (FreeElem *) crCalloc(sizeof(FreeElem)); - newelem->min = id + 1; - newelem->max = f->max; - f->max = id - 1; - newelem->next = f->next; - if (f->next) - f->next->prev = newelem; - newelem->prev = f; - f->next = newelem; + RTListNodeRemove(&f->Node); + crFree(f); + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE); } - return; } - f = f->next; + + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE); + return GL_TRUE; } /* if we get here, the ID was already allocated - that's OK */ + CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE); + return GL_FALSE; } /* * Determine if the given id is free. Return GL_TRUE if so. */ -static GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id ) +GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id ) { - FreeElem *i; + FreeElem *f; + CRASSERT(id <= pool->max); - /* First find which region it fits in */ - for (i = pool->freeList; i && !(i->min <= id && id <= i->max); i=i->next) + RTListForEach(&pool->freeList, f, FreeElem, Node) { - /* EMPTY BODY */ - } - - if (i) + if (f->max <= id) + continue; + if (f->min > id) + return GL_FALSE; return GL_TRUE; - else - return GL_FALSE; + } + return GL_FALSE; } +void crHashIdWalkKeys( CRHashIdPool *pool, CRHashIdWalkKeys walkFunc , void *data) +{ + FreeElem *prev = NULL, *f; + + RTListForEach(&pool->freeList, f, FreeElem, Node) + { + if (prev) + { + Assert(prev->max < f->min); + walkFunc(prev->max+1, f->min - prev->max, data); + } + else if (f->min > pool->min) + { + walkFunc(pool->min, f->min - pool->min, data); + } + + prev = f; + } + Assert(prev->max <= pool->max); -CRHashTable *crAllocHashtable( void ) + if (prev->max < pool->max) + { + walkFunc(prev->max+1, pool->max - prev->max, data); + } +} + +CRHashTable *crAllocHashtableEx( GLuint min, GLuint max ) { int i; CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ; @@ -305,13 +380,18 @@ CRHashTable *crAllocHashtable( void ) { hash->buckets[i] = NULL; } - hash->idPool = crAllocHashIdPool(); + hash->idPool = crAllocHashIdPoolEx( min, max ); #ifdef CHROMIUM_THREADSAFE crInitMutex(&hash->mutex); #endif return hash; } +CRHashTable *crAllocHashtable( void ) +{ + return crAllocHashtableEx(CR_HASH_ID_MIN, CR_HASH_ID_MAX); +} + void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc ) { int i; @@ -366,17 +446,11 @@ void crHashtableUnlock(CRHashTable *h) #endif } -void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2) +void crHashtableWalkUnlocked( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2) { int i; CRHashNode *entry, *next; - if (!hash) - return; - -#ifdef CHROMIUM_THREADSAFE - crLockMutex(&hash->mutex); -#endif for (i = 0; i < CR_NUM_BUCKETS; i++) { entry = hash->buckets[i]; @@ -390,6 +464,17 @@ void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void entry = next; } } +} + +void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2) +{ + if (!hash) + return; + +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&hash->mutex); +#endif + crHashtableWalkUnlocked(hash, walkFunc , dataPtr2); #ifdef CHROMIUM_THREADSAFE crUnlockMutex(&hash->mutex); #endif @@ -417,6 +502,30 @@ void crHashtableAdd( CRHashTable *h, unsigned long key, void *data ) #endif } +GLboolean crHashtableAllocRegisterKey( CRHashTable *h, GLuint key) +{ + GLboolean fAllocated; +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&h->mutex); +#endif + fAllocated = crHashIdPoolAllocId (h->idPool, key); +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&h->mutex); +#endif + return fAllocated; +} + +void crHashtableWalkKeys( CRHashTable *h, CRHashIdWalkKeys walkFunc , void *data) +{ +#ifdef CHROMIUM_THREADSAFE + crLockMutex(&h->mutex); +#endif + crHashIdWalkKeys(h->idPool, walkFunc , data); +#ifdef CHROMIUM_THREADSAFE + crUnlockMutex(&h->mutex); +#endif +} + GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range) { GLuint res; @@ -426,6 +535,14 @@ GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range) crLockMutex(&h->mutex); #endif res = crHashIdPoolAllocBlock (h->idPool, range); +#ifdef DEBUG_misha + Assert(res); + for (i = 0; i < range; ++i) + { + void *search = crHashtableSearch( h, res+i ); + Assert(!search); + } +#endif #ifdef CHROMIUM_THREADSAFE crUnlockMutex(&h->mutex); #endif @@ -446,23 +563,20 @@ void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback d break; beftemp = temp; } - if ( !temp ) { -#ifdef CHROMIUM_THREADSAFE - crUnlockMutex(&h->mutex); -#endif - return; /* not an error */ - } - if ( beftemp ) - beftemp->next = temp->next; - else - h->buckets[index] = temp->next; - h->num_elements--; - if (temp->data && deleteFunc) { - (*deleteFunc)( temp->data ); - } - - crFree( temp ); + if ( temp ) + { + if ( beftemp ) + beftemp->next = temp->next; + else + h->buckets[index] = temp->next; + h->num_elements--; + if (temp->data && deleteFunc) { + (*deleteFunc)( temp->data ); + } + crFree( temp ); + } + crHashIdPoolFreeBlock( h->idPool, key, 1 ); #ifdef CHROMIUM_THREADSAFE crUnlockMutex(&h->mutex); diff --git a/src/VBox/GuestHost/OpenGL/util/htable.cpp b/src/VBox/GuestHost/OpenGL/util/htable.cpp new file mode 100644 index 00000000..bb9434c7 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/htable.cpp @@ -0,0 +1,195 @@ +/* $Id: htable.cpp $ */ + +/** @file + * uint32_t handle to void simple table impl + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +#include <iprt/cdefs.h> +#include <iprt/asm.h> +#include "cr_spu.h" +#include "cr_vreg.h" + +#include "cr_htable.h" +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "cr_mem.h" +#include "cr_string.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/mem.h> +#include <iprt/err.h> + +VBOXHTABLEDECL(int) CrHTableCreate(PCRHTABLE pTbl, uint32_t cSize) +{ + memset(pTbl, 0, sizeof (*pTbl)); + if (!cSize) + return VINF_SUCCESS; + pTbl->paData = (void**)RTMemAllocZ(sizeof (pTbl->paData[0]) * cSize); + if (pTbl->paData) + { + pTbl->cSize = cSize; + return VINF_SUCCESS; + } + WARN(("RTMemAllocZ failed!")); + return VERR_NO_MEMORY; +} + +VBOXHTABLEDECL(void) CrHTableDestroy(PCRHTABLE pTbl) +{ + if (!pTbl->paData) + return; + + RTMemFree(pTbl->paData); +} + +int crHTableRealloc(PCRHTABLE pTbl, uint32_t cNewSize) +{ + Assert(cNewSize > pTbl->cSize); + if (cNewSize > pTbl->cSize) + { + void **pvNewData = (void**)RTMemAllocZ(sizeof (pTbl->paData[0]) * cNewSize); + if (!pvNewData) + { + WARN(("RTMemAllocZ failed for size (%d)", (int)(sizeof (pTbl->paData[0]) * cNewSize))); + return VERR_NO_MEMORY; + } + memcpy(pvNewData, pTbl->paData, sizeof (pTbl->paData[0]) * pTbl->cSize); + RTMemFree(pTbl->paData); + pTbl->iNext2Search = pTbl->cSize; + pTbl->cSize = cNewSize; + pTbl->paData = pvNewData; + return VINF_SUCCESS; + } + else if (cNewSize >= pTbl->cData) + { + WARN(("not implemented")); + return VERR_NOT_IMPLEMENTED; + } + WARN(("invalid parameter")); + return VERR_INVALID_PARAMETER; + +} + +VBOXHTABLEDECL(int) CrHTableRealloc(PCRHTABLE pTbl, uint32_t cNewSize) +{ + return crHTableRealloc(pTbl, cNewSize); +} + +VBOXHTABLEDECL(void) CrHTableEmpty(PCRHTABLE pTbl) +{ + pTbl->cData = 0; + pTbl->iNext2Search = 0; + if (pTbl->cSize) + memset(pTbl->paData, 0, sizeof (pTbl->paData[0]) * pTbl->cSize); +} + +static void* crHTablePutToSlot(PCRHTABLE pTbl, uint32_t iSlot, void* pvData) +{ + Assert(pvData); + void* pvOld = pTbl->paData[iSlot]; + pTbl->paData[iSlot] = pvData; + if (!pvOld) + ++pTbl->cData; + Assert(pTbl->cData <= pTbl->cSize); + return pvOld; +} + +VBOXHTABLEDECL(int) CrHTablePutToSlot(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle, void* pvData) +{ + if (!pvData) + { + AssertMsgFailed(("pvData is NULL\n")); + return VERR_INVALID_PARAMETER; + } + uint32_t iIndex = crHTableHandle2Index(hHandle); + if (iIndex >= pTbl->cSize) + { + int rc = crHTableRealloc(pTbl, iIndex + RT_MAX(10, pTbl->cSize/4)); + if (!RT_SUCCESS(rc)) + { + WARN(("crHTableRealloc failed rc %d", rc)); + return CRHTABLE_HANDLE_INVALID; + } + } + + crHTablePutToSlot(pTbl, iIndex, pvData); + + return VINF_SUCCESS; +} + +VBOXHTABLEDECL(CRHTABLE_HANDLE) CrHTablePut(PCRHTABLE pTbl, void* pvData) +{ + if (!pvData) + { + AssertMsgFailed(("pvData is NULL\n")); + return VERR_INVALID_PARAMETER; + } + + if (pTbl->cSize == pTbl->cData) + { + int rc = crHTableRealloc(pTbl, pTbl->cSize + RT_MAX(10, pTbl->cSize/4)); + if (!RT_SUCCESS(rc)) + { + WARN(("crHTableRealloc failed rc %d", rc)); + return CRHTABLE_HANDLE_INVALID; + } + } + for (uint32_t i = pTbl->iNext2Search; ; ++i, i %= pTbl->cSize) + { + Assert(i < pTbl->cSize); + if (!pTbl->paData[i]) + { + void *pvOld = crHTablePutToSlot(pTbl, i, pvData); + Assert(!pvOld); + pTbl->iNext2Search = i+1; + pTbl->iNext2Search %= pTbl->cSize; + return crHTableIndex2Handle(i); + } + } + WARN(("should not be here")); + return CRHTABLE_HANDLE_INVALID; +} + +VBOXHTABLEDECL(void*) CrHTableRemove(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle) +{ + uint32_t iIndex = crHTableHandle2Index(hHandle); + Assert(iIndex < pTbl->cSize); + if (iIndex < pTbl->cSize) + { + void* pvData = pTbl->paData[iIndex]; + if (pvData) + { + pTbl->paData[iIndex] = NULL; + --pTbl->cData; + Assert(pTbl->cData <= pTbl->cSize); + pTbl->iNext2Search = iIndex; + } + return pvData; + } + WARN(("invalid handle supplied %d", hHandle)); + return NULL; +} + +VBOXHTABLEDECL(void*) CrHTableGet(PCRHTABLE pTbl, CRHTABLE_HANDLE hHandle) +{ + uint32_t iIndex = crHTableHandle2Index(hHandle); + if (iIndex < pTbl->cSize) + return pTbl->paData[iIndex]; + LOG(("invalid handle supplied %d", hHandle)); + return NULL; +} diff --git a/src/VBox/GuestHost/OpenGL/util/net.c b/src/VBox/GuestHost/OpenGL/util/net.c index cc2966f9..72d9f7ae 100644 --- a/src/VBox/GuestHost/OpenGL/util/net.c +++ b/src/VBox/GuestHost/OpenGL/util/net.c @@ -993,7 +993,7 @@ crNetRecvFlowControl( CRConnection *conn, CRMessageFlowControl *msg, conn->InstantReclaim( conn, (CRMessage *) msg ); } - +#ifdef IN_GUEST /** * Called by the main receive function when we get a CR_MESSAGE_WRITEBACK * message. Writeback is used to implement glGet*() functions. @@ -1026,7 +1026,7 @@ crNetRecvReadback( CRMessageReadback *rb, unsigned int len ) (*writeback)--; crMemcpy( dest_ptr, ((char *)rb) + sizeof(*rb), payload_len ); } - +#endif /** * This is used by the SPUs that do packing (such as Pack, Tilesort and @@ -1104,13 +1104,21 @@ crNetDefaultRecv( CRConnection *conn, CRMessage *msg, unsigned int len ) } break; case CR_MESSAGE_READ_PIXELS: - crError( "Can't handle read pixels" ); + WARN(( "Can't handle read pixels" )); return; case CR_MESSAGE_WRITEBACK: +#ifdef IN_GUEST crNetRecvWriteback( &(pRealMsg->writeback) ); +#else + WARN(("CR_MESSAGE_WRITEBACK not expected\n")); +#endif return; case CR_MESSAGE_READBACK: +#ifdef IN_GUEST crNetRecvReadback( &(pRealMsg->readback), len ); +#else + WARN(("CR_MESSAGE_READBACK not expected\n")); +#endif return; case CR_MESSAGE_CRUT: /* nothing */ @@ -1128,10 +1136,10 @@ crNetDefaultRecv( CRConnection *conn, CRMessage *msg, unsigned int len ) { char string[128]; crBytesToString( string, sizeof(string), msg, len ); - crError("crNetDefaultRecv: received a bad message: type=%d buf=[%s]\n" + WARN(("crNetDefaultRecv: received a bad message: type=%d buf=[%s]\n" "Did you add a new message type and forget to tell " "crNetDefaultRecv() about it?\n", - msg->header.type, string ); + msg->header.type, string )); } } diff --git a/src/VBox/GuestHost/OpenGL/util/pixel.c b/src/VBox/GuestHost/OpenGL/util/pixel.c index c153dee2..5bea3e1f 100644 --- a/src/VBox/GuestHost/OpenGL/util/pixel.c +++ b/src/VBox/GuestHost/OpenGL/util/pixel.c @@ -11,6 +11,8 @@ #include <stdio.h> #include <math.h> +#include <iprt/string.h> + #if defined(WINDOWS) # include <float.h> # define isnan(x) _isnan(x) @@ -1691,7 +1693,9 @@ void crPixelCopy3D( GLsizei width, GLsizei height, GLsizei depth, /*@todo this should be implemented properly*/ +#ifndef DEBUG_misha crWarning( "crPixelCopy3D: simply crMemcpy'ing from srcPtr to dstPtr" ); +#endif if (dstFormat != srcFormat) crWarning( "crPixelCopy3D: formats don't match!" ); if (dstType != srcType) @@ -1841,3 +1845,19 @@ void crDumpNamedTGA(const char* fname, GLint w, GLint h, GLvoid *data) fclose(out); } + +void crDumpNamedTGAV(GLint w, GLint h, GLvoid *data, const char* fname, va_list va) +{ + char szName[4096]; + RTStrPrintfV(szName, sizeof(szName), fname, va); + crDumpNamedTGA(szName, w, h, data); +} + +void crDumpNamedTGAF(GLint w, GLint h, GLvoid *data, const char* fname, ...) +{ + va_list va; + int rc; + va_start(va, fname); + crDumpNamedTGAV(w, h, data, fname, va); + va_end(va); +} diff --git a/src/VBox/GuestHost/OpenGL/util/string.c b/src/VBox/GuestHost/OpenGL/util/string.c index 75df10bc..0d7fff0b 100644 --- a/src/VBox/GuestHost/OpenGL/util/string.c +++ b/src/VBox/GuestHost/OpenGL/util/string.c @@ -6,6 +6,7 @@ #include "cr_mem.h" #include "cr_string.h" +#include "cr_error.h" #include <string.h> #include <stdio.h> @@ -408,3 +409,125 @@ int crIsDigit(char c) { return c >= '0' && c <= '9'; } + + +static int crStrParseGlSubver(const char * ver, const char ** pNext, bool bSpacePrefixAllowed) +{ + const char * initVer = ver; + int val = 0; + + for(;;++ver) + { + if(*ver >= '0' && *ver <= '9') + { + if(!val) + { + if(*ver == '0') + continue; + } + else + { + val *= 10; + } + val += *ver - '0'; + } + else if(*ver == '.') + { + *pNext = ver+1; + break; + } + else if(*ver == '\0') + { + *pNext = NULL; + break; + } + else if(*ver == ' ' || *ver == '\t' || *ver == 0x0d || *ver == 0x0a) + { + if(bSpacePrefixAllowed) + { + if(!val) + { + continue; + } + } + + /* treat this as the end of version string */ + *pNext = NULL; + break; + } + else + { + crWarning("error parsing version %s", initVer); + val = -1; + break; + } + } + + return val; +} + +int crStrParseGlVersion(const char * ver) +{ + const char * initVer = ver; + int tmp; + int iVer = crStrParseGlSubver(ver, &ver, true); + if(iVer <= 0) + { + crWarning("parsing major version returned %d, '%s'", iVer, initVer); + return iVer; + } + + if (iVer > CR_GLVERSION_MAX_MAJOR) + { + crWarning("major version %d is bigger than the max supported %#x, this is somewhat not expected, failing", iVer, CR_GLVERSION_MAX_MAJOR); + return -1; + } + + iVer <<= CR_GLVERSION_OFFSET_MAJOR; + if(!ver) + { + crDebug("no minor version supplied"); + goto done; + } + + tmp = crStrParseGlSubver(ver, &ver, false); + if (tmp < 0) + { + crWarning("parsing minor version failed, '%s'", initVer); + return -1; + } + + if (tmp > CR_GLVERSION_MAX_MINOR) + { + crWarning("minor version %d is bigger than the max supported %#x, this is somewhat not expected, failing", iVer, CR_GLVERSION_MAX_MAJOR); + return -1; + } + + iVer |= tmp << CR_GLVERSION_OFFSET_MINOR; + + if (!ver) + { + crDebug("no build version supplied"); + goto done; + } + + tmp = crStrParseGlSubver(ver, &ver, false); + if (tmp < 0) + { + crWarning("parsing build version failed, '%s', using 0", initVer); + tmp = 0; + } + + if (tmp > CR_GLVERSION_MAX_BUILD) + { + crWarning("build version %d is bigger than the max supported, using max supported val %#x", tmp, CR_GLVERSION_MAX_BUILD); + tmp = CR_GLVERSION_MAX_MAJOR; + } + + iVer |= tmp << CR_GLVERSION_OFFSET_BUILD; + +done: + crDebug("returning version %#x for string '%s'", iVer, initVer); + + return iVer; +} diff --git a/src/VBox/GuestHost/OpenGL/util/util.def b/src/VBox/GuestHost/OpenGL/util/util.def index d4b6cd64..4fa97058 100644 --- a/src/VBox/GuestHost/OpenGL/util/util.def +++ b/src/VBox/GuestHost/OpenGL/util/util.def @@ -82,7 +82,10 @@ crHashtableSearch crHashtableReplace crHashtableNumElements crHashtableWalk +crHashtableWalkUnlocked +crHashtableAllocRegisterKey crAllocHashtable +crAllocHashtableEx crFreeHashtable crHashtableGetDataKey crDetermineEndianness @@ -145,7 +148,6 @@ crGetCurrentDir crHashtableAllocKeys crHashtableDeleteBlock crHashtableIsKeyUsed -crHashtableWalk crMatrixInit crMatrixInitFromString crMatrixInitFromFloats diff --git a/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c b/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c index fbf35304..d5d057d9 100644 --- a/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c +++ b/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -195,9 +195,6 @@ typedef enum { CR_VBOXHGCM_USERALLOCATED, CR_VBOXHGCM_MEMORY, CR_VBOXHGCM_MEMORY_BIG -#ifdef RT_OS_WINDOWS - ,CR_VBOXHGCM_DDRAW_SURFACE -#endif #if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST) ,CR_VBOXHGCM_UHGSMI_BUFFER #endif @@ -220,9 +217,6 @@ typedef struct CRVBOXHGCMBUFFER { PVBOXUHGSMI_BUFFER pBuffer; #endif }; -#ifdef RT_OS_WINDOWS - LPDIRECTDRAWSURFACE pDDS; -#endif } CRVBOXHGCMBUFFER; #ifndef RT_OS_WINDOWS @@ -705,92 +699,6 @@ static void *_crVBoxHGCMAlloc(CRConnection *conn) (void *) g_crvboxhgcm.bufpool, (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size); -#if defined(IN_GUEST) && defined(RT_OS_WINDOWS) - /* Try to start DDRAW on guest side */ - if (!g_crvboxhgcm.pDirectDraw && 0) - { - HRESULT hr; - - hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL); - if (hr != DD_OK) - { - crWarning("Failed to create DirectDraw interface (%x)\n", hr); - g_crvboxhgcm.pDirectDraw = NULL; - } - else - { - hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL); - if (hr != DD_OK) - { - crWarning("Failed to SetCooperativeLevel (%x)\n", hr); - IDirectDraw_Release(g_crvboxhgcm.pDirectDraw); - g_crvboxhgcm.pDirectDraw = NULL; - } - crDebug("Created DirectDraw and set CooperativeLevel successfully\n"); - } - } - - /* Try to allocate buffer via DDRAW */ - if (g_crvboxhgcm.pDirectDraw) - { - DDSURFACEDESC ddsd; - HRESULT hr; - LPDIRECTDRAWSURFACE lpDDS; - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason - * also, it would be better to request dwLinearSize but it fails too - * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size; - */ - - ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - /* use 1 byte per pixel format */ - ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); - ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; - ddsd.ddpfPixelFormat.dwRGBBitCount = 8; - ddsd.ddpfPixelFormat.dwRBitMask = 0xFF; - ddsd.ddpfPixelFormat.dwGBitMask = 0; - ddsd.ddpfPixelFormat.dwBBitMask = 0; - /* request given buffer size, rounded to 1k */ - ddsd.dwWidth = 1024; - ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth; - - hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL); - if (hr != DD_OK) - { - crWarning("Failed to create DirectDraw surface (%x)\n", hr); - } - else - { - crDebug("Created DirectDraw surface (%x)\n", lpDDS); - - hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL); - if (hr != DD_OK) - { - crWarning("Failed to lock DirectDraw surface (%x)\n", hr); - IDirectDrawSurface_Release(lpDDS); - } - else - { - uint32_t cbLocked; - cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight; - - crDebug("Locked %d bytes DirectDraw surface\n", cbLocked); - - buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface; - CRASSERT(buf); - buf->magic = CR_VBOXHGCM_BUFFER_MAGIC; - buf->kind = CR_VBOXHGCM_DDRAW_SURFACE; - buf->allocated = cbLocked; - buf->pDDS = lpDDS; - } - } - } -#endif - /* We're either on host side, or we failed to allocate DDRAW buffer */ if (!buf) { @@ -800,9 +708,6 @@ static void *_crVBoxHGCMAlloc(CRConnection *conn) buf->magic = CR_VBOXHGCM_BUFFER_MAGIC; buf->kind = CR_VBOXHGCM_MEMORY; buf->allocated = conn->buffer_size; -#ifdef RT_OS_WINDOWS - buf->pDDS = NULL; -#endif } } @@ -944,18 +849,9 @@ crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ; parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ; - //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE) - { - parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In; - parms.pBuffer.u.Pointer.size = len; - parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf; - } - /*else ///@todo it fails badly, have to check why. bird: This fails because buf isn't a physical address? - { - parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr; - parms.pBuffer.u.Pointer.size = len; - parms.pBuffer.u.Pointer.u.physAddr = (uintptr_t) buf; - }*/ + parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In; + parms.pBuffer.u.Pointer.size = len; + parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf; CRASSERT(!conn->pBuffer); //make sure there's no data to process parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out; @@ -1202,9 +1098,6 @@ static void _crVBoxHGCMFree(CRConnection *conn, void *buf) switch (hgcm_buffer->kind) { case CR_VBOXHGCM_MEMORY: -#ifdef RT_OS_WINDOWS - case CR_VBOXHGCM_DDRAW_SURFACE: -#endif #ifdef CHROMIUM_THREADSAFE crLockMutex(&g_crvboxhgcm.mutex); #endif @@ -1283,7 +1176,7 @@ static void _crVBoxHGCMReceiveMessage(CRConnection *conn) else { /* we should NEVER have redir_ptr disabled with HGSMI command now */ - CRASSERT(!conn->CmdData.pCmd); + CRASSERT(!conn->CmdData.pvCmd); if ( len <= conn->buffer_size ) { /* put in pre-allocated buffer */ @@ -1298,9 +1191,6 @@ static void _crVBoxHGCMReceiveMessage(CRConnection *conn) hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC; hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG; hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len; -# ifdef RT_OS_WINDOWS - hgcm_buffer->pDDS = NULL; -# endif } hgcm_buffer->len = len; @@ -1998,25 +1888,30 @@ _crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void else if (VERR_BUFFER_OVERFLOW == rc) { VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0}; - PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer; + PVBOXUHGSMI_BUFFER pNewBuf; CRASSERT(!pClient->pvHGBuffer); CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer); crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback); - rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pClient->pHGBuffer); + rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pNewBuf); if (RT_SUCCESS(rc)) { - rc = pOldBuf->pfnDestroy(pOldBuf); + rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer); CRASSERT(RT_SUCCESS(rc)); + pClient->pHGBuffer = pNewBuf; + _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/); } else { crWarning("_crVBoxHGSMIWriteReadExact: pfnBufferCreate(%d) failed!", CRVBOXHGSMI_PAGE_ALIGN(cbWriteback)); - crFree(conn->pHostBuffer); - conn->cbHostBufferAllocated = cbWriteback; - conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated); + if (conn->cbHostBufferAllocated < cbWriteback) + { + crFree(conn->pHostBuffer); + conn->cbHostBufferAllocated = cbWriteback; + conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated); + } crVBoxHGCMReadExact(conn, NULL, cbWriteback); } } @@ -2415,9 +2310,6 @@ void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned /* Callback function used to free buffer pool entries */ void crVBoxHGCMBufferFree(void *data) { -#ifdef RT_OS_WINDOWS - LPDIRECTDRAWSURFACE lpDDS; -#endif CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data; CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC); @@ -2427,15 +2319,6 @@ void crVBoxHGCMBufferFree(void *data) case CR_VBOXHGCM_MEMORY: crFree( hgcm_buffer ); break; -#ifdef RT_OS_WINDOWS - case CR_VBOXHGCM_DDRAW_SURFACE: - lpDDS = hgcm_buffer->pDDS; - CRASSERT(lpDDS); - IDirectDrawSurface_Unlock(lpDDS, NULL); - IDirectDrawSurface_Release(lpDDS); - crDebug("DDraw surface freed (%x)\n", lpDDS); - break; -#endif case CR_VBOXHGCM_MEMORY_BIG: crFree( hgcm_buffer ); break; diff --git a/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c b/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c index 60d5ce21..3da3496a 100644 --- a/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c +++ b/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2010 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/GuestHost/OpenGL/util/vreg.cpp b/src/VBox/GuestHost/OpenGL/util/vreg.cpp new file mode 100644 index 00000000..e2cea3b3 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/util/vreg.cpp @@ -0,0 +1,1692 @@ +/* $Id: vreg.cpp $ */ + +/** @file + * Visible Regions processing API implementation + */ + +/* + * Copyright (C) 2012 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_vreg.h> +#include <iprt/err.h> +#include <iprt/assert.h> +#include <iprt/asm.h> + +#include <cr_error.h> + +#ifdef DEBUG_misha +# define VBOXVDBG_VR_LAL_DISABLE +#endif + +#ifndef IN_RING0 +#include <iprt/memcache.h> +#ifndef VBOXVDBG_VR_LAL_DISABLE +static RTMEMCACHE g_VBoxVrLookasideList; +#define vboxVrRegLaAlloc(_c) RTMemCacheAlloc((_c)) +#define vboxVrRegLaFree(_c, _e) RTMemCacheFree((_c), (_e)) +DECLINLINE(int) vboxVrLaCreate(RTMEMCACHE *pCache, size_t cbElement) +{ + int rc = RTMemCacheCreate(pCache, cbElement, + 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)) + { + WARN(("RTMemCacheCreate failed rc %d", rc)); + return rc; + } + return VINF_SUCCESS; +} +#define vboxVrLaDestroy(_c) RTMemCacheDestroy((_c)) +#endif +#else +# ifdef RT_OS_WINDOWS +# ifdef PAGE_SIZE +# undef PAGE_SIZE +# endif +# ifdef PAGE_SHIFT +# undef PAGE_SHIFT +# endif +# define VBOX_WITH_WORKAROUND_MISSING_PACK +# if (_MSC_VER >= 1400) && !defined(VBOX_WITH_PATCHED_DDK) +# define _InterlockedExchange _InterlockedExchange_StupidDDKVsCompilerCrap +# define _InterlockedExchangeAdd _InterlockedExchangeAdd_StupidDDKVsCompilerCrap +# define _InterlockedCompareExchange _InterlockedCompareExchange_StupidDDKVsCompilerCrap +# define _InterlockedAddLargeStatistic _InterlockedAddLargeStatistic_StupidDDKVsCompilerCrap +# define _interlockedbittestandset _interlockedbittestandset_StupidDDKVsCompilerCrap +# define _interlockedbittestandreset _interlockedbittestandreset_StupidDDKVsCompilerCrap +# define _interlockedbittestandset64 _interlockedbittestandset64_StupidDDKVsCompilerCrap +# define _interlockedbittestandreset64 _interlockedbittestandreset64_StupidDDKVsCompilerCrap +# pragma warning(disable : 4163) +# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK +# pragma warning(disable : 4103) +# endif +# include <ntddk.h> +# pragma warning(default : 4163) +# ifdef VBOX_WITH_WORKAROUND_MISSING_PACK +# pragma pack() +# pragma warning(default : 4103) +# endif +# undef _InterlockedExchange +# undef _InterlockedExchangeAdd +# undef _InterlockedCompareExchange +# undef _InterlockedAddLargeStatistic +# undef _interlockedbittestandset +# undef _interlockedbittestandreset +# undef _interlockedbittestandset64 +# undef _interlockedbittestandreset64 +# else +# include <ntddk.h> +# endif +#ifndef VBOXVDBG_VR_LAL_DISABLE +static LOOKASIDE_LIST_EX g_VBoxVrLookasideList; +#define vboxVrRegLaAlloc(_c) ExAllocateFromLookasideListEx(&(_c)) +#define vboxVrRegLaFree(_c, _e) ExFreeToLookasideListEx(&(_c), (_e)) +#define VBOXWDDMVR_MEMTAG 'vDBV' +DECLINLINE(int) vboxVrLaCreate(LOOKASIDE_LIST_EX *pCache, size_t cbElement) +{ + NTSTATUS Status = ExInitializeLookasideListEx(pCache, + NULL, /* PALLOCATE_FUNCTION_EX Allocate */ + NULL, /* PFREE_FUNCTION_EX Free */ + NonPagedPool, + 0, /* ULONG Flags */ + cbElement, + VBOXWDDMVR_MEMTAG, + 0 /* USHORT Depth - reserved, must be null */ + ); + if (!NT_SUCCESS(Status)) + { + WARN(("ExInitializeLookasideListEx failed, Status (0x%x)", Status)); + return VERR_GENERAL_FAILURE; + } + + return VINF_SUCCESS; +} +#define vboxVrLaDestroy(_c) ExDeleteLookasideListEx(&(_c)) +#endif +# else +# error "port me!" +# endif +#endif + +static volatile int32_t g_cVBoxVrInits = 0; + +static PVBOXVR_REG vboxVrRegCreate() +{ +#ifndef VBOXVDBG_VR_LAL_DISABLE + PVBOXVR_REG pReg = (PVBOXVR_REG)vboxVrRegLaAlloc(g_VBoxVrLookasideList); + if (!pReg) + { + WARN(("ExAllocateFromLookasideListEx failed!")); + } + return pReg; +#else + return (PVBOXVR_REG)RTMemAlloc(sizeof (VBOXVR_REG)); +#endif +} + +static void vboxVrRegTerm(PVBOXVR_REG pReg) +{ +#ifndef VBOXVDBG_VR_LAL_DISABLE + vboxVrRegLaFree(g_VBoxVrLookasideList, pReg); +#else + RTMemFree(pReg); +#endif +} + +VBOXVREGDECL(void) VBoxVrListClear(PVBOXVR_LIST pList) +{ + PVBOXVR_REG pReg, pRegNext; + + RTListForEachSafe(&pList->ListHead, pReg, pRegNext, VBOXVR_REG, ListEntry) + { + vboxVrRegTerm(pReg); + } + VBoxVrListInit(pList); +} + +/* moves list data to pDstList and empties the pList */ +VBOXVREGDECL(void) VBoxVrListMoveTo(PVBOXVR_LIST pList, PVBOXVR_LIST pDstList) +{ + *pDstList = *pList; + pDstList->ListHead.pNext->pPrev = &pDstList->ListHead; + pDstList->ListHead.pPrev->pNext = &pDstList->ListHead; + VBoxVrListInit(pList); +} + +#define VBOXVR_MEMTAG 'vDBV' + +VBOXVREGDECL(int) VBoxVrInit() +{ + int32_t cNewRefs = ASMAtomicIncS32(&g_cVBoxVrInits); + Assert(cNewRefs >= 1); + Assert(cNewRefs == 1); /* <- debugging */ + if (cNewRefs > 1) + return VINF_SUCCESS; + +#ifndef VBOXVDBG_VR_LAL_DISABLE + int rc = vboxVrLaCreate(&g_VBoxVrLookasideList, sizeof (VBOXVR_REG)); + if (!RT_SUCCESS(rc)) + { + WARN(("ExInitializeLookasideListEx failed, rc (%d)", rc)); + return rc; + } +#endif + + return VINF_SUCCESS; +} + +VBOXVREGDECL(void) VBoxVrTerm() +{ + int32_t cNewRefs = ASMAtomicDecS32(&g_cVBoxVrInits); + Assert(cNewRefs >= 0); + if (cNewRefs > 0) + return; + +#ifndef VBOXVDBG_VR_LAL_DISABLE + vboxVrLaDestroy(g_VBoxVrLookasideList); +#endif +} + +typedef DECLCALLBACK(int) FNVBOXVR_CB_COMPARATOR(const VBOXVR_REG *pReg1, const VBOXVR_REG *pReg2); +typedef FNVBOXVR_CB_COMPARATOR *PFNVBOXVR_CB_COMPARATOR; + +static DECLCALLBACK(int) vboxVrRegNonintersectedComparator(const RTRECT* pRect1, const RTRECT* pRect2) +{ + Assert(!VBoxRectIsIntersect(pRect1, pRect2)); + if (pRect1->yTop != pRect2->yTop) + return pRect1->yTop - pRect2->yTop; + return pRect1->xLeft - pRect2->xLeft; +} + +#ifdef DEBUG_misha +static void vboxVrDbgListDoVerify(PVBOXVR_LIST pList) +{ + PVBOXVR_REG pReg1, pReg2; + RTListForEach(&pList->ListHead, pReg1, VBOXVR_REG, ListEntry) + { + Assert(!VBoxRectIsZero(&pReg1->Rect)); + for (RTLISTNODE *pEntry2 = pReg1->ListEntry.pNext; pEntry2 != &pList->ListHead; pEntry2 = pEntry2->pNext) + { + pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2); + Assert(vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0); + } + } +} + +#define vboxVrDbgListVerify vboxVrDbgListDoVerify +#else +#define vboxVrDbgListVerify(_p) do {} while (0) +#endif + +static int vboxVrListUniteIntersection(PVBOXVR_LIST pList, PVBOXVR_LIST pIntersection); + +#define VBOXVR_INVALID_COORD (~0U) + +DECLINLINE(void) vboxVrListRegAdd(PVBOXVR_LIST pList, PVBOXVR_REG pReg, PRTLISTNODE pPlace, bool fAfter) +{ + if (fAfter) + RTListPrepend(pPlace, &pReg->ListEntry); + else + RTListAppend(pPlace, &pReg->ListEntry); + ++pList->cEntries; + vboxVrDbgListVerify(pList); +} + +DECLINLINE(void) vboxVrListRegRemove(PVBOXVR_LIST pList, PVBOXVR_REG pReg) +{ + RTListNodeRemove(&pReg->ListEntry); + --pList->cEntries; + vboxVrDbgListVerify(pList); +} + +static void vboxVrListRegAddOrder(PVBOXVR_LIST pList, PRTLISTNODE pMemberEntry, PVBOXVR_REG pReg) +{ + do + { + if (pMemberEntry != &pList->ListHead) + { + PVBOXVR_REG pMemberReg = PVBOXVR_REG_FROM_ENTRY(pMemberEntry); + if (vboxVrRegNonintersectedComparator(&pMemberReg->Rect, &pReg->Rect) < 0) + { + pMemberEntry = pMemberEntry->pNext; + continue; + } + } + vboxVrListRegAdd(pList, pReg, pMemberEntry, false); + break; + } while (1); +} + +static void vboxVrListAddNonintersected(PVBOXVR_LIST pList1, PVBOXVR_LIST pList2) +{ + PRTLISTNODE pEntry1 = pList1->ListHead.pNext; + + for (PRTLISTNODE pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pList2->ListHead.pNext) + { + PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2); + do { + if (pEntry1 != &pList1->ListHead) + { + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + if (vboxVrRegNonintersectedComparator(&pReg1->Rect, &pReg2->Rect) < 0) + { + pEntry1 = pEntry1->pNext; + continue; + } + } + vboxVrListRegRemove(pList2, pReg2); + vboxVrListRegAdd(pList1, pReg2, pEntry1, false); + break; + } while (1); + } + + Assert(VBoxVrListIsEmpty(pList2)); +} + +static int vboxVrListRegIntersectSubstNoJoin(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2) +{ + uint32_t topLim = VBOXVR_INVALID_COORD; + uint32_t bottomLim = VBOXVR_INVALID_COORD; + RTLISTNODE List; + PVBOXVR_REG pBottomReg = NULL; +#ifdef DEBUG_misha + RTRECT tmpRect = pReg1->Rect; + vboxVrDbgListVerify(pList1); +#endif + Assert(!VBoxRectIsZero(pRect2)); + + RTListInit(&List); + + Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2)); + + if (pReg1->Rect.yTop < pRect2->yTop) + { + Assert(pRect2->yTop < pReg1->Rect.yBottom); + PVBOXVR_REG pRegResult = vboxVrRegCreate(); + pRegResult->Rect.yTop = pReg1->Rect.yTop; + pRegResult->Rect.xLeft = pReg1->Rect.xLeft; + pRegResult->Rect.yBottom = pRect2->yTop; + pRegResult->Rect.xRight = pReg1->Rect.xRight; + topLim = pRect2->yTop; + RTListAppend(&List, &pRegResult->ListEntry); + } + + if (pReg1->Rect.yBottom > pRect2->yBottom) + { + Assert(pRect2->yBottom > pReg1->Rect.yTop); + PVBOXVR_REG pRegResult = vboxVrRegCreate(); + pRegResult->Rect.yTop = pRect2->yBottom; + pRegResult->Rect.xLeft = pReg1->Rect.xLeft; + pRegResult->Rect.yBottom = pReg1->Rect.yBottom; + pRegResult->Rect.xRight = pReg1->Rect.xRight; + bottomLim = pRect2->yBottom; + pBottomReg = pRegResult; + } + + if (pReg1->Rect.xLeft < pRect2->xLeft) + { + Assert(pRect2->xLeft < pReg1->Rect.xRight); + PVBOXVR_REG pRegResult = vboxVrRegCreate(); + pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim; + pRegResult->Rect.xLeft = pReg1->Rect.xLeft; + pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim; + pRegResult->Rect.xRight = pRect2->xLeft; + RTListAppend(&List, &pRegResult->ListEntry); + } + + if (pReg1->Rect.xRight > pRect2->xRight) + { + Assert(pRect2->xRight > pReg1->Rect.xLeft); + PVBOXVR_REG pRegResult = vboxVrRegCreate(); + pRegResult->Rect.yTop = topLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yTop : topLim; + pRegResult->Rect.xLeft = pRect2->xRight; + pRegResult->Rect.yBottom = bottomLim == VBOXVR_INVALID_COORD ? pReg1->Rect.yBottom : bottomLim; + pRegResult->Rect.xRight = pReg1->Rect.xRight; + RTListAppend(&List, &pRegResult->ListEntry); + } + + if (pBottomReg) + RTListAppend(&List, &pBottomReg->ListEntry); + + PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext; + vboxVrListRegRemove(pList1, pReg1); + vboxVrRegTerm(pReg1); + + if (RTListIsEmpty(&List)) + return VINF_SUCCESS; /* the region is covered by the pRect2 */ + + PRTLISTNODE pEntry = List.pNext, pNext; + for (; pEntry != &List; pEntry = pNext) + { + pNext = pEntry->pNext; + PVBOXVR_REG pReg = PVBOXVR_REG_FROM_ENTRY(pEntry); + + vboxVrListRegAddOrder(pList1, pMemberEntry, pReg); + pMemberEntry = pEntry->pNext; /* the following elements should go after the given pEntry since they are ordered already */ + } + return VINF_SUCCESS; +} + +/* @returns Entry to be used for continuing the rectangles iterations being made currently on the callback call. + * ListHead is returned to break the current iteration + * @param ppNext specifies next reg entry to be used for iteration. the default is pReg1->ListEntry.pNext */ +typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_INTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT * pRect2, void *pvContext, PRTLISTNODE *ppNext); +typedef FNVBOXVR_CB_INTERSECTED_VISITOR *PFNVBOXVR_CB_INTERSECTED_VISITOR; + +static void vboxVrListVisitIntersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_INTERSECTED_VISITOR pfnVisitor, void* pvVisitor) +{ + PRTLISTNODE pEntry1 = pList1->ListHead.pNext; + PRTLISTNODE pNext1; + uint32_t iFirst2 = 0; + + for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1) + { + pNext1 = pEntry1->pNext; + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + for (uint32_t i = iFirst2; i < cRects; ++i) + { + const RTRECT *pRect2 = &aRects[i]; + if (VBoxRectIsZero(pRect2)) + continue; + + if (!VBoxRectIsIntersect(&pReg1->Rect, pRect2)) + continue; + + /* the visitor can modify the list 1, apply necessary adjustments after it */ + pEntry1 = pfnVisitor (pList1, pReg1, pRect2, pvVisitor, &pNext1); + if (pEntry1 == &pList1->ListHead) + break; + else + pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + } + } +} + +/* @returns Entry to be iterated next. ListHead is returned to break the iteration + * + */ +typedef DECLCALLBACK(PRTLISTNODE) FNVBOXVR_CB_NONINTERSECTED_VISITOR(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext); +typedef FNVBOXVR_CB_NONINTERSECTED_VISITOR *PFNVBOXVR_CB_NONINTERSECTED_VISITOR; + +static void vboxVrListVisitNonintersected(PVBOXVR_LIST pList1, uint32_t cRects, const RTRECT *aRects, PFNVBOXVR_CB_NONINTERSECTED_VISITOR pfnVisitor, void* pvVisitor) +{ + PRTLISTNODE pEntry1 = pList1->ListHead.pNext; + PRTLISTNODE pNext1; + uint32_t iFirst2 = 0; + + for (; pEntry1 != &pList1->ListHead; pEntry1 = pNext1) + { + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + uint32_t i = iFirst2; + for (; i < cRects; ++i) + { + const RTRECT *pRect2 = &aRects[i]; + if (VBoxRectIsZero(pRect2)) + continue; + + if (VBoxRectIsIntersect(&pReg1->Rect, pRect2)) + break; + } + + if (i == cRects) + pNext1 = pfnVisitor(pList1, pReg1, pvVisitor); + else + pNext1 = pEntry1->pNext; + } +} + +static void vboxVrListJoinRectsHV(PVBOXVR_LIST pList, bool fHorizontal) +{ + PRTLISTNODE pNext1, pNext2; + + for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1) + { + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + pNext1 = pEntry1->pNext; + for (PRTLISTNODE pEntry2 = pEntry1->pNext; pEntry2 != &pList->ListHead; pEntry2 = pNext2) + { + PVBOXVR_REG pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2); + pNext2 = pEntry2->pNext; + if (fHorizontal) + { + if (pReg1->Rect.yTop == pReg2->Rect.yTop) + { + if (pReg1->Rect.xRight == pReg2->Rect.xLeft) + { + /* join rectangles */ + vboxVrListRegRemove(pList, pReg2); + if (pReg1->Rect.yBottom > pReg2->Rect.yBottom) + { + int32_t oldRight1 = pReg1->Rect.xRight; + int32_t oldBottom1 = pReg1->Rect.yBottom; + pReg1->Rect.xRight = pReg2->Rect.xRight; + pReg1->Rect.yBottom = pReg2->Rect.yBottom; + + vboxVrDbgListVerify(pList); + + pReg2->Rect.xLeft = pReg1->Rect.xLeft; + pReg2->Rect.yTop = pReg1->Rect.yBottom; + pReg2->Rect.xRight = oldRight1; + pReg2->Rect.yBottom = oldBottom1; + vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2); + /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension + * and thus can match one of the previous rects */ + pNext1 = pList->ListHead.pNext; + break; + } + else if (pReg1->Rect.yBottom < pReg2->Rect.yBottom) + { + pReg1->Rect.xRight = pReg2->Rect.xRight; + vboxVrDbgListVerify(pList); + pReg2->Rect.yTop = pReg1->Rect.yBottom; + vboxVrListRegAddOrder(pList, pReg1->ListEntry.pNext, pReg2); + /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension + * and thus can match one of the previous rects */ + pNext1 = pList->ListHead.pNext; + break; + } + else + { + pReg1->Rect.xRight = pReg2->Rect.xRight; + vboxVrDbgListVerify(pList); + /* reset the pNext1 since it could be the pReg2 being destroyed */ + pNext1 = pEntry1->pNext; + /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */ + vboxVrRegTerm(pReg2); + } + } + continue; + } + else if (pReg1->Rect.yBottom == pReg2->Rect.yBottom) + { + Assert(pReg1->Rect.yTop < pReg2->Rect.yTop); /* <- since pReg1 > pReg2 && pReg1->Rect.yTop != pReg2->Rect.yTop*/ + if (pReg1->Rect.xRight == pReg2->Rect.xLeft) + { + /* join rectangles */ + vboxVrListRegRemove(pList, pReg2); + + pReg1->Rect.yBottom = pReg2->Rect.yTop; + vboxVrDbgListVerify(pList); + pReg2->Rect.xLeft = pReg1->Rect.xLeft; + + vboxVrListRegAddOrder(pList, pNext2, pReg2); + + /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension + * and thus can match one of the previous rects */ + pNext1 = pList->ListHead.pNext; + break; + } + else if (pReg1->Rect.xLeft == pReg2->Rect.xRight) + { + /* join rectangles */ + vboxVrListRegRemove(pList, pReg2); + + pReg1->Rect.yBottom = pReg2->Rect.yTop; + vboxVrDbgListVerify(pList); + pReg2->Rect.xRight = pReg1->Rect.xRight; + + vboxVrListRegAddOrder(pList, pNext2, pReg2); + + /* restart the pNext1 & pNext2 since regs are splitted into smaller ones in y dimension + * and thus can match one of the previous rects */ + pNext1 = pList->ListHead.pNext; + break; + } + continue; + } + } + else + { + if (pReg1->Rect.yBottom == pReg2->Rect.yTop) + { + if (pReg1->Rect.xLeft == pReg2->Rect.xLeft) + { + if (pReg1->Rect.xRight == pReg2->Rect.xRight) + { + /* join rects */ + vboxVrListRegRemove(pList, pReg2); + + pReg1->Rect.yBottom = pReg2->Rect.yBottom; + vboxVrDbgListVerify(pList); + + /* reset the pNext1 since it could be the pReg2 being destroyed */ + pNext1 = pEntry1->pNext; + /* pNext2 stays the same since it is pReg2->ListEntry.pNext, which is kept intact */ + vboxVrRegTerm(pReg2); + continue; + } + /* no more to be done for for pReg1 */ + break; + } + else if (pReg1->Rect.xRight > pReg2->Rect.xLeft) + { + /* no more to be done for for pReg1 */ + break; + } + + continue; + } + else if (pReg1->Rect.yBottom < pReg2->Rect.yTop) + { + /* no more to be done for for pReg1 */ + break; + } + } + } + } +} + +static void vboxVrListJoinRects(PVBOXVR_LIST pList) +{ + vboxVrListJoinRectsHV(pList, true); + vboxVrListJoinRectsHV(pList, false); +} + +typedef struct VBOXVR_CBDATA_SUBST +{ + int rc; + bool fChanged; +} VBOXVR_CBDATA_SUBST, *PVBOXVR_CBDATA_SUBST; + +static DECLCALLBACK(PRTLISTNODE) vboxVrListSubstNoJoinCb(PVBOXVR_LIST pList, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext) +{ + PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext; + /* store the prev to get the new pNext out of it*/ + PRTLISTNODE pPrev = pReg1->ListEntry.pPrev; + pData->fChanged = true; + + Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2)); + + /* NOTE: the pReg1 will be invalid after the vboxVrListRegIntersectSubstNoJoin call!!! */ + int rc = vboxVrListRegIntersectSubstNoJoin(pList, pReg1, pRect2); + if (RT_SUCCESS(rc)) + { + *ppNext = pPrev->pNext; + return &pList->ListHead; + } + WARN(("vboxVrListRegIntersectSubstNoJoin failed!")); + Assert(!RT_SUCCESS(rc)); + pData->rc = rc; + *ppNext = &pList->ListHead; + return &pList->ListHead; +} + +static int vboxVrListSubstNoJoin(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged) +{ + if (pfChanged) + *pfChanged = false; + + if (VBoxVrListIsEmpty(pList)) + return VINF_SUCCESS; + + VBOXVR_CBDATA_SUBST Data; + Data.rc = VINF_SUCCESS; + Data.fChanged = false; + + vboxVrListVisitIntersected(pList, cRects, aRects, vboxVrListSubstNoJoinCb, &Data); + if (!RT_SUCCESS(Data.rc)) + { + WARN(("vboxVrListVisitIntersected failed!")); + return Data.rc; + } + + if (pfChanged) + *pfChanged = Data.fChanged; + + return VINF_SUCCESS; +} + +#if 0 +static const RTRECT * vboxVrRectsOrder(uint32_t cRects, const RTRECT * aRects) +{ +#ifdef DEBUG + { + for (uint32_t i = 0; i < cRects; ++i) + { + RTRECT *pRectI = &aRects[i]; + for (uint32_t j = i + 1; j < cRects; ++j) + { + RTRECT *pRectJ = &aRects[j]; + Assert(!VBoxRectIsIntersect(pRectI, pRectJ)); + } + } + } +#endif + + RTRECT * pRects = (RTRECT *)aRects; + /* check if rects are ordered already */ + for (uint32_t i = 0; i < cRects - 1; ++i) + { + RTRECT *pRect1 = &pRects[i]; + RTRECT *pRect2 = &pRects[i+1]; + if (vboxVrRegNonintersectedComparator(pRect1, pRect2) < 0) + continue; + + WARN(("rects are unoreded!")); + + if (pRects == aRects) + { + pRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cRects); + if (!pRects) + { + WARN(("RTMemAlloc failed!")); + return NULL; + } + + memcpy(pRects, aRects, sizeof (RTRECT) * cRects); + } + + Assert(pRects != aRects); + + int j = (int)i - 1; + do { + RTRECT Tmp = *pRect1; + *pRect1 = *pRect2; + *pRect2 = Tmp; + + if (j < 0) + break; + + if (vboxVrRegNonintersectedComparator(pRect1, pRect1-1) > 0) + break; + + pRect2 = pRect1--; + --j; + } while (1); + } + + return pRects; +} +#endif + +VBOXVREGDECL(void) VBoxVrListTranslate(PVBOXVR_LIST pList, int32_t x, int32_t y) +{ + for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext) + { + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + VBoxRectTranslate(&pReg1->Rect, x, y); + } +} + +static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinNonintersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, void *pvContext) +{ + VBOXVR_CBDATA_SUBST *pData = (VBOXVR_CBDATA_SUBST*)pvContext; + + PRTLISTNODE pNext = pReg1->ListEntry.pNext; + + vboxVrDbgListVerify(pList1); + + vboxVrListRegRemove(pList1, pReg1); + vboxVrRegTerm(pReg1); + + vboxVrDbgListVerify(pList1); + + pData->fChanged = true; + + return pNext; +} + +static DECLCALLBACK(PRTLISTNODE) vboxVrListIntersectNoJoinIntersectedCb(PVBOXVR_LIST pList1, PVBOXVR_REG pReg1, const RTRECT *pRect2, void *pvContext, PRTLISTNODE *ppNext) +{ + PVBOXVR_CBDATA_SUBST pData = (PVBOXVR_CBDATA_SUBST)pvContext; + pData->fChanged = true; + + vboxVrDbgListVerify(pList1); + + PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext; + + Assert(VBoxRectIsIntersect(&pReg1->Rect, pRect2)); + Assert(!VBoxRectIsZero(pRect2)); + + vboxVrListRegRemove(pList1, pReg1); + VBoxRectIntersect(&pReg1->Rect, pRect2); + Assert(!VBoxRectIsZero(&pReg1->Rect)); + + vboxVrListRegAddOrder(pList1, pMemberEntry, pReg1); + + vboxVrDbgListVerify(pList1); + + return &pReg1->ListEntry; +} + +static int vboxVrListIntersectNoJoin(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + bool fChanged = false; + *pfChanged = false; + + if (VBoxVrListIsEmpty(pList)) + return VINF_SUCCESS; + + if (VBoxVrListIsEmpty(pList2)) + { + if (pfChanged) + *pfChanged = true; + + VBoxVrListClear(pList); + return VINF_SUCCESS; + } + + PRTLISTNODE pNext1; + + for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pNext1) + { + pNext1 = pEntry1->pNext; + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + RTRECT RegRect1 = pReg1->Rect; + PRTLISTNODE pMemberEntry = pReg1->ListEntry.pNext; + + for (const RTLISTNODE *pEntry2 = pList2->ListHead.pNext; pEntry2 != &pList2->ListHead; pEntry2 = pEntry2->pNext) + { + const VBOXVR_REG *pReg2 = PVBOXVR_REG_FROM_ENTRY(pEntry2); + const RTRECT *pRect2 = &pReg2->Rect; + + if (!VBoxRectIsIntersect(&RegRect1, pRect2)) + continue; + + if (pReg1) + { + if (VBoxRectCovers(pRect2, &RegRect1)) + { + /* no change */ + + /* zero up the pReg1 to mark it as intersected (see the code after this inner loop) */ + pReg1 = NULL; + + if (!VBoxRectCmp(pRect2, &RegRect1)) + break; /* and we can break the iteration here */ + } + else + { + /*just to ensure the VBoxRectCovers is true for equal rects */ + Assert(VBoxRectCmp(pRect2, &RegRect1)); + + /* @todo: this can have false-alarming sometimes if the separated rects will then be joind into the original rect, + * so far this should not be a problem for VReg clients, so keep it this way for now */ + fChanged = true; + + /* re-use the reg entry */ + vboxVrListRegRemove(pList, pReg1); + VBoxRectIntersect(&pReg1->Rect, pRect2); + Assert(!VBoxRectIsZero(&pReg1->Rect)); + + vboxVrListRegAddOrder(pList, pMemberEntry, pReg1); + pReg1 = NULL; + } + } + else + { + Assert(fChanged); /* <- should be set by the if branch above */ + PVBOXVR_REG pReg = vboxVrRegCreate(); + if (!pReg) + { + WARN(("vboxVrRegCreate failed!")); + return VERR_NO_MEMORY; + } + VBoxRectIntersected(&RegRect1, pRect2, &pReg->Rect); + Assert(!VBoxRectIsZero(&pReg->Rect)); + vboxVrListRegAddOrder(pList, pList->ListHead.pNext, pReg); + } + } + + if (pReg1) + { + /* the region has no intersections, remove it */ + vboxVrListRegRemove(pList, pReg1); + vboxVrRegTerm(pReg1); + fChanged = true; + } + } + + *pfChanged = fChanged; + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) VBoxVrListIntersect(PVBOXVR_LIST pList, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + if (pfChanged) + *pfChanged = false; + + int rc = vboxVrListIntersectNoJoin(pList, pList2, pfChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("vboxVrListSubstNoJoin failed!")); + return rc; + } + + if (*pfChanged) + { + vboxVrListJoinRects(pList); + } + + return rc; +} + +VBOXVREGDECL(int) VBoxVrListRectsIntersect(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged) +{ + if (pfChanged) + *pfChanged = false; + + if (VBoxVrListIsEmpty(pList)) + return VINF_SUCCESS; + + if (!cRects) + { + if (pfChanged) + *pfChanged = true; + + VBoxVrListClear(pList); + return VINF_SUCCESS; + } + + /* we perform intersection using lists because the algorythm axpects the rects to be non-intersected, + * which list guaranties to us */ + + VBOXVR_LIST TmpList; + VBoxVrListInit(&TmpList); + + int rc = VBoxVrListRectsAdd(&TmpList, cRects, aRects, NULL); + if (RT_SUCCESS(rc)) + { + rc = VBoxVrListIntersect(pList, &TmpList, pfChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListIntersect failed! rc %d", rc)); + } + } + else + { + WARN(("VBoxVrListRectsAdd failed, rc %d", rc)); + } + VBoxVrListClear(&TmpList); + + return rc; +} + +VBOXVREGDECL(int) VBoxVrListRectsSubst(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged) +{ +#if 0 + const RTRECT * pRects = vboxVrRectsOrder(cRects, aRects); + if (!pRects) + { + WARN(("vboxVrRectsOrder failed!")); + return VERR_NO_MEMORY; + } +#endif + + bool fChanged = false; + + int rc = vboxVrListSubstNoJoin(pList, cRects, aRects, &fChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("vboxVrListSubstNoJoin failed!")); + goto done; + } + + if (fChanged) + goto done; + + vboxVrListJoinRects(pList); + +done: +#if 0 + if (pRects != aRects) + RTMemFree(pRects); +#endif + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) VBoxVrListRectsSet(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged) +{ + if (pfChanged) + *pfChanged = false; + + if (!cRects && VBoxVrListIsEmpty(pList)) + { + return VINF_SUCCESS; + } + + /* @todo: fChanged will have false alarming here, fix if needed */ + VBoxVrListClear(pList); + + int rc = VBoxVrListRectsAdd(pList, cRects, aRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsSet failed rc %d", rc)); + return rc; + } + + if (pfChanged) + *pfChanged = true; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) VBoxVrListRectsAdd(PVBOXVR_LIST pList, uint32_t cRects, const RTRECT * aRects, bool *pfChanged) +{ + uint32_t cCovered = 0; + + if (pfChanged) + *pfChanged = false; + +#if 0 +#ifdef DEBUG + { + for (uint32_t i = 0; i < cRects; ++i) + { + RTRECT *pRectI = &aRects[i]; + for (uint32_t j = i + 1; j < cRects; ++j) + { + RTRECT *pRectJ = &aRects[j]; + Assert(!VBoxRectIsIntersect(pRectI, pRectJ)); + } + } + } +#endif +#endif + + /* early sort out the case when there are no new rects */ + for (uint32_t i = 0; i < cRects; ++i) + { + if (VBoxRectIsZero(&aRects[i])) + { + cCovered++; + continue; + } + + for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext) + { + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + + if (VBoxRectCovers(&pReg1->Rect, &aRects[i])) + { + cCovered++; + break; + } + } + } + + if (cCovered == cRects) + return VINF_SUCCESS; + + /* rects are not covered, need to go the slow way */ + + VBOXVR_LIST DiffList; + VBoxVrListInit(&DiffList); + RTRECT * pListRects = NULL; + uint32_t cAllocatedRects = 0; + bool fNeedRectreate = true; + bool fChanged = false; + int rc = VINF_SUCCESS; + + for (uint32_t i = 0; i < cRects; ++i) + { + if (VBoxRectIsZero(&aRects[i])) + continue; + + PVBOXVR_REG pReg = vboxVrRegCreate(); + if (!pReg) + { + WARN(("vboxVrRegCreate failed!")); + rc = VERR_NO_MEMORY; + break; + } + pReg->Rect = aRects[i]; + + uint32_t cListRects = VBoxVrListRectsCount(pList); + if (!cListRects) + { + vboxVrListRegAdd(pList, pReg, &pList->ListHead, false); + fChanged = true; + continue; + } + else + { + Assert(VBoxVrListIsEmpty(&DiffList)); + vboxVrListRegAdd(&DiffList, pReg, &DiffList.ListHead, false); + } + + if (cAllocatedRects < cListRects) + { + cAllocatedRects = cListRects + cRects; + Assert(fNeedRectreate); + if (pListRects) + RTMemFree(pListRects); + pListRects = (RTRECT *)RTMemAlloc(sizeof (RTRECT) * cAllocatedRects); + if (!pListRects) + { + WARN(("RTMemAlloc failed!")); + rc = VERR_NO_MEMORY; + break; + } + } + + + if (fNeedRectreate) + { + rc = VBoxVrListRectsGet(pList, cListRects, pListRects); + Assert(rc == VINF_SUCCESS); + fNeedRectreate = false; + } + + bool fDummyChanged = false; + rc = vboxVrListSubstNoJoin(&DiffList, cListRects, pListRects, &fDummyChanged); + if (!RT_SUCCESS(rc)) + { + WARN(("vboxVrListSubstNoJoin failed!")); + rc = VERR_NO_MEMORY; + break; + } + + if (!VBoxVrListIsEmpty(&DiffList)) + { + vboxVrListAddNonintersected(pList, &DiffList); + fNeedRectreate = true; + fChanged = true; + } + + Assert(VBoxVrListIsEmpty(&DiffList)); + } + + if (pListRects) + RTMemFree(pListRects); + + Assert(VBoxVrListIsEmpty(&DiffList) || rc != VINF_SUCCESS); + VBoxVrListClear(&DiffList); + + if (fChanged) + vboxVrListJoinRects(pList); + + if (pfChanged) + *pfChanged = fChanged; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) VBoxVrListRectsGet(PVBOXVR_LIST pList, uint32_t cRects, RTRECT * aRects) +{ + if (cRects < VBoxVrListRectsCount(pList)) + return VERR_BUFFER_OVERFLOW; + + uint32_t i = 0; + for (PRTLISTNODE pEntry1 = pList->ListHead.pNext; pEntry1 != &pList->ListHead; pEntry1 = pEntry1->pNext, ++i) + { + PVBOXVR_REG pReg1 = PVBOXVR_REG_FROM_ENTRY(pEntry1); + aRects[i] = pReg1->Rect; + } + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) VBoxVrListCmp(const VBOXVR_LIST *pList1, const VBOXVR_LIST *pList2) +{ + int cTmp = pList1->cEntries - pList2->cEntries; + if (cTmp) + return cTmp; + + PVBOXVR_REG pReg1, pReg2; + + for (pReg1 = RTListNodeGetNext(&pList1->ListHead, VBOXVR_REG, ListEntry), + pReg2 = RTListNodeGetNext(&pList2->ListHead, VBOXVR_REG, ListEntry); + !RTListNodeIsDummy(&pList1->ListHead, pReg1, VBOXVR_REG, ListEntry); + pReg1 = RT_FROM_MEMBER(pReg1->ListEntry.pNext, VBOXVR_REG, ListEntry), + pReg2 = RT_FROM_MEMBER(pReg2->ListEntry.pNext, VBOXVR_REG, ListEntry)) + { + Assert(!RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry)); + cTmp = VBoxRectCmp(&pReg1->Rect, &pReg2->Rect); + if (cTmp) + return cTmp; + } + Assert(RTListNodeIsDummy(&pList2->ListHead, pReg2, VBOXVR_REG, ListEntry)); + return 0; +} + +VBOXVREGDECL(int) VBoxVrListClone(const VBOXVR_LIST *pList, VBOXVR_LIST *pDstList) +{ + VBoxVrListInit(pDstList); + const VBOXVR_REG *pReg; + RTListForEach(&pList->ListHead, pReg, const VBOXVR_REG, ListEntry) + { + PVBOXVR_REG pDstReg = vboxVrRegCreate(); + if (!pDstReg) + { + WARN(("vboxVrRegLaAlloc failed")); + VBoxVrListClear(pDstList); + return VERR_NO_MEMORY; + } + pDstReg->Rect = pReg->Rect; + vboxVrListRegAdd(pDstList, pDstReg, &pDstList->ListHead, true /*bool fAfter*/); + } + + Assert(pDstList->cEntries == pList->cEntries); + + return VINF_SUCCESS; +} + +VBOXVREGDECL(void) VBoxVrCompositorInit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_ENTRY_RELEASED pfnEntryReleased) +{ + RTListInit(&pCompositor->List); + pCompositor->pfnEntryReleased = pfnEntryReleased; +} + +VBOXVREGDECL(void) VBoxVrCompositorRegionsClear(PVBOXVR_COMPOSITOR pCompositor, bool *pfChanged) +{ + bool fChanged = false; + PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext; + RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node) + { + VBoxVrCompositorEntryRemove(pCompositor, pEntry); + fChanged = true; + } + + if (pfChanged) + *pfChanged = fChanged; +} + +VBOXVREGDECL(void) VBoxVrCompositorClear(PVBOXVR_COMPOSITOR pCompositor) +{ + VBoxVrCompositorRegionsClear(pCompositor, NULL); +} + +DECLINLINE(void) vboxVrCompositorEntryRelease(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry) +{ + if (--pEntry->cRefs) + { + Assert(pEntry->cRefs < UINT32_MAX/2); + return; + } + + Assert(!VBoxVrCompositorEntryIsInList(pEntry)); + + if (pCompositor->pfnEntryReleased) + pCompositor->pfnEntryReleased(pCompositor, pEntry, pReplacingEntry); +} + +DECLINLINE(void) vboxVrCompositorEntryAddRef(PVBOXVR_COMPOSITOR_ENTRY pEntry) +{ + ++pEntry->cRefs; +} + +DECLINLINE(void) vboxVrCompositorEntryAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry) +{ + RTListPrepend(&pCompositor->List, &pEntry->Node); + vboxVrCompositorEntryAddRef(pEntry); +} + +DECLINLINE(void) vboxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry) +{ + RTListNodeRemove(&pEntry->Node); + vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry); +} + +static void vboxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pReplacingEntry) +{ + VBoxVrListMoveTo(&pEntry->Vr, &pReplacingEntry->Vr); + + pReplacingEntry->Node = pEntry->Node; + pReplacingEntry->Node.pNext->pPrev = &pReplacingEntry->Node; + pReplacingEntry->Node.pPrev->pNext = &pReplacingEntry->Node; + pEntry->Node.pNext = NULL; + pEntry->Node.pPrev = NULL; + + vboxVrCompositorEntryAddRef(pReplacingEntry); + vboxVrCompositorEntryRelease(pCompositor, pEntry, pReplacingEntry); +} + + + +VBOXVREGDECL(void) VBoxVrCompositorEntryInit(PVBOXVR_COMPOSITOR_ENTRY pEntry) +{ + VBoxVrListInit(&pEntry->Vr); + pEntry->cRefs = 0; +} + +VBOXVREGDECL(bool) VBoxVrCompositorEntryRemove(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry) +{ + if (!VBoxVrCompositorEntryIsInList(pEntry)) + return false; + + vboxVrCompositorEntryAddRef(pEntry); + + VBoxVrListClear(&pEntry->Vr); + vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL); + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return true; +} + +VBOXVREGDECL(bool) VBoxVrCompositorEntryReplace(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, PVBOXVR_COMPOSITOR_ENTRY pNewEntry) +{ + if (!VBoxVrCompositorEntryIsInList(pEntry)) + return false; + + vboxVrCompositorEntryReplace(pCompositor, pEntry, pNewEntry); + + return true; +} + +static int vboxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged) +{ + bool fChanged; + vboxVrCompositorEntryAddRef(pEntry); + + int rc = VBoxVrListRectsSubst(&pEntry->Vr, cRects, paRects, &fChanged); + if (RT_SUCCESS(rc)) + { + if (VBoxVrListIsEmpty(&pEntry->Vr)) + { + Assert(fChanged); + vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL); + } + if (pfChanged) + *pfChanged = false; + } + else + WARN(("VBoxVrListRectsSubst failed, rc %d", rc)); + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return rc; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsAdd(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, PVBOXVR_COMPOSITOR_ENTRY *ppReplacedEntry, uint32_t *pfChangeFlags) +{ + bool fOthersChanged = false, fCurChanged = false, fEntryChanged = false, fEntryWasInList = false; + PVBOXVR_COMPOSITOR_ENTRY pCur, pNext, pReplacedEntry = NULL; + int rc = VINF_SUCCESS; + + if (pEntry) + vboxVrCompositorEntryAddRef(pEntry); + + if (!cRects) + { + if (pfChangeFlags) + *pfChangeFlags = 0; + if (pEntry) + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return VINF_SUCCESS; + } + + if (pEntry) + { + fEntryWasInList = VBoxVrCompositorEntryIsInList(pEntry); + rc = VBoxVrListRectsAdd(&pEntry->Vr, cRects, paRects, &fEntryChanged); + if (RT_SUCCESS(rc)) + { + if (VBoxVrListIsEmpty(&pEntry->Vr)) + { +// WARN(("Empty rectangles passed in, is it expected?")); + if (pfChangeFlags) + *pfChangeFlags = 0; + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return VINF_SUCCESS; + } + } + else + { + WARN(("VBoxVrListRectsAdd failed, rc %d", rc)); + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return rc; + } + + Assert(!VBoxVrListIsEmpty(&pEntry->Vr)); + } + else + { + fEntryChanged = true; + } + + RTListForEachSafe(&pCompositor->List, pCur, pNext, VBOXVR_COMPOSITOR_ENTRY, Node) + { + Assert(!VBoxVrListIsEmpty(&pCur->Vr)); + if (pCur != pEntry) + { + if (pEntry && !VBoxVrListCmp(&pCur->Vr, &pEntry->Vr)) + { + VBoxVrListClear(&pCur->Vr); + pReplacedEntry = pCur; + vboxVrCompositorEntryAddRef(pReplacedEntry); + vboxVrCompositorEntryRemove(pCompositor, pCur, pEntry); + if (ppReplacedEntry) + *ppReplacedEntry = pReplacedEntry; + break; + } + else + { + rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, &fCurChanged); + if (RT_SUCCESS(rc)) + fOthersChanged |= fCurChanged; + else + { + WARN(("vboxVrCompositorEntryRegionsSubst failed, rc %d", rc)); + return rc; + } + } + } + } + + AssertRC(rc); + + if (pEntry) + { + if (!fEntryWasInList) + { + Assert(!VBoxVrListIsEmpty(&pEntry->Vr)); + vboxVrCompositorEntryAdd(pCompositor, pEntry); + } + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + } + + uint32_t fFlags = 0; + if (fOthersChanged) + { + Assert(!pReplacedEntry); + fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_OTHER_ENTRIES_REGIONS_CHANGED; + } + else if (pReplacedEntry) + { + vboxVrCompositorEntryRelease(pCompositor, pReplacedEntry, pEntry); + Assert(fEntryChanged); + fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED; + } + else if (fEntryChanged) + { + Assert(!pReplacedEntry); + fFlags = VBOXVR_COMPOSITOR_CF_ENTRY_REGIONS_CHANGED | VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED; + } + else + { + Assert(!pReplacedEntry); + } + + if (!fEntryWasInList) + Assert(fEntryChanged); + + if (pfChangeFlags) + *pfChangeFlags = fFlags; + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSubst(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT * paRects, bool *pfChanged) +{ + if (!pEntry) + { + WARN(("VBoxVrCompositorEntryRegionsSubst called with zero entry, unsupported!")); + if (pfChanged) + *pfChanged = false; + return VERR_INVALID_PARAMETER; + } + + vboxVrCompositorEntryAddRef(pEntry); + + if (VBoxVrListIsEmpty(&pEntry->Vr)) + { + if (pfChanged) + *pfChanged = false; + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return VINF_SUCCESS; + } + + int rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pEntry, cRects, paRects, pfChanged); + if (!RT_SUCCESS(rc)) + WARN(("pfChanged failed, rc %d", rc)); + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + + return rc; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsSet(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged) +{ + if (!pEntry) + { + WARN(("VBoxVrCompositorEntryRegionsSet called with zero entry, unsupported!")); + if (pfChanged) + *pfChanged = false; + return VERR_INVALID_PARAMETER; + } + + vboxVrCompositorEntryAddRef(pEntry); + + bool fChanged = false, fCurChanged = false; + uint32_t fChangeFlags = 0; + int rc; + fCurChanged = VBoxVrCompositorEntryRemove(pCompositor, pEntry); + fChanged |= fCurChanged; + + rc = VBoxVrCompositorEntryRegionsAdd(pCompositor, pEntry, cRects, paRects, NULL, &fChangeFlags); + if (RT_SUCCESS(rc)) + { + fChanged |= !!fChangeFlags; + if (pfChanged) + *pfChanged = fChanged; + } + else + WARN(("VBoxVrCompositorEntryRegionsAdd failed, rc %d", rc)); + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + + return VINF_SUCCESS; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + int rc = VINF_SUCCESS; + bool fChanged = false; + + vboxVrCompositorEntryAddRef(pEntry); + + if (VBoxVrCompositorEntryIsInList(pEntry)) + { + rc = VBoxVrListIntersect(&pEntry->Vr, pList2, &fChanged); + if (RT_SUCCESS(rc)) + { + if (VBoxVrListIsEmpty(&pEntry->Vr)) + { + Assert(fChanged); + vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL); + } + } + else + { + WARN(("VBoxVrListRectsIntersect failed, rc %d", rc)); + } + } + + if (pfChanged) + *pfChanged = fChanged; + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + + return rc; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersect(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, uint32_t cRects, const RTRECT *paRects, bool *pfChanged) +{ + int rc = VINF_SUCCESS; + bool fChanged = false; + + vboxVrCompositorEntryAddRef(pEntry); + + if (VBoxVrCompositorEntryIsInList(pEntry)) + { + rc = VBoxVrListRectsIntersect(&pEntry->Vr, cRects, paRects, &fChanged); + if (RT_SUCCESS(rc)) + { + if (VBoxVrListIsEmpty(&pEntry->Vr)) + { + Assert(fChanged); + vboxVrCompositorEntryRemove(pCompositor, pEntry, NULL); + } + } + else + { + WARN(("VBoxVrListRectsIntersect failed, rc %d", rc)); + } + } + + if (pfChanged) + *pfChanged = fChanged; + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + + return rc; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryListIntersectAll(PVBOXVR_COMPOSITOR pCompositor, const VBOXVR_LIST *pList2, bool *pfChanged) +{ + VBOXVR_COMPOSITOR_ITERATOR Iter; + VBoxVrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_COMPOSITOR_ENTRY pEntry; + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL) + { + bool fTmpChanged = false; + int tmpRc = VBoxVrCompositorEntryListIntersect(pCompositor, pEntry, pList2, &fTmpChanged); + if (RT_SUCCESS(tmpRc)) + { + fChanged |= fChanged; + } + else + { + WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc)); + rc = tmpRc; + } + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsIntersectAll(PVBOXVR_COMPOSITOR pCompositor, uint32_t cRegions, const RTRECT *paRegions, bool *pfChanged) +{ + VBOXVR_COMPOSITOR_ITERATOR Iter; + VBoxVrCompositorIterInit(pCompositor, &Iter); + PVBOXVR_COMPOSITOR_ENTRY pEntry; + int rc = VINF_SUCCESS; + bool fChanged = false; + + while ((pEntry = VBoxVrCompositorIterNext(&Iter)) != NULL) + { + bool fTmpChanged = false; + int tmpRc = VBoxVrCompositorEntryRegionsIntersect(pCompositor, pEntry, cRegions, paRegions, &fTmpChanged); + if (RT_SUCCESS(tmpRc)) + { + fChanged |= fChanged; + } + else + { + WARN(("VBoxVrCompositorEntryRegionsIntersect failed, rc %d", tmpRc)); + rc = tmpRc; + } + } + + if (pfChanged) + *pfChanged = fChanged; + + return rc; +} + +VBOXVREGDECL(int) VBoxVrCompositorEntryRegionsTranslate(PVBOXVR_COMPOSITOR pCompositor, PVBOXVR_COMPOSITOR_ENTRY pEntry, int32_t x, int32_t y, bool *pfChanged) +{ + if (!pEntry) + { + WARN(("VBoxVrCompositorEntryRegionsTranslate called with zero entry, unsupported!")); + if (pfChanged) + *pfChanged = false; + return VERR_INVALID_PARAMETER; + } + + vboxVrCompositorEntryAddRef(pEntry); + + if ((!x && !y) + || !VBoxVrCompositorEntryIsInList(pEntry)) + { + if (pfChanged) + *pfChanged = false; + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + return VINF_SUCCESS; + } + + VBoxVrListTranslate(&pEntry->Vr, x, y); + + Assert(!VBoxVrListIsEmpty(&pEntry->Vr)); + + PVBOXVR_COMPOSITOR_ENTRY pCur; + uint32_t cRects = 0; + RTRECT *paRects = NULL; + int rc = VINF_SUCCESS; + RTListForEach(&pCompositor->List, pCur, VBOXVR_COMPOSITOR_ENTRY, Node) + { + Assert(!VBoxVrListIsEmpty(&pCur->Vr)); + + if (pCur == pEntry) + continue; + + if (!paRects) + { + cRects = VBoxVrListRectsCount(&pEntry->Vr); + Assert(cRects); + paRects = (RTRECT*)RTMemAlloc(cRects * sizeof (RTRECT)); + if (!paRects) + { + WARN(("RTMemAlloc failed!")); + rc = VERR_NO_MEMORY; + break; + } + + rc = VBoxVrListRectsGet(&pEntry->Vr, cRects, paRects); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsGet failed! rc %d", rc)); + break; + } + } + + rc = vboxVrCompositorEntryRegionsSubst(pCompositor, pCur, cRects, paRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("vboxVrCompositorEntryRegionsSubst failed! rc %d", rc)); + break; + } + } + + if (pfChanged) + *pfChanged = true; + + if (paRects) + RTMemFree(paRects); + + vboxVrCompositorEntryRelease(pCompositor, pEntry, NULL); + + return rc; +} + +VBOXVREGDECL(void) VBoxVrCompositorVisit(PVBOXVR_COMPOSITOR pCompositor, PFNVBOXVRCOMPOSITOR_VISITOR pfnVisitor, void *pvVisitor) +{ + PVBOXVR_COMPOSITOR_ENTRY pEntry, pEntryNext; + RTListForEachSafe(&pCompositor->List, pEntry, pEntryNext, VBOXVR_COMPOSITOR_ENTRY, Node) + { + if (!pfnVisitor(pCompositor, pEntry, pvVisitor)) + return; + } +} diff --git a/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp b/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp index 3834683b..ad96ece7 100644 --- a/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp +++ b/src/VBox/GuestHost/SharedClipboard/clipboard-helper.cpp @@ -4,9 +4,9 @@ */ /* - * Includes contributions from François Revol + * Includes contributions from François Revol * - * Copyright (C) 2006-2008 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; diff --git a/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp b/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp index 2dbfc859..d5cd9333 100644 --- a/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp +++ b/src/VBox/GuestHost/SharedClipboard/x11-clipboard.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2006-2007 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -53,7 +53,7 @@ #include <VBox/GuestHost/clipboard-helper.h> #include <VBox/HostServices/VBoxClipboardSvc.h> -static Atom clipGetAtom(Widget widget, const char *pszName); +static Atom clipGetAtom(CLIPBACKEND *pCtx, const char *pszName); /** The different clipboard formats which we support. */ enum CLIPFORMAT @@ -61,8 +61,8 @@ enum CLIPFORMAT INVALID = 0, TARGETS, TEXT, /* Treat this as Utf8, but it may really be ascii */ - CTEXT, - UTF8 + UTF8, + BMP }; /** The table mapping X11 names to data formats and to the corresponding @@ -87,7 +87,10 @@ static struct _CLIPFORMATTABLE { "STRING", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT }, { "TEXT", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT }, { "text/plain", TEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT }, - { "COMPOUND_TEXT", CTEXT, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT } + { "image/bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP }, + { "image/x-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP }, + { "image/x-MS-bmp", BMP, VBOX_SHARED_CLIPBOARD_FMT_BITMAP }, + /* TODO: Inkscape exports image/png but not bmp... */ }; typedef unsigned CLIPX11FORMAT; @@ -101,9 +104,9 @@ enum /** Return the atom corresponding to a supported X11 format. * @param widget a valid Xt widget */ -static Atom clipAtomForX11Format(Widget widget, CLIPX11FORMAT format) +static Atom clipAtomForX11Format(CLIPBACKEND *pCtx, CLIPX11FORMAT format) { - return clipGetAtom(widget, g_aFormats[format].pcszAtom); + return clipGetAtom(pCtx, g_aFormats[format].pcszAtom); } /** Return the CLIPFORMAT corresponding to a supported X11 format. */ @@ -122,10 +125,22 @@ static uint32_t clipVBoxFormatForX11Format(CLIPX11FORMAT format) * @returns the format on success, NIL_CLIPX11FORMAT on failure * @param widget a valid Xt widget */ -static CLIPX11FORMAT clipFindX11FormatByAtom(Widget widget, Atom atomFormat) +static CLIPX11FORMAT clipFindX11FormatByAtom(CLIPBACKEND *pCtx, Atom atomFormat) { for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i) - if (clipAtomForX11Format(widget, i) == atomFormat) + if (clipAtomForX11Format(pCtx, i) == atomFormat) + return i; + return NIL_CLIPX11FORMAT; +} + +/** Lookup the X11 format matching a given X11 atom text. + * @returns the format on success, NIL_CLIPX11FORMAT on failure + * @param widget a valid Xt widget + */ +static CLIPX11FORMAT clipFindX11FormatByAtomText(const char *pcsz) +{ + for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i) + if (!strcmp(g_aFormats[i].pcszAtom, pcsz)) return i; return NIL_CLIPX11FORMAT; } @@ -187,6 +202,12 @@ struct _CLIPBACKEND void (*fixesSelectInput)(Display *, Window, Atom, unsigned long); /** The first XFixes event number */ int fixesEventBase; + /** The Xt Intrinsics can only handle one outstanding clipboard operation + * at a time, so we keep track of whether one is in process. */ + bool fBusy; + /** We can't handle a clipboard update event while we are busy, so remember + * it for later. */ + bool fUpdateNeeded; }; /** The number of simultaneous instances we support. For all normal purposes @@ -263,42 +284,40 @@ static CLIPBACKEND *clipLookupContext(Widget widget) /** Convert an atom name string to an X11 atom, looking it up in a cache * before asking the server */ -static Atom clipGetAtom(Widget widget, const char *pszName) +static Atom clipGetAtom(CLIPBACKEND *pCtx, const char *pszName) { AssertPtrReturn(pszName, None); - Atom retval = None; - XrmValue nameVal, atomVal; - nameVal.addr = (char *) pszName; - nameVal.size = strlen(pszName); - atomVal.size = sizeof(Atom); - atomVal.addr = (char *) &retval; - XtConvertAndStore(widget, XtRString, &nameVal, XtRAtom, &atomVal); - return retval; + return XInternAtom(XtDisplay(pCtx->widget), pszName, False); } -static void clipQueueToEventThread(CLIPBACKEND *pCtx, - XtTimerCallbackProc proc, - XtPointer client_data); +#ifdef TESTCASE +static void testQueueToEventThread(void (*proc)(void *, void *), + void *client_data); +#endif /** String written to the wakeup pipe. */ #define WAKE_UP_STRING "WakeUp!" /** Length of the string written. */ #define WAKE_UP_STRING_LEN ( sizeof(WAKE_UP_STRING) - 1 ) -#ifndef TESTCASE /** Schedule a function call to run on the Xt event thread by passing it to * the application context as a 0ms timeout and waking up the event loop by * writing to the wakeup pipe which it monitors. */ void clipQueueToEventThread(CLIPBACKEND *pCtx, - XtTimerCallbackProc proc, - XtPointer client_data) + void (*proc)(void *, void *), + void *client_data) { LogRel2(("clipQueueToEventThread: proc=%p, client_data=%p\n", proc, client_data)); - XtAppAddTimeOut(pCtx->appContext, 0, proc, client_data); - write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN); -} +#ifndef TESTCASE + XtAppAddTimeOut(pCtx->appContext, 0, (XtTimerCallbackProc)proc, + (XtPointer)client_data); + ssize_t cbWritten = write(pCtx->wakeupPipeWrite, WAKE_UP_STRING, WAKE_UP_STRING_LEN); + NOREF(cbWritten); +#else + testQueueToEventThread(proc, client_data); #endif +} /** * Report the formats currently supported by the X11 clipboard to VBox. @@ -306,6 +325,7 @@ void clipQueueToEventThread(CLIPBACKEND *pCtx, static void clipReportFormatsToVBox(CLIPBACKEND *pCtx) { uint32_t u32VBoxFormats = clipVBoxFormatForX11Format(pCtx->X11TextFormat); + u32VBoxFormats |= clipVBoxFormatForX11Format(pCtx->X11BitmapFormat); ClipReportX11Formats(pCtx->pFrontend, u32VBoxFormats); } @@ -328,13 +348,13 @@ static void clipReportEmptyX11CB(CLIPBACKEND *pCtx) /** * Go through an array of X11 clipboard targets to see if they contain a text * format we can support, and if so choose the ones we prefer (e.g. we like - * Utf8 better than compound text). + * Utf8 better than plain text). * @param pCtx the clipboard backend context structure * @param pTargets the list of targets * @param cTargets the size of the list in @a pTargets */ static CLIPX11FORMAT clipGetTextFormatFromTargets(CLIPBACKEND *pCtx, - Atom *pTargets, + CLIPX11FORMAT *pTargets, size_t cTargets) { CLIPX11FORMAT bestTextFormat = NIL_CLIPX11FORMAT; @@ -343,8 +363,7 @@ static CLIPX11FORMAT clipGetTextFormatFromTargets(CLIPBACKEND *pCtx, AssertReturn(VALID_PTR(pTargets) || cTargets == 0, NIL_CLIPX11FORMAT); for (unsigned i = 0; i < cTargets; ++i) { - CLIPX11FORMAT format = clipFindX11FormatByAtom(pCtx->widget, - pTargets[i]); + CLIPX11FORMAT format = pTargets[i]; if (format != NIL_CLIPX11FORMAT) { if ( (clipVBoxFormatForX11Format(format) @@ -363,18 +382,16 @@ static CLIPX11FORMAT clipGetTextFormatFromTargets(CLIPBACKEND *pCtx, static bool clipTestTextFormatConversion(CLIPBACKEND *pCtx) { bool success = true; - Atom targets[3]; + CLIPX11FORMAT targets[2]; CLIPX11FORMAT x11Format; - targets[0] = clipGetAtom(NULL, "COMPOUND_TEXT"); - targets[1] = clipGetAtom(NULL, "text/plain"); - targets[2] = clipGetAtom(NULL, "TARGETS"); - x11Format = clipGetTextFormatFromTargets(pCtx, targets, 3); - if (clipRealFormatForX11Format(x11Format) != CTEXT) + targets[0] = clipFindX11FormatByAtomText("text/plain"); + targets[1] = clipFindX11FormatByAtomText("image/bmp"); + x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2); + if (clipRealFormatForX11Format(x11Format) != TEXT) success = false; - targets[0] = clipGetAtom(NULL, "UTF8_STRING"); - targets[1] = clipGetAtom(NULL, "text/plain"); - targets[2] = clipGetAtom(NULL, "COMPOUND_TEXT"); - x11Format = clipGetTextFormatFromTargets(pCtx, targets, 3); + targets[0] = clipFindX11FormatByAtomText("UTF8_STRING"); + targets[1] = clipFindX11FormatByAtomText("text/plain"); + x11Format = clipGetTextFormatFromTargets(pCtx, targets, 2); if (clipRealFormatForX11Format(x11Format) != UTF8) success = false; return success; @@ -382,37 +399,68 @@ static bool clipTestTextFormatConversion(CLIPBACKEND *pCtx) #endif /** + * Go through an array of X11 clipboard targets to see if they contain a bitmap + * format we can support, and if so choose the ones we prefer (e.g. we like + * BMP better than PNG because we don't have to convert). + * @param pCtx the clipboard backend context structure + * @param pTargets the list of targets + * @param cTargets the size of the list in @a pTargets + */ +static CLIPX11FORMAT clipGetBitmapFormatFromTargets(CLIPBACKEND *pCtx, + CLIPX11FORMAT *pTargets, + size_t cTargets) +{ + CLIPX11FORMAT bestBitmapFormat = NIL_CLIPX11FORMAT; + CLIPFORMAT enmBestBitmapTarget = INVALID; + AssertPtrReturn(pCtx, NIL_CLIPX11FORMAT); + AssertReturn(VALID_PTR(pTargets) || cTargets == 0, NIL_CLIPX11FORMAT); + for (unsigned i = 0; i < cTargets; ++i) + { + CLIPX11FORMAT format = pTargets[i]; + if (format != NIL_CLIPX11FORMAT) + { + if ( (clipVBoxFormatForX11Format(format) + == VBOX_SHARED_CLIPBOARD_FMT_BITMAP) + && enmBestBitmapTarget < clipRealFormatForX11Format(format)) + { + enmBestBitmapTarget = clipRealFormatForX11Format(format); + bestBitmapFormat = format; + } + } + } + return bestBitmapFormat; +} + +/** * Go through an array of X11 clipboard targets to see if we can support any * of them and if relevant to choose the ones we prefer (e.g. we like Utf8 - * better than compound text). + * better than plain text). * @param pCtx the clipboard backend context structure * @param pTargets the list of targets * @param cTargets the size of the list in @a pTargets */ -static void clipGetFormatsFromTargets(CLIPBACKEND *pCtx, Atom *pTargets, - size_t cTargets) +static void clipGetFormatsFromTargets(CLIPBACKEND *pCtx, + CLIPX11FORMAT *pTargets, size_t cTargets) { AssertPtrReturnVoid(pCtx); AssertPtrReturnVoid(pTargets); CLIPX11FORMAT bestTextFormat; + CLIPX11FORMAT bestBitmapFormat; bestTextFormat = clipGetTextFormatFromTargets(pCtx, pTargets, cTargets); if (pCtx->X11TextFormat != bestTextFormat) { pCtx->X11TextFormat = bestTextFormat; -#if defined(DEBUG) && !defined(TESTCASE) - for (unsigned i = 0; i < cTargets; ++i) - if (pTargets[i]) - { - char *pszName = XGetAtomName(XtDisplay(pCtx->widget), - pTargets[i]); - LogRel2(("%s: found target %s\n", __PRETTY_FUNCTION__, pszName)); - XFree(pszName); - } -#endif } pCtx->X11BitmapFormat = INVALID; /* not yet supported */ + bestBitmapFormat = clipGetBitmapFormatFromTargets(pCtx, pTargets, cTargets); + if (pCtx->X11BitmapFormat != bestBitmapFormat) + { + pCtx->X11BitmapFormat = bestBitmapFormat; + } } +static void clipQueryX11CBFormats(CLIPBACKEND *pCtx); + /** * Update the context's information about targets currently supported by X11, * based on an array of X11 atoms. @@ -420,10 +468,23 @@ static void clipGetFormatsFromTargets(CLIPBACKEND *pCtx, Atom *pTargets, * @param pTargets the array of atoms describing the targets supported * @param cTargets the size of the array @a pTargets */ -static void clipUpdateX11Targets(CLIPBACKEND *pCtx, Atom *pTargets, +static void clipUpdateX11Targets(CLIPBACKEND *pCtx, CLIPX11FORMAT *pTargets, size_t cTargets) { - LogRel2 (("%s: called\n", __PRETTY_FUNCTION__)); + LogRel2 (("%s: called\n", __FUNCTION__)); + pCtx->fBusy = false; + if (pCtx->fUpdateNeeded) + { + /* We may already be out of date. */ + pCtx->fUpdateNeeded = false; + clipQueryX11CBFormats(pCtx); + return; + } + if (pTargets == NULL) { + /* No data available */ + clipReportEmptyX11CB(pCtx); + return; + } clipGetFormatsFromTargets(pCtx, pTargets, cTargets); clipReportFormatsToVBox(pCtx); } @@ -431,39 +492,89 @@ static void clipUpdateX11Targets(CLIPBACKEND *pCtx, Atom *pTargets, /** * Notify the VBox clipboard about available data formats, based on the * "targets" information obtained from the X11 clipboard. - * @note callback for XtGetSelectionValue + * @note Callback for XtGetSelectionValue + * @note This function is treated as API glue, and as such is not part of any + * unit test. So keep it simple, be paranoid and log everything. */ -static void clipConvertX11Targets(Widget, XtPointer pClientData, +static void clipConvertX11Targets(Widget widget, XtPointer pClientData, Atom * /* selection */, Atom *atomType, XtPointer pValue, long unsigned int *pcLen, int *piFormat) { CLIPBACKEND *pCtx = reinterpret_cast<CLIPBACKEND *>(pClientData); - LogRel2(("clipConvertX11Targets: pValue=%p, *pcLen=%u, *atomType=%d, XT_CONVERT_FAIL=%d\n", - pValue, *pcLen, *atomType, XT_CONVERT_FAIL)); - if ( (*atomType == XT_CONVERT_FAIL) /* timeout */ - || (pValue == NULL)) /* No data available */ + Atom *pAtoms = (Atom *)pValue; + unsigned i, j; + LogRel2(("%s: pValue=%p, *pcLen=%u, *atomType=%d%s\n", __FUNCTION__, + pValue, *pcLen, *atomType, + *atomType == XT_CONVERT_FAIL ? " (XT_CONVERT_FAIL)" : "")); + CLIPX11FORMAT *pFormats = NULL; + if (*pcLen && pValue && (*atomType != XT_CONVERT_FAIL /* time out */)) + pFormats = (CLIPX11FORMAT *)RTMemAllocZ(*pcLen * sizeof(CLIPX11FORMAT)); +#if defined(DEBUG) && !defined(TESTCASE) + if (pValue) + for (i = 0; i < *pcLen; ++i) + if (pAtoms[i]) + { + char *pszName = XGetAtomName(XtDisplay(widget), pAtoms[i]); + LogRel2(("%s: found target %s\n", __FUNCTION__, + pszName)); + XFree(pszName); + } + else + LogRel2(("%s: found empty target.\n", __FUNCTION__)); +#endif + if (pFormats) { - clipReportEmptyX11CB(pCtx); - return; + for (i = 0; i < *pcLen; ++i) + { + for (j = 0; j < RT_ELEMENTS(g_aFormats); ++j) + { + Atom target = XInternAtom(XtDisplay(widget), + g_aFormats[j].pcszAtom, False); + if (*(pAtoms + i) == target) + pFormats[i] = j; + } +#if defined(DEBUG) && !defined(TESTCASE) + LogRel2(("%s: reporting format %d (%s)\n", __FUNCTION__, + pFormats[i], g_aFormats[pFormats[i]].pcszAtom)); +#endif + } } - clipUpdateX11Targets(pCtx, (Atom *)pValue, *pcLen); + else + LogRel2(("%s: reporting empty targets (none reported or allocation failure).\n", + __FUNCTION__)); + clipUpdateX11Targets(pCtx, pFormats, *pcLen); + RTMemFree(pFormats); XtFree(reinterpret_cast<char *>(pValue)); } +#ifdef TESTCASE + void testRequestTargets(CLIPBACKEND *pCtx); +#endif + /** * Callback to notify us when the contents of the X11 clipboard change. */ -void clipQueryX11CBFormats(CLIPBACKEND *pCtx) +static void clipQueryX11CBFormats(CLIPBACKEND *pCtx) { LogRel2 (("%s: requesting the targets that the X11 clipboard offers\n", __PRETTY_FUNCTION__)); + if (pCtx->fBusy) + { + pCtx->fUpdateNeeded = true; + return; + } + pCtx->fBusy = true; +#ifndef TESTCASE XtGetSelectionValue(pCtx->widget, - clipGetAtom(pCtx->widget, "CLIPBOARD"), - clipGetAtom(pCtx->widget, "TARGETS"), + clipGetAtom(pCtx, "CLIPBOARD"), + clipGetAtom(pCtx, "TARGETS"), clipConvertX11Targets, pCtx, CurrentTime); +#else + testRequestTargets(pCtx); +#endif } #ifndef TESTCASE @@ -554,7 +665,7 @@ static void clipUninit(CLIPBACKEND *pCtx) /** Worker function for stopping the clipboard which runs on the event * thread. */ -static void clipStopEventThreadWorker(XtPointer pUserData, XtIntervalId *) +static void clipStopEventThreadWorker(void *pUserData, void *) { CLIPBACKEND *pCtx = (CLIPBACKEND *)pUserData; @@ -663,7 +774,7 @@ static int clipInit(CLIPBACKEND *pCtx) #ifndef TESTCASE /* Enable clipboard update notification */ pCtx->fixesSelectInput(pDisplay, XtWindow(pCtx->widget), - clipGetAtom(pCtx->widget, "CLIPBOARD"), + clipGetAtom(pCtx, "CLIPBOARD"), 7 /* All XFixes*Selection*NotifyMask flags */); #endif } @@ -845,15 +956,14 @@ static int clipCreateX11Targets(CLIPBACKEND *pCtx, Atom *atomTypeReturn, format = clipEnumX11Formats(pCtx->vboxFormats, format); if (format != NIL_CLIPX11FORMAT) { - atomTargets[cTargets] = clipAtomForX11Format(pCtx->widget, - format); + atomTargets[cTargets] = clipAtomForX11Format(pCtx, format); ++cTargets; } } while (format != NIL_CLIPX11FORMAT); /* We always offer these */ - atomTargets[cTargets] = clipGetAtom(pCtx->widget, "TARGETS"); - atomTargets[cTargets + 1] = clipGetAtom(pCtx->widget, "MULTIPLE"); - atomTargets[cTargets + 2] = clipGetAtom(pCtx->widget, "TIMESTAMP"); + atomTargets[cTargets] = clipGetAtom(pCtx, "TARGETS"); + atomTargets[cTargets + 1] = clipGetAtom(pCtx, "MULTIPLE"); + atomTargets[cTargets + 2] = clipGetAtom(pCtx, "TIMESTAMP"); *atomTypeReturn = XA_ATOM; *pValReturn = (XtPointer)atomTargets; *pcLenReturn = cTargets + 3; @@ -1009,83 +1119,14 @@ static int clipWinTxtToUtf8ForX11CB(Display *pDisplay, PRTUTF16 pwszSrc, } /** - * Satisfy a request from X11 to convert the clipboard text to - * COMPOUND_TEXT. We return null-terminated text, but can cope with non-null- - * terminated input. - * - * @returns iprt status code - * @param pDisplay an X11 display structure, needed for conversions - * performed by Xlib - * @param pv the text to be converted (UCS-2 with Windows EOLs) - * @param cb the length of the text in @cb in bytes - * @param atomTypeReturn where to store the atom for the type of the data - * we are returning - * @param pValReturn where to store the pointer to the data we are - * returning. This should be to memory allocated by - * XtMalloc, which will be freed by the Xt toolkit - * later. - * @param pcLenReturn where to store the length of the data we are - * returning - * @param piFormatReturn where to store the bit width (8, 16, 32) of the - * data we are returning - */ -static int clipWinTxtToCTextForX11CB(Display *pDisplay, PRTUTF16 pwszSrc, - size_t cbSrc, Atom *atomTypeReturn, - XtPointer *pValReturn, - unsigned long *pcLenReturn, - int *piFormatReturn) -{ - char *pszTmp = NULL, *pszTmp2 = NULL; - size_t cbTmp = 0, cbActual = 0; - XTextProperty property; - int rc = VINF_SUCCESS, xrc = 0; - - LogRelFlowFunc(("pwszSrc=%.*ls, cbSrc=%u\n", cbSrc / 2, pwszSrc, cbSrc)); - AssertPtrReturn(pDisplay, false); - AssertPtrReturn(pwszSrc, false); - rc = clipWinTxtBufSizeForUtf8(pwszSrc, cbSrc / 2, &cbTmp); - if (RT_SUCCESS(rc)) - { - pszTmp = (char *)RTMemAlloc(cbTmp); - if (!pszTmp) - rc = VERR_NO_MEMORY; - } - if (RT_SUCCESS(rc)) - rc = clipWinTxtToUtf8(pwszSrc, cbSrc, pszTmp, cbTmp + 1, - &cbActual); - /* Convert the Utf8 text to the current encoding (usually a noop). */ - if (RT_SUCCESS(rc)) - rc = RTStrUtf8ToCurrentCP(&pszTmp2, pszTmp); - /* And finally (!) convert the resulting text to compound text. */ - if (RT_SUCCESS(rc)) - xrc = XmbTextListToTextProperty(pDisplay, &pszTmp2, 1, - XCompoundTextStyle, &property); - if (RT_SUCCESS(rc) && xrc < 0) - rc = ( xrc == XNoMemory ? VERR_NO_MEMORY - : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED - : xrc == XConverterNotFound ? VERR_NOT_SUPPORTED - : VERR_UNRESOLVED_ERROR); - RTMemFree(pszTmp); - RTStrFree(pszTmp2); - *atomTypeReturn = property.encoding; - *pValReturn = reinterpret_cast<XtPointer>(property.value); - *pcLenReturn = property.nitems + 1; - *piFormatReturn = property.format; - LogRelFlowFunc(("returning %Rrc\n", rc)); - if (RT_SUCCESS(rc)) - LogRelFlowFunc (("converted string is %s\n", property.value)); - return rc; -} - -/** * Does this atom correspond to one of the two selection types we support? * @param widget a valid Xt widget * @param selType the atom in question */ -static bool clipIsSupportedSelectionType(Widget widget, Atom selType) +static bool clipIsSupportedSelectionType(CLIPBACKEND *pCtx, Atom selType) { - return( (selType == clipGetAtom(widget, "CLIPBOARD")) - || (selType == clipGetAtom(widget, "PRIMARY"))); + return( (selType == clipGetAtom(pCtx, "CLIPBOARD")) + || (selType == clipGetAtom(pCtx, "PRIMARY"))); } /** @@ -1100,7 +1141,7 @@ static void clipTrimTrailingNul(XtPointer pText, unsigned long *pcText, { AssertPtrReturnVoid(pText); AssertPtrReturnVoid(pcText); - AssertReturnVoid((format == UTF8) || (format == CTEXT) || (format == TEXT)); + AssertReturnVoid((format == UTF8) || (format == TEXT)); if (((char *)pText)[*pcText - 1] == '\0') --(*pcText); } @@ -1112,10 +1153,9 @@ static int clipConvertVBoxCBForX11(CLIPBACKEND *pCtx, Atom *atomTarget, int *piFormatReturn) { int rc = VINF_SUCCESS; - CLIPX11FORMAT x11Format = clipFindX11FormatByAtom(pCtx->widget, - *atomTarget); + CLIPX11FORMAT x11Format = clipFindX11FormatByAtom(pCtx, *atomTarget); CLIPFORMAT format = clipRealFormatForX11Format(x11Format); - if ( ((format == UTF8) || (format == CTEXT) || (format == TEXT)) + if ( ((format == UTF8) || (format == TEXT)) && (pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)) { void *pv = NULL; @@ -1130,15 +1170,36 @@ static int clipConvertVBoxCBForX11(CLIPBACKEND *pCtx, Atom *atomTarget, (PRTUTF16)pv, cb, atomTarget, atomTypeReturn, pValReturn, pcLenReturn, piFormatReturn); - else if (RT_SUCCESS(rc) && (format == CTEXT)) - rc = clipWinTxtToCTextForX11CB(XtDisplay(pCtx->widget), - (PRTUTF16)pv, cb, - atomTypeReturn, pValReturn, - pcLenReturn, piFormatReturn); if (RT_SUCCESS(rc)) clipTrimTrailingNul(*(XtPointer *)pValReturn, pcLenReturn, format); RTMemFree(pv); } + else if ( (format == BMP) + && (pCtx->vboxFormats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)) + { + void *pv = NULL; + uint32_t cb = 0; + rc = clipReadVBoxClipboard(pCtx, + VBOX_SHARED_CLIPBOARD_FMT_BITMAP, + &pv, &cb); + if (RT_SUCCESS(rc) && (cb == 0)) + rc = VERR_NO_DATA; + if (RT_SUCCESS(rc) && (format == BMP)) + { + /* Create a full BMP from it */ + rc = vboxClipboardDibToBmp(pv, cb, (void **)pValReturn, + (size_t *)pcLenReturn); + } + else + rc = VERR_NOT_SUPPORTED; + + if (RT_SUCCESS(rc)) + { + *atomTypeReturn = *atomTarget; + *piFormatReturn = 8; + } + RTMemFree(pv); + } else rc = VERR_NOT_SUPPORTED; return rc; @@ -1161,9 +1222,9 @@ static Boolean clipXtConvertSelectionProc(Widget widget, Atom *atomSelection, LogRelFlowFunc(("\n")); if (!pCtx) return false; - if (!clipIsSupportedSelectionType(pCtx->widget, *atomSelection)) + if (!clipIsSupportedSelectionType(pCtx, *atomSelection)) return false; - if (*atomTarget == clipGetAtom(pCtx->widget, "TARGETS")) + if (*atomTarget == clipGetAtom(pCtx, "TARGETS")) rc = clipCreateX11Targets(pCtx, atomTypeReturn, pValReturn, pcLenReturn, piFormatReturn); else @@ -1197,13 +1258,23 @@ static void clipInvalidateVBoxCBCache(CLIPBACKEND *pCtx) */ static void clipGrabX11CB(CLIPBACKEND *pCtx, uint32_t u32Formats) { - if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"), + if (XtOwnSelection(pCtx->widget, clipGetAtom(pCtx, "CLIPBOARD"), CurrentTime, clipXtConvertSelectionProc, NULL, 0)) { pCtx->vboxFormats = u32Formats; /* Grab the middle-button paste selection too. */ - XtOwnSelection(pCtx->widget, clipGetAtom(pCtx->widget, "PRIMARY"), + XtOwnSelection(pCtx->widget, clipGetAtom(pCtx, "PRIMARY"), CurrentTime, clipXtConvertSelectionProc, NULL, 0); +#ifndef TESTCASE + /* Xt suppresses these if we already own the clipboard, so send them + * ourselves. */ + XSetSelectionOwner(XtDisplay(pCtx->widget), + clipGetAtom(pCtx, "CLIPBOARD"), + XtWindow(pCtx->widget), CurrentTime); + XSetSelectionOwner(XtDisplay(pCtx->widget), + clipGetAtom(pCtx, "PRIMARY"), + XtWindow(pCtx->widget), CurrentTime); +#endif } } @@ -1214,8 +1285,8 @@ static void clipGrabX11CB(CLIPBACKEND *pCtx, uint32_t u32Formats) * information about the VBox formats available and the * clipboard context data. Must be freed by the worker. */ -static void clipNewVBoxFormatsWorker(XtPointer pUserData, - XtIntervalId * /* interval */) +static void clipNewVBoxFormatsWorker(void *pUserData, + void * /* interval */) { CLIPNEWVBOXFORMATS *pFormats = (CLIPNEWVBOXFORMATS *)pUserData; CLIPBACKEND *pCtx = pFormats->pCtx; @@ -1335,77 +1406,6 @@ static int clipUtf8ToWinTxt(const char *pcSrc, unsigned cbSrc, } /** - * Convert COMPOUND TEXT with CR end-of-lines into Utf-16 as Windows expects - * it and return the result in a RTMemAlloc allocated buffer. - * @returns IPRT status code - * @param widget An Xt widget, necessary because we use Xt/Xlib for the - * conversion - * @param pcSrc The source text - * @param cbSrc The size of the source in bytes, not counting the - * terminating zero - * @param ppwszDest Where to store the buffer address - * @param pcbDest On success, where to store the number of bytes written. - * Undefined otherwise. Optional - */ -static int clipCTextToWinTxt(Widget widget, unsigned char *pcSrc, - unsigned cbSrc, PRTUTF16 *ppwszDest, - uint32_t *pcbDest) -{ - LogRelFlowFunc(("widget=%p, pcSrc=%p, cbSrc=%u, ppwszDest=%p\n", widget, - pcSrc, cbSrc, ppwszDest)); - AssertReturn(widget, VERR_INVALID_PARAMETER); - AssertPtrReturn(pcSrc, VERR_INVALID_POINTER); - AssertPtrReturn(ppwszDest, VERR_INVALID_POINTER); - if (pcbDest) - *pcbDest = 0; - - /* Special case as X*TextProperty* can't seem to handle empty strings. */ - if (cbSrc == 0) - { - *ppwszDest = (PRTUTF16) RTMemAlloc(2); - if (!*ppwszDest) - return VERR_NO_MEMORY; - **ppwszDest = 0; - if (pcbDest) - *pcbDest = 2; - return VINF_SUCCESS; - } - - if (pcbDest) - *pcbDest = 0; - /* Intermediate conversion to Utf8 */ - int rc = VINF_SUCCESS; - XTextProperty property; - char **ppcTmp = NULL, *pszTmp = NULL; - int cProps; - - property.value = pcSrc; - property.encoding = clipGetAtom(widget, "COMPOUND_TEXT"); - property.format = 8; - property.nitems = cbSrc; - int xrc = XmbTextPropertyToTextList(XtDisplay(widget), &property, - &ppcTmp, &cProps); - if (xrc < 0) - rc = ( xrc == XNoMemory ? VERR_NO_MEMORY - : xrc == XLocaleNotSupported ? VERR_NOT_SUPPORTED - : xrc == XConverterNotFound ? VERR_NOT_SUPPORTED - : VERR_UNRESOLVED_ERROR); - /* Convert the text returned to UTF8 */ - if (RT_SUCCESS(rc)) - rc = RTStrCurrentCPToUtf8(&pszTmp, *ppcTmp); - /* Now convert the UTF8 to UTF16 */ - if (RT_SUCCESS(rc)) - rc = clipUtf8ToWinTxt(pszTmp, strlen(pszTmp), ppwszDest, pcbDest); - if (ppcTmp != NULL) - XFreeStringList(ppcTmp); - RTStrFree(pszTmp); - LogRelFlowFunc(("Returning %Rrc\n", rc)); - if (pcbDest) - LogRelFlowFunc(("*pcbDest=%u\n", *pcbDest)); - return rc; -} - -/** * Convert Latin-1 text with CR end-of-lines into Utf-16 as Windows expects * it and return the result in a RTMemAlloc allocated buffer. * @returns IPRT status code @@ -1474,6 +1474,8 @@ struct _CLIPREADX11CBREQ uint32_t mFormat; /** The text format we requested from X11 if we requested text */ CLIPX11FORMAT mTextFormat; + /** The bitmap format we requested from X11 if we requested bitmap */ + CLIPX11FORMAT mBitmapFormat; /** The clipboard context this request is associated with */ CLIPBACKEND *mCtx; /** The request structure passed in from the backend. */ @@ -1483,41 +1485,38 @@ struct _CLIPREADX11CBREQ typedef struct _CLIPREADX11CBREQ CLIPREADX11CBREQ; /** - * Convert the text obtained from the X11 clipboard to UTF-16LE with Windows - * EOLs, place it in the buffer supplied and signal that data has arrived. + * Convert the data obtained from the X11 clipboard to the required format, + * place it in the buffer supplied and signal that data has arrived. + * Convert the text obtained UTF-16LE with Windows EOLs. + * Convert full BMP data to DIB format. * @note X11 backend code, callback for XtGetSelectionValue, for use when - * the X11 clipboard contains a text format we understand. + * the X11 clipboard contains a format we understand. */ -static void clipConvertX11CB(Widget widget, XtPointer pClientData, - Atom * /* selection */, Atom *atomType, - XtPointer pvSrc, long unsigned int *pcLen, - int *piFormat) +static void clipConvertX11CB(void *pClientData, void *pvSrc, unsigned cbSrc) { CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *) pClientData; - LogRelFlowFunc(("pReq->mFormat=%02X, pReq->mTextFormat=%u, pReq->mCtx=%p\n", - pReq->mFormat, pReq->mTextFormat, pReq->mCtx)); + LogRelFlowFunc(("pReq->mFormat=%02X, pReq->mTextFormat=%u, " + "pReq->mBitmapFormat=%u, pReq->mCtx=%p\n", + pReq->mFormat, pReq->mTextFormat, pReq->mBitmapFormat, + pReq->mCtx)); AssertPtr(pReq->mCtx); Assert(pReq->mFormat != 0); /* sanity */ int rc = VINF_SUCCESS; CLIPBACKEND *pCtx = pReq->mCtx; - unsigned cbSrc = (*pcLen) * (*piFormat) / 8; void *pvDest = NULL; uint32_t cbDest = 0; + pCtx->fBusy = false; + if (pCtx->fUpdateNeeded) + clipQueryX11CBFormats(pCtx); if (pvSrc == NULL) /* The clipboard selection may have changed before we could get it. */ rc = VERR_NO_DATA; - else if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */ - rc = VERR_TIMEOUT; else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { /* In which format is the clipboard data? */ switch (clipRealFormatForX11Format(pReq->mTextFormat)) { - case CTEXT: - rc = clipCTextToWinTxt(widget, (unsigned char *)pvSrc, cbSrc, - (PRTUTF16 *) &pvDest, &cbDest); - break; case UTF8: case TEXT: { @@ -1536,9 +1535,36 @@ static void clipConvertX11CB(Widget widget, XtPointer pClientData, rc = VERR_INVALID_PARAMETER; } } + else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_BITMAP) + { + /* In which format is the clipboard data? */ + switch (clipRealFormatForX11Format(pReq->mBitmapFormat)) + { + case BMP: + { + const void *pDib; + size_t cbDibSize; + rc = vboxClipboardBmpGetDib((const void *)pvSrc, cbSrc, + &pDib, &cbDibSize); + if (RT_SUCCESS(rc)) + { + pvDest = RTMemAlloc(cbDibSize); + if (!pvDest) + rc = VERR_NO_MEMORY; + else + { + memcpy(pvDest, pDib, cbDibSize); + cbDest = cbDibSize; + } + } + break; + } + default: + rc = VERR_INVALID_PARAMETER; + } + } else rc = VERR_NOT_IMPLEMENTED; - XtFree((char *)pvSrc); ClipCompleteDataRequestFromX11(pReq->mCtx->pFrontend, rc, pReq->mReq, pvDest, cbDest); RTMemFree(pvDest); @@ -1546,21 +1572,66 @@ static void clipConvertX11CB(Widget widget, XtPointer pClientData, LogRelFlowFunc(("rc=%Rrc\n", rc)); } +/** + * Convert the data obtained from the X11 clipboard to the required format, + * place it in the buffer supplied and signal that data has arrived. + * Convert the text obtained UTF-16LE with Windows EOLs. + * Convert full BMP data to DIB format. + * @note X11 backend code, callback for XtGetSelectionValue, for use when + * the X11 clipboard contains a format we understand. + */ +static void cbConvertX11CB(Widget widget, XtPointer pClientData, + Atom * /* selection */, Atom *atomType, + XtPointer pvSrc, long unsigned int *pcLen, + int *piFormat) +{ + if (*atomType == XT_CONVERT_FAIL) /* Xt timeout */ + clipConvertX11CB(pClientData, NULL, 0); + else + clipConvertX11CB(pClientData, pvSrc, (*pcLen) * (*piFormat) / 8); + + XtFree((char *)pvSrc); +} + +#ifdef TESTCASE +static void testRequestData(CLIPBACKEND* pCtx, CLIPX11FORMAT target, + void *closure); +#endif + +static void getSelectionValue(CLIPBACKEND *pCtx, CLIPX11FORMAT format, + CLIPREADX11CBREQ *pReq) +{ +#ifndef TESTCASE + XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx, "CLIPBOARD"), + clipAtomForX11Format(pCtx, format), + cbConvertX11CB, + reinterpret_cast<XtPointer>(pReq), + CurrentTime); +#else + testRequestData(pCtx, format, (void *)pReq); +#endif +} + /** Worker function for ClipRequestDataFromX11 which runs on the event * thread. */ -static void vboxClipboardReadX11Worker(XtPointer pUserData, - XtIntervalId * /* interval */) +static void vboxClipboardReadX11Worker(void *pUserData, + void * /* interval */) { CLIPREADX11CBREQ *pReq = (CLIPREADX11CBREQ *)pUserData; CLIPBACKEND *pCtx = pReq->mCtx; LogRelFlowFunc (("pReq->mFormat = %02X\n", pReq->mFormat)); int rc = VINF_SUCCESS; - /* - * VBox wants to read data in the given format. - */ - if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) + bool fBusy = pCtx->fBusy; + pCtx->fBusy = true; + if (fBusy) + /* If the clipboard is busy just fend off the request. */ + rc = VERR_TRY_AGAIN; + else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) { + /* + * VBox wants to read data in the given format. + */ pReq->mTextFormat = pCtx->X11TextFormat; if (pReq->mTextFormat == INVALID) /* VBox thinks we have data and we don't */ @@ -1568,12 +1639,18 @@ static void vboxClipboardReadX11Worker(XtPointer pUserData, else /* Send out a request for the data to the current clipboard * owner */ - XtGetSelectionValue(pCtx->widget, clipGetAtom(pCtx->widget, "CLIPBOARD"), - clipAtomForX11Format(pCtx->widget, - pCtx->X11TextFormat), - clipConvertX11CB, - reinterpret_cast<XtPointer>(pReq), - CurrentTime); + getSelectionValue(pCtx, pCtx->X11TextFormat, pReq); + } + else if (pReq->mFormat == VBOX_SHARED_CLIPBOARD_FMT_BITMAP) + { + pReq->mBitmapFormat = pCtx->X11BitmapFormat; + if (pReq->mBitmapFormat == INVALID) + /* VBox thinks we have data and we don't */ + rc = VERR_NO_DATA; + else + /* Send out a request for the data to the current clipboard + * owner */ + getSelectionValue(pCtx, pCtx->X11BitmapFormat, pReq); } else rc = VERR_NOT_IMPLEMENTED; @@ -1640,9 +1717,8 @@ int ClipRequestDataFromX11(CLIPBACKEND *pCtx, uint32_t u32Format, /* For the purpose of the test case, we just execute the procedure to be * scheduled, as we are running single threaded. */ -void clipQueueToEventThread(CLIPBACKEND *pCtx, - XtTimerCallbackProc proc, - XtPointer client_data) +void testQueueToEventThread(void (*proc)(void *, void *), + void *client_data) { proc(client_data, NULL); } @@ -1708,79 +1784,6 @@ int ClipRequestDataForX11(VBOXCLIPBOARDCONTEXT *pCtx, Display *XtDisplay(Widget w) { return (Display *) 0xffff; } -int XmbTextListToTextProperty(Display *display, char **list, int count, - XICCEncodingStyle style, - XTextProperty *text_prop_return) -{ - /* We don't fully reimplement this API for obvious reasons. */ - AssertReturn(count == 1, XLocaleNotSupported); - AssertReturn(style == XCompoundTextStyle, XLocaleNotSupported); - /* We simplify the conversion by only accepting ASCII. */ - for (unsigned i = 0; (*list)[i] != 0; ++i) - AssertReturn(((*list)[i] & 0x80) == 0, XLocaleNotSupported); - text_prop_return->value = - (unsigned char*)RTMemDup(*list, strlen(*list) + 1); - text_prop_return->encoding = clipGetAtom(NULL, "COMPOUND_TEXT"); - text_prop_return->format = 8; - text_prop_return->nitems = strlen(*list); - return 0; -} - -int Xutf8TextListToTextProperty(Display *display, char **list, int count, - XICCEncodingStyle style, - XTextProperty *text_prop_return) -{ - return XmbTextListToTextProperty(display, list, count, style, - text_prop_return); -} - -int XmbTextPropertyToTextList(Display *display, - const XTextProperty *text_prop, - char ***list_return, int *count_return) -{ - int rc = 0; - if (text_prop->nitems == 0) - { - *list_return = NULL; - *count_return = 0; - return 0; - } - /* Only accept simple ASCII properties */ - for (unsigned i = 0; i < text_prop->nitems; ++i) - AssertReturn(!(text_prop->value[i] & 0x80), XConverterNotFound); - char **ppList = (char **)RTMemAlloc(sizeof(char *)); - char *pValue = (char *)RTMemAlloc(text_prop->nitems + 1); - if (pValue) - { - memcpy(pValue, text_prop->value, text_prop->nitems); - pValue[text_prop->nitems] = 0; - } - if (ppList) - *ppList = pValue; - if (!ppList || !pValue) - { - RTMemFree(ppList); - RTMemFree(pValue); - rc = XNoMemory; - } - else - { - /* NULL-terminate the string */ - pValue[text_prop->nitems] = '\0'; - *count_return = 1; - *list_return = ppList; - } - return rc; -} - -int Xutf8TextPropertyToTextList(Display *display, - const XTextProperty *text_prop, - char ***list_return, int *count_return) -{ - return XmbTextPropertyToTextList(display, text_prop, list_return, - count_return); -} - void XtAppSetExitFlag(XtAppContext app_context) {} void XtDestroyWidget(Widget w) {} @@ -1823,85 +1826,54 @@ static const char *g_apszSupAtoms[] = /* This just looks for the atom names in a couple of tables and returns an * index with an offset added. */ -Boolean XtConvertAndStore(Widget widget, _Xconst _XtString from_type, - XrmValue* from, _Xconst _XtString to_type, - XrmValue* to_in_out) -{ - Boolean rc = False; - /* What we support is: */ - AssertReturn(from_type == XtRString, False); - AssertReturn(to_type == XtRAtom, False); +Atom XInternAtom(Display *, const char *pcsz, int) +{ + Atom atom = 0; for (unsigned i = 0; i < RT_ELEMENTS(g_aFormats); ++i) - if (!strcmp(from->addr, g_aFormats[i].pcszAtom)) - { - *(Atom *)(to_in_out->addr) = (Atom) (i + 0x1000); - rc = True; - } + if (!strcmp(pcsz, g_aFormats[i].pcszAtom)) + atom = (Atom) (i + 0x1000); for (unsigned i = 0; i < RT_ELEMENTS(g_apszSupAtoms); ++i) - if (!strcmp(from->addr, g_apszSupAtoms[i])) - { - *(Atom *)(to_in_out->addr) = (Atom) (i + 0x2000); - rc = True; - } - Assert(rc == True); /* Have we missed any atoms? */ - return rc; + if (!strcmp(pcsz, g_apszSupAtoms[i])) + atom = (Atom) (i + 0x2000); + Assert(atom); /* Have we missed any atoms? */ + return atom; +} + +/* Take a request for the targets we are currently offering. */ +static CLIPX11FORMAT g_selTargets[10] = { 0 }; +static size_t g_cTargets = 0; + +void testRequestTargets(CLIPBACKEND* pCtx) +{ + clipUpdateX11Targets(pCtx, g_selTargets, g_cTargets); } /* The current values of the X selection, which will be returned to the * XtGetSelectionValue callback. */ -static Atom g_selTarget[1] = { 0 }; static Atom g_selType = 0; static const void *g_pSelData = NULL; static unsigned long g_cSelData = 0; static int g_selFormat = 0; -static bool g_fTargetsTimeout = false; -static bool g_fTargetsFailure = false; -void XtGetSelectionValue(Widget widget, Atom selection, Atom target, - XtSelectionCallbackProc callback, - XtPointer closure, Time time) +void testRequestData(CLIPBACKEND* pCtx, CLIPX11FORMAT target, void *closure) { unsigned long count = 0; int format = 0; - Atom type = XA_STRING; - if ( ( selection != clipGetAtom(NULL, "PRIMARY") - && selection != clipGetAtom(NULL, "CLIPBOARD") - && selection != clipGetAtom(NULL, "TARGETS")) - || ( target != g_selTarget[0] - && target != clipGetAtom(NULL, "TARGETS"))) + if (target != g_selTargets[0]) { - /* Otherwise this is probably a caller error. */ - Assert(target != g_selTarget[0]); - callback(widget, closure, &selection, &type, NULL, &count, &format); - /* Could not convert to target. */ + clipConvertX11CB(closure, NULL, 0); /* Could not convert to target. */ return; } - XtPointer pValue = NULL; - if (target == clipGetAtom(NULL, "TARGETS")) - { - if (g_fTargetsFailure) - pValue = NULL; - else - pValue = (XtPointer) RTMemDup(&g_selTarget, sizeof(g_selTarget)); - type = g_fTargetsTimeout ? XT_CONVERT_FAIL : XA_ATOM; - count = g_fTargetsFailure ? 0 : RT_ELEMENTS(g_selTarget); - format = 32; - } - else - { - pValue = (XtPointer) g_pSelData ? RTMemDup(g_pSelData, g_cSelData) - : NULL; - type = g_selType; - count = g_pSelData ? g_cSelData : 0; - format = g_selFormat; - } + void *pValue = NULL; + pValue = g_pSelData ? RTMemDup(g_pSelData, g_cSelData) : NULL; + count = g_pSelData ? g_cSelData : 0; + format = g_selFormat; if (!pValue) { count = 0; format = 0; } - callback(widget, closure, &selection, &type, pValue, - &count, &format); + clipConvertX11CB(closure, pValue, count * format / 8); } /* The formats currently on offer from X11 via the shared clipboard */ @@ -1938,7 +1910,7 @@ Boolean XtOwnSelection(Widget widget, Atom selection, Time time, XtLoseSelectionProc lose, XtSelectionDoneProc done) { - if (selection != clipGetAtom(NULL, "CLIPBOARD")) + if (selection != XInternAtom(NULL, "CLIPBOARD", 0)) return True; /* We don't really care about this. */ g_ownsSel = true; /* Always succeed. */ g_pfnSelConvert = convert; @@ -1960,7 +1932,7 @@ static bool clipConvertSelection(const char *pcszTarget, Atom *type, XtPointer *value, unsigned long *length, int *format) { - Atom target = clipGetAtom(NULL, pcszTarget); + Atom target = XInternAtom(NULL, pcszTarget, 0); if (target == 0) return false; /* Initialise all return values in case we make a quick exit. */ @@ -1972,7 +1944,7 @@ static bool clipConvertSelection(const char *pcszTarget, Atom *type, return false; if (!g_pfnSelConvert) return false; - Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD"); + Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0); if (!g_pfnSelConvert(TEST_WIDGET, &clipAtom, &target, type, value, length, format)) return false; @@ -1986,8 +1958,9 @@ static void clipSetSelectionValues(const char *pcszTarget, Atom type, const void *data, unsigned long count, int format) { - Atom clipAtom = clipGetAtom(NULL, "CLIPBOARD"); - g_selTarget[0] = clipGetAtom(NULL, pcszTarget); + Atom clipAtom = XInternAtom(NULL, "CLIPBOARD", 0); + g_selTargets[0] = clipFindX11FormatByAtomText(pcszTarget); + g_cTargets = 1; g_selType = type; g_pSelData = data; g_cSelData = count; @@ -1995,20 +1968,17 @@ static void clipSetSelectionValues(const char *pcszTarget, Atom type, if (g_pfnSelLose) g_pfnSelLose(TEST_WIDGET, &clipAtom); g_ownsSel = false; - g_fTargetsTimeout = false; - g_fTargetsFailure = false; } static void clipSendTargetUpdate(CLIPBACKEND *pCtx) { - clipUpdateX11Targets(pCtx, g_selTarget, RT_ELEMENTS(g_selTarget)); + clipQueryX11CBFormats(pCtx); } /* Configure if and how the X11 TARGETS clipboard target will fail */ -static void clipSetTargetsFailure(bool fTimeout, bool fFailure) +static void clipSetTargetsFailure(void) { - g_fTargetsTimeout = fTimeout; - g_fTargetsFailure = fFailure; + g_cTargets = 0; } char *XtMalloc(Cardinal size) { return (char *) RTMemAlloc(size); } @@ -2325,33 +2295,6 @@ int main() "hello world", sizeof("hello world") - 1, 8); testStringFromX11(hTest, pCtx, "hello world", VINF_SUCCESS); - /*** COMPOUND TEXT from X11 ***/ - RTTestSub(hTest, "reading compound text from X11"); - /* Simple test */ - clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello world", - sizeof("hello world"), 8); - testStringFromX11(hTest, pCtx, "hello world", VINF_SUCCESS); - /* With an embedded carriage return */ - clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello\nworld", - sizeof("hello\nworld"), 8); - testStringFromX11(hTest, pCtx, "hello\r\nworld", VINF_SUCCESS); - /* With an embedded CRLF */ - clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello\r\nworld", - sizeof("hello\r\nworld"), 8); - testStringFromX11(hTest, pCtx, "hello\r\r\nworld", VINF_SUCCESS); - /* With an embedded LFCR */ - clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "hello\n\rworld", - sizeof("hello\n\rworld"), 8); - testStringFromX11(hTest, pCtx, "hello\r\n\rworld", VINF_SUCCESS); - /* An empty string */ - clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, "", - sizeof(""), 8); - testStringFromX11(hTest, pCtx, "", VINF_SUCCESS); - /* A non-zero-terminated string */ - clipSetSelectionValues("COMPOUND_TEXT", XA_STRING, - "hello world", sizeof("hello world") - 1, 8); - testStringFromX11(hTest, pCtx, "hello world", VINF_SUCCESS); - /*** Latin1 from X11 ***/ RTTestSub(hTest, "reading Latin1 from X11"); /* Simple test */ @@ -2387,9 +2330,8 @@ int main() /*** Timeout from X11 ***/ RTTestSub(hTest, "X11 timeout"); - clipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, "hello world", - sizeof("hello world"), 8); - testStringFromX11(hTest, pCtx, "hello world", VERR_TIMEOUT); + clipSetSelectionValues("UTF8_STRING", XT_CONVERT_FAIL, NULL,0, 8); + testStringFromX11(hTest, pCtx, "", VERR_NO_DATA); /*** No data in X11 clipboard ***/ RTTestSub(hTest, "a data request from an empty X11 clipboard"); @@ -2427,7 +2369,7 @@ int main() RTTestSub(hTest, "X11 targets conversion failure"); clipSetSelectionValues("UTF8_STRING", XA_STRING, "hello world", sizeof("hello world"), 8); - clipSetTargetsFailure(false, true); + clipSetTargetsFailure(); Atom atom = XA_STRING; long unsigned int cLen = 0; int format = 8; @@ -2448,72 +2390,40 @@ int main() clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world", sizeof("hello world") * 2); testStringFromVBox(hTest, pCtx, "UTF8_STRING", - clipGetAtom(NULL, "UTF8_STRING"), "hello world"); + clipGetAtom(pCtx, "UTF8_STRING"), "hello world"); /* With an embedded carriage return */ clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\nworld", sizeof("hello\r\nworld") * 2); testStringFromVBox(hTest, pCtx, "text/plain;charset=UTF-8", - clipGetAtom(NULL, "text/plain;charset=UTF-8"), + clipGetAtom(pCtx, "text/plain;charset=UTF-8"), "hello\nworld"); /* With an embedded CRCRLF */ clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\r\nworld", sizeof("hello\r\r\nworld") * 2); testStringFromVBox(hTest, pCtx, "text/plain;charset=UTF-8", - clipGetAtom(NULL, "text/plain;charset=UTF-8"), + clipGetAtom(pCtx, "text/plain;charset=UTF-8"), "hello\r\nworld"); /* With an embedded CRLFCR */ clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\n\rworld", sizeof("hello\r\n\rworld") * 2); testStringFromVBox(hTest, pCtx, "text/plain;charset=UTF-8", - clipGetAtom(NULL, "text/plain;charset=UTF-8"), + clipGetAtom(pCtx, "text/plain;charset=UTF-8"), "hello\n\rworld"); /* An empty string */ clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "", 2); testStringFromVBox(hTest, pCtx, "text/plain;charset=utf-8", - clipGetAtom(NULL, "text/plain;charset=utf-8"), ""); + clipGetAtom(pCtx, "text/plain;charset=utf-8"), ""); /* With an embedded Utf-8 character. */ clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "100\xE2\x82\xAC" /* 100 Euro */, 10); testStringFromVBox(hTest, pCtx, "STRING", - clipGetAtom(NULL, "STRING"), "100\xE2\x82\xAC"); + clipGetAtom(pCtx, "STRING"), "100\xE2\x82\xAC"); /* A non-zero-terminated string */ clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world", sizeof("hello world") * 2 - 2); - testStringFromVBox(hTest, pCtx, "TEXT", clipGetAtom(NULL, "TEXT"), + testStringFromVBox(hTest, pCtx, "TEXT", clipGetAtom(pCtx, "TEXT"), "hello world"); - /*** COMPOUND TEXT from VBox ***/ - RTTestSub(hTest, "reading COMPOUND TEXT from VBox"); - /* Simple test */ - clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world", - sizeof("hello world") * 2); - testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT", - clipGetAtom(NULL, "COMPOUND_TEXT"), "hello world"); - /* With an embedded carriage return */ - clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\nworld", - sizeof("hello\r\nworld") * 2); - testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT", - clipGetAtom(NULL, "COMPOUND_TEXT"), "hello\nworld"); - /* With an embedded CRCRLF */ - clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\r\nworld", - sizeof("hello\r\r\nworld") * 2); - testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT", - clipGetAtom(NULL, "COMPOUND_TEXT"), "hello\r\nworld"); - /* With an embedded CRLFCR */ - clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello\r\n\rworld", - sizeof("hello\r\n\rworld") * 2); - testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT", - clipGetAtom(NULL, "COMPOUND_TEXT"), "hello\n\rworld"); - /* An empty string */ - clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "", 2); - testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT", - clipGetAtom(NULL, "COMPOUND_TEXT"), ""); - /* A non-zero-terminated string */ - clipSetVBoxUtf16(pCtx, VINF_SUCCESS, "hello world", - sizeof("hello world") * 2 - 2); - testStringFromVBox(hTest, pCtx, "COMPOUND_TEXT", - clipGetAtom(NULL, "COMPOUND_TEXT"), "hello world"); - /*** Timeout from VBox ***/ RTTestSub(hTest, "reading from VBox with timeout"); clipEmptyVBox(pCtx, VERR_TIMEOUT); |
