diff options
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib')
26 files changed, 11072 insertions, 1278 deletions
diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_components.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_components.py deleted file mode 100644 index e1909d71..00000000 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_components.py +++ /dev/null @@ -1,144 +0,0 @@ -# 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 """static unsigned int lookupComponents( 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 lookupComponents: %d", (int) pname ); - break; - } - /* NOTREACHED */ - return 0; -} -""" - - diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py index 8475344a..f8d281dc 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py @@ -393,8 +393,10 @@ extensions_num_get_values = { # Point sprite (2.0) # 'GL_POINT_SPRITE': (1, 'CR_OPENGL_VERSION_2_0'), # Separate stencil (2.0) # - 'GL_STENCIL_BACK_FAIL': (1, 'CR_OPENGL_VERSION_2_0'), 'GL_STENCIL_BACK_FUNC': (1, 'CR_OPENGL_VERSION_2_0'), + 'GL_STENCIL_BACK_REF': (1, 'CR_OPENGL_VERSION_2_0'), + 'GL_STENCIL_BACK_VALUE_MASK': (1, 'CR_OPENGL_VERSION_2_0'), + 'GL_STENCIL_BACK_FAIL': (1, 'CR_OPENGL_VERSION_2_0'), 'GL_STENCIL_BACK_PASS_DEPTH_FAIL': (1, 'CR_OPENGL_VERSION_2_0'), 'GL_STENCIL_BACK_PASS_DEPTH_PASS': (1, 'CR_OPENGL_VERSION_2_0'), # Frame buffer object EXT # @@ -404,22 +406,52 @@ extensions_num_get_values = { 'GL_MAX_RENDERBUFFER_SIZE_EXT': (1, 'CR_EXT_framebuffer_object'), # ARB_shader_objects 'GL_CURRENT_PROGRAM': (1, 'CR_ARB_shader_objects'), + # EXT_framebuffer_blit + 'GL_READ_FRAMEBUFFER_BINDING_EXT': (1, 'CR_EXT_framebuffer_blit'), + 'GL_DRAW_FRAMEBUFFER_BINDING_EXT': (1, 'CR_EXT_framebuffer_blit'), + # EXT_stencil_two_side + 'GL_ACTIVE_STENCIL_FACE_EXT': (1, 'CR_EXT_stencil_two_side'), } get_keys = num_get_values.keys() + extensions_num_get_values.keys() get_keys.sort() +max_keyvalues = 0 -print "struct nv_struct { GLenum pname; unsigned int num_values; } num_values_array[] = {" +print """ +static struct nv_struct { GLenum pname; unsigned int num_values; +#ifdef VBOX_WITH_CRDUMPER +const char* pszName; +#endif +} num_values_array[] = { +""" for key in get_keys: try: - print '\t{ %s, %d },' % (key, num_get_values[key]) + keyvalues = num_get_values[key] + if max_keyvalues < keyvalues: + max_keyvalues = keyvalues + print """ + \t{ %s, %d +#ifdef VBOX_WITH_CRDUMPER + , "%s" +#endif + }, + """ % (key, keyvalues, key) except KeyError: (nv, ifdef) = extensions_num_get_values[key] + if max_keyvalues < nv: + max_keyvalues = nv print '#ifdef %s' % ifdef - print '\t{ %s, %d },' % (key, nv) + print """ + \t{ %s, %d + #ifdef VBOX_WITH_CRDUMPER + , "%s" + #endif + }, + """ % (key, nv, key) print '#endif /* %s */' % ifdef print "\t{ 0, 0 }" print "};" +print "#define CR_MAX_GET_VALUES %d" % max_keyvalues print """ static unsigned int __numValues( GLenum pname ) diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h b/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h index 4e14a86e..677bcf0e 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h @@ -14,10 +14,16 @@ #include "state/cr_currentpointers.h" #include "cr_server.h" +#include <cr_htable.h> +#include <cr_compositor.h> #ifdef VBOX_WITH_CRHGSMI # include <VBox/VBoxVideo.h> +#include <iprt/cdefs.h> + +RT_C_DECLS_BEGIN + extern uint8_t* g_pvVRamBase; extern uint32_t g_cbVRam; extern HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion; @@ -37,9 +43,10 @@ DECLINLINE(void) crServerCrHgsmiCmdComplete(struct VBOXVDMACMD_CHROMIUM_CMD *pCm } #define VBOXCRHGSMI_CMD_COMPLETE(_pData, _rc) do { \ + Assert(CRVBOXHGSMI_CMDDATA_IS_HGSMICMD(_pData)); \ CRVBOXHGSMI_CMDDATA_ASSERT_ISSET(_pData); \ CRVBOXHGSMI_CMDDATA_RC(_pData, _rc); \ - crServerCrHgsmiCmdComplete((_pData)->pCmd, VINF_SUCCESS); \ + crServerCrHgsmiCmdComplete((_pData)->pHgsmiCmd, VINF_SUCCESS); \ } while (0) #define VBOXCRHGSMI_CMD_CHECK_COMPLETE(_pData, _rc) do { \ @@ -108,8 +115,12 @@ GLboolean crServerClientInBeginEnd(const CRClient *client); GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID); GLint crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID); - -void crServerCreateInfoDeleteCB(void *data); +GLint crServerMuralInit(CRMuralInfo *mural, GLboolean fGuestWindow, GLint visBits, GLint preloadWinID); +void crServerMuralTerm(CRMuralInfo *mural); +GLboolean crServerMuralSize(CRMuralInfo *mural, GLint width, GLint height); +void crServerMuralPosition(CRMuralInfo *mural, GLint x, GLint y); +void crServerMuralVisibleRegion( CRMuralInfo *mural, GLint cRects, const GLint *pRects ); +void crServerMuralShow( CRMuralInfo *mural, GLint state ); GLint crServerGenerateID(GLint *pCounter); @@ -117,15 +128,577 @@ GLint crServerSPUWindowID(GLint serverWindow); GLuint crServerTranslateProgramID(GLuint id); -void crServerSetupOutputRedirect(CRMuralInfo *mural); +CRMuralInfo * crServerGetDummyMural(GLint visualBits); + void crServerCheckMuralGeometry(CRMuralInfo *mural); +void crServerCheckAllMuralGeometry(CRMuralInfo *pMI); GLboolean crServerSupportRedirMuralFBO(void); -void crServerRedirMuralFBO(CRMuralInfo *mural, GLboolean redir); -void crServerCreateMuralFBO(CRMuralInfo *mural); + +void crVBoxServerMuralFbResizeBegin(HCR_FRAMEBUFFER hFb); +void crVBoxServerMuralFbResizeEnd(HCR_FRAMEBUFFER hFb); + +void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void*pvData); + +void crServerRedirMuralFbClear(CRMuralInfo *mural); + +void crServerWindowReparent(CRMuralInfo *pMural); + +void crServerRedirMuralFBO(CRMuralInfo *mural, bool fEnabled); void crServerDeleteMuralFBO(CRMuralInfo *mural); void crServerPresentFBO(CRMuralInfo *mural); GLboolean crServerIsRedirectedToFBO(); +GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer); +void crServerMuralFBOSwapBuffers(CRMuralInfo *mural); + +HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled(); +HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb); +HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized(); +HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb); + +int CrFbRegionsClear(HCR_FRAMEBUFFER hFb); + + +#define CR_SERVER_FBO_BB_IDX(_mural) ((_mural)->iBbBuffer) +#define CR_SERVER_FBO_FB_IDX(_mural) (((_mural)->iBbBuffer + 1) % ((_mural)->cBuffers)) +/* returns a valid index to be used for negative _idx, i.e. for GL_NONE cases */ +//#define CR_SERVER_FBO_ADJUST_IDX(_mural, _idx) ((_idx) >= 0 ? (_idx) : CR_SERVER_FBO_BB_IDX(_mural)) +/* just a helper that uses CR_SERVER_FBO_ADJUST_IDX for getting mural's FBO id for buffer index*/ +//#define CR_SERVER_FBO_FOR_IDX(_mural, _idx) ((_mural)->aidFBOs[CR_SERVER_FBO_ADJUST_IDX((_mural), (_idx))]) +//#define CR_SERVER_FBO_TEX_FOR_IDX(_mural, _idx) ((_mural)->aidColorTexs[CR_SERVER_FBO_ADJUST_IDX((_mural), (_idx))]) +#define CR_SERVER_FBO_FOR_IDX(_mural, _idx) ((_idx) >= 0 ? (_mural)->aidFBOs[(_idx)] : 0) +#define CR_SERVER_FBO_TEX_FOR_IDX(_mural, _idx) ((_idx) >= 0 ? (_mural)->aidColorTexs[(_idx)] : 0) int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer); +void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo ); + +PCR_BLITTER crServerVBoxBlitterGet(); +PCR_BLITTER crServerVBoxBlitterGetInitialized(); + +DECLINLINE(void) crServerVBoxBlitterWinInit(CR_BLITTER_WINDOW *win, CRMuralInfo *mural) +{ + win->Base.id = mural->spuWindow; + win->Base.visualBits = mural->CreateInfo.realVisualBits; + win->width = mural->width; + win->height = mural->height; +} + +DECLINLINE(void) crServerVBoxBlitterCtxInit(CR_BLITTER_CONTEXT *ctx, CRContextInfo *ctxInfo) +{ + ctx->Base.id = ctxInfo->SpuContext; + if (ctx->Base.id < 0) + ctx->Base.id = cr_server.MainContextInfo.SpuContext; + ctx->Base.visualBits = cr_server.curClient->currentCtxInfo->CreateInfo.realVisualBits; +} + +/* display worker thread. + * see comments for CR_SERVER_RPW struct definition in cr_server.h */ +DECLINLINE(void) crServerXchgI8(int8_t *pu8Val1, int8_t *pu8Val2) +{ + int8_t tmp; + tmp = *pu8Val1; + *pu8Val1 = *pu8Val2; + *pu8Val2 = tmp; +} + +#ifdef DEBUG +# define CR_GLERR_CHECK(_op) do { \ + GLenum status; \ + while ((status = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) {/*Assert(0);*/} \ + _op \ + while ((status = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) {Assert(0);} \ + } while (0) +#else +# define CR_GLERR_CHECK(_op) do { \ + _op \ + } while (0) +#endif + +#ifdef DEBUG_misha +# define CR_SERVER_RPW_DEBUG +#endif +/* * + * _name : Draw, Submitted, Worker, Gpu + */ + +#ifdef CR_SERVER_RPW_DEBUG +# define crServerRpwEntryDbgVerify(_pE) crServerRpwEntryDbgDoVerify(_pE) +#else +# define crServerRpwEntryDbgVerify(_pE) do {} while (0) +#endif + + +#define CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _name) ((_pEntry)->iTex##_name > 0) + +#define CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(_pEntry, _name) do { \ + crServerRpwEntryDbgVerify(_pEntry); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _name)); \ + (_pEntry)->iTex##_name = -(_pEntry)->iTex##_name; \ + crServerRpwEntryDbgVerify(_pEntry); \ + } while (0) + +#define CR_SERVER_RPW_ENTRY_TEX_PROMOTE(_pEntry, _fromName, _toName) do { \ + crServerRpwEntryDbgVerify(_pEntry); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \ + Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \ + crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \ + crServerRpwEntryDbgVerify(_pEntry); \ + } while (0) + +#define CR_SERVER_RPW_ENTRY_TEX_XCHG_VALID(_pEntry, _fromName, _toName) do { \ + crServerRpwEntryDbgVerify(_pEntry); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \ + crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \ + crServerRpwEntryDbgVerify(_pEntry); \ + } while (0) + + +#define CR_SERVER_RPW_ENTRY_TEX_PROMOTE_KEEPVALID(_pEntry, _fromName, _toName) do { \ + crServerRpwEntryDbgVerify(_pEntry); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \ + Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \ + crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \ + (_pEntry)->iTex##_fromName = -(_pEntry)->iTex##_fromName; \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \ + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \ + crServerRpwEntryDbgVerify(_pEntry); \ + } while (0) + +#define CR_SERVER_RPW_ENTRY_TEX(_pEntry, _name) ((_pEntry)->aidWorkerTexs[(_pEntry)->iTex##_name - 1]) + +#define CR_SERVER_RPW_ENTRY_PBO_NEXT_ID(_i) (((_i) + 1) % 2) +#define CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(_pEntry) ((_pEntry)->iCurPBO >= 0) +#define CR_SERVER_RPW_ENTRY_PBO_CUR(_pEntry) ((_pEntry)->aidPBOs[(_pEntry)->iCurPBO]) +#define CR_SERVER_RPW_ENTRY_PBO_COMPLETED(_pEntry) ((_pEntry)->aidPBOs[CR_SERVER_RPW_ENTRY_PBO_NEXT_ID((_pEntry)->iCurPBO)]) +#define CR_SERVER_RPW_ENTRY_PBO_FLIP(_pEntry) do { \ + (_pEntry)->iCurPBO = CR_SERVER_RPW_ENTRY_PBO_NEXT_ID((_pEntry)->iCurPBO); \ + } while (0) + +#ifdef CR_SERVER_RPW_DEBUG +DECLINLINE(void) crServerRpwEntryDbgDoVerify(CR_SERVER_RPW_ENTRY *pEntry) +{ + int tstMask = 0; + int8_t iVal; + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw)); + +#define CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(_v) do { \ + iVal = RT_ABS(_v); \ + Assert(iVal > 0); \ + Assert(iVal < 5); \ + Assert(!(tstMask & (1 << iVal))); \ + tstMask |= (1 << iVal); \ + } while (0) + + CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexDraw); + CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexSubmitted); + CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexWorker); + CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexGpu); + Assert(tstMask == 0x1E); +} +#endif + +DECLINLINE(bool) crServerRpwIsInitialized(const CR_SERVER_RPW *pWorker) +{ + return !!pWorker->ctxId; +} +int crServerRpwInit(CR_SERVER_RPW *pWorker); +int crServerRpwTerm(CR_SERVER_RPW *pWorker); +DECLINLINE(bool) crServerRpwEntryIsInitialized(const CR_SERVER_RPW_ENTRY *pEntry) +{ + return !!pEntry->pfnData; +} +int crServerRpwEntryInit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height, PFNCR_SERVER_RPW_DATA pfnData); +int crServerRpwEntryCleanup(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry); +int crServerRpwEntryResize(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height); +int crServerRpwEntrySubmit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry); +int crServerRpwEntryWaitComplete(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry); +int crServerRpwEntryCancel(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry); +DECLINLINE(void) crServerRpwEntryDrawSettingsToTex(const CR_SERVER_RPW_ENTRY *pEntry, VBOXVR_TEXTURE *pTex) +{ + pTex->width = pEntry->Size.cx; + pTex->height = pEntry->Size.cy; + pTex->target = GL_TEXTURE_2D; + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw)); + pTex->hwid = CR_SERVER_RPW_ENTRY_TEX(pEntry, Draw); +} +/**/ + +typedef struct CR_SERVER_CTX_SWITCH +{ + GLuint idDrawFBO, idReadFBO; + CRContext *pNewCtx; + CRContext *pOldCtx; +} CR_SERVER_CTX_SWITCH; + +DECLINLINE(void) crServerCtxSwitchPrepare(CR_SERVER_CTX_SWITCH *pData, CRContext *pNewCtx) +{ + CRMuralInfo *pCurrentMural = cr_server.currentMural; + CRContextInfo *pCurCtxInfo = cr_server.currentCtxInfo; + GLuint idDrawFBO, idReadFBO; + CRContext *pCurCtx = pCurCtxInfo ? pCurCtxInfo->pContext : NULL; + + CRASSERT(pCurCtx == crStateGetCurrent()); + + if (pCurrentMural) + { + idDrawFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurDrawBuffer); + idReadFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurReadBuffer); + } + else + { + idDrawFBO = 0; + idReadFBO = 0; + } + + crStateSwitchPrepare(pNewCtx, pCurCtx, idDrawFBO, idReadFBO); + + pData->idDrawFBO = idDrawFBO; + pData->idReadFBO = idReadFBO; + pData->pNewCtx = pNewCtx; + pData->pOldCtx = pCurCtx; +} + +DECLINLINE(void) crServerCtxSwitchPostprocess(CR_SERVER_CTX_SWITCH *pData) +{ + crStateSwitchPostprocess(pData->pOldCtx, pData->pNewCtx, pData->idDrawFBO, pData->idReadFBO); +} + +void crServerInitTmpCtxDispatch(); + +int crServerVBoxParseNumerics(const char *pszStr, const int defaultVal); + +typedef struct CR_FBMAP +{ + uint8_t Map[(CR_MAX_GUEST_MONITORS+7)/8]; +} CR_FBMAP; + +DECLINLINE(void) CrFBmInit(CR_FBMAP *pMap) +{ + memset(pMap, 0, sizeof (*pMap)); +} + +DECLINLINE(bool) CrFBmIsSet(CR_FBMAP *pMap, uint32_t i) +{ + return ASMBitTest(&pMap->Map, i); +} + +DECLINLINE(void) CrFBmSet(CR_FBMAP *pMap, uint32_t i) +{ + ASMBitSet(&pMap->Map, i); +} + +DECLINLINE(void) CrFBmSetAtomic(CR_FBMAP *pMap, uint32_t i) +{ + ASMAtomicBitSet(&pMap->Map, i); +} + +DECLINLINE(void) CrFBmClear(CR_FBMAP *pMap, uint32_t i) +{ + ASMBitClear(&pMap->Map, i); +} + +/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */ +int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap); +/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */ +void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap); +HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled(); +HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb); +HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idScreen); +int CrPMgrModeVrdp(bool fEnable); +int CrPMgrModeRootVr(bool fEnable); +int CrPMgrModeWinVisible(bool fEnable); +int CrPMgrRootVrUpdate(); +int CrPMgrViewportUpdate(uint32_t idScreen); +int CrPMgrScreenChanged(uint32_t idScreen); +int CrPMgrNotifyResize(HCR_FRAMEBUFFER hFb); +int CrPMgrSaveState(PSSMHANDLE pSSM); +int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version); +HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idScreen); +/*cleanup stuff*/ + +int CrPMgrInit(); +void CrPMgrTerm(); + +typedef DECLCALLBACKPTR(bool, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext); + +bool CrFbHas3DData(HCR_FRAMEBUFFER hFb); +void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext); +int CrFbResize(HCR_FRAMEBUFFER hFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM); +int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pPrects, CR_BLITTER_IMG *pImg); +bool CrFbIsEnabled(HCR_FRAMEBUFFER hFb); +int CrFbEntryCreateForTexId(HCR_FRAMEBUFFER hFb, GLuint idTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry); +int CrFbEntryCreateForTexData(HCR_FRAMEBUFFER hFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry); +void CrFbEntryAddRef(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry); +void CrFbEntryRelease(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry); +const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb); +void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb); +const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(HCR_FRAMEBUFFER hFb); +const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry); + +/* start doing modifications to the framebuffer */ +int CrFbUpdateBegin(HCR_FRAMEBUFFER hFb); +/*below commands can only be used in Framebuffer update mode, i.e. after the CrFbUpdateBegin succeeded */ +int CrFbEntryRegions(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry); + +/* complete doing modifications to the framebuffer */ +void CrFbUpdateEnd(HCR_FRAMEBUFFER hFb); + +int CrFbEntryRegionsAdd(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated); +int CrFbEntryRegionsSet(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated); + +int CrFbEntryTexDataUpdate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex); + +CRHTABLE_HANDLE CrFbDDataAllocSlot(HCR_FRAMEBUFFER hFb); + +typedef DECLCALLBACKPTR(void, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext); + +void CrFbDDataReleaseSlot(HCR_FRAMEBUFFER hFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext); +int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData); +void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot); +void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot); + +CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex); +void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased); + +int32_t crVBoxServerCrCmdBltProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd); + +//#define VBOX_WITH_CRSERVER_DUMPER +#ifdef VBOX_WITH_CRSERVER_DUMPER +void crServerDumpCheckTerm(); +int crServerDumpCheckInit(); +void crServerDumpBuffer(int idx); +void crServerDumpTextures(); +void crServerDumpTexture(const VBOXVR_TEXTURE *pTex); +void crServerDumpShader(GLint id); +void crServerDumpProgram(GLint id); +void crServerDumpCurrentProgram(); +void crServerDumpRecompileDumpCurrentProgram(); +void crServerRecompileCurrentProgram(); +void crServerDumpCurrentProgramUniforms(); +void crServerDumpCurrentProgramAttribs(); +void crServerDumpFramesCheck(); +void crServerDumpState(); +void crServerDumpDrawel(const char*pszFormat, ...); +void crServerDumpDrawelv(GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal); + +extern int64_t g_CrDbgDumpPid; +extern unsigned long g_CrDbgDumpEnabled; +extern unsigned long g_CrDbgDumpDraw; +extern unsigned long g_CrDbgDumpDrawFramesSettings; +extern unsigned long g_CrDbgDumpDrawFramesAppliedSettings; +extern unsigned long g_CrDbgDumpDrawFramesCount; + +extern uint32_t g_CrDbgDumpVertattrFixupOn; + +bool crServerDumpFilterDmp(unsigned long event, CR_DUMPER *pDumper); +bool crServerDumpFilterOpEnter(unsigned long event, CR_DUMPER *pDumper); +void crServerDumpFilterOpLeave(unsigned long event, CR_DUMPER *pDumper); + +//#define CR_SERVER_DUMP_MASK_OP 0x0000fffc +//#define CR_SERVER_DUMP_OFF_OP 2 +// +//#define CR_SERVER_DUMP_MASK_DIR 0x00000003 +//#define CR_SERVER_DUMP_OFF_DIR 0 +// +//#define CR_SERVER_DUMP_MASK_DMP 0xffff0000 +//#define CR_SERVER_DUMP_OFF_DMP 16 +// +//#define CR_SERVER_DUMP_MAKE_OP(_v) (1 << ((_v) + CR_SERVER_DUMP_OFF_OP)) +//#define CR_SERVER_DUMP_MAKE_DIR(_v) (1 << ((_v) + CR_SERVER_DUMP_OFF_DIR)) +//#define CR_SERVER_DUMP_MAKE_DMP(_v) (1 << ((_v) + CR_SERVER_DUMP_OFF_DMP)) +// +//#define CR_SERVER_DUMP_GET_OP(_v) ((_v) & CR_SERVER_DUMP_MASK_OP) +//#define CR_SERVER_DUMP_GET_DMP(_v) ((_v) & CR_SERVER_DUMP_MASK_DMP) +//#define CR_SERVER_DUMP_GET_DIR(_v) ((_v) & CR_SERVER_DUMP_MASK_DIR) +// +//#define CR_SERVER_DUMP_ISANY_OP(_v1, _v2) (!!(CR_SERVER_DUMP_GET_OP(_v1) & CR_SERVER_DUMP_GET_OP(_v2))) +//#define CR_SERVER_DUMP_ISANY_DIR(_v1, _v2) (!!(CR_SERVER_DUMP_GET_DIR(_v1) & CR_SERVER_DUMP_GET_DIR(_v2))) +//#define CR_SERVER_DUMP_ISANY_DMP(_v1, _v2) (!!(CR_SERVER_DUMP_GET_DMP(_v1) & CR_SERVER_DUMP_GET_DMP(_v2))) +// +//#define CR_SERVER_DUMP_ISANY_OP(_v1, _v2) ((CR_SERVER_DUMP_GET_OP(_v1) & CR_SERVER_DUMP_GET_OP(_v2)) == CR_SERVER_DUMP_GET_OP(_v2)) +//#define CR_SERVER_DUMP_ISANY_DIR(_v1, _v2) ((CR_SERVER_DUMP_GET_DIR(_v1) & CR_SERVER_DUMP_GET_DIR(_v2)) == CR_SERVER_DUMP_GET_DIR(_v2)) +//#define CR_SERVER_DUMP_ISANY_DMP(_v1, _v2) ((CR_SERVER_DUMP_GET_DMP(_v1) & CR_SERVER_DUMP_GET_DMP(_v2)) == CR_SERVER_DUMP_GET_DMP(_v2)) +// +//#define CR_SERVER_DUMP_F_DIR_ENTER CR_SERVER_DUMP_MAKE_DIR(0) +//#define CR_SERVER_DUMP_F_DIR_LEAVE CR_SERVER_DUMP_MAKE_DIR(1) +// +//#define CR_SERVER_DUMP_F_OP_DRAW CR_SERVER_DUMP_MAKE_OP(0) +//#define CR_SERVER_DUMP_F_OP_SWAPBUFFERS CR_SERVER_DUMP_MAKE_OP(1) +//#define CR_SERVER_DUMP_F_OP_LINK_PROGRAM CR_SERVER_DUMP_MAKE_OP(2) +//#define CR_SERVER_DUMP_F_OP_COMPILE_PROGRAM CR_SERVER_DUMP_MAKE_OP(3) +// +//#define CR_SERVER_DUMP_F_DMP_BUFF CR_SERVER_DUMP_MAKE_DMP(0) +//#define CR_SERVER_DUMP_F_DMP_TEX CR_SERVER_DUMP_MAKE_DMP(0) +//#define CR_SERVER_DUMP_F_DMP_PROGRAM CR_SERVER_DUMP_MAKE_DMP(0) +//#define CR_SERVER_DUMP_F_DMP_PROGRAM_UNIFORMS CR_SERVER_DUMP_MAKE_DMP(0) +//#define CR_SERVER_DUMP_F_DMP_STATE CR_SERVER_DUMP_MAKE_DMP(0) +// +//#define CR_SERVER_DUMP_GET_OP(_v) ((_v) & CR_SERVER_DUMP_MASK_OP) +//#define CR_SERVER_DUMP_GET_DMP(_v) ((_v) & CR_SERVER_DUMP_MASK_DMP) +//#define CR_SERVER_DUMP_GET_DIR(_v) ((_v) & CR_SERVER_DUMP_MASK_DIR) + +#define CR_SERVER_DUMP_F_DRAW_BUFF_ENTER 0x00000001 +#define CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE 0x00000002 +#define CR_SERVER_DUMP_F_DRAW_STATE_ENTER 0x00000004 +#define CR_SERVER_DUMP_F_DRAW_STATE_LEAVE 0x00000008 +#define CR_SERVER_DUMP_F_DRAW_TEX_ENTER 0x00000010 +#define CR_SERVER_DUMP_F_DRAW_TEX_LEAVE 0x00000020 +#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER 0x00000040 +#define CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE 0x00000080 +#define CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER 0x00000100 +#define CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE 0x00000200 +#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER 0x00000400 +#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE 0x00000800 + +#define CR_SERVER_DUMP_F_DRAW_ENTER_ALL (CR_SERVER_DUMP_F_DRAW_BUFF_ENTER \ + | CR_SERVER_DUMP_F_DRAW_TEX_ENTER \ + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER \ + | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER \ + | CR_SERVER_DUMP_F_DRAW_STATE_ENTER \ + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER) + +#define CR_SERVER_DUMP_F_DRAW_LEAVE_ALL (CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE \ + | CR_SERVER_DUMP_F_DRAW_TEX_LEAVE \ + | CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE \ + | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE \ + | CR_SERVER_DUMP_F_DRAW_STATE_LEAVE \ + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE) + +#define CR_SERVER_DUMP_F_DRAW_ALL (CR_SERVER_DUMP_F_DRAW_ENTER_ALL | CR_SERVER_DUMP_F_DRAW_LEAVE_ALL) + +#define CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER 0x00010000 +#define CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE 0x00020000 +#define CR_SERVER_DUMP_F_TEXPRESENT 0x00040000 +#define CR_SERVER_DUMP_F_DRAWEL 0x00100000 +#define CR_SERVER_DUMP_F_COMPILE_SHADER 0x01000000 +#define CR_SERVER_DUMP_F_SHADER_SOURCE 0x02000000 +#define CR_SERVER_DUMP_F_LINK_PROGRAM 0x04000000 + + +#define CR_SERVER_DUMP_DEFAULT_FILTER_OP(_ev) ((((_ev) & g_CrDbgDumpDraw) != 0) \ + || ((_ev) == CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER && g_CrDbgDumpDrawFramesCount)) + +#define CR_SERVER_DUMP_DEFAULT_FILTER_DMP(_ev) (((_ev) & g_CrDbgDumpDraw) != 0) + +#define CR_SERVER_DUMP_FILTER_OP(_ev, _pDumper) (g_CrDbgDumpEnabled \ + && (!g_CrDbgDumpPid \ + || (g_CrDbgDumpPid > 0 && ((uint64_t)g_CrDbgDumpPid) == cr_server.curClient->pid) \ + || (g_CrDbgDumpPid < 0 && ((uint64_t)(-g_CrDbgDumpPid)) != cr_server.curClient->pid)) \ + && crServerDumpFilterOpEnter((_ev), (_pDumper))) +#define CR_SERVER_DUMP_FILTER_DMP(_ev, _pDumper) (crServerDumpFilterDmp((_ev), (_pDumper))) + +#define CR_SERVER_DUMP_DRAW_ENTER() do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAW_ENTER_ALL, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_STATE_ENTER, cr_server.Recorder.pDumper)) { crServerDumpState(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgram(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramUniforms(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramAttribs(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_TEX_ENTER, cr_server.Recorder.pDumper)) { crServerDumpTextures(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_BUFF_ENTER, cr_server.Recorder.pDumper)) { crServerDumpBuffer(-1); } \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAW_ENTER_ALL, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_DRAW_LEAVE() do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAW_LEAVE_ALL, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_TEX_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpTextures(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpBuffer(-1); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramUniforms(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramAttribs(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgram(); } \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_STATE_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpState(); } \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAW_LEAVE_ALL, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_COMPILE_SHADER(_id) do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_COMPILE_SHADER, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpShader((_id)); \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_COMPILE_SHADER, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_SHADER_SOURCE(_id) do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SHADER_SOURCE, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpShader((_id)); \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SHADER_SOURCE, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_LINK_PROGRAM(_id) do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_LINK_PROGRAM, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpProgram((_id)); \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_LINK_PROGRAM, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_SWAPBUFFERS_ENTER() do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpBuffer(CR_SERVER_FBO_BB_IDX(cr_server.currentMural)); } \ + if (g_CrDbgDumpDrawFramesCount) { crServerDumpFramesCheck(); } \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_TEXPRESENT(_pTex) do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_TEXPRESENT, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpTexture((_pTex)); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_TEXPRESENT, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_SWAPBUFFERS_LEAVE() do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE, cr_server.Recorder.pDumper)) break; \ + crDmpStrF(cr_server.Recorder.pDumper, "==LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==Done LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_DRAWEL_F(_msg) do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpDrawel _msg; \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper); \ + } while (0) + +#define CR_SERVER_DUMP_DRAWEL_V(_index, _pszElFormat, _cbEl, _pvVal, _cVal) do { \ + if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper)) break; \ + crServerDumpCheckInit(); \ + crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \ + crServerDumpDrawelv((_index), (_pszElFormat), (_cbEl), (_pvVal), (_cVal)); \ + crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper); \ + } while (0) +#else /* if !defined VBOX_WITH_CRSERVER_DUMPER */ +#define CR_SERVER_DUMP_DRAW_ENTER() do {} while (0) +#define CR_SERVER_DUMP_DRAW_LEAVE() do {} while (0) +#define CR_SERVER_DUMP_COMPILE_SHADER(_id) do {} while (0) +#define CR_SERVER_DUMP_LINK_PROGRAM(_id) do {} while (0) +#define CR_SERVER_DUMP_TEXPRESENT(_pTex) do {} while (0) +#define CR_SERVER_DUMP_SWAPBUFFERS_ENTER() do {} while (0) +#define CR_SERVER_DUMP_SWAPBUFFERS_LEAVE() do {} while (0) +#define CR_SERVER_DUMP_SHADER_SOURCE(_id) do {} while (0) +#define CR_SERVER_DUMP_DRAWEL_F(_msg) do {} while (0) +#define CR_SERVER_DUMP_DRAWEL_V(_index, _pszElFormat, _cbEl, _pvVal, _cVal) do {} while (0) +#endif /* !VBOX_WITH_CRSERVER_DUMPER */ + +RT_C_DECLS_END + #endif /* CR_SERVER_H */ diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c index 9210d83b..e3c0100c 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c @@ -27,11 +27,18 @@ crServerDispatchGenBuffersARB(GLsizei n, GLuint *buffers) { GLuint *local_buffers = (GLuint *) crAlloc( n * sizeof(*local_buffers) ); (void) buffers; - cr_server.head_spu->dispatch_table.GenBuffersARB( n, local_buffers ); + + crStateGenBuffersARB(n, local_buffers); + crServerReturnValue( local_buffers, n * sizeof(*local_buffers) ); crFree( local_buffers ); } +void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteBuffersARB( GLsizei n, const GLuint * buffer ) +{ + crStateDeleteBuffersARB( n, buffer ); +} + void SERVER_DISPATCH_APIENTRY crServerDispatchGetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) { @@ -69,8 +76,9 @@ crServerDispatchBindBufferARB(GLenum target, GLuint buffer) GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsBufferARB(GLuint buffer) { - GLboolean retval; - retval = cr_server.head_spu->dispatch_table.IsBufferARB(crStateGetBufferHWID(buffer)); + /* since GenBuffersARB issued to host ogl only on bind + some other ops, the host drivers may not know about them + * so use state data*/ + GLboolean retval = crStateIsBufferARB(buffer); crServerReturnValue( &retval, sizeof(retval) ); return retval; /* WILL PROBABLY BE IGNORED */ } diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c index a6e6103f..64ef9462 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c @@ -427,18 +427,25 @@ crServerDispatchSwapBuffers( GLint window, GLint flags ) ctx = crStateGetCurrent(); + CRASSERT(cr_server.curClient && cr_server.curClient->currentMural == mural); + if (ctx->framebufferobject.drawFB || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT)) - cr_server.curClient->currentMural->bFbDraw = GL_FALSE; + mural->bFbDraw = GL_FALSE; + + CR_SERVER_DUMP_SWAPBUFFERS_ENTER(); if (crServerIsRedirectedToFBO()) { + crServerMuralFBOSwapBuffers(mural); crServerPresentFBO(mural); } else { cr_server.head_spu->dispatch_table.SwapBuffers( mural->spuWindow, flags ); } + + CR_SERVER_DUMP_SWAPBUFFERS_LEAVE(); } void SERVER_DISPATCH_APIENTRY @@ -447,20 +454,19 @@ crServerDispatchFlush(void) CRContext *ctx = crStateGetCurrent(); cr_server.head_spu->dispatch_table.Flush(); - if (!cr_server.curClient->currentMural) /* <- on window destroy this will be zero */ - return; - - if (cr_server.curClient->currentMural->bFbDraw && crServerIsRedirectedToFBO()) + if (cr_server.curClient && cr_server.curClient->currentMural) { -#ifdef DEBUG_misha - CRASSERT(0); -#endif - crServerPresentFBO(cr_server.curClient->currentMural); - } + CRMuralInfo *mural = cr_server.curClient->currentMural; + if (mural->bFbDraw) + { + if (crServerIsRedirectedToFBO()) + crServerPresentFBO(mural); + } - if (ctx->framebufferobject.drawFB - || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT)) - cr_server.curClient->currentMural->bFbDraw = GL_FALSE; + if (ctx->framebufferobject.drawFB + || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT)) + mural->bFbDraw = GL_FALSE; + } } void SERVER_DISPATCH_APIENTRY @@ -470,15 +476,17 @@ crServerDispatchFinish(void) cr_server.head_spu->dispatch_table.Finish(); - if (cr_server.curClient->currentMural->bFbDraw && crServerIsRedirectedToFBO()) + if (cr_server.curClient && cr_server.curClient->currentMural) { -#ifdef DEBUG_misha - CRASSERT(0); -#endif - crServerPresentFBO(cr_server.curClient->currentMural); - } + CRMuralInfo *mural = cr_server.curClient->currentMural; + if (mural->bFbDraw) + { + if (crServerIsRedirectedToFBO()) + crServerPresentFBO(mural); + } - if (ctx->framebufferobject.drawFB - || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT)) - cr_server.curClient->currentMural->bFbDraw = GL_FALSE; + if (ctx->framebufferobject.drawFB + || (ctx->buffer.drawBuffer != GL_FRONT && ctx->buffer.drawBuffer != GL_FRONT_LEFT)) + mural->bFbDraw = GL_FALSE; + } } diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c index 1621dcfc..c4b0ab93 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c @@ -50,14 +50,67 @@ setDefaults(void) cr_server.uniqueWindows = 0; - cr_server.idsPool.freeWindowID = 1; - cr_server.idsPool.freeContextID = 1; - cr_server.idsPool.freeClientID = 1; - cr_server.screenCount = 0; - cr_server.bForceOffscreenRendering = GL_FALSE; cr_server.bUsePBOForReadback = GL_FALSE; - cr_server.bUseOutputRedirect = GL_FALSE; + cr_server.bWindowsInitiallyHidden = GL_FALSE; + + cr_server.pfnNotifyEventCB = NULL; +} + +int crServerVBoxParseNumerics(const char *pszStr, const int defaultVal) +{ + int result = 0; + bool neg = false; + unsigned char iDigit = 0; + if (!pszStr || pszStr[0] == '\0') + return defaultVal; + + for (;;) + { + if (pszStr[0] == '\0') + return defaultVal; + + if (pszStr[0] == ' ' || pszStr[0] == '\t' || pszStr[0] == '\n') + { + ++pszStr; + continue; + } + + if (pszStr[0] == '-') + { + if (neg) + return defaultVal; + + neg = true; + ++pszStr; + continue; + } + + break; + } + + for (;;) + { + unsigned char digit; + if (pszStr[0] == '\0') + { + if (!iDigit) + return defaultVal; + break; + } + + digit = pszStr[0] - '0'; + if (digit > 9) + return defaultVal; + + result *= 10; + result += digit; + ++iDigit; + + ++pszStr; + } + + return !neg ? result : -result; } void crServerSetVBoxConfiguration() @@ -79,6 +132,7 @@ void crServerSetVBoxConfiguration() char hostname[1024]; char **clientchain, **clientlist; GLint dims[4]; + const char * env; defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0); CRASSERT(defaultMural); @@ -155,6 +209,37 @@ void crServerSetVBoxConfiguration() cr_server.head_spu = crSPULoadChain(num_spus, spu_ids, spu_names, spu_dir, &cr_server); + env = crGetenv( "CR_SERVER_DEFAULT_VISUAL_BITS" ); + if (env != NULL && env[0] != '\0') + { + unsigned int bits = (unsigned int)crServerVBoxParseNumerics(env, 0); + if (bits <= CR_ALL_BITS) + cr_server.fVisualBitsDefault = bits; + else + crWarning("invalid bits option %c", bits); + } + else + cr_server.fVisualBitsDefault = CR_RGB_BIT | CR_ALPHA_BIT | CR_DOUBLE_BIT; + + env = crGetenv("CR_SERVER_CAPS"); + if (env && env[0] != '\0') + { + cr_server.u32Caps = crServerVBoxParseNumerics(env, 0); + cr_server.u32Caps &= ~(CR_VBOX_CAP_TEX_PRESENT | CR_VBOX_CAP_CMDVBVA); + } + else + { + cr_server.u32Caps = CR_VBOX_CAP_TEX_PRESENT/* | CR_VBOX_CAP_CMDVBVA*/; +#ifdef DEBUG_misha + cr_server.u32Caps |= CR_VBOX_CAP_CMDVBVA; +#endif + + } + + crInfo("Cfg: u32Caps(%#x), fVisualBitsDefault(%#x)", + cr_server.u32Caps, + cr_server.fVisualBitsDefault); + /* Need to do this as early as possible */ cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_POSITION_CR, 0, GL_INT, 2, &dims[0]); @@ -258,6 +343,7 @@ void crServerSetVBoxConfigurationHGCM() char *spu_dir = NULL; int i; GLint dims[4]; + const char * env; defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0); CRASSERT(defaultMural); @@ -272,6 +358,37 @@ void crServerSetVBoxConfigurationHGCM() if (!cr_server.head_spu) return; + + env = crGetenv( "CR_SERVER_DEFAULT_VISUAL_BITS" ); + if (env != NULL && env[0] != '\0') + { + unsigned int bits = (unsigned int)crServerVBoxParseNumerics(env, 0); + if (bits <= CR_ALL_BITS) + cr_server.fVisualBitsDefault = bits; + else + crWarning("invalid bits option %c", bits); + } + else + cr_server.fVisualBitsDefault = CR_RGB_BIT | CR_ALPHA_BIT | CR_DOUBLE_BIT; + + env = crGetenv("CR_SERVER_CAPS"); + if (env && env[0] != '\0') + { + cr_server.u32Caps = crServerVBoxParseNumerics(env, 0); + cr_server.u32Caps &= ~(CR_VBOX_CAP_TEX_PRESENT | CR_VBOX_CAP_CMDVBVA); + } + else + { + cr_server.u32Caps = CR_VBOX_CAP_TEX_PRESENT/* | CR_VBOX_CAP_CMDVBVA*/; +#ifdef DEBUG_misha + cr_server.u32Caps |= CR_VBOX_CAP_CMDVBVA; +#endif + } + + crInfo("Cfg: u32Caps(%#x), fVisualBitsDefault(%#x)", + cr_server.u32Caps, + cr_server.fVisualBitsDefault); + cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_POSITION_CR, 0, GL_INT, 2, &dims[0]); cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, 0, GL_INT, 2, &dims[2]); diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c index 5c2ce040..afa2a208 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c @@ -27,6 +27,8 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi CRContextInfo *pContextInfo; GLboolean fFirst = GL_FALSE; + dpyName = ""; + if (shareCtx > 0) { crWarning("CRServer: context sharing not implemented."); shareCtx = 0; @@ -39,16 +41,23 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi return -1; } - pContextInfo->CreateInfo.visualBits = visualBits; + pContextInfo->currentMural = NULL; + + pContextInfo->CreateInfo.requestedVisualBits = visualBits; + + if (cr_server.fVisualBitsDefault) + visualBits = cr_server.fVisualBitsDefault; + + pContextInfo->CreateInfo.realVisualBits = visualBits; /* Since the Cr server serialized all incoming clients/contexts into * one outgoing GL stream, we only need to create one context for the * head SPU. We'll only have to make it current once too, below. */ if (cr_server.firstCallCreateContext) { - cr_server.MainContextInfo.CreateInfo.visualBits = visualBits; + cr_server.MainContextInfo.CreateInfo.realVisualBits = visualBits; cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table. - CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, shareCtx); + CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, shareCtx); if (cr_server.MainContextInfo.SpuContext < 0) { crWarning("crServerDispatchCreateContext() failed."); crFree(pContextInfo); @@ -58,16 +67,19 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi CRASSERT(cr_server.MainContextInfo.pContext); cr_server.firstCallCreateContext = GL_FALSE; fFirst = GL_TRUE; + + cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_SET_DEFAULT_SHARED_CTX, cr_server.MainContextInfo.SpuContext); } else { /* second or third or ... context */ - if (!cr_server.bUseMultipleContexts && ((visualBits & cr_server.MainContextInfo.CreateInfo.visualBits) != visualBits)) { + if (!cr_server.bUseMultipleContexts && ((visualBits & cr_server.MainContextInfo.CreateInfo.realVisualBits) != visualBits)) { int oldSpuContext; - + /* should never be here */ + CRASSERT(0); /* the new context needs new visual attributes */ - cr_server.MainContextInfo.CreateInfo.visualBits |= visualBits; - crDebug("crServerDispatchCreateContext requires new visual (0x%x).", - cr_server.MainContextInfo.CreateInfo.visualBits); + cr_server.MainContextInfo.CreateInfo.realVisualBits |= visualBits; + crWarning("crServerDispatchCreateContext requires new visual (0x%x).", + cr_server.MainContextInfo.CreateInfo.realVisualBits); /* Here, we used to just destroy the old rendering context. * Unfortunately, this had the side effect of destroying @@ -82,7 +94,7 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi /* create new rendering context with suitable visual */ oldSpuContext = cr_server.MainContextInfo.SpuContext; cr_server.MainContextInfo.SpuContext = cr_server.head_spu->dispatch_table. - CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, cr_server.MainContextInfo.SpuContext); + CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext); /* destroy old rendering context */ cr_server.head_spu->dispatch_table.DestroyContext(oldSpuContext); if (cr_server.MainContextInfo.SpuContext < 0) { @@ -90,12 +102,16 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi crFree(pContextInfo); return -1; } + + /* we do not need to clean up the old default context explicitly, since the above cr_server.head_spu->dispatch_table.DestroyContext call + * will do that for us */ + cr_server.head_spu->dispatch_table.ChromiumParameteriCR(GL_HH_SET_DEFAULT_SHARED_CTX, cr_server.MainContextInfo.SpuContext); } } if (cr_server.bUseMultipleContexts) { pContextInfo->SpuContext = cr_server.head_spu->dispatch_table. - CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.visualBits, cr_server.MainContextInfo.SpuContext); + CreateContext(dpyName, cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext); if (pContextInfo->SpuContext < 0) { crWarning("crServerDispatchCreateContext() failed."); crStateEnableDiffOnMakeCurrent(GL_TRUE); @@ -120,10 +136,10 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi if (newCtx) { crStateSetCurrentPointers( newCtx, &(cr_server.current) ); crStateResetCurrentPointers(&(cr_server.current)); - retVal = preloadCtxID<0 ? crServerGenerateID(&cr_server.idsPool.freeContextID) : preloadCtxID; + retVal = preloadCtxID<0 ? (GLint)crHashtableAllocKeys( cr_server.contextTable, 1 ) : preloadCtxID; pContextInfo->pContext = newCtx; - pContextInfo->CreateInfo.visualBits = visualBits; + Assert(pContextInfo->CreateInfo.realVisualBits == visualBits); pContextInfo->CreateInfo.externalID = retVal; pContextInfo->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL; crHashtableAdd(cr_server.contextTable, retVal, pContextInfo); @@ -139,25 +155,6 @@ GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLi } } - { - /* As we're using only one host context to serve all client contexts, newly created context will still - * hold last error value from any previous failed opengl call. Proper solution would be to redirect any - * client glGetError calls to our state tracker, but right now it's missing quite a lot of checks and doesn't - * reflect host driver/gpu specific issues. Thus we just reset last opengl error at context creation. - */ - GLint err; - - err = cr_server.head_spu->dispatch_table.GetError(); - if (err!=GL_NO_ERROR) - { -#ifdef DEBUG_misha - crDebug("Cleared gl error %#x on context creation", err); -#else - crWarning("Cleared gl error %#x on context creation", err); -#endif - } - } - crServerReturnValue( &retVal, sizeof(retVal) ); return retVal; @@ -179,6 +176,14 @@ static int crServerRemoveClientContext(CRClient *pClient, GLint ctx) return false; } +static void crServerCleanupMuralCtxUsageCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo *mural = (CRMuralInfo *) data1; + CRContext *ctx = (CRContext *) data2; + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(mural, ctx); +} + void SERVER_DISPATCH_APIENTRY crServerDispatchDestroyContext( GLint ctx ) { @@ -198,6 +203,15 @@ crServerDispatchDestroyContext( GLint ctx ) crDebug("CRServer: DestroyContext context %d", ctx); + if (cr_server.currentCtxInfo == crCtxInfo) + { + CRMuralInfo *dummyMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + crServerPerformMakeCurrent(dummyMural, &cr_server.MainContextInfo); + CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo); + } + + crHashtableWalk(cr_server.muralTable, crServerCleanupMuralCtxUsageCB, crCtx); + crCtxInfo->currentMural = NULL; crHashtableDelete(cr_server.contextTable, ctx, NULL); crStateDestroyContext( crCtx ); @@ -268,82 +282,56 @@ crServerDispatchDestroyContext( GLint ctx ) pNode = pNode->next; } - if (cr_server.currentCtxInfo == crCtxInfo) - { - cr_server.currentCtxInfo = &cr_server.MainContextInfo; - } + CRASSERT(cr_server.currentCtxInfo != crCtxInfo); } -void SERVER_DISPATCH_APIENTRY -crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context ) +void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo ) { - CRMuralInfo *mural, *oldMural; - CRContextInfo *ctxInfo = NULL; + CRMuralInfo *oldMural; CRContext *ctx, *oldCtx = NULL; - - if (context >= 0 && window >= 0) { - mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window); - if (!mural) - { - crWarning("CRServer: invalid window %d passed to crServerDispatchMakeCurrent()", window); - return; - } - - /* Update the state tracker's current context */ - ctxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, context); - if (!ctxInfo) { - crWarning("CRserver: NULL context in MakeCurrent %d", context); - return; - } - } - else { -#if 0 - oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow); - if (oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO()) - { - if (!crStateGetCurrent()->framebufferobject.drawFB) - { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - } - if (!crStateGetCurrent()->framebufferobject.readFB) - { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - } - } - - ctxInfo = &cr_server.MainContextInfo; - window = -1; - mural = NULL; -#endif - cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE; - return; - } + GLuint idDrawFBO, idReadFBO; + GLint context = ctxInfo->CreateInfo.externalID; + GLint window = mural->CreateInfo.externalID; cr_server.bForceMakeCurrentOnClientSwitch = GL_FALSE; ctx = ctxInfo->pContext; CRASSERT(ctx); - oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow); + oldMural = cr_server.currentMural; /* Ubuntu 11.04 hosts misbehave if context window switch is * done with non-default framebuffer object settings. - * crStateSwichPrepare & crStateSwichPostprocess are supposed to work around this problem - * crStateSwichPrepare restores the FBO state to its default values before the context window switch, - * while crStateSwichPostprocess restores it back to the original values */ - oldCtx = crStateSwichPrepare(ctx, cr_server.bUseMultipleContexts, oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO() ? oldMural->idFBO : 0); - - /* - crDebug("**** %s client %d curCtx=%d curWin=%d", __func__, - cr_server.curClient->number, ctxPos, window); - */ - cr_server.curClient->currentContextNumber = context; - cr_server.curClient->currentCtxInfo = ctxInfo; - cr_server.curClient->currentMural = mural; - cr_server.curClient->currentWindow = window; + * crStateSwitchPrepare & crStateSwitchPostprocess are supposed to work around this problem + * crStateSwitchPrepare restores the FBO state to its default values before the context window switch, + * while crStateSwitchPostprocess restores it back to the original values */ + oldCtx = crStateGetCurrent(); + if (oldMural && oldMural->fRedirected && crServerSupportRedirMuralFBO()) + { + idDrawFBO = CR_SERVER_FBO_FOR_IDX(oldMural, oldMural->iCurDrawBuffer); + idReadFBO = CR_SERVER_FBO_FOR_IDX(oldMural, oldMural->iCurReadBuffer); + } + else + { + idDrawFBO = 0; + idReadFBO = 0; + } + crStateSwitchPrepare(cr_server.bUseMultipleContexts ? NULL : ctx, oldCtx, idDrawFBO, idReadFBO); - CRASSERT(cr_server.curClient->currentCtxInfo); - CRASSERT(cr_server.curClient->currentCtxInfo->pContext); + if (cr_server.curClient) + { + /* + crDebug("**** %s client %d curCtx=%d curWin=%d", __func__, + cr_server.curClient->number, ctxPos, window); + */ + cr_server.curClient->currentContextNumber = context; + cr_server.curClient->currentCtxInfo = ctxInfo; + cr_server.curClient->currentMural = mural; + cr_server.curClient->currentWindow = window; + + CRASSERT(cr_server.curClient->currentCtxInfo); + CRASSERT(cr_server.curClient->currentCtxInfo->pContext); + } /* This is a hack to force updating the 'current' attribs */ crStateUpdateColorBits(); @@ -380,26 +368,58 @@ crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context ) * used though. */ cr_server.head_spu->dispatch_table.MakeCurrent( mural->spuWindow, - nativeWindow, + 0, ctxInfo->SpuContext >= 0 ? ctxInfo->SpuContext : cr_server.MainContextInfo.SpuContext); + + CR_STATE_SHAREDOBJ_USAGE_SET(mural, ctx); + if (cr_server.currentCtxInfo) + cr_server.currentCtxInfo->currentMural = NULL; + ctxInfo->currentMural = mural; + cr_server.firstCallMakeCurrent = GL_FALSE; cr_server.currentCtxInfo = ctxInfo; cr_server.currentWindow = window; - cr_server.currentNativeWindow = nativeWindow; + cr_server.currentNativeWindow = 0; + cr_server.currentMural = mural; } /* This used to be earlier, after crStateUpdateColorBits() call */ crStateMakeCurrent( ctx ); - crStateSwichPostprocess(oldCtx, cr_server.bUseMultipleContexts, mural->bUseFBO && crServerSupportRedirMuralFBO() ? mural->idFBO : 0); + if (mural && mural->fRedirected && crServerSupportRedirMuralFBO()) + { + GLuint id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer); + if (id != mural->iCurDrawBuffer) + { + crDebug("DBO draw buffer changed on make current"); + mural->iCurDrawBuffer = id; + } + + id = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer); + if (id != mural->iCurReadBuffer) + { + crDebug("DBO read buffer changed on make current"); + mural->iCurReadBuffer = id; + } + + idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer); + idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer); + } + else + { + idDrawFBO = 0; + idReadFBO = 0; + } + crStateSwitchPostprocess(ctx, cr_server.bUseMultipleContexts ? NULL : oldCtx, idDrawFBO, idReadFBO); if (!ctx->framebufferobject.drawFB - && (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT)) + && (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT) + && cr_server.curClient) cr_server.curClient->currentMural->bFbDraw = GL_TRUE; - if (!mural->bUseFBO) + if (!mural->fRedirected) { ctx->buffer.width = mural->width; ctx->buffer.height = mural->height; @@ -411,3 +431,51 @@ crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context ) } } + +void SERVER_DISPATCH_APIENTRY +crServerDispatchMakeCurrent( GLint window, GLint nativeWindow, GLint context ) +{ + CRMuralInfo *mural; + CRContextInfo *ctxInfo = NULL; + + if (context >= 0 && window >= 0) { + mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window); + if (!mural) + { + crWarning("CRServer: invalid window %d passed to crServerDispatchMakeCurrent()", window); + return; + } + + /* Update the state tracker's current context */ + ctxInfo = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, context); + if (!ctxInfo) { + crWarning("CRserver: NULL context in MakeCurrent %d", context); + return; + } + } + else { +#if 0 + oldMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, cr_server.currentWindow); + if (oldMural && oldMural->bUseFBO && crServerSupportRedirMuralFBO()) + { + if (!crStateGetCurrent()->framebufferobject.drawFB) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); + } + if (!crStateGetCurrent()->framebufferobject.readFB) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); + } + } + + ctxInfo = &cr_server.MainContextInfo; + window = -1; + mural = NULL; +#endif + cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE; + return; + } + + crServerPerformMakeCurrent( mural, ctxInfo ); +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py index cacc3530..9e5b5397 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py @@ -46,6 +46,7 @@ keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt") for func_name in keys: current = 0 array = "" + condition = "" m = re.search( r"^(Color|Normal)([1234])(ub|b|us|s|ui|i|f|d)$", func_name ) if m : current = 1 @@ -68,6 +69,7 @@ for func_name in keys: name = "texCoord" type = m.group(3) + m.group(2) array = "[texture-GL_TEXTURE0_ARB]" + condition = "if (texture >= GL_TEXTURE0_ARB && texture < GL_TEXTURE0_ARB + CR_MAX_TEXTURE_UNITS)" m = re.match( r"^(Index)(ub|b|us|s|ui|i|f|d)$", func_name ) if m : current = 1 @@ -91,18 +93,23 @@ for func_name in keys: name = string.lower( m.group(1)[:1] ) + m.group(1)[1:] type = m.group(3) + m.group(2) array = "[index]" + condition = "if (index < CR_MAX_VERTEX_ATTRIBS)" if func_name == "VertexAttrib4NubARB": current = 1 name = "vertexAttrib" type = "ub4" array = "[index]" + condition = "if (index < CR_MAX_VERTEX_ATTRIBS)" if current: params = apiutil.Parameters(func_name) print 'void SERVER_DISPATCH_APIENTRY crServerDispatch%s( %s )' % ( func_name, apiutil.MakeDeclarationString(params) ) print '{' - print '\tcr_server.head_spu->dispatch_table.%s( %s );' % (func_name, apiutil.MakeCallString(params) ) - print "\tcr_server.current.c.%s.%s%s = cr_unpackData;" % (name,type,array) + print '\t%s' % (condition) + print '\t{' + print '\t\tcr_server.head_spu->dispatch_table.%s( %s );' % (func_name, apiutil.MakeCallString(params) ) + print "\t\tcr_server.current.c.%s.%s%s = cr_unpackData;" % (name,type,array) + print '\t}' print '}\n' print """ diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py index f1db1f05..9ac9895a 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py @@ -22,6 +22,11 @@ print """ #include "chromium.h" #include "state/cr_statetypes.h" + +#if defined(__cplusplus) +extern "C" { +#endif + """ keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt") @@ -36,4 +41,10 @@ for func_name in keys: print '%s SERVER_DISPATCH_APIENTRY crServerDispatch%s( %s );' % (return_type, func_name, apiutil.MakeDeclarationString( params )) -print '#endif /* SERVER_DISPATCH_HEADER */' +print """ +#if defined(__cplusplus) +} +#endif + +#endif /* SERVER_DISPATCH_HEADER */ +""" diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c index cc609377..da25dbb0 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_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; @@ -28,7 +28,9 @@ crServerDispatchGenFramebuffersEXT(GLsizei n, GLuint *framebuffers) { GLuint *local_buffers = (GLuint *) crAlloc(n * sizeof(*local_buffers)); (void) framebuffers; - cr_server.head_spu->dispatch_table.GenFramebuffersEXT(n, local_buffers); + + crStateGenFramebuffersEXT(n, local_buffers); + crServerReturnValue(local_buffers, n * sizeof(*local_buffers)); crFree(local_buffers); } @@ -38,7 +40,9 @@ crServerDispatchGenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) { GLuint *local_buffers = (GLuint *) crAlloc(n * sizeof(*local_buffers)); (void) renderbuffers; - cr_server.head_spu->dispatch_table.GenFramebuffersEXT(n, local_buffers); + + crStateGenRenderbuffersEXT(n, local_buffers); + crServerReturnValue(local_buffers, n * sizeof(*local_buffers)); crFree(local_buffers); } @@ -71,29 +75,54 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchBindFramebufferEXT(GLenum target, if (0==framebuffer) { CRContext *ctx = crStateGetCurrent(); - if (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT) + if (ctx->buffer.drawBuffer == GL_FRONT || ctx->buffer.drawBuffer == GL_FRONT_LEFT || ctx->buffer.drawBuffer == GL_FRONT_RIGHT) cr_server.curClient->currentMural->bFbDraw = GL_TRUE; } if (0==framebuffer && crServerIsRedirectedToFBO()) { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(target, cr_server.curClient->currentMural->idFBO); + CRMuralInfo *mural = cr_server.curClient->currentMural; + if (target == GL_FRAMEBUFFER) + { + GLuint idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer); + GLuint idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer); + if (idDrawFBO == idReadFBO) + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_FRAMEBUFFER, idDrawFBO); + else + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO); + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO); + } + } + else if (target == GL_READ_FRAMEBUFFER) + { + GLuint idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer); + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO); + } + else if (target == GL_DRAW_FRAMEBUFFER) + { + GLuint idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer); + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO); + } + else + { + crWarning("unknown target %d", target); + } #ifdef DEBUG_misha - Assert(0); cr_server.head_spu->dispatch_table.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb); cr_server.head_spu->dispatch_table.GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb); if (GL_FRAMEBUFFER_EXT == target) { - Assert(rfb == cr_server.curClient->currentMural->idFBO); - Assert(dfb == cr_server.curClient->currentMural->idFBO); + Assert(rfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer)); + Assert(dfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer)); } else if (GL_READ_FRAMEBUFFER_EXT == target) { - Assert(rfb == cr_server.curClient->currentMural->idFBO); + Assert(rfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer)); } else if (GL_DRAW_FRAMEBUFFER_EXT == target) { - Assert(dfb == cr_server.curClient->currentMural->idFBO); + Assert(dfb == CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer)); } else { @@ -163,16 +192,18 @@ crServerDispatchGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum att GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsFramebufferEXT( GLuint framebuffer ) { - GLboolean retval; - retval = cr_server.head_spu->dispatch_table.IsFramebufferEXT(crStateGetFramebufferHWID(framebuffer)); + /* since GenFramebuffers/Renderbuffers issued to host ogl only on bind + some other ops, the host drivers may not know about them + * so use state data*/ + GLboolean retval = crStateIsFramebufferEXT(framebuffer); crServerReturnValue( &retval, sizeof(retval) ); return retval; /* WILL PROBABLY BE IGNORED */ } GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsRenderbufferEXT( GLuint renderbuffer ) { - GLboolean retval; - retval = cr_server.head_spu->dispatch_table.IsRenderbufferEXT(crStateGetRenderbufferHWID(renderbuffer)); + /* since GenFramebuffers/Renderbuffers issued to host ogl only on bind + some other ops, the host drivers may not know about them + * so use state data*/ + GLboolean retval = crStateIsRenderbufferEXT(renderbuffer); crServerReturnValue( &retval, sizeof(retval) ); return retval; /* WILL PROBABLY BE IGNORED */ } diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py index 89391d6c..58d4953e 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py @@ -108,8 +108,6 @@ convert_bufferid = [ 'GetVertexAttribivNV' ]; -from get_components import *; - keys = apiutil.GetDispatchedFunctions(sys.argv[1]+"/APIspec.txt") for func_name in keys: #(return_type, arg_names, arg_types) = gl_mapping[func_name] @@ -142,5 +140,5 @@ for func_name in keys: if func_name in no_pnames: print '\tcrServerReturnValue( &(%s[0]), %d*sizeof(%s) );' % (local_argname, max_components[func_name], local_argtype ); else: - print '\tcrServerReturnValue( &(%s[0]), lookupComponents(pname)*sizeof(%s) );' % (local_argname, local_argtype ); + print '\tcrServerReturnValue( &(%s[0]), crStateHlpComponentsCount(pname)*sizeof(%s) );' % (local_argname, local_argtype ); print '}\n' diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c index 12677f84..20acbc05 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.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; @@ -46,6 +46,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetActiveAttrib(GLuint program, GL zero.length = 0; crServerReturnValue(&zero, sizeof(zero)); } + /* zero out just the header to ensure it initially contains zero size values */ + memset(pLocal, 0, sizeof (*pLocal)); cr_server.head_spu->dispatch_table.GetActiveAttrib(crStateGetProgramHWID(program), index, bufSize, &pLocal->length, &pLocal->size, &pLocal->type, (char*)&pLocal[1]); crServerReturnValue(pLocal, pLocal->length+1+sizeof(crGetActive_t)); crFree(pLocal); @@ -62,6 +64,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetActiveUniform(GLuint program, G zero.length = 0; crServerReturnValue(&zero, sizeof(zero)); } + /* zero out just the header to ensure it initially contains zero size values */ + memset(pLocal, 0, sizeof (*pLocal)); cr_server.head_spu->dispatch_table.GetActiveUniform(crStateGetProgramHWID(program), index, bufSize, &pLocal->length, &pLocal->size, &pLocal->type, (char*)&pLocal[1]); crServerReturnValue(pLocal, pLocal->length+1+sizeof(crGetActive_t)); crFree(pLocal); @@ -77,6 +81,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedShaders(GLuint program, GLsizei zero=0; crServerReturnValue(&zero, sizeof(zero)); } + /* initial (fallback )value */ + *pLocal = 0; cr_server.head_spu->dispatch_table.GetAttachedShaders(crStateGetProgramHWID(program), maxCount, pLocal, (GLuint*)&pLocal[1]); { @@ -91,17 +97,19 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedShaders(GLuint program, crFree(pLocal); } -void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedObjectsARB(GLhandleARB containerObj, GLsizei maxCount, GLsizei * count, GLhandleARB * obj) +void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedObjectsARB(VBoxGLhandleARB containerObj, GLsizei maxCount, GLsizei * count, VBoxGLhandleARB * obj) { GLsizei *pLocal; - pLocal = (GLsizei*) crAlloc(maxCount*sizeof(GLhandleARB)+sizeof(GLsizei)); + pLocal = (GLsizei*) crAlloc(maxCount*sizeof(VBoxGLhandleARB)+sizeof(GLsizei)); if (!pLocal) { GLsizei zero=0; crServerReturnValue(&zero, sizeof(zero)); } - cr_server.head_spu->dispatch_table.GetAttachedObjectsARB(crStateGetProgramHWID(containerObj), maxCount, pLocal, (GLhandleARB*)&pLocal[1]); + /* initial (fallback )value */ + *pLocal = 0; + cr_server.head_spu->dispatch_table.GetAttachedObjectsARB(crStateGetProgramHWID(containerObj), maxCount, pLocal, (VBoxGLhandleARB*)&pLocal[1]); { GLsizei i; @@ -111,13 +119,13 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetAttachedObjectsARB(GLhandleARB ids[i] = crStateGLSLShaderHWIDtoID(ids[i]); } - crServerReturnValue(pLocal, (*pLocal)*sizeof(GLhandleARB)+sizeof(GLsizei)); + crServerReturnValue(pLocal, (*pLocal)*sizeof(VBoxGLhandleARB)+sizeof(GLsizei)); crFree(pLocal); } AssertCompile(sizeof(GLsizei) == 4); -void SERVER_DISPATCH_APIENTRY crServerDispatchGetInfoLogARB(GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog) +void SERVER_DISPATCH_APIENTRY crServerDispatchGetInfoLogARB(VBoxGLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * infoLog) { GLsizei *pLocal; GLuint hwid; @@ -128,6 +136,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetInfoLogARB(GLhandleARB obj, GLs GLsizei zero=0; crServerReturnValue(&zero, sizeof(zero)); } + /* initial (fallback )value */ + *pLocal = 0; /*@todo: recheck*/ hwid = crStateGetProgramHWID(obj); if (!hwid) hwid = crStateGetShaderHWID(obj); @@ -147,6 +157,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetShaderInfoLog(GLuint shader, GL GLsizei zero=0; crServerReturnValue(&zero, sizeof(zero)); } + /* initial (fallback )value */ + *pLocal = 0; cr_server.head_spu->dispatch_table.GetShaderInfoLog(crStateGetShaderHWID(shader), bufSize, pLocal, (char*)&pLocal[1]); crServerReturnValue(pLocal, pLocal[0]+sizeof(GLsizei)); crFree(pLocal); @@ -162,6 +174,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetProgramInfoLog(GLuint program, GLsizei zero=0; crServerReturnValue(&zero, sizeof(zero)); } + /* initial (fallback )value */ + *pLocal = 0; cr_server.head_spu->dispatch_table.GetProgramInfoLog(crStateGetProgramHWID(program), bufSize, pLocal, (char*)&pLocal[1]); CRASSERT(pLocal[0] <= bufSize); crServerReturnValue(pLocal, pLocal[0]+sizeof(GLsizei)); @@ -178,6 +192,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetShaderSource(GLuint shader, GLs GLsizei zero=0; crServerReturnValue(&zero, sizeof(zero)); } + /* initial (fallback )value */ + *pLocal = 0; cr_server.head_spu->dispatch_table.GetShaderSource(crStateGetShaderHWID(shader), bufSize, pLocal, (char*)&pLocal[1]); CRASSERT(pLocal[0] <= bufSize); crServerReturnValue(pLocal, pLocal[0]+sizeof(GLsizei)); @@ -199,6 +215,8 @@ crServerDispatchGetUniformsLocations(GLuint program, GLsizei maxcbData, GLsizei crServerReturnValue(&zero, sizeof(zero)); } + /* initial (fallback )value */ + *pLocal = 0; crStateGLSLProgramCacheUniforms(program, maxcbData, pLocal, (char*)&pLocal[1]); crServerReturnValue(pLocal, (*pLocal)+sizeof(GLsizei)); @@ -207,8 +225,8 @@ crServerDispatchGetUniformsLocations(GLuint program, GLsizei maxcbData, GLsizei static GLint __GetUniformSize(GLuint program, GLint location) { - GLint size; - GLenum type; + GLint size = 0; + GLenum type = 0; /*@todo: check if index and location is the same*/ cr_server.head_spu->dispatch_table.GetActiveUniform(crStateGetProgramHWID(program), location, 0, NULL, &size, &type, NULL); @@ -286,7 +304,7 @@ GLboolean SERVER_DISPATCH_APIENTRY crServerDispatchIsProgram(GLuint program) return retval; /* ignored */ } -void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterfvARB( GLhandleARB obj, GLenum pname, GLfloat * params ) +void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterfvARB( VBoxGLhandleARB obj, GLenum pname, GLfloat * params ) { GLfloat local_params[1]; GLuint hwid = crStateGetProgramHWID(obj); @@ -305,7 +323,7 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterfvARB( GLhandleA crServerReturnValue( &(local_params[0]), 1*sizeof(GLfloat) ); } -void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterivARB( GLhandleARB obj, GLenum pname, GLint * params ) +void SERVER_DISPATCH_APIENTRY crServerDispatchGetObjectParameterivARB( VBoxGLhandleARB obj, GLenum pname, GLint * params ) { GLint local_params[1]; GLuint hwid = crStateGetProgramHWID(obj); diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c index c11d2d00..25d4b91e 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_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; @@ -29,13 +29,29 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchShaderSource(GLuint shader, GLsizei count, const char ** string, const GLint * length) { /*@todo?crStateShaderSource(shader...);*/ +#ifdef DEBUG_misha + GLenum err = cr_server.head_spu->dispatch_table.GetError(); +#endif cr_server.head_spu->dispatch_table.ShaderSource(crStateGetShaderHWID(shader), count, string, length); +#ifdef DEBUG_misha + err = cr_server.head_spu->dispatch_table.GetError(); + CRASSERT(err == GL_NO_ERROR); +#endif + CR_SERVER_DUMP_SHADER_SOURCE(shader); } void SERVER_DISPATCH_APIENTRY crServerDispatchCompileShader(GLuint shader) { +#ifdef DEBUG_misha + GLint iCompileStatus = GL_FALSE; +#endif crStateCompileShader(shader); cr_server.head_spu->dispatch_table.CompileShader(crStateGetShaderHWID(shader)); +#ifdef DEBUG_misha + cr_server.head_spu->dispatch_table.GetShaderiv(crStateGetShaderHWID(shader), GL_COMPILE_STATUS, &iCompileStatus); + Assert(iCompileStatus == GL_TRUE); +#endif + CR_SERVER_DUMP_COMPILE_SHADER(shader); } void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteShader(GLuint shader) @@ -64,6 +80,7 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchLinkProgram(GLuint program) { crStateLinkProgram(program); cr_server.head_spu->dispatch_table.LinkProgram(crStateGetProgramHWID(program)); + CR_SERVER_DUMP_LINK_PROGRAM(program); } void SERVER_DISPATCH_APIENTRY crServerDispatchUseProgram(GLuint program) @@ -94,23 +111,14 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchBindAttribLocation(GLuint program, cr_server.head_spu->dispatch_table.BindAttribLocation(crStateGetProgramHWID(program), index, name); } -void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteObjectARB(GLhandleARB obj) +void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteObjectARB(VBoxGLhandleARB obj) { - GLuint hwid = crStateGetProgramHWID(obj); - - if (!hwid) - { - hwid = crStateGetShaderHWID(obj); - CRASSERT(hwid); - crStateDeleteShader(obj); - } - else - { - crStateDeleteProgram(obj); - } + GLuint hwid = crStateDeleteObjectARB(obj); if (hwid) cr_server.head_spu->dispatch_table.DeleteObjectARB(hwid); + else + crWarning("zero hwid for object %d", obj); } GLint SERVER_DISPATCH_APIENTRY crServerDispatchGetAttribLocation( GLuint program, const char * name ) @@ -121,9 +129,9 @@ GLint SERVER_DISPATCH_APIENTRY crServerDispatchGetAttribLocation( GLuint program return retval; /* WILL PROBABLY BE IGNORED */ } -GLhandleARB SERVER_DISPATCH_APIENTRY crServerDispatchGetHandleARB( GLenum pname ) +VBoxGLhandleARB SERVER_DISPATCH_APIENTRY crServerDispatchGetHandleARB( GLenum pname ) { - GLhandleARB retval; + VBoxGLhandleARB retval; retval = cr_server.head_spu->dispatch_table.GetHandleARB(pname); if (pname==GL_PROGRAM_OBJECT_ARB) { @@ -141,4 +149,19 @@ GLint SERVER_DISPATCH_APIENTRY crServerDispatchGetUniformLocation(GLuint program return retval; /* WILL PROBABLY BE IGNORED */ } +void SERVER_DISPATCH_APIENTRY crServerDispatchGetProgramiv( GLuint program, GLenum pname, GLint * params ) +{ + GLint local_params[1]; + (void) params; + cr_server.head_spu->dispatch_table.GetProgramiv(crStateGetProgramHWID(program), pname, local_params); + crServerReturnValue( &(local_params[0]), 1*sizeof(GLint) ); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchGetShaderiv( GLuint shader, GLenum pname, GLint * params ) +{ + GLint local_params[1]; + (void) params; + cr_server.head_spu->dispatch_table.GetShaderiv( crStateGetShaderHWID(shader), pname, local_params ); + crServerReturnValue( &(local_params[0]), 1*sizeof(GLint) ); +} #endif /* #ifdef CR_OPENGL_VERSION_2_0 */ diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c index 3079c15b..6c3d9bd0 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c @@ -60,6 +60,7 @@ GLuint crServerTranslateProgramID( GLuint id ) void SERVER_DISPATCH_APIENTRY crServerDispatchNewList( GLuint list, GLenum mode ) { + Assert(0); if (mode == GL_COMPILE_AND_EXECUTE) crWarning("using glNewList(GL_COMPILE_AND_EXECUTE) can confuse the crserver"); @@ -68,10 +69,37 @@ crServerDispatchNewList( GLuint list, GLenum mode ) cr_server.head_spu->dispatch_table.NewList( list, mode ); } +static void crServerQueryHWState() +{ + GLuint fbFbo, bbFbo; + CRClient *client = cr_server.curClient; + CRMuralInfo *mural = client ? client->currentMural : NULL; + if (mural && mural->fRedirected) + { + fbFbo = mural->aidFBOs[CR_SERVER_FBO_FB_IDX(mural)]; + bbFbo = mural->aidFBOs[CR_SERVER_FBO_BB_IDX(mural)]; + } + else + { + fbFbo = bbFbo = 0; + } + crStateQueryHWState(fbFbo, bbFbo); +} + void SERVER_DISPATCH_APIENTRY crServerDispatchEndList(void) { + CRContext *g = crStateGetCurrent(); + CRListsState *l = &(g->lists); + cr_server.head_spu->dispatch_table.EndList(); crStateEndList(); + +#ifndef IN_GUEST + if (l->mode==GL_COMPILE) + { + crServerQueryHWState(); + } +#endif } void SERVER_DISPATCH_APIENTRY @@ -83,7 +111,7 @@ crServerDispatchCallList( GLuint list ) /* we're not compiling, so execute the list now */ /* Issue the list as-is */ cr_server.head_spu->dispatch_table.CallList( list ); - crStateQueryHWState(); + crServerQueryHWState(); } else { /* we're compiling glCallList into another list - just pass it through */ @@ -211,7 +239,7 @@ crServerDispatchCallLists( GLsizei n, GLenum type, const GLvoid *lists ) /* we're not compiling, so execute the list now */ /* Issue the list as-is */ cr_server.head_spu->dispatch_table.CallLists( n, type, lists ); - crStateQueryHWState(); + crServerQueryHWState(); } else { /* we're compiling glCallList into another list - just pass it through */ @@ -264,6 +292,12 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchDeleteTextures( GLsizei n, const G newTextures[i] = crStateGetTextureHWID(textures[i]); } + for (i = 0; i < n; ++i) + { + crDebug("DeleteTexture: %d, pid %d, ctx %d", textures[i], (uint32_t)cr_server.curClient->pid, cr_server.currentCtxInfo->pContext->id); + } + + crStateDeleteTextures(n, textures); cr_server.head_spu->dispatch_table.DeleteTextures(n, newTextures); crFree(newTextures); @@ -280,12 +314,13 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchPrioritizeTextures( GLsizei n, con return; } + crStatePrioritizeTextures(n, textures, priorities); + for (i = 0; i < n; i++) { newTextures[i] = crStateGetTextureHWID(textures[i]); } - crStatePrioritizeTextures(n, textures, priorities); cr_server.head_spu->dispatch_table.PrioritizeTextures(n, newTextures, priorities); crFree(newTextures); } diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c index f914569e..1a7e360c 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c @@ -12,7 +12,9 @@ #include "cr_string.h" #include "cr_mem.h" #include "cr_hash.h" +#include "cr_vreg.h" #include "cr_environment.h" +#include "cr_pixeldata.h" #include "server_dispatch.h" #include "state/cr_texture.h" #include "render/renderspu.h" @@ -25,6 +27,7 @@ #endif #include <iprt/assert.h> #include <VBox/err.h> +#include <VBox/log.h> #ifdef VBOXCR_LOGFPS #include <iprt/timer.h> @@ -56,6 +59,8 @@ CRServer cr_server; int tearingdown = 0; /* can't be static */ +static DECLCALLBACK(int) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd); + DECLINLINE(int32_t) crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient) { CRClient *pClient = NULL; @@ -118,11 +123,22 @@ static void deleteContextInfoCallback( void *data ) crFree(c); } +static void deleteMuralInfoCallback( void *data ) +{ + CRMuralInfo *m = (CRMuralInfo *) data; + if (m->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID) /* <- do not do term for default mural as it does not contain any info to be freed, + * and renderspu will destroy it up itself*/ + { + crServerMuralTerm(m); + } + crFree(m); +} static void crServerTearDown( void ) { GLint i; CRClientNode *pNode, *pNext; + GLboolean fOldEnableDiff; /* avoid a race condition */ if (tearingdown) @@ -138,6 +154,17 @@ static void crServerTearDown( void ) crFree( cr_server.overlap_intens ); cr_server.overlap_intens = NULL; + /* needed to make sure window dummy mural not get created on mural destruction + * and generally this should be zeroed up */ + cr_server.currentCtxInfo = NULL; + cr_server.currentWindow = -1; + cr_server.currentNativeWindow = 0; + cr_server.currentMural = NULL; + + /* sync our state with renderspu, + * do it before mural & context deletion to avoid deleting currently set murals/contexts*/ + cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID); + /* Deallocate all semaphores */ crFreeHashtable(cr_server.semaphores, crFree); cr_server.semaphores = NULL; @@ -149,12 +176,28 @@ static void crServerTearDown( void ) /* Free all context info */ crFreeHashtable(cr_server.contextTable, deleteContextInfoCallback); - /* Free context/window creation info */ - crFreeHashtable(cr_server.pWindowCreateInfoTable, crServerCreateInfoDeleteCB); + /* synchronize with reality */ + fOldEnableDiff = crStateEnableDiffOnMakeCurrent(GL_FALSE); + if(cr_server.MainContextInfo.pContext) + crStateMakeCurrent(cr_server.MainContextInfo.pContext); + crStateEnableDiffOnMakeCurrent(fOldEnableDiff); /* Free vertex programs */ crFreeHashtable(cr_server.programTable, crFree); + /* Free murals */ + crFreeHashtable(cr_server.muralTable, deleteMuralInfoCallback); + + CrPMgrTerm(); + + if (CrBltIsInitialized(&cr_server.Blitter)) + { + CrBltTerm(&cr_server.Blitter); + } + + /* Free dummy murals */ + crFreeHashtable(cr_server.dummyMuralTable, deleteMuralInfoCallback); + for (i = 0; i < cr_server.numClients; i++) { if (cr_server.clients[i]) { CRConnection *conn = cr_server.clients[i]->conn; @@ -174,6 +217,11 @@ static void crServerTearDown( void ) } cr_server.pCleanupClient = NULL; + if (crServerRpwIsInitialized(&cr_server.RpwWorker)) + { + crServerRpwTerm(&cr_server.RpwWorker); + } + #if 1 /* disable these two lines if trying to get stack traces with valgrind */ crSPUUnloadChain(cr_server.head_spu); @@ -183,6 +231,10 @@ static void crServerTearDown( void ) crStateDestroy(); crNetTearDown(); + + VBoxVrListClear(&cr_server.RootVr); + + VBoxVrTerm(); } static void crServerClose( unsigned int id ) @@ -226,8 +278,15 @@ void crServerInit(int argc, char *argv[]) { int i; + const char*env; char *mothership = NULL; CRMuralInfo *defaultMural; + int rc = VBoxVrInit(); + if (!RT_SUCCESS(rc)) + { + crWarning("VBoxVrInit failed, rc %d", rc); + return; + } for (i = 1 ; i < argc ; i++) { @@ -294,6 +353,7 @@ crServerInit(int argc, char *argv[]) */ cr_server.muralTable = crAllocHashtable(); defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo)); + defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID; crHashtableAdd(cr_server.muralTable, 0, defaultMural); cr_server.programTable = crAllocHashtable(); @@ -311,9 +371,39 @@ crServerInit(int argc, char *argv[]) cr_server.contextTable = crAllocHashtable(); cr_server.curClient->currentCtxInfo = &cr_server.MainContextInfo; + cr_server.dummyMuralTable = crAllocHashtable(); + + CrPMgrInit(); + + cr_server.fRootVrOn = GL_FALSE; + VBoxVrListInit(&cr_server.RootVr); + crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint)); + + crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker)); + + env = crGetenv("CR_SERVER_BFB"); + if (env) + { + cr_server.fBlitterMode = env[0] - '0'; + } + else + { + cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED; + } + crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter)); + crServerInitDispatch(); + crServerInitTmpCtxDispatch(); crStateDiffAPI( &(cr_server.head_spu->dispatch_table) ); +#ifdef VBOX_WITH_CRSERVER_DUMPER + crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder)); + crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter)); + crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper)); + crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper)); + cr_server.pDumper = NULL; +#endif + crUnpackSetReturnPointer( &(cr_server.return_ptr) ); crUnpackSetWritebackPointer( &(cr_server.writeback_ptr) ); @@ -332,6 +422,13 @@ void crVBoxServerTearDown(void) GLboolean crVBoxServerInit(void) { CRMuralInfo *defaultMural; + const char*env; + int rc = VBoxVrInit(); + if (!RT_SUCCESS(rc)) + { + crWarning("VBoxVrInit failed, rc %d", rc); + return GL_FALSE; + } #if DEBUG_FP_EXCEPTIONS { @@ -367,6 +464,7 @@ GLboolean crVBoxServerInit(void) */ cr_server.muralTable = crAllocHashtable(); defaultMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo)); + defaultMural->spuWindow = CR_RENDER_DEFAULT_WINDOW_ID; crHashtableAdd(cr_server.muralTable, 0, defaultMural); cr_server.programTable = crAllocHashtable(); @@ -385,8 +483,27 @@ GLboolean crVBoxServerInit(void) * Default context */ cr_server.contextTable = crAllocHashtable(); -// cr_server.pContextCreateInfoTable = crAllocHashtable(); - cr_server.pWindowCreateInfoTable = crAllocHashtable(); + + cr_server.dummyMuralTable = crAllocHashtable(); + + CrPMgrInit(); + + cr_server.fRootVrOn = GL_FALSE; + VBoxVrListInit(&cr_server.RootVr); + crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint)); + + crMemset(&cr_server.RpwWorker, 0, sizeof (cr_server.RpwWorker)); + + env = crGetenv("CR_SERVER_BFB"); + if (env) + { + cr_server.fBlitterMode = env[0] - '0'; + } + else + { + cr_server.fBlitterMode = CR_SERVER_BFB_DISABLED; + } + crMemset(&cr_server.Blitter, 0, sizeof (cr_server.Blitter)); crServerSetVBoxConfigurationHGCM(); @@ -394,8 +511,17 @@ GLboolean crVBoxServerInit(void) return GL_FALSE; crServerInitDispatch(); + crServerInitTmpCtxDispatch(); crStateDiffAPI( &(cr_server.head_spu->dispatch_table) ); +#ifdef VBOX_WITH_CRSERVER_DUMPER + crMemset(&cr_server.Recorder, 0, sizeof (cr_server.Recorder)); + crMemset(&cr_server.RecorderBlitter, 0, sizeof (cr_server.RecorderBlitter)); + crMemset(&cr_server.DbgPrintDumper, 0, sizeof (cr_server.DbgPrintDumper)); + crMemset(&cr_server.HtmlDumper, 0, sizeof (cr_server.HtmlDumper)); + cr_server.pDumper = NULL; +#endif + /*Check for PBO support*/ if (crStateGetCurrent()->extensions.ARB_pixel_buffer_object) { @@ -405,6 +531,38 @@ GLboolean crVBoxServerInit(void) return GL_TRUE; } +static int32_t crVBoxServerAddClientObj(uint32_t u32ClientID, CRClient **ppNewClient) +{ + CRClient *newClient; + + if (cr_server.numClients>=CR_MAX_CLIENTS) + { + if (ppNewClient) + *ppNewClient = NULL; + return VERR_MAX_THRDS_REACHED; + } + + newClient = (CRClient *) crCalloc(sizeof(CRClient)); + crDebug("crServer: AddClient u32ClientID=%d", u32ClientID); + + newClient->spu_id = 0; + newClient->currentCtxInfo = &cr_server.MainContextInfo; + newClient->currentContextNumber = -1; + newClient->conn = crNetAcceptClient(cr_server.protocol, NULL, + cr_server.tcpip_port, + cr_server.mtu, 0); + newClient->conn->u32ClientID = u32ClientID; + + cr_server.clients[cr_server.numClients++] = newClient; + + crServerAddToRunQueue(newClient); + + if (ppNewClient) + *ppNewClient = newClient; + + return VINF_SUCCESS; +} + int32_t crVBoxServerAddClient(uint32_t u32ClientID) { CRClient *newClient; @@ -614,6 +772,23 @@ int32_t crVBoxServerClientRead(uint32_t u32ClientID, uint8_t *pBuffer, uint32_t return crVBoxServerInternalClientRead(pClient, pBuffer, pcbBuffer); } +extern DECLEXPORT(int32_t) crVBoxServerClientGetCaps(uint32_t u32ClientID, uint32_t *pu32Caps) +{ + *pu32Caps = cr_server.u32Caps; + return VINF_SUCCESS; +} + +static int32_t crVBoxServerClientObjSetVersion(CRClient *pClient, uint32_t vMajor, uint32_t vMinor) +{ + pClient->conn->vMajor = vMajor; + pClient->conn->vMinor = vMinor; + + if (vMajor != CR_PROTOCOL_VERSION_MAJOR + || vMinor != CR_PROTOCOL_VERSION_MINOR) + return VERR_NOT_SUPPORTED; + return VINF_SUCCESS; +} + int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint32_t vMinor) { CRClient *pClient=NULL; @@ -630,15 +805,14 @@ int32_t crVBoxServerClientSetVersion(uint32_t u32ClientID, uint32_t vMajor, uint } if (!pClient) return VERR_INVALID_PARAMETER; - pClient->conn->vMajor = vMajor; - pClient->conn->vMinor = vMinor; + return crVBoxServerClientObjSetVersion(pClient, vMajor, vMinor); +} - if (vMajor != CR_PROTOCOL_VERSION_MAJOR - || vMinor != CR_PROTOCOL_VERSION_MINOR) - { - return VERR_NOT_SUPPORTED; - } - else return VINF_SUCCESS; +static int32_t crVBoxServerClientObjSetPID(CRClient *pClient, uint64_t pid) +{ + pClient->pid = pid; + + return VINF_SUCCESS; } int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid) @@ -657,9 +831,7 @@ int32_t crVBoxServerClientSetPID(uint32_t u32ClientID, uint64_t pid) } if (!pClient) return VERR_INVALID_PARAMETER; - pClient->pid = pid; - - return VINF_SUCCESS; + return crVBoxServerClientObjSetPID(pClient, pid); } int @@ -690,13 +862,16 @@ static void crVBoxServerSaveMuralCB(unsigned long key, void *data1, void *data2) rc = SSMR3PutMem(pSSM, &key, sizeof(key)); CRASSERT(rc == VINF_SUCCESS); - rc = SSMR3PutMem(pSSM, pMI, sizeof(*pMI)); + rc = SSMR3PutMem(pSSM, pMI, RT_OFFSETOF(CRMuralInfo, CreateInfo)); CRASSERT(rc == VINF_SUCCESS); if (pMI->pVisibleRects) { rc = SSMR3PutMem(pSSM, pMI->pVisibleRects, 4*sizeof(GLint)*pMI->cVisibleRects); } + + rc = SSMR3PutMem(pSSM, pMI->ctxUsage, sizeof (pMI->ctxUsage)); + CRASSERT(rc == VINF_SUCCESS); } /* @todo add hashtable walker with result info and intermediate abort */ @@ -708,6 +883,9 @@ static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *d CRASSERT(pCreateInfo && pSSM); + /* Don't store default mural create info */ + if (!key) return; + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); CRASSERT(rc == VINF_SUCCESS); @@ -721,10 +899,22 @@ static void crVBoxServerSaveCreateInfoCB(unsigned long key, void *data1, void *d } } +static void crVBoxServerSaveCreateInfoFromMuralInfoCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo *pMural = (CRMuralInfo *)data1; + CRCreateInfo_t CreateInfo; + CreateInfo.pszDpyName = pMural->CreateInfo.pszDpyName; + CreateInfo.visualBits = pMural->CreateInfo.requestedVisualBits; + CreateInfo.externalID = pMural->CreateInfo.externalID; + crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2); +} + static void crVBoxServerSaveCreateInfoFromCtxInfoCB(unsigned long key, void *data1, void *data2) { CRContextInfo *pContextInfo = (CRContextInfo *)data1; - CRCreateInfo_t CreateInfo = pContextInfo->CreateInfo; + CRCreateInfo_t CreateInfo; + CreateInfo.pszDpyName = pContextInfo->CreateInfo.pszDpyName; + CreateInfo.visualBits = pContextInfo->CreateInfo.requestedVisualBits; /* saved state contains internal id */ CreateInfo.externalID = pContextInfo->pContext->id; crVBoxServerSaveCreateInfoCB(key, &CreateInfo, data2); @@ -739,40 +929,672 @@ static void crVBoxServerSyncTextureCB(unsigned long key, void *data1, void *data crStateTextureObjectDiff(pContext, NULL, NULL, pTexture, GL_TRUE); } +typedef struct CRVBOX_SAVE_STATE_GLOBAL +{ + /* context id -> mural association + * on context data save, each context will be made current with the corresponding mural from this table + * thus saving the mural front & back buffer data */ + CRHashTable *contextMuralTable; + /* mural id -> context info + * for murals that do not have associated context in contextMuralTable + * we still need to save*/ + CRHashTable *additionalMuralContextTable; + + PSSMHANDLE pSSM; + + int rc; +} CRVBOX_SAVE_STATE_GLOBAL, *PCRVBOX_SAVE_STATE_GLOBAL; + + +typedef struct CRVBOX_CTXWND_CTXWALKER_CB +{ + PCRVBOX_SAVE_STATE_GLOBAL pGlobal; + CRHashTable *usedMuralTable; + GLuint cAdditionalMurals; +} CRVBOX_CTXWND_CTXWALKER_CB, *PCRVBOX_CTXWND_CTXWALKER_CB; + +static void crVBoxServerBuildAdditionalWindowContextMapCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo * pMural = (CRMuralInfo *) data1; + PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2; + CRContextInfo *pContextInfo = NULL; + + if (!pMural->CreateInfo.externalID) + { + CRASSERT(!key); + return; + } + + if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID)) + { + Assert(crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL)); + return; + } + + Assert(!crHashtableGetDataKey(pData->pGlobal->contextMuralTable, pMural, NULL)); + + if (cr_server.MainContextInfo.CreateInfo.realVisualBits == pMural->CreateInfo.realVisualBits) + { + pContextInfo = &cr_server.MainContextInfo; + } + else + { + crWarning("different visual bits not implemented!"); + pContextInfo = &cr_server.MainContextInfo; + } + + crHashtableAdd(pData->pGlobal->additionalMuralContextTable, pMural->CreateInfo.externalID, pContextInfo); +} + + +typedef struct CRVBOX_CTXWND_WNDWALKER_CB +{ + PCRVBOX_SAVE_STATE_GLOBAL pGlobal; + CRHashTable *usedMuralTable; + CRContextInfo *pContextInfo; + CRMuralInfo * pMural; +} CRVBOX_CTXWND_WNDWALKER_CB, *PCRVBOX_CTXWND_WNDWALKER_CB; + +static void crVBoxServerBuildContextWindowMapWindowWalkerCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo * pMural = (CRMuralInfo *) data1; + PCRVBOX_CTXWND_WNDWALKER_CB pData = (PCRVBOX_CTXWND_WNDWALKER_CB)data2; + + Assert(pData->pMural != pMural); + Assert(pData->pContextInfo); + + if (pData->pMural) + return; + + if (!pMural->CreateInfo.externalID) + { + CRASSERT(!key); + return; + } + + if (!CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pData->pContextInfo->pContext)) + return; + + if (crHashtableSearch(pData->usedMuralTable, pMural->CreateInfo.externalID)) + return; + + CRASSERT(pMural->CreateInfo.realVisualBits == pData->pContextInfo->CreateInfo.realVisualBits); + pData->pMural = pMural; +} + +static void crVBoxServerBuildContextUsedWindowMapCB(unsigned long key, void *data1, void *data2) +{ + CRContextInfo *pContextInfo = (CRContextInfo *)data1; + PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2; + + if (!pContextInfo->currentMural) + return; + + crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pContextInfo->currentMural); + crHashtableAdd(pData->usedMuralTable, pContextInfo->currentMural->CreateInfo.externalID, pContextInfo->currentMural); +} + +CRMuralInfo * crServerGetDummyMural(GLint visualBits) +{ + CRMuralInfo * pMural = (CRMuralInfo *)crHashtableSearch(cr_server.dummyMuralTable, visualBits); + if (!pMural) + { + GLint id; + pMural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo)); + if (!pMural) + { + crWarning("crCalloc failed!"); + return NULL; + } + id = crServerMuralInit(pMural, GL_FALSE, visualBits, 0); + if (id < 0) + { + crWarning("crServerMuralInit failed!"); + crFree(pMural); + return NULL; + } + + crHashtableAdd(cr_server.dummyMuralTable, visualBits, pMural); + } + + return pMural; +} + +static void crVBoxServerBuildContextUnusedWindowMapCB(unsigned long key, void *data1, void *data2) +{ + CRContextInfo *pContextInfo = (CRContextInfo *)data1; + PCRVBOX_CTXWND_CTXWALKER_CB pData = (PCRVBOX_CTXWND_CTXWALKER_CB)data2; + CRMuralInfo * pMural = NULL; + + if (pContextInfo->currentMural) + return; + + Assert(crHashtableNumElements(pData->pGlobal->contextMuralTable) <= crHashtableNumElements(cr_server.muralTable) - 1); + if (crHashtableNumElements(pData->pGlobal->contextMuralTable) < crHashtableNumElements(cr_server.muralTable) - 1) + { + CRVBOX_CTXWND_WNDWALKER_CB MuralData; + MuralData.pGlobal = pData->pGlobal; + MuralData.usedMuralTable = pData->usedMuralTable; + MuralData.pContextInfo = pContextInfo; + MuralData.pMural = NULL; + + crHashtableWalk(cr_server.muralTable, crVBoxServerBuildContextWindowMapWindowWalkerCB, &MuralData); + + pMural = MuralData.pMural; + + } + + if (!pMural) + { + pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits); + if (!pMural) + { + crWarning("crServerGetDummyMural failed"); + return; + } + } + else + { + crHashtableAdd(pData->usedMuralTable, pMural->CreateInfo.externalID, pMural); + ++pData->cAdditionalMurals; + } + + crHashtableAdd(pData->pGlobal->contextMuralTable, pContextInfo->CreateInfo.externalID, pMural); +} + +static void crVBoxServerBuildSaveStateGlobal(PCRVBOX_SAVE_STATE_GLOBAL pGlobal) +{ + CRVBOX_CTXWND_CTXWALKER_CB Data; + GLuint cMurals; + pGlobal->contextMuralTable = crAllocHashtable(); + pGlobal->additionalMuralContextTable = crAllocHashtable(); + /* 1. go through all contexts and match all having currentMural set */ + Data.pGlobal = pGlobal; + Data.usedMuralTable = crAllocHashtable(); + Data.cAdditionalMurals = 0; + crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUsedWindowMapCB, &Data); + + cMurals = crHashtableNumElements(pGlobal->contextMuralTable); + CRASSERT(cMurals <= crHashtableNumElements(cr_server.contextTable)); + CRASSERT(cMurals <= crHashtableNumElements(cr_server.muralTable) - 1); + CRASSERT(cMurals == crHashtableNumElements(Data.usedMuralTable)); + if (cMurals < crHashtableNumElements(cr_server.contextTable)) + { + Data.cAdditionalMurals = 0; + crHashtableWalk(cr_server.contextTable, crVBoxServerBuildContextUnusedWindowMapCB, &Data); + } + + CRASSERT(crHashtableNumElements(pGlobal->contextMuralTable) == crHashtableNumElements(cr_server.contextTable)); + CRASSERT(cMurals + Data.cAdditionalMurals <= crHashtableNumElements(cr_server.muralTable) - 1); + if (cMurals + Data.cAdditionalMurals < crHashtableNumElements(cr_server.muralTable) - 1) + { + crHashtableWalk(cr_server.muralTable, crVBoxServerBuildAdditionalWindowContextMapCB, &Data); + CRASSERT(cMurals + Data.cAdditionalMurals + crHashtableNumElements(pGlobal->additionalMuralContextTable) == crHashtableNumElements(cr_server.muralTable) - 1); + } + + crFreeHashtable(Data.usedMuralTable, NULL); +} + +static void crVBoxServerFBImageDataTerm(CRFBData *pData) +{ + GLuint i; + for (i = 0; i < pData->cElements; ++i) + { + CRFBDataElement * pEl = &pData->aElements[i]; + if (pEl->pvData) + { + crFree(pEl->pvData); + /* sanity */ + pEl->pvData = NULL; + } + } + pData->cElements = 0; +} + +static int crVBoxServerFBImageDataInitEx(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite, uint32_t version, GLuint overrideWidth, GLuint overrideHeight) +{ + CRContext *pContext; + GLuint i; + GLfloat *pF; + CRFBDataElement *pEl; + GLuint width; + GLuint height; + + crMemset(pData, 0, sizeof (*pData)); + + pContext = pCtxInfo->pContext; + + /* the version should be always actual when we do reads, + * i.e. it could differ on writes when snapshot is getting loaded */ + CRASSERT(fWrite || version == SHCROGL_SSM_VERSION); + + width = overrideWidth ? overrideWidth : pMural->width; + height = overrideHeight ? overrideHeight : pMural->height; + + if (!width || !height) + return VINF_SUCCESS; + + if (pMural) + { + if (fWrite) + { + if (!pContext->framebufferobject.drawFB) + pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurDrawBuffer); + } + else + { + if (!pContext->framebufferobject.readFB) + pData->idOverrrideFBO = CR_SERVER_FBO_FOR_IDX(pMural, pMural->iCurReadBuffer); + } + } + pData->cElements = 0; + + pEl = &pData->aElements[pData->cElements]; + pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0; + pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_FRONT; + pEl->posX = 0; + pEl->posY = 0; + pEl->width = width; + pEl->height = height; + pEl->enmFormat = GL_RGBA; + pEl->enmType = GL_UNSIGNED_BYTE; + pEl->cbData = width * height * 4; + pEl->pvData = crCalloc(pEl->cbData); + if (!pEl->pvData) + { + crVBoxServerFBImageDataTerm(pData); + crWarning("crVBoxServerFBImageDataInit: crCalloc failed"); + return VERR_NO_MEMORY; + } + ++pData->cElements; + + /* there is a lot of code that assumes we have double buffering, just assert here to print a warning in the log + * so that we know that something irregular is going on */ + CRASSERT(pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT); + if ((pCtxInfo->CreateInfo.requestedVisualBits & CR_DOUBLE_BIT) + || version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL /* <- older version had a typo which lead to back always being used, + * no matter what the visual bits are */ + ) + { + pEl = &pData->aElements[pData->cElements]; + pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_BB_IDX(pMural)] : 0; + pEl->enmBuffer = pData->aElements[1].idFBO ? GL_COLOR_ATTACHMENT0 : GL_BACK; + pEl->posX = 0; + pEl->posY = 0; + pEl->width = width; + pEl->height = height; + pEl->enmFormat = GL_RGBA; + pEl->enmType = GL_UNSIGNED_BYTE; + pEl->cbData = width * height * 4; + pEl->pvData = crCalloc(pEl->cbData); + if (!pEl->pvData) + { + crVBoxServerFBImageDataTerm(pData); + crWarning("crVBoxServerFBImageDataInit: crCalloc failed"); + return VERR_NO_MEMORY; + } + ++pData->cElements; + } + + if (version < SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER) + return VINF_SUCCESS; + + + if (version < SHCROGL_SSM_VERSION_WITH_SINGLE_DEPTH_STENCIL) + { +/* if (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT) */ /* <- older version had a typo which lead to back always being used, + * no matter what the visual bits are */ + { + AssertCompile(sizeof (GLfloat) == 4); + pEl = &pData->aElements[pData->cElements]; + pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0; + pEl->enmBuffer = 0; /* we do not care */ + pEl->posX = 0; + pEl->posY = 0; + pEl->width = width; + pEl->height = height; + pEl->enmFormat = GL_DEPTH_COMPONENT; + pEl->enmType = GL_FLOAT; + pEl->cbData = width * height * 4; + pEl->pvData = crCalloc(pEl->cbData); + if (!pEl->pvData) + { + crVBoxServerFBImageDataTerm(pData); + crWarning("crVBoxServerFBImageDataInit: crCalloc failed"); + return VERR_NO_MEMORY; + } + + /* init to default depth value, just in case */ + pF = (GLfloat*)pEl->pvData; + for (i = 0; i < width * height; ++i) + { + pF[i] = 1.; + } + ++pData->cElements; + } + + /* if (pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT) */ /* <- older version had a typo which lead to back always being used, + * no matter what the visual bits are */ + { + AssertCompile(sizeof (GLuint) == 4); + pEl = &pData->aElements[pData->cElements]; + pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0; + pEl->enmBuffer = 0; /* we do not care */ + pEl->posX = 0; + pEl->posY = 0; + pEl->width = width; + pEl->height = height; + pEl->enmFormat = GL_STENCIL_INDEX; + pEl->enmType = GL_UNSIGNED_INT; + pEl->cbData = width * height * 4; + pEl->pvData = crCalloc(pEl->cbData); + if (!pEl->pvData) + { + crVBoxServerFBImageDataTerm(pData); + crWarning("crVBoxServerFBImageDataInit: crCalloc failed"); + return VERR_NO_MEMORY; + } + ++pData->cElements; + } + return VINF_SUCCESS; + } + + if ((pCtxInfo->CreateInfo.requestedVisualBits & CR_STENCIL_BIT) + || (pCtxInfo->CreateInfo.requestedVisualBits & CR_DEPTH_BIT)) + { + pEl = &pData->aElements[pData->cElements]; + pEl->idFBO = pMural && pMural->fRedirected ? pMural->aidFBOs[CR_SERVER_FBO_FB_IDX(pMural)] : 0; + pEl->enmBuffer = 0; /* we do not care */ + pEl->posX = 0; + pEl->posY = 0; + pEl->width = width; + pEl->height = height; + pEl->enmFormat = GL_DEPTH_STENCIL; + pEl->enmType = GL_UNSIGNED_INT_24_8; + pEl->cbData = width * height * 4; + pEl->pvData = crCalloc(pEl->cbData); + if (!pEl->pvData) + { + crVBoxServerFBImageDataTerm(pData); + crWarning("crVBoxServerFBImageDataInit: crCalloc failed"); + return VERR_NO_MEMORY; + } + ++pData->cElements; + } + return VINF_SUCCESS; +} + +static int crVBoxServerFBImageDataInit(CRFBData *pData, CRContextInfo *pCtxInfo, CRMuralInfo *pMural, GLboolean fWrite) +{ + return crVBoxServerFBImageDataInitEx(pData, pCtxInfo, pMural, fWrite, SHCROGL_SSM_VERSION, 0, 0); +} + +static int crVBoxServerSaveFBImage(PSSMHANDLE pSSM) +{ + CRContextInfo *pCtxInfo; + CRContext *pContext; + CRMuralInfo *pMural; + int32_t rc; + GLuint i; + struct + { + CRFBData data; + CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */ + } Data; + + Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4])); + + pCtxInfo = cr_server.currentCtxInfo; + pContext = pCtxInfo->pContext; + pMural = pCtxInfo->currentMural; + + rc = crVBoxServerFBImageDataInit(&Data.data, pCtxInfo, pMural, GL_FALSE); + if (!RT_SUCCESS(rc)) + { + crWarning("crVBoxServerFBImageDataInit failed rc %d", rc); + return rc; + } + + rc = crStateAcquireFBImage(pContext, &Data.data); + AssertRCReturn(rc, rc); + + for (i = 0; i < Data.data.cElements; ++i) + { + CRFBDataElement * pEl = &Data.data.aElements[i]; + rc = SSMR3PutMem(pSSM, pEl->pvData, pEl->cbData); + AssertRCReturn(rc, rc); + } + + crVBoxServerFBImageDataTerm(&Data.data); + + return VINF_SUCCESS; +} + +#define CRSERVER_ASSERTRC_RETURN_VOID(_rc) do { \ + if(!RT_SUCCESS((_rc))) { \ + AssertFailed(); \ + return; \ + } \ + } while (0) + +static void crVBoxServerSaveAdditionalMuralsCB(unsigned long key, void *data1, void *data2) +{ + CRContextInfo *pContextInfo = (CRContextInfo *) data1; + PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2; + CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key); + PSSMHANDLE pSSM = pData->pSSM; + CRbitvalue initialCtxUsage[CR_MAX_BITARRAY]; + CRMuralInfo *pInitialCurMural = pContextInfo->currentMural; + + crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage)); + + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + + pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + + pData->rc = SSMR3PutMem(pSSM, &pContextInfo->CreateInfo.externalID, sizeof(pContextInfo->CreateInfo.externalID)); + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + + crServerPerformMakeCurrent(pMural, pContextInfo); + + pData->rc = crVBoxServerSaveFBImage(pSSM); + + /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */ + crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage)); + pContextInfo->currentMural = pInitialCurMural; + + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); +} + static void crVBoxServerSaveContextStateCB(unsigned long key, void *data1, void *data2) { CRContextInfo *pContextInfo = (CRContextInfo *) data1; CRContext *pContext = pContextInfo->pContext; - PSSMHANDLE pSSM = (PSSMHANDLE) data2; - int32_t rc; + PCRVBOX_SAVE_STATE_GLOBAL pData = (PCRVBOX_SAVE_STATE_GLOBAL)data2; + PSSMHANDLE pSSM = pData->pSSM; + CRMuralInfo *pMural = (CRMuralInfo*)crHashtableSearch(pData->contextMuralTable, key); + CRMuralInfo *pContextCurrentMural = pContextInfo->currentMural; + const int32_t i32Dummy = 0; + + AssertCompile(sizeof (i32Dummy) == sizeof (pMural->CreateInfo.externalID)); + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); CRASSERT(pContext && pSSM); + CRASSERT(pMural); + CRASSERT(pMural->CreateInfo.externalID); /* We could have skipped saving the key and use similar callback to load context states back, * but there's no guarantee we'd traverse hashtable in same order after loading. */ - rc = SSMR3PutMem(pSSM, &key, sizeof(key)); - CRASSERT(rc == VINF_SUCCESS); + pData->rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + +#ifdef DEBUG_misha + { + unsigned long id; + if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id)) + crWarning("No client id for server ctx %d", pContextInfo->CreateInfo.externalID); + else + CRASSERT(id == key); + } +#endif #ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE - if (cr_server.curClient) + if (pContextInfo->currentMural + || crHashtableSearch(cr_server.muralTable, pMural->CreateInfo.externalID) /* <- this is not a dummy mural */ + ) + { + CRASSERT(pMural->CreateInfo.externalID); + CRASSERT(!crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID)); + pData->rc = SSMR3PutMem(pSSM, &pMural->CreateInfo.externalID, sizeof(pMural->CreateInfo.externalID)); + } + else + { + /* this is a dummy mural */ + CRASSERT(!pMural->width); + CRASSERT(!pMural->height); + CRASSERT(crHashtableSearch(cr_server.dummyMuralTable, pMural->CreateInfo.externalID)); + pData->rc = SSMR3PutMem(pSSM, &i32Dummy, sizeof(pMural->CreateInfo.externalID)); + } + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + + CRASSERT(CR_STATE_SHAREDOBJ_USAGE_IS_SET(pMural, pContext)); + CRASSERT(pContextInfo->currentMural == pMural || !pContextInfo->currentMural); + CRASSERT(cr_server.curClient); + + crServerPerformMakeCurrent(pMural, pContextInfo); +#endif + + pData->rc = crStateSaveContext(pContext, pSSM); + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + + pData->rc = crVBoxServerSaveFBImage(pSSM); + CRSERVER_ASSERTRC_RETURN_VOID(pData->rc); + + /* restore the initial current mural */ + pContextInfo->currentMural = pContextCurrentMural; +} + +#if 0 +typedef struct CR_SERVER_CHECK_BUFFERS +{ + CRBufferObject *obj; + CRContext *ctx; +}CR_SERVER_CHECK_BUFFERS, *PCR_SERVER_CHECK_BUFFERS; + +static void crVBoxServerCheckConsistencyContextBuffersCB(unsigned long key, void *data1, void *data2) +{ + CRContextInfo* pContextInfo = (CRContextInfo*)data1; + CRContext *ctx = pContextInfo->pContext; + PCR_SERVER_CHECK_BUFFERS pBuffers = (PCR_SERVER_CHECK_BUFFERS)data2; + CRBufferObject *obj = pBuffers->obj; + CRBufferObjectState *b = &(ctx->bufferobject); + int j, k; + + if (obj == b->arrayBuffer) + { + Assert(!pBuffers->ctx || pBuffers->ctx == ctx); + pBuffers->ctx = ctx; + } + if (obj == b->elementsBuffer) + { + Assert(!pBuffers->ctx || pBuffers->ctx == ctx); + pBuffers->ctx = ctx; + } +#ifdef CR_ARB_pixel_buffer_object + if (obj == b->packBuffer) + { + Assert(!pBuffers->ctx || pBuffers->ctx == ctx); + pBuffers->ctx = ctx; + } + if (obj == b->unpackBuffer) + { + Assert(!pBuffers->ctx || pBuffers->ctx == ctx); + pBuffers->ctx = ctx; + } +#endif + +#ifdef CR_ARB_vertex_buffer_object + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) { - unsigned long id; - if (!crHashtableGetDataKey(cr_server.contextTable, pContextInfo, &id)) + CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array); + if (obj == cp->buffer) { - crWarning("No client id for server ctx %d", pContext->id); + Assert(!pBuffers->ctx || pBuffers->ctx == ctx); + pBuffers->ctx = ctx; } - else + } + + for (k=0; k<ctx->client.vertexArrayStackDepth; ++k) + { + CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k]; + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) { - crServerDispatchMakeCurrent(cr_server.curClient->currentWindow, 0, id); + CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray); + if (obj == cp->buffer) + { + Assert(!pBuffers->ctx || pBuffers->ctx == ctx); + pBuffers->ctx = ctx; + } } } #endif +} - rc = crStateSaveContext(pContext, pSSM); - CRASSERT(rc == VINF_SUCCESS); +static void crVBoxServerCheckConsistencyBuffersCB(unsigned long key, void *data1, void *data2) +{ + CRBufferObject *obj = (CRBufferObject *)data1; + CR_SERVER_CHECK_BUFFERS Buffers = {0}; + Buffers.obj = obj; + crHashtableWalk(cr_server.contextTable, crVBoxServerCheckConsistencyContextBuffersCB, (void*)&Buffers); } +//static void crVBoxServerCheckConsistency2CB(unsigned long key, void *data1, void *data2) +//{ +// CRContextInfo* pContextInfo1 = (CRContextInfo*)data1; +// CRContextInfo* pContextInfo2 = (CRContextInfo*)data2; +// +// CRASSERT(pContextInfo1->pContext); +// CRASSERT(pContextInfo2->pContext); +// +// if (pContextInfo1 == pContextInfo2) +// { +// CRASSERT(pContextInfo1->pContext == pContextInfo2->pContext); +// return; +// } +// +// CRASSERT(pContextInfo1->pContext != pContextInfo2->pContext); +// CRASSERT(pContextInfo1->pContext->shared); +// CRASSERT(pContextInfo2->pContext->shared); +// CRASSERT(pContextInfo1->pContext->shared == pContextInfo2->pContext->shared); +// if (pContextInfo1->pContext->shared != pContextInfo2->pContext->shared) +// return; +// +// crHashtableWalk(pContextInfo1->pContext->shared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, pContextInfo2); +//} +static void crVBoxServerCheckSharedCB(unsigned long key, void *data1, void *data2) +{ + CRContextInfo* pContextInfo = (CRContextInfo*)data1; + void **ppShared = (void**)data2; + if (!*ppShared) + *ppShared = pContextInfo->pContext->shared; + else + Assert(pContextInfo->pContext->shared == *ppShared); +} + +static void crVBoxServerCheckConsistency() +{ + CRSharedState *pShared = NULL; + crHashtableWalk(cr_server.contextTable, crVBoxServerCheckSharedCB, (void*)&pShared); + Assert(pShared); + if (pShared) + { + crHashtableWalk(pShared->buffersTable, crVBoxServerCheckConsistencyBuffersCB, NULL); + } +} +#endif + static uint32_t g_hackVBoxServerSaveLoadCallsLeft = 0; DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) @@ -781,8 +1603,18 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) uint32_t ui32; GLboolean b; unsigned long key; + GLenum err; #ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE - unsigned long ctxID=-1, winID=-1; + CRClient *curClient; + CRMuralInfo *curMural = NULL; + CRContextInfo *curCtxInfo = NULL; +#endif + CRVBOX_SAVE_STATE_GLOBAL Data; + + crMemset(&Data, 0, sizeof (Data)); + +#if 0 + crVBoxServerCheckConsistency(); #endif /* We shouldn't be called if there's no clients at all*/ @@ -811,6 +1643,14 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) return VINF_SUCCESS; } +#ifdef DEBUG_misha +#define CR_DBG_STR_STATE_SAVE_START "VBox.Cr.StateSaveStart" +#define CR_DBG_STR_STATE_SAVE_STOP "VBox.Cr.StateSaveStop" + + if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY) + cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_START), CR_DBG_STR_STATE_SAVE_START); +#endif + /* Save rendering contexts creation info */ ui32 = crHashtableNumElements(cr_server.contextTable); rc = SSMR3PutU32(pSSM, (uint32_t) ui32); @@ -818,50 +1658,71 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) crHashtableWalk(cr_server.contextTable, crVBoxServerSaveCreateInfoFromCtxInfoCB, pSSM); #ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE + curClient = cr_server.curClient; /* Save current win and ctx IDs, as we'd rebind contexts when saving textures */ - if (cr_server.curClient) + if (curClient) { - ctxID = cr_server.curClient->currentContextNumber; - winID = cr_server.curClient->currentWindow; + curCtxInfo = cr_server.curClient->currentCtxInfo; + curMural = cr_server.curClient->currentMural; } -#endif - - /* Save contexts state tracker data */ - /* @todo For now just some blind data dumps, - * but I've a feeling those should be saved/restored in a very strict sequence to - * allow diff_api to work correctly. - * Should be tested more with multiply guest opengl apps working when saving VM snapshot. - */ - crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, pSSM); - -#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE - /* Restore original win and ctx IDs*/ - if (cr_server.curClient) + else if (cr_server.numClients) { - crServerDispatchMakeCurrent(winID, 0, ctxID); + cr_server.curClient = cr_server.clients[0]; } #endif + /* first save windows info */ /* Save windows creation info */ - ui32 = crHashtableNumElements(cr_server.pWindowCreateInfoTable); - rc = SSMR3PutU32(pSSM, (uint32_t) ui32); + ui32 = crHashtableNumElements(cr_server.muralTable); + /* There should be default mural always */ + CRASSERT(ui32>=1); + rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1); AssertRCReturn(rc, rc); - crHashtableWalk(cr_server.pWindowCreateInfoTable, crVBoxServerSaveCreateInfoCB, pSSM); + crHashtableWalk(cr_server.muralTable, crVBoxServerSaveCreateInfoFromMuralInfoCB, pSSM); /* Save cr_server.muralTable * @todo we don't need it all, just geometry info actually */ - ui32 = crHashtableNumElements(cr_server.muralTable); - /* There should be default mural always */ - CRASSERT(ui32>=1); rc = SSMR3PutU32(pSSM, (uint32_t) ui32-1); AssertRCReturn(rc, rc); crHashtableWalk(cr_server.muralTable, crVBoxServerSaveMuralCB, pSSM); - /* Save starting free context and window IDs */ - rc = SSMR3PutMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool)); + /* we need to save front & backbuffer data for each mural first create a context -> mural association */ + crVBoxServerBuildSaveStateGlobal(&Data); + + rc = crStateSaveGlobals(pSSM); AssertRCReturn(rc, rc); + Data.pSSM = pSSM; + /* Save contexts state tracker data */ + /* @todo For now just some blind data dumps, + * but I've a feeling those should be saved/restored in a very strict sequence to + * allow diff_api to work correctly. + * Should be tested more with multiply guest opengl apps working when saving VM snapshot. + */ + crHashtableWalk(cr_server.contextTable, crVBoxServerSaveContextStateCB, &Data); + AssertRCReturn(Data.rc, Data.rc); + + ui32 = crHashtableNumElements(Data.additionalMuralContextTable); + rc = SSMR3PutU32(pSSM, (uint32_t) ui32); + AssertRCReturn(rc, rc); + + crHashtableWalk(Data.additionalMuralContextTable, crVBoxServerSaveAdditionalMuralsCB, &Data); + AssertRCReturn(Data.rc, Data.rc); + +#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE + cr_server.curClient = curClient; + /* Restore original win and ctx IDs*/ + if (curClient && curMural && curCtxInfo) + { + crServerPerformMakeCurrent(curMural, curCtxInfo); + } + else + { + cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE; + } +#endif + /* Save clients info */ for (i = 0; i < cr_server.numClients; i++) { @@ -881,7 +1742,7 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient)); AssertRCReturn(rc, rc); - if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber>=0) + if (pClient->currentCtxInfo && pClient->currentCtxInfo->pContext && pClient->currentContextNumber > 0) { b = crHashtableGetDataKey(cr_server.contextTable, pClient->currentCtxInfo, &key); CRASSERT(b); @@ -889,7 +1750,7 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) AssertRCReturn(rc, rc); } - if (pClient->currentMural && pClient->currentWindow>=0) + if (pClient->currentMural && pClient->currentWindow > 0) { b = crHashtableGetDataKey(cr_server.muralTable, pClient->currentMural, &key); CRASSERT(b); @@ -899,8 +1760,21 @@ DECLEXPORT(int32_t) crVBoxServerSaveState(PSSMHANDLE pSSM) } } + rc = CrPMgrSaveState(pSSM); + AssertRCReturn(rc, rc); + + /* all context gl error states should have now be synced with chromium erro states, + * reset the error if any */ + while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) + crWarning("crServer: glGetError %d after saving snapshot", err); + cr_server.bIsInSavingState = GL_FALSE; +#ifdef DEBUG_misha + if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY) + cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_SAVE_STOP), CR_DBG_STR_STATE_SAVE_STOP); +#endif + return VINF_SUCCESS; } @@ -912,11 +1786,527 @@ static DECLCALLBACK(CRContext*) crVBoxServerGetContextCB(void* pvData) return pContextInfo->pContext; } +typedef struct CR_SERVER_LOADSTATE_READER +{ + PSSMHANDLE pSSM; + uint32_t cbBuffer; + uint32_t cbData; + uint32_t offData; + uint8_t *pu8Buffer; +} CR_SERVER_LOADSTATE_READER; + +static void crServerLsrInit(CR_SERVER_LOADSTATE_READER *pReader, PSSMHANDLE pSSM) +{ + memset(pReader, 0, sizeof (*pReader)); + pReader->pSSM = pSSM; +} + +static void crServerLsrTerm(CR_SERVER_LOADSTATE_READER *pReader) +{ + if (pReader->pu8Buffer) + RTMemFree(pReader->pu8Buffer); + + /* sanity */ + memset(pReader, 0, sizeof (*pReader)); +} + +static int crServerLsrDataGetMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer) +{ + int rc = VINF_SUCCESS; + uint32_t cbRemaining = cbBuffer; + if (pReader->cbData) + { + uint8_t cbData = RT_MIN(pReader->cbData, cbBuffer); + memcpy(pvBuffer, pReader->pu8Buffer + pReader->offData, cbData); + pReader->cbData -= cbData; + pReader->offData += cbData; + + cbRemaining -= cbData; + pvBuffer = ((uint8_t*)pvBuffer) + cbData; + } + + if (cbRemaining) + { + rc = SSMR3GetMem(pReader->pSSM, pvBuffer, cbRemaining); + AssertRC(rc); + } + + return rc; +} + +static int crServerLsrDataGetU32(CR_SERVER_LOADSTATE_READER *pReader, uint32_t *pu32) +{ + return crServerLsrDataGetMem(pReader, pu32, sizeof (*pu32)); +} + +static int crServerLsrDataPutMem(CR_SERVER_LOADSTATE_READER *pReader, void *pvBuffer, uint32_t cbBuffer) +{ + if (!pReader->cbData && pReader->cbBuffer >= cbBuffer) + { + pReader->offData = 0; + pReader->cbData = cbBuffer; + memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer); + } + else if (pReader->offData >= cbBuffer) + { + pReader->offData -= cbBuffer; + pReader->cbData += cbBuffer; + memcpy(pReader->pu8Buffer + pReader->offData, pvBuffer, cbBuffer); + } + else + { + uint8_t *pu8Buffer = pReader->pu8Buffer; + + pReader->pu8Buffer = (uint8_t*)RTMemAlloc(cbBuffer + pReader->cbData); + if (!pReader->pu8Buffer) + { + crWarning("failed to allocate mem %d", cbBuffer + pReader->cbData); + return VERR_NO_MEMORY; + } + + memcpy(pReader->pu8Buffer, pvBuffer, cbBuffer); + if (pu8Buffer) + { + memcpy(pReader->pu8Buffer + cbBuffer, pu8Buffer + pReader->offData, pReader->cbData); + RTMemFree(pu8Buffer); + } + else + { + Assert(!pReader->cbData); + } + pReader->offData = 0; + pReader->cbData += cbBuffer; + } + + return VINF_SUCCESS; +} + +/* data to be skipped */ + +typedef struct CR_SERVER_BUGGY_MURAL_DATA_2 +{ + void*ListHead_pNext; + void*ListHead_pPrev; + uint32_t cEntries; +} CR_SERVER_BUGGY_MURAL_DATA_2; +typedef struct CR_SERVER_BUGGY_MURAL_DATA_1 +{ + /* VBOXVR_COMPOSITOR_ENTRY Ce; */ + void*Ce_Node_pNext; + void*Ce_Node_pPrev; + CR_SERVER_BUGGY_MURAL_DATA_2 Vr; + /* VBOXVR_TEXTURE Tex; */ + uint32_t Tex_width; + uint32_t Tex_height; + uint32_t Tex_target; + uint32_t Tex_hwid; + /* RTPOINT Pos; */ + uint32_t Pos_x; + uint32_t Pos_y; + uint32_t fChanged; + uint32_t cRects; + void* paSrcRects; + void* paDstRects; +} CR_SERVER_BUGGY_MURAL_DATA_1; + +typedef struct CR_SERVER_BUGGY_MURAL_DATA_4 +{ + uint32_t u32Magic; + int32_t cLockers; + RTNATIVETHREAD NativeThreadOwner; + int32_t cNestings; + uint32_t fFlags; + void* EventSem; + R3R0PTRTYPE(PRTLOCKVALRECEXCL) pValidatorRec; + RTHCPTR Alignment; +} CR_SERVER_BUGGY_MURAL_DATA_4; + +typedef struct CR_SERVER_BUGGY_MURAL_DATA_3 +{ + void*Compositor_List_pNext; + void*Compositor_List_pPrev; + void*Compositor_pfnEntryRemoved; + float StretchX; + float StretchY; + uint32_t cRects; + uint32_t cRectsBuffer; + void*paSrcRects; + void*paDstRects; + CR_SERVER_BUGGY_MURAL_DATA_4 CritSect; +} CR_SERVER_BUGGY_MURAL_DATA_3; + +typedef struct CR_SERVER_BUGGY_MURAL_DATA +{ + uint8_t fRootVrOn; + CR_SERVER_BUGGY_MURAL_DATA_1 RootVrCEntry; + CR_SERVER_BUGGY_MURAL_DATA_3 RootVrCompositor; +} CR_SERVER_BUGGY_MURAL_DATA; + +AssertCompile(sizeof (CR_SERVER_BUGGY_MURAL_DATA) < sizeof (CRClient)); + +static int32_t crVBoxServerLoadMurals(CR_SERVER_LOADSTATE_READER *pReader, uint32_t version) +{ + unsigned long key; + uint32_t ui, uiNumElems; + bool fBuggyMuralData = false; + /* Load windows */ + int32_t rc = crServerLsrDataGetU32(pReader, &uiNumElems); + AssertRCReturn(rc, rc); + for (ui=0; ui<uiNumElems; ++ui) + { + CRCreateInfo_t createInfo; + char psz[200]; + GLint winID; + unsigned long key; + + rc = crServerLsrDataGetMem(pReader, &key, sizeof(key)); + AssertRCReturn(rc, rc); + rc = crServerLsrDataGetMem(pReader, &createInfo, sizeof(createInfo)); + AssertRCReturn(rc, rc); + + CRASSERT(!pReader->cbData); + + if (createInfo.pszDpyName) + { + rc = SSMR3GetStrZEx(pReader->pSSM, psz, 200, NULL); + AssertRCReturn(rc, rc); + createInfo.pszDpyName = psz; + } + + winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key); + CRASSERT((int64_t)winID == (int64_t)key); + } + + /* Load cr_server.muralTable */ + rc = SSMR3GetU32(pReader->pSSM, &uiNumElems); + AssertRCReturn(rc, rc); + for (ui=0; ui<uiNumElems; ++ui) + { + CRMuralInfo muralInfo; + CRMuralInfo *pActualMural = NULL; + + rc = crServerLsrDataGetMem(pReader, &key, sizeof(key)); + AssertRCReturn(rc, rc); + rc = crServerLsrDataGetMem(pReader, &muralInfo, RT_OFFSETOF(CRMuralInfo, CreateInfo)); + AssertRCReturn(rc, rc); + + if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING) + muralInfo.bFbDraw = GL_TRUE; + + if (!ui && version == SHCROGL_SSM_VERSION_WITH_BUGGY_MURAL_INFO) + { + /* Lookahead buffer used to determine whether the data erroneously stored root visible regions data */ + union + { + void * apv[1]; + CR_SERVER_BUGGY_MURAL_DATA Data; + /* need to chak spuWindow, so taking the offset of filed following it*/ + uint8_t au8[RT_OFFSETOF(CRMuralInfo, screenId)]; + RTRECT aVisRects[sizeof (CR_SERVER_BUGGY_MURAL_DATA) / sizeof (RTRECT)]; + } LaBuf; + + do { + /* first value is bool (uint8_t) value followed by pointer-size-based alignment. + * the mural memory is zero-initialized initially, so we can be sure the padding is zeroed */ + rc = crServerLsrDataGetMem(pReader, &LaBuf, sizeof (LaBuf)); + AssertRCReturn(rc, rc); + if (LaBuf.apv[0] != NULL && LaBuf.apv[0] != ((void*)1)) + break; + + /* check that the pointers are either valid or NULL */ + if(LaBuf.Data.RootVrCEntry.Ce_Node_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pNext)) + break; + if(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Ce_Node_pPrev)) + break; + if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext)) + break; + if(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev && !RT_VALID_PTR(LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev)) + break; + + /* the entry can can be the only one within the (mural) compositor, + * so its compositor entry node can either contain NULL pNext and pPrev, + * or both of them pointing to compositor's list head */ + if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext != LaBuf.Data.RootVrCEntry.Ce_Node_pPrev) + break; + + /* can either both or none be NULL */ + if (!LaBuf.Data.RootVrCEntry.Ce_Node_pNext != !LaBuf.Data.RootVrCEntry.Ce_Node_pPrev) + break; + + if (!LaBuf.Data.fRootVrOn) + { + if (LaBuf.Data.RootVrCEntry.Ce_Node_pNext || LaBuf.Data.RootVrCEntry.Ce_Node_pPrev) + break; + + /* either non-initialized (zeroed) or empty list */ + if (LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext != LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev) + break; + + if (LaBuf.Data.RootVrCEntry.Vr.cEntries) + break; + } + else + { + /* the entry should be initialized */ + if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pNext) + break; + if (!LaBuf.Data.RootVrCEntry.Vr.ListHead_pPrev) + break; + + if (LaBuf.Data.RootVrCEntry.Vr.cEntries) + { + /* entry should be in compositor list*/ + if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev == NULL) + break; + CRASSERT(LaBuf.Data.RootVrCEntry.Ce_Node_pNext); + } + else + { + /* entry should NOT be in compositor list*/ + if (LaBuf.Data.RootVrCEntry.Ce_Node_pPrev != NULL) + break; + CRASSERT(!LaBuf.Data.RootVrCEntry.Ce_Node_pNext); + } + } + +#if 0 + if (muralInfo.pVisibleRects) + { + int j; + int cRects = RT_MIN(muralInfo.cVisibleRects, RT_ELEMENTS(LaBuf.aVisRects)); + CRASSERT(cRects); + for (j = 0; j < cRects; ++j) + { + PRTRECT pRect = &LaBuf.aVisRects[j]; + if (pRect->xLeft >= pRect->xRight) + break; + if (pRect->yTop >= pRect->yBottom) + break; + if (pRect->xLeft < 0 || pRect->xRight < 0 + || pRect->yTop < 0 || pRect->yBottom < 0) + break; + if (pRect->xLeft > (GLint)muralInfo.width + || pRect->xRight > (GLint)muralInfo.width) + break; + if (pRect->yTop > (GLint)muralInfo.height + || pRect->yBottom > (GLint)muralInfo.height) + break; + } + + if (j < cRects) + { + fBuggyMuralData = true; + break; + } + } + + if (muralInfo.pVisibleRects) + { + /* @todo: do we actually need any further checks here? */ + fBuggyMuralData = true; + break; + } + + /* no visible regions*/ + + if (ui == uiNumElems - 1) + { + /* this is the last mural, next it goes idsPool, whose content can not match the above template again */ + fBuggyMuralData = true; + break; + } + + /* next it goes a next mural info */ +// if (!fExpectPtr) +// { +// CRMuralInfo *pNextSpuWindowInfoMural = (CRMuralInfo*)((void*)&LaBuf); +// if (!pNextSpuWindowInfoMural->spuWindow) +// fBuggyMuralData = true; +// +// break; +// } +#endif + /* fExpectPtr == true, the valid pointer values should not match possible mural width/height/position */ + fBuggyMuralData = true; + break; + + } while (0); + + rc = crServerLsrDataPutMem(pReader, &LaBuf, sizeof (LaBuf)); + AssertRCReturn(rc, rc); + } + + if (fBuggyMuralData) + { + CR_SERVER_BUGGY_MURAL_DATA Tmp; + rc = crServerLsrDataGetMem(pReader, &Tmp, sizeof (Tmp)); + AssertRCReturn(rc, rc); + } + + if (muralInfo.pVisibleRects) + { + muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects); + if (!muralInfo.pVisibleRects) + { + return VERR_NO_MEMORY; + } + + rc = crServerLsrDataGetMem(pReader, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects); + AssertRCReturn(rc, rc); + } + + pActualMural = (CRMuralInfo *)crHashtableSearch(cr_server.muralTable, key); + CRASSERT(pActualMural); + + if (version >= SHCROGL_SSM_VERSION_WITH_WINDOW_CTX_USAGE) + { + rc = crServerLsrDataGetMem(pReader, pActualMural->ctxUsage, sizeof (pActualMural->ctxUsage)); + CRASSERT(rc == VINF_SUCCESS); + } + + /* Restore windows geometry info */ + crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height); + crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY); + /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/ + if (muralInfo.bReceivedRects) + { + crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects); + } + crServerDispatchWindowShow(key, muralInfo.bVisible); + + if (muralInfo.pVisibleRects) + { + crFree(muralInfo.pVisibleRects); + } + } + + CRASSERT(RT_SUCCESS(rc)); + return VINF_SUCCESS; +} + +static int crVBoxServerLoadFBImage(PSSMHANDLE pSSM, uint32_t version, + CRContextInfo* pContextInfo, CRMuralInfo *pMural) +{ + CRContext *pContext = pContextInfo->pContext; + int32_t rc = VINF_SUCCESS; + GLuint i; + /* can apply the data right away */ + struct + { + CRFBData data; + CRFBDataElement buffer[3]; /* CRFBData::aElements[1] + buffer[3] gives 4: back, front, depth and stencil */ + } Data; + + Assert(sizeof (Data) >= RT_OFFSETOF(CRFBData, aElements[4])); + + if (version >= SHCROGL_SSM_VERSION_WITH_SAVED_DEPTH_STENCIL_BUFFER) + { + if (!pMural->width || !pMural->height) + return VINF_SUCCESS; + + rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, 0, 0); + if (!RT_SUCCESS(rc)) + { + crWarning("crVBoxServerFBImageDataInit failed rc %d", rc); + return rc; + } + } + else + { + GLint storedWidth, storedHeight; + + if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA) + { + CRASSERT(cr_server.currentCtxInfo == pContextInfo); + CRASSERT(cr_server.currentMural == pMural); + storedWidth = pMural->width; + storedHeight = pMural->height; + } + else + { + storedWidth = pContext->buffer.storedWidth; + storedHeight = pContext->buffer.storedHeight; + } + + if (!storedWidth || !storedHeight) + return VINF_SUCCESS; + + rc = crVBoxServerFBImageDataInitEx(&Data.data, pContextInfo, pMural, GL_TRUE, version, storedWidth, storedHeight); + if (!RT_SUCCESS(rc)) + { + crWarning("crVBoxServerFBImageDataInit failed rc %d", rc); + return rc; + } + } + + CRASSERT(Data.data.cElements); + + for (i = 0; i < Data.data.cElements; ++i) + { + CRFBDataElement * pEl = &Data.data.aElements[i]; + rc = SSMR3GetMem(pSSM, pEl->pvData, pEl->cbData); + AssertRCReturn(rc, rc); + } + + if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA) + { + CRBufferState *pBuf = &pContext->buffer; + /* can apply the data right away */ + CRASSERT(cr_server.currentCtxInfo == &cr_server.MainContextInfo); + CRASSERT(cr_server.currentMural); + + cr_server.head_spu->dispatch_table.MakeCurrent( pMural->spuWindow, + 0, + pContextInfo->SpuContext >= 0 + ? pContextInfo->SpuContext + : cr_server.MainContextInfo.SpuContext); + crStateApplyFBImage(pContext, &Data.data); + CRASSERT(!pBuf->pFrontImg); + CRASSERT(!pBuf->pBackImg); + crVBoxServerFBImageDataTerm(&Data.data); + + crServerPresentFBO(pMural); + + CRASSERT(cr_server.currentMural); + cr_server.head_spu->dispatch_table.MakeCurrent( cr_server.currentMural->spuWindow, + 0, + cr_server.currentCtxInfo->SpuContext >= 0 + ? cr_server.currentCtxInfo->SpuContext + : cr_server.MainContextInfo.SpuContext); + } + else + { + CRBufferState *pBuf = &pContext->buffer; + CRASSERT(!pBuf->pFrontImg); + CRASSERT(!pBuf->pBackImg); + CRASSERT(Data.data.cElements); /* <- older versions always saved front and back, and we filtered out the null-sized buffers above */ + + if (Data.data.cElements) + { + CRFBData *pLazyData = crAlloc(RT_OFFSETOF(CRFBData, aElements[Data.data.cElements])); + if (!RT_SUCCESS(rc)) + { + crVBoxServerFBImageDataTerm(&Data.data); + crWarning("crAlloc failed"); + return VERR_NO_MEMORY; + } + + crMemcpy(pLazyData, &Data.data, RT_OFFSETOF(CRFBData, aElements[Data.data.cElements])); + pBuf->pFrontImg = pLazyData; + } + } + + CRASSERT(RT_SUCCESS(rc)); + return VINF_SUCCESS; +} + DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) { int32_t rc, i; uint32_t ui, uiNumElems; unsigned long key; + GLenum err; + CR_SERVER_LOADSTATE_READER Reader; if (!cr_server.bIsInLoadingState) { @@ -941,6 +2331,16 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) return VERR_SSM_DATA_UNIT_FORMAT_CHANGED; } + crServerLsrInit(&Reader, pSSM); + +#ifdef DEBUG_misha +#define CR_DBG_STR_STATE_LOAD_START "VBox.Cr.StateLoadStart" +#define CR_DBG_STR_STATE_LOAD_STOP "VBox.Cr.StateLoadStop" + + if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY) + cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_START), CR_DBG_STR_STATE_LOAD_START); +#endif + /* Load and recreate rendering contexts */ rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); @@ -974,11 +2374,44 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) pContext->shared->id=-1; } + if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA) + { + CRASSERT(!Reader.pu8Buffer); + /* we have a mural data here */ + rc = crVBoxServerLoadMurals(&Reader, version); + AssertRCReturn(rc, rc); + CRASSERT(!Reader.pu8Buffer); + } + + if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA && uiNumElems) + { + /* set the current client to allow doing crServerPerformMakeCurrent later */ + CRASSERT(cr_server.numClients); + cr_server.curClient = cr_server.clients[0]; + } + + rc = crStateLoadGlobals(pSSM, version); + AssertRCReturn(rc, rc); + + if (uiNumElems) + { + /* ensure we have main context set up as current */ + CRMuralInfo *pMural; + CRASSERT(cr_server.MainContextInfo.SpuContext > 0); + CRASSERT(!cr_server.currentCtxInfo); + CRASSERT(!cr_server.currentMural); + pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + CRASSERT(pMural); + crServerPerformMakeCurrent(pMural, &cr_server.MainContextInfo); + } + /* Restore context state data */ for (ui=0; ui<uiNumElems; ++ui) { CRContextInfo* pContextInfo; CRContext *pContext; + CRMuralInfo *pMural = NULL; + int32_t winId = 0; rc = SSMR3GetMem(pSSM, &key, sizeof(key)); AssertRCReturn(rc, rc); @@ -988,82 +2421,91 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) CRASSERT(pContextInfo->pContext); pContext = pContextInfo->pContext; - rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version); - AssertRCReturn(rc, rc); - } - - /* Load windows */ - rc = SSMR3GetU32(pSSM, &uiNumElems); - AssertRCReturn(rc, rc); - for (ui=0; ui<uiNumElems; ++ui) - { - CRCreateInfo_t createInfo; - char psz[200]; - GLint winID; - unsigned long key; - - rc = SSMR3GetMem(pSSM, &key, sizeof(key)); - AssertRCReturn(rc, rc); - rc = SSMR3GetMem(pSSM, &createInfo, sizeof(createInfo)); - AssertRCReturn(rc, rc); - - if (createInfo.pszDpyName) + if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA) { - rc = SSMR3GetStrZEx(pSSM, psz, 200, NULL); + rc = SSMR3GetMem(pSSM, &winId, sizeof(winId)); AssertRCReturn(rc, rc); - createInfo.pszDpyName = psz; + + if (winId) + { + pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, winId); + CRASSERT(pMural); + } + else + { + /* null winId means a dummy mural, get it */ + pMural = crServerGetDummyMural(pContextInfo->CreateInfo.realVisualBits); + CRASSERT(pMural); + } } - winID = crServerDispatchWindowCreateEx(createInfo.pszDpyName, createInfo.visualBits, key); - CRASSERT((int64_t)winID == (int64_t)key); + rc = crStateLoadContext(pContext, cr_server.contextTable, crVBoxServerGetContextCB, pSSM, version); + AssertRCReturn(rc, rc); + + /*Restore front/back buffer images*/ + rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural); + AssertRCReturn(rc, rc); } - /* Load cr_server.muralTable */ - rc = SSMR3GetU32(pSSM, &uiNumElems); - AssertRCReturn(rc, rc); - for (ui=0; ui<uiNumElems; ++ui) + if (version > SHCROGL_SSM_VERSION_WITH_BUGGY_FB_IMAGE_DATA) { - CRMuralInfo muralInfo; + CRContextInfo *pContextInfo; + CRMuralInfo *pMural; + GLint ctxId; - rc = SSMR3GetMem(pSSM, &key, sizeof(key)); - AssertRCReturn(rc, rc); - rc = SSMR3GetMem(pSSM, &muralInfo, sizeof(muralInfo)); + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); + for (ui=0; ui<uiNumElems; ++ui) + { + CRbitvalue initialCtxUsage[CR_MAX_BITARRAY]; + CRMuralInfo *pInitialCurMural; - if (version <= SHCROGL_SSM_VERSION_BEFORE_FRONT_DRAW_TRACKING) - muralInfo.bFbDraw = GL_TRUE; + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); - if (muralInfo.pVisibleRects) - { - muralInfo.pVisibleRects = crAlloc(4*sizeof(GLint)*muralInfo.cVisibleRects); - if (!muralInfo.pVisibleRects) + rc = SSMR3GetMem(pSSM, &ctxId, sizeof(ctxId)); + AssertRCReturn(rc, rc); + + pMural = (CRMuralInfo*)crHashtableSearch(cr_server.muralTable, key); + CRASSERT(pMural); + if (ctxId) { - return VERR_NO_MEMORY; + pContextInfo = (CRContextInfo *)crHashtableSearch(cr_server.contextTable, ctxId); + CRASSERT(pContextInfo); } + else + pContextInfo = &cr_server.MainContextInfo; - rc = SSMR3GetMem(pSSM, muralInfo.pVisibleRects, 4*sizeof(GLint)*muralInfo.cVisibleRects); + crMemcpy(initialCtxUsage, pMural->ctxUsage, sizeof (initialCtxUsage)); + pInitialCurMural = pContextInfo->currentMural; + + rc = crVBoxServerLoadFBImage(pSSM, version, pContextInfo, pMural); AssertRCReturn(rc, rc); - } - /* Restore windows geometry info */ - crServerDispatchWindowSize(key, muralInfo.width, muralInfo.height); - crServerDispatchWindowPosition(key, muralInfo.gX, muralInfo.gY); - /* Same workaround as described in stub.c:stubUpdateWindowVisibileRegions for compiz on a freshly booted VM*/ - if (muralInfo.bReceivedRects) - { - crServerDispatchWindowVisibleRegion(key, muralInfo.cVisibleRects, muralInfo.pVisibleRects); + /* restore the reference data, we synchronize it with the HW state in a later crServerPerformMakeCurrent call */ + crMemcpy(pMural->ctxUsage, initialCtxUsage, sizeof (initialCtxUsage)); + pContextInfo->currentMural = pInitialCurMural; } - crServerDispatchWindowShow(key, muralInfo.bVisible); - if (muralInfo.pVisibleRects) - { - crFree(muralInfo.pVisibleRects); - } + CRASSERT(!uiNumElems || cr_server.currentCtxInfo == &cr_server.MainContextInfo); + + cr_server.curClient = NULL; + cr_server.bForceMakeCurrentOnClientSwitch = GL_TRUE; } + else + { + CRServerFreeIDsPool_t dummyIdsPool; - /* Load starting free context and window IDs */ - rc = SSMR3GetMem(pSSM, &cr_server.idsPool, sizeof(cr_server.idsPool)); - CRASSERT(rc == VINF_SUCCESS); + CRASSERT(!Reader.pu8Buffer); + + /* we have a mural data here */ + rc = crVBoxServerLoadMurals(&Reader, version); + AssertRCReturn(rc, rc); + + /* not used any more, just read it out and ignore */ + rc = crServerLsrDataGetMem(&Reader, &dummyIdsPool, sizeof(dummyIdsPool)); + CRASSERT(rc == VINF_SUCCESS); + } /* Load clients info */ for (i = 0; i < cr_server.numClients; i++) @@ -1074,21 +2516,21 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) CRClient client; unsigned long ctxID=-1, winID=-1; - rc = SSMR3GetU32(pSSM, &ui); + rc = crServerLsrDataGetU32(&Reader, &ui); AssertRCReturn(rc, rc); /* If this assert fires, then we should search correct client in the list first*/ CRASSERT(ui == pClient->conn->u32ClientID); if (version>=4) { - rc = SSMR3GetU32(pSSM, &pClient->conn->vMajor); + rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMajor); AssertRCReturn(rc, rc); - rc = SSMR3GetU32(pSSM, &pClient->conn->vMinor); + rc = crServerLsrDataGetU32(&Reader, &pClient->conn->vMinor); AssertRCReturn(rc, rc); } - rc = SSMR3GetMem(pSSM, &client, sizeof(client)); + rc = crServerLsrDataGetMem(&Reader, &client, sizeof(client)); CRASSERT(rc == VINF_SUCCESS); client.conn = pClient->conn; @@ -1105,9 +2547,9 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) cr_server.curClient = pClient; - if (client.currentCtxInfo && client.currentContextNumber>=0) + if (client.currentCtxInfo && client.currentContextNumber > 0) { - rc = SSMR3GetMem(pSSM, &ctxID, sizeof(ctxID)); + rc = crServerLsrDataGetMem(&Reader, &ctxID, sizeof(ctxID)); AssertRCReturn(rc, rc); client.currentCtxInfo = (CRContextInfo*) crHashtableSearch(cr_server.contextTable, ctxID); CRASSERT(client.currentCtxInfo); @@ -1116,9 +2558,9 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) //pClient->currentContextNumber = ctxID; } - if (client.currentMural && client.currentWindow>=0) + if (client.currentMural && client.currentWindow > 0) { - rc = SSMR3GetMem(pSSM, &winID, sizeof(winID)); + rc = crServerLsrDataGetMem(&Reader, &winID, sizeof(winID)); AssertRCReturn(rc, rc); client.currentMural = (CRMuralInfo*) crHashtableSearch(cr_server.muralTable, winID); CRASSERT(client.currentMural); @@ -1126,6 +2568,8 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) //pClient->currentWindow = winID; } + CRASSERT(!Reader.cbData); + /* Restore client active context and window */ crServerDispatchMakeCurrent(winID, 0, ctxID); @@ -1195,40 +2639,68 @@ DECLEXPORT(int32_t) crVBoxServerLoadState(PSSMHANDLE pSSM, uint32_t version) cr_server.curClient = NULL; + if (version >= SHCROGL_SSM_VERSION_WITH_SCREEN_INFO) { - GLenum err = crServerDispatchGetError(); - - if (err != GL_NO_ERROR) - { - crWarning("crServer: glGetError %d after loading snapshot", err); - } + rc = CrPMgrLoadState(pSSM, version); + AssertRCReturn(rc, rc); } + while ((err = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) + crWarning("crServer: glGetError %d after loading snapshot", err); + cr_server.bIsInLoadingState = GL_FALSE; +#if 0 + crVBoxServerCheckConsistency(); +#endif + +#ifdef DEBUG_misha + if (cr_server.head_spu->dispatch_table.StringMarkerGREMEDY) + cr_server.head_spu->dispatch_table.StringMarkerGREMEDY(sizeof (CR_DBG_STR_STATE_LOAD_STOP), CR_DBG_STR_STATE_LOAD_STOP); +#endif + + CRASSERT(!Reader.cbData); + crServerLsrTerm(&Reader); + return VINF_SUCCESS; } #define SCREEN(i) (cr_server.screen[i]) #define MAPPED(screen) ((screen).winID != 0) -static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2) +extern DECLEXPORT(void) crServerVBoxSetNotifyEventCB(PFNCRSERVERNOTIFYEVENT pfnCb) { - CRMuralInfo *pMI = (CRMuralInfo*) data1; - int *sIndex = (int*) data2; + cr_server.pfnNotifyEventCB = pfnCb; +} - if (pMI->screenId == *sIndex) +void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void*pvData) +{ + /* this is something unexpected, but just in case */ + if (idScreen >= cr_server.screenCount) { - renderspuReparentWindow(pMI->spuWindow); + crWarning("invalid screen id %d", idScreen); + return; } + + cr_server.pfnNotifyEventCB(idScreen, uEvent, pvData); } -static void crVBoxServerCheckMuralCB(unsigned long key, void *data1, void *data2) +void crServerWindowReparent(CRMuralInfo *pMural) +{ + pMural->fHasParentWindow = !!cr_server.screen[pMural->screenId].winID; + + renderspuReparentWindow(pMural->spuWindow); +} + +static void crVBoxServerReparentMuralCB(unsigned long key, void *data1, void *data2) { CRMuralInfo *pMI = (CRMuralInfo*) data1; - (void) data2; + int *sIndex = (int*) data2; - crServerCheckMuralGeometry(pMI); + if (pMI->screenId == *sIndex) + { + crServerWindowReparent(pMI); + } } DECLEXPORT(int32_t) crVBoxServerSetScreenCount(int sCount) @@ -1269,9 +2741,14 @@ DECLEXPORT(int32_t) crVBoxServerUnmapScreen(int sIndex) renderspuSetWindowId(0); crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex); + + crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex); + + CrPMgrScreenChanged((uint32_t)sIndex); } renderspuSetWindowId(SCREEN(0).winID); + return VINF_SUCCESS; } @@ -1296,9 +2773,9 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint renderspuSetWindowId(SCREEN(sIndex).winID); crHashtableWalk(cr_server.muralTable, crVBoxServerReparentMuralCB, &sIndex); - renderspuSetWindowId(SCREEN(0).winID); - crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL); + crHashtableWalk(cr_server.dummyMuralTable, crVBoxServerReparentMuralCB, &sIndex); + renderspuSetWindowId(SCREEN(0).winID); #ifndef WINDOWS /*Restore FB content for clients, which have current window on a screen being remapped*/ @@ -1310,7 +2787,7 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint cr_server.curClient = cr_server.clients[i]; if (cr_server.curClient->currentCtxInfo && cr_server.curClient->currentCtxInfo->pContext - && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg || cr_server.curClient->currentCtxInfo->pContext->buffer.pBackImg) + && (cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg) && cr_server.curClient->currentMural && cr_server.curClient->currentMural->screenId == sIndex && cr_server.curClient->currentCtxInfo->pContext->buffer.storedHeight == h @@ -1318,25 +2795,74 @@ DECLEXPORT(int32_t) crVBoxServerMapScreen(int sIndex, int32_t x, int32_t y, uint { int clientWindow = cr_server.curClient->currentWindow; int clientContext = cr_server.curClient->currentContextNumber; + CRFBData *pLazyData = (CRFBData *)cr_server.curClient->currentCtxInfo->pContext->buffer.pFrontImg; if (clientWindow && clientWindow != cr_server.currentWindow) { crServerDispatchMakeCurrent(clientWindow, 0, clientContext); } - crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext); + crStateApplyFBImage(cr_server.curClient->currentCtxInfo->pContext, pLazyData); + crStateFreeFBImageLegacy(cr_server.curClient->currentCtxInfo->pContext); } } cr_server.curClient = NULL; } #endif + CrPMgrScreenChanged((uint32_t)sIndex); + return VINF_SUCCESS; } -DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, GLint *pRects) +DECLEXPORT(int32_t) crVBoxServerSetRootVisibleRegion(GLint cRects, const RTRECT *pRects) { - renderspuSetRootVisibleRegion(cRects, pRects); + int32_t rc = VINF_SUCCESS; + GLboolean fOldRootVrOn = cr_server.fRootVrOn; + + /* non-zero rects pointer indicate rects are present and switched on + * i.e. cRects==0 and pRects!=NULL means root visible regioning is ON and there are no visible regions, + * while pRects==NULL means root visible regioning is OFF, i.e. everything is visible */ + if (pRects) + { + crMemset(&cr_server.RootVrCurPoint, 0, sizeof (cr_server.RootVrCurPoint)); + rc = VBoxVrListRectsSet(&cr_server.RootVr, cRects, pRects, NULL); + if (!RT_SUCCESS(rc)) + { + crWarning("VBoxVrListRectsSet failed! rc %d", rc); + return rc; + } + + cr_server.fRootVrOn = GL_TRUE; + } + else + { + if (!cr_server.fRootVrOn) + return VINF_SUCCESS; + + VBoxVrListClear(&cr_server.RootVr); + + cr_server.fRootVrOn = GL_FALSE; + } + + if (!fOldRootVrOn != !cr_server.fRootVrOn) + { + rc = CrPMgrModeRootVr(cr_server.fRootVrOn); + if (!RT_SUCCESS(rc)) + { + crWarning("CrPMgrModeRootVr failed rc %d", rc); + return rc; + } + } + else if (cr_server.fRootVrOn) + { + rc = CrPMgrRootVrUpdate(); + if (!RT_SUCCESS(rc)) + { + crWarning("CrPMgrRootVrUpdate failed rc %d", rc); + return rc; + } + } return VINF_SUCCESS; } @@ -1348,21 +2874,7 @@ DECLEXPORT(void) crVBoxServerSetPresentFBOCB(PFNCRSERVERPRESENTFBO pfnPresentFBO DECLEXPORT(int32_t) crVBoxServerSetOffscreenRendering(GLboolean value) { - if (cr_server.bForceOffscreenRendering==value) - { - return VINF_SUCCESS; - } - - if (value && !crServerSupportRedirMuralFBO()) - { - return VERR_NOT_SUPPORTED; - } - - cr_server.bForceOffscreenRendering=value; - - crHashtableWalk(cr_server.muralTable, crVBoxServerCheckMuralCB, NULL); - - return VINF_SUCCESS; + return CrPMgrModeVrdp(value); } DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallbacks) @@ -1371,74 +2883,502 @@ DECLEXPORT(int32_t) crVBoxServerOutputRedirectSet(const CROutputRedirect *pCallb if (pCallbacks) { cr_server.outputRedirect = *pCallbacks; - cr_server.bUseOutputRedirect = true; } else { - cr_server.bUseOutputRedirect = false; + memset (&cr_server.outputRedirect, 0, sizeof (cr_server.outputRedirect)); } - // @todo dynamically intercept already existing output: - // crHashtableWalk(cr_server.muralTable, crVBoxServerOutputRedirectCB, NULL); + return VINF_SUCCESS; +} + +DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h) +{ + CRScreenViewportInfo *pViewport; + RTRECT NewRect; + int rc; + + crDebug("crVBoxServerSetScreenViewport(%i)", sIndex); + + if (sIndex<0 || sIndex>=cr_server.screenCount) + { + crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex); + return VERR_INVALID_PARAMETER; + } + + NewRect.xLeft = x; + NewRect.yTop = y; + NewRect.xRight = x + w; + NewRect.yBottom = y + h; + + pViewport = &cr_server.screenVieport[sIndex]; + /*always do viewport updates no matter whether the rectangle actually changes, + * this is needed to ensure window is adjusted properly on OSX */ + pViewport->Rect = NewRect; + rc = CrPMgrViewportUpdate((uint32_t)sIndex); + if (!RT_SUCCESS(rc)) + { + crWarning("CrPMgrViewportUpdate failed %d", rc); + return rc; + } return VINF_SUCCESS; } -static void crVBoxServerUpdateScreenViewportCB(unsigned long key, void *data1, void *data2) +static void crVBoxServerDefaultContextSet() { - CRMuralInfo *mural = (CRMuralInfo*) data1; - int *sIndex = (int*) data2; + GLint spuWindow, spuCtx; - if (mural->screenId != *sIndex) - return; + if (cr_server.MainContextInfo.SpuContext) + { + CRMuralInfo *pMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + if (!pMural) + { + WARN(("dummy mural is NULL")); + spuCtx = CR_RENDER_DEFAULT_CONTEXT_ID; + spuWindow = CR_RENDER_DEFAULT_WINDOW_ID; + } + else + { + spuCtx = cr_server.MainContextInfo.SpuContext; + spuWindow = pMural->CreateInfo.realVisualBits; + } + } + else + { + spuCtx = CR_RENDER_DEFAULT_CONTEXT_ID; + spuWindow = CR_RENDER_DEFAULT_WINDOW_ID; + } - crServerCheckMuralGeometry(mural); + cr_server.head_spu->dispatch_table.MakeCurrent(spuWindow, 0, spuCtx); } +#ifdef VBOX_WITH_CRHGSMI -DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t y, uint32_t w, uint32_t h) +static int32_t crVBoxServerCmdVbvaCrCmdProcess(struct VBOXCMDVBVA_CRCMD_CMD *pCmd, uint32_t cbCmd) { - CRScreenViewportInfo *pVieport; - GLboolean fPosChanged, fSizeChanged; + int32_t rc; + uint32_t cBuffers = pCmd->cBuffers; + uint32_t cParams; + uint32_t cbHdr; + CRVBOXHGSMIHDR *pHdr; + uint32_t u32Function; + uint32_t u32ClientID; + CRClient *pClient; - crDebug("crVBoxServerSetScreenViewport(%i)", sIndex); + if (!g_pvVRamBase) + { + WARN(("g_pvVRamBase is not initialized")); + return VERR_INVALID_STATE; + } - if (sIndex<0 || sIndex>=cr_server.screenCount) + if (!cBuffers) { - crWarning("crVBoxServerSetScreenViewport: invalid screen id %d", sIndex); + WARN(("zero buffers passed in!")); return VERR_INVALID_PARAMETER; } - pVieport = &cr_server.screenVieport[sIndex]; - fPosChanged = (pVieport->x != x || pVieport->y != y); - fSizeChanged = (pVieport->w != w || pVieport->h != h); + cParams = cBuffers-1; - if (!fPosChanged && !fSizeChanged) + if (cbCmd != RT_OFFSETOF(VBOXCMDVBVA_CRCMD_CMD, aBuffers[cBuffers])) { - crDebug("crVBoxServerSetScreenViewport: no changes"); - return VINF_SUCCESS; + WARN(("invalid buffer size")); + return VERR_INVALID_PARAMETER; } - if (fPosChanged) + cbHdr = pCmd->aBuffers[0].cbBuffer; + pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR); + if (!pHdr) { - pVieport->x = x; - pVieport->y = y; + WARN(("invalid header buffer!")); + return VERR_INVALID_PARAMETER; + } - crHashtableWalk(cr_server.muralTable, crVBoxServerUpdateScreenViewportCB, &sIndex); + if (cbHdr < sizeof (*pHdr)) + { + WARN(("invalid header buffer size!")); + return VERR_INVALID_PARAMETER; } - if (fSizeChanged) + u32Function = pHdr->u32Function; + u32ClientID = pHdr->u32ClientID; + + switch (u32Function) { - pVieport->w = w; - pVieport->h = h; + case SHCRGL_GUEST_FN_WRITE: + { + Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n")); + + /* @todo: Verify */ + if (cParams == 1) + { + CRVBOXHGSMIWRITE* pFnCmd = (CRVBOXHGSMIWRITE*)pHdr; + VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1]; + /* Fetch parameters. */ + uint32_t cbBuffer = pBuf->cbBuffer; + uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t); + + if (cbHdr < sizeof (*pFnCmd)) + { + crWarning("invalid write cmd buffer size!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + CRASSERT(cbBuffer); + if (!pBuffer) + { + crWarning("invalid buffer data received from guest!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + rc = crVBoxServerClientGet(u32ClientID, &pClient); + if (RT_FAILURE(rc)) + { + break; + } + + /* This should never fire unless we start to multithread */ + CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0); + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + + pClient->conn->pBuffer = pBuffer; + pClient->conn->cbBuffer = cbBuffer; + CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false); + rc = crVBoxServerInternalClientWriteRead(pClient); + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + return rc; + } + else + { + crWarning("invalid number of args"); + rc = VERR_INVALID_PARAMETER; + break; + } + break; + } + + case SHCRGL_GUEST_FN_INJECT: + { + Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n")); + + /* @todo: Verify */ + if (cParams == 1) + { + CRVBOXHGSMIINJECT *pFnCmd = (CRVBOXHGSMIINJECT*)pHdr; + /* Fetch parameters. */ + uint32_t u32InjectClientID = pFnCmd->u32ClientID; + VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1]; + uint32_t cbBuffer = pBuf->cbBuffer; + uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t); + + if (cbHdr < sizeof (*pFnCmd)) + { + crWarning("invalid inject cmd buffer size!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + CRASSERT(cbBuffer); + if (!pBuffer) + { + crWarning("invalid buffer data received from guest!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + rc = crVBoxServerClientGet(u32InjectClientID, &pClient); + if (RT_FAILURE(rc)) + { + break; + } + + /* This should never fire unless we start to multithread */ + CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0); + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + + pClient->conn->pBuffer = pBuffer; + pClient->conn->cbBuffer = cbBuffer; + CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, false); + rc = crVBoxServerInternalClientWriteRead(pClient); + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + return rc; + } + + crWarning("invalid number of args"); + rc = VERR_INVALID_PARAMETER; + break; + } + + case SHCRGL_GUEST_FN_READ: + { + Log(("svcCall: SHCRGL_GUEST_FN_READ\n")); + + /* @todo: Verify */ + if (cParams == 1) + { + CRVBOXHGSMIREAD *pFnCmd = (CRVBOXHGSMIREAD*)pHdr; + VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1]; + /* Fetch parameters. */ + uint32_t cbBuffer = pBuf->cbBuffer; + uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t); + + if (cbHdr < sizeof (*pFnCmd)) + { + crWarning("invalid read cmd buffer size!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + + if (!pBuffer) + { + crWarning("invalid buffer data received from guest!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + rc = crVBoxServerClientGet(u32ClientID, &pClient); + if (RT_FAILURE(rc)) + { + break; + } + + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + + rc = crVBoxServerInternalClientRead(pClient, pBuffer, &cbBuffer); + + /* Return the required buffer size always */ + pFnCmd->cbBuffer = cbBuffer; + + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + + /* the read command is never pended, complete it right away */ + pHdr->result = rc; + + return VINF_SUCCESS; + } + + crWarning("invalid number of args"); + rc = VERR_INVALID_PARAMETER; + break; + } + + case SHCRGL_GUEST_FN_WRITE_READ: + { + Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n")); + + /* @todo: Verify */ + if (cParams == 2) + { + CRVBOXHGSMIWRITEREAD *pFnCmd = (CRVBOXHGSMIWRITEREAD*)pHdr; + VBOXCMDVBVA_CRCMD_BUFFER *pBuf = &pCmd->aBuffers[1]; + VBOXCMDVBVA_CRCMD_BUFFER *pWbBuf = &pCmd->aBuffers[2]; + + /* Fetch parameters. */ + uint32_t cbBuffer = pBuf->cbBuffer; + uint8_t *pBuffer = VBOXCRHGSMI_PTR_SAFE(pBuf->offBuffer, cbBuffer, uint8_t); + + uint32_t cbWriteback = pWbBuf->cbBuffer; + char *pWriteback = VBOXCRHGSMI_PTR_SAFE(pWbBuf->offBuffer, cbWriteback, char); + + if (cbHdr < sizeof (*pFnCmd)) + { + crWarning("invalid write_read cmd buffer size!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + + CRASSERT(cbBuffer); + if (!pBuffer) + { + crWarning("invalid write buffer data received from guest!"); + rc = VERR_INVALID_PARAMETER; + break; + } + + CRASSERT(cbWriteback); + if (!pWriteback) + { + crWarning("invalid writeback buffer data received from guest!"); + rc = VERR_INVALID_PARAMETER; + break; + } + rc = crVBoxServerClientGet(u32ClientID, &pClient); + if (RT_FAILURE(rc)) + { + pHdr->result = rc; + return VINF_SUCCESS; + } + + /* This should never fire unless we start to multithread */ + CRASSERT(pClient->conn->pBuffer==NULL && pClient->conn->cbBuffer==0); + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + + pClient->conn->pBuffer = pBuffer; + pClient->conn->cbBuffer = cbBuffer; + CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, false); + rc = crVBoxServerInternalClientWriteRead(pClient); + CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); + return rc; + } + + crWarning("invalid number of args"); + rc = VERR_INVALID_PARAMETER; + break; + } + + case SHCRGL_GUEST_FN_SET_VERSION: + { + crWarning("invalid function"); + rc = VERR_NOT_IMPLEMENTED; + break; + } + + case SHCRGL_GUEST_FN_SET_PID: + { + crWarning("invalid function"); + rc = VERR_NOT_IMPLEMENTED; + break; + } + + default: + { + crWarning("invalid function"); + rc = VERR_NOT_IMPLEMENTED; + break; + } - /* no need to do anything here actually */ } + + /* we can be on fail only here */ + CRASSERT(RT_FAILURE(rc)); + pHdr->result = rc; + + return rc; +} + +static DECLCALLBACK(int) crVBoxCrCmdEnable(HVBOXCRCMDSVR hSvr, VBOXCRCMD_SVRENABLE_INFO *pInfo) +{ + cr_server.CrCmdClientInfo = *pInfo; + + crVBoxServerDefaultContextSet(); + return VINF_SUCCESS; } +static DECLCALLBACK(int) crVBoxCrCmdDisable(HVBOXCRCMDSVR hSvr) +{ + cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0); + + memset(&cr_server.CrCmdClientInfo, 0, sizeof (cr_server.CrCmdClientInfo)); + + return VINF_SUCCESS; +} + +static DECLCALLBACK(int) crVBoxCrCmdHostCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd) +{ + return crVBoxServerHostCtl((VBOXCRCMDCTL*)pCmd, cbCmd); +} + +static DECLCALLBACK(int) crVBoxCrCmdGuestCtl(HVBOXCRCMDSVR hSvr, uint8_t* pCmd, uint32_t cbCmd) +{ + VBOXCMDVBVA_3DCTL *pCtl = (VBOXCMDVBVA_3DCTL*)pCmd; + if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL)) + { + WARN(("invalid buffer size")); + return VERR_INVALID_PARAMETER; + } + + switch (pCtl->u32Type) + { + case VBOXCMDVBVA3DCTL_TYPE_CONNECT: + { + VBOXCMDVBVA_3DCTL_CONNECT *pConnect = (VBOXCMDVBVA_3DCTL_CONNECT*)pCtl; + + return VERR_NOT_SUPPORTED; + } + case VBOXCMDVBVA3DCTL_TYPE_DISCONNECT: + { + return VERR_NOT_SUPPORTED; + } + case VBOXCMDVBVA3DCTL_TYPE_CMD: + { + VBOXCMDVBVA_3DCTL_CMD *p3DCmd; + if (cbCmd < sizeof (VBOXCMDVBVA_3DCTL_CMD)) + { + WARN(("invalid size")); + return VERR_INVALID_PARAMETER; + } + + p3DCmd = (VBOXCMDVBVA_3DCTL_CMD*)pCmd; + + return crVBoxCrCmdCmd(NULL, &p3DCmd->Cmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_3DCTL_CMD, Cmd)); + } + default: + WARN(("invalid function")); + return VERR_INVALID_PARAMETER; + } +} + +static DECLCALLBACK(int) crVBoxCrCmdSaveState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM) +{ + AssertFailed(); + return VERR_NOT_IMPLEMENTED; +} + +static DECLCALLBACK(int) crVBoxCrCmdLoadState(HVBOXCRCMDSVR hSvr, PSSMHANDLE pSSM, uint32_t u32Version) +{ + AssertFailed(); + return VERR_NOT_IMPLEMENTED; +} + + +static DECLCALLBACK(int) crVBoxCrCmdCmd(HVBOXCRCMDSVR hSvr, PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd) +{ + AssertFailed(); + switch (pCmd->u8OpCode) + { + case VBOXCMDVBVA_OPTYPE_CRCMD: + { + VBOXCMDVBVA_CRCMD *pCrCmdDr; + VBOXCMDVBVA_CRCMD_CMD *pCrCmd; + int rc; + pCrCmdDr = (VBOXCMDVBVA_CRCMD*)pCmd; + pCrCmd = &pCrCmdDr->Cmd; + if (cbCmd < sizeof (VBOXCMDVBVA_CRCMD)) + { + WARN(("invalid buffer size")); + pCmd->u.i8Result = -1; + break; + } + rc = crVBoxServerCmdVbvaCrCmdProcess(pCrCmd, cbCmd - RT_OFFSETOF(VBOXCMDVBVA_CRCMD, Cmd)); + if (RT_SUCCESS(rc)) + { + /* success */ + pCmd->u.i8Result = 0; + } + else + { + WARN(("crVBoxServerCmdVbvaCrCmdProcess failed, rc %d", rc)); + pCmd->u.i8Result = -1; + } + break; + } + case VBOXCMDVBVA_OPTYPE_BLT_OFFPRIMSZFMT_OR_ID: + { + crVBoxServerCrCmdBltProcess(pCmd, cbCmd); + break; + } + default: + WARN(("unsupported command")); + pCmd->u.i8Result = -1; + } + return VINF_SUCCESS; +} -#ifdef VBOX_WITH_CRHGSMI /* We moved all CrHgsmi command processing to crserverlib to keep the logic of dealing with CrHgsmi commands in one place. * * For now we need the notion of CrHgdmi commands in the crserver_lib to be able to complete it asynchronously once it is really processed. @@ -1452,8 +3392,11 @@ DECLEXPORT(int32_t) crVBoxServerSetScreenViewport(int sIndex, int32_t x, int32_t * * NOTE: it is ALWAYS responsibility of the crVBoxServerCrHgsmiCmd to complete the command! * */ + + int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t cbCmd) { + int32_t rc; uint32_t cBuffers = pCmd->cBuffers; uint32_t cParams; @@ -1465,14 +3408,16 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c if (!g_pvVRamBase) { - crWarning("g_pvVRamBase is not initialized"); + WARN(("g_pvVRamBase is not initialized")); + crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_STATE); return VINF_SUCCESS; } if (!cBuffers) { - crWarning("zero buffers passed in!"); + WARN(("zero buffers passed in!")); + crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER); return VINF_SUCCESS; } @@ -1483,14 +3428,16 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c pHdr = VBOXCRHGSMI_PTR_SAFE(pCmd->aBuffers[0].offBuffer, cbHdr, CRVBOXHGSMIHDR); if (!pHdr) { - crWarning("invalid header buffer!"); + WARN(("invalid header buffer!")); + crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER); return VINF_SUCCESS; } if (cbHdr < sizeof (*pHdr)) { - crWarning("invalid header buffer size!"); + WARN(("invalid header buffer size!")); + crServerCrHgsmiCmdComplete(pCmd, VERR_INVALID_PARAMETER); return VINF_SUCCESS; } @@ -1502,7 +3449,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c { case SHCRGL_GUEST_FN_WRITE: { - crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE\n")); + Log(("svcCall: SHCRGL_GUEST_FN_WRITE\n")); /* @todo: Verify */ if (cParams == 1) @@ -1540,7 +3487,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c pClient->conn->pBuffer = pBuffer; pClient->conn->cbBuffer = cbBuffer; - CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr); + CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true); rc = crVBoxServerInternalClientWriteRead(pClient); CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); return rc; @@ -1556,7 +3503,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c case SHCRGL_GUEST_FN_INJECT: { - crDebug(("svcCall: SHCRGL_GUEST_FN_INJECT\n")); + Log(("svcCall: SHCRGL_GUEST_FN_INJECT\n")); /* @todo: Verify */ if (cParams == 1) @@ -1595,7 +3542,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c pClient->conn->pBuffer = pBuffer; pClient->conn->cbBuffer = cbBuffer; - CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr); + CRVBOXHGSMI_CMDDATA_SET(&pClient->conn->CmdData, pCmd, pHdr, true); rc = crVBoxServerInternalClientWriteRead(pClient); CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); return rc; @@ -1608,7 +3555,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c case SHCRGL_GUEST_FN_READ: { - crDebug(("svcCall: SHCRGL_GUEST_FN_READ\n")); + Log(("svcCall: SHCRGL_GUEST_FN_READ\n")); /* @todo: Verify */ if (cParams == 1) @@ -1651,6 +3598,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c /* the read command is never pended, complete it right away */ pHdr->result = rc; + crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS); return VINF_SUCCESS; } @@ -1662,7 +3610,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c case SHCRGL_GUEST_FN_WRITE_READ: { - crDebug(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n")); + Log(("svcCall: SHCRGL_GUEST_FN_WRITE_READ\n")); /* @todo: Verify */ if (cParams == 2) @@ -1715,7 +3663,7 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c pClient->conn->pBuffer = pBuffer; pClient->conn->cbBuffer = cbBuffer; - CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback); + CRVBOXHGSMI_CMDDATA_SETWB(&pClient->conn->CmdData, pCmd, pHdr, pWriteback, cbWriteback, &pFnCmd->cbWriteback, true); rc = crVBoxServerInternalClientWriteRead(pClient); CRVBOXHGSMI_CMDDATA_ASSERT_CLEANED(&pClient->conn->CmdData); return rc; @@ -1752,8 +3700,24 @@ int32_t crVBoxServerCrHgsmiCmd(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, uint32_t c /* we can be on fail only here */ CRASSERT(RT_FAILURE(rc)); pHdr->result = rc; + crServerCrHgsmiCmdComplete(pCmd, VINF_SUCCESS); return rc; + +} + +static DECLCALLBACK(bool) crVBoxServerHasData() +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + for (; + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + if (CrFbHas3DData(hFb)) + return true; + } + + return false; } int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t cbCtl) @@ -1767,6 +3731,14 @@ int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t c PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP)pCtl; g_pvVRamBase = (uint8_t*)pSetup->pvVRamBase; g_cbVRam = pSetup->cbVRam; + pSetup->CrCmdServerInfo.hSvr = NULL; + pSetup->CrCmdServerInfo.pfnEnable = crVBoxCrCmdEnable; + pSetup->CrCmdServerInfo.pfnDisable = crVBoxCrCmdDisable; + pSetup->CrCmdServerInfo.pfnCmd = crVBoxCrCmdCmd; + pSetup->CrCmdServerInfo.pfnHostCtl = crVBoxCrCmdHostCtl; + pSetup->CrCmdServerInfo.pfnGuestCtl = crVBoxCrCmdGuestCtl; + pSetup->CrCmdServerInfo.pfnSaveState = crVBoxCrCmdSaveState; + pSetup->CrCmdServerInfo.pfnLoadState = crVBoxCrCmdLoadState; rc = VINF_SUCCESS; break; } @@ -1774,11 +3746,14 @@ int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t c case VBOXVDMACMD_CHROMIUM_CTL_TYPE_SAVESTATE_END: rc = VINF_SUCCESS; break; - case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION: + case VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB: { - PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_COMPLETION)pCtl; + PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB pSetup = (PVBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB)pCtl; g_hCrHgsmiCompletion = pSetup->hCompletion; g_pfnCrHgsmiCompletion = pSetup->pfnCompletion; + + pSetup->MainInterface.pfnHasData = crVBoxServerHasData; + rc = VINF_SUCCESS; break; } @@ -1795,4 +3770,40 @@ int32_t crVBoxServerCrHgsmiCtl(struct VBOXVDMACMD_CHROMIUM_CTL *pCtl, uint32_t c * or Hgcm Host Fast Call commands that do require completion. All this details are hidden here */ return rc; } + +int32_t crVBoxServerHgcmEnable(HVBOXCRCMDCTL_REMAINING_HOST_COMMAND hRHCmd, PFNVBOXCRCMDCTL_REMAINING_HOST_COMMAND pfnRHCmd) +{ + int rc = VINF_SUCCESS; + uint8_t* pCtl; + uint32_t cbCtl; + + if (cr_server.numClients) + { + WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients)); + return VERR_INVALID_STATE; + } + + for (pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc); pCtl; pCtl = pfnRHCmd(hRHCmd, &cbCtl, rc)) + { + rc = crVBoxCrCmdHostCtl(NULL, pCtl, cbCtl); + } + + crVBoxServerDefaultContextSet(); + + return VINF_SUCCESS; +} + +int32_t crVBoxServerHgcmDisable() +{ + if (cr_server.numClients) + { + WARN(("cr_server.numClients(%d) is not NULL", cr_server.numClients)); + return VERR_INVALID_STATE; + } + + cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0); + + return VINF_SUCCESS; +} + #endif diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c index 20a71e3f..e9385996 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c @@ -49,7 +49,40 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchGetChromiumParametervCR(GLenum tar CRASSERT(bytes >= 0); CRASSERT(bytes < 4096); - cr_server.head_spu->dispatch_table.GetChromiumParametervCR( target, index, type, count, local_storage ); + switch (target) + { + case GL_DBG_CHECK_BREAK_CR: + { + if (bytes > 0) + { + GLubyte *pbRc = local_storage; + GLuint *puRc = (GLuint *)(bytes >=4 ? local_storage : NULL); + int rc; + memset(local_storage, 0, bytes); + if (cr_server.RcToGuestOnce) + { + rc = cr_server.RcToGuestOnce; + cr_server.RcToGuestOnce = 0; + } + else + { + rc = cr_server.RcToGuest; + } + if (puRc) + *puRc = rc; + else + *pbRc = !!rc; + } + else + { + crWarning("zero bytes for GL_DBG_CHECK_BREAK_CR"); + } + break; + } + default: + cr_server.head_spu->dispatch_table.GetChromiumParametervCR( target, index, type, count, local_storage ); + break; + } crServerReturnValue( local_storage, bytes ); } @@ -96,13 +129,13 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target break; case GL_GATHER_CONNECT_CR: - /* + /* * We want the last connect to go through, * otherwise we might deadlock in CheckWindowSize() * in the readback spu */ gather_connect_count++; - if (cr_server.only_swap_once && (gather_connect_count != cr_server.numClients)) + if (cr_server.only_swap_once && (gather_connect_count != cr_server.numClients)) { break; } @@ -122,8 +155,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target const GLfloat *v = (const GLfloat *) values; const int eye = v[1] == 0.0 ? 0 : 1; crMatrixInitFromFloats(&cr_server.viewMatrix[eye], v + 2); - - crDebug("Got GL_SERVER_VIEW_MATRIX_CR:\n" + + crDebug("Got GL_SERVER_VIEW_MATRIX_CR:\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n" @@ -160,8 +193,8 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target const GLfloat *v = (const GLfloat *) values; const int eye = v[1] == 0.0 ? 0 : 1; crMatrixInitFromFloats(&cr_server.projectionMatrix[eye], v + 2); - - crDebug("Got GL_SERVER_PROJECTION_MATRIX_CR:\n" + + crDebug("Got GL_SERVER_PROJECTION_MATRIX_CR:\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n" @@ -196,7 +229,7 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target float right = 2.0f * znear / x + left; float bottom = znear * (b - 1.0f) / y; float top = 2.0f * znear / y + bottom; - crDebug("Frustum: left, right, bottom, top, near, far: %f, %f, %f, %f, %f, %f", left, right, bottom, top, znear, zfar); + crDebug("Frustum: left, right, bottom, top, near, far: %f, %f, %f, %f, %f, %f", left, right, bottom, top, znear, zfar); } else { /* Todo: Add debug output for orthographic projection*/ @@ -206,6 +239,10 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target cr_server.projectionOverride = GL_TRUE; break; + case GL_HH_SET_TMPCTX_MAKE_CURRENT: + /*we should not receive it from the guest! */ + break; + default: /* Pass the parameter info to the head SPU */ cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values ); @@ -238,6 +275,12 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParameteriCR(GLenum target case GL_SERVER_CURRENT_EYE_CR: cr_server.currentEye = value ? 1 : 0; break; + case GL_HOST_WND_CREATED_HIDDEN_CR: + cr_server.bWindowsInitiallyHidden = value ? 1 : 0; + break; + case GL_HH_SET_DEFAULT_SHARED_CTX: + crWarning("Recieved GL_HH_SET_DEFAULT_SHARED_CTX from guest, ignoring"); + break; default: /* Pass the parameter info to the head SPU */ cr_server.head_spu->dispatch_table.ChromiumParameteriCR( target, value ); @@ -263,14 +306,6 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParameterfCR(GLenum target } } -void crServerCreateInfoDeleteCB(void *data) -{ - CRCreateInfo_t *pCreateInfo = (CRCreateInfo_t *) data; - if (pCreateInfo->pszDpyName) - crFree(pCreateInfo->pszDpyName); - crFree(pCreateInfo); -} - GLint crServerGenerateID(GLint *pCounter) { return (*pCounter)++; @@ -284,14 +319,14 @@ static int copynum=0; #endif # ifdef DEBUG_misha -# define CR_CHECK_BLITS +//# define CR_CHECK_BLITS # include <iprt/assert.h> # undef CRASSERT /* iprt assert's int3 are inlined that is why are more convenient to use since they can be easily disabled individually */ # define CRASSERT Assert # endif -void SERVER_DISPATCH_APIENTRY +void SERVER_DISPATCH_APIENTRY crServerDispatchCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { /*@todo pbo/fbo disabled for now as it's slower, check on other gpus*/ @@ -392,7 +427,7 @@ crServerDispatchCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLi gl->CopyTexImage2D(target, level, GL_RGBA, x, y, width, -height, 0); gl->GenFramebuffersEXT(1, &fboID); gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID); - gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, + gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid, level); status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) @@ -460,7 +495,7 @@ crServerDispatchCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLi gl->GetTexImage(target, level, GL_BGRA, GL_UNSIGNED_BYTE, img1); - + for (dRow=yoffset, sRow=y-height-1; dRow<yoffset-height; dRow++, sRow--) { gl->CopyTexSubImage2D(target, level, xoffset, dRow, x, sRow, width, 1); @@ -632,18 +667,252 @@ void crDbgDumpTexImage2D(const char* pszDesc, GLint texTarget, GLint texName, GL } #endif -void SERVER_DISPATCH_APIENTRY +PCR_BLITTER crServerVBoxBlitterGet() +{ + if (!CrBltIsInitialized(&cr_server.Blitter)) + { + CR_BLITTER_CONTEXT Ctx; + int rc; + CRASSERT(cr_server.MainContextInfo.SpuContext); + Ctx.Base.id = cr_server.MainContextInfo.SpuContext; + Ctx.Base.visualBits = cr_server.MainContextInfo.CreateInfo.realVisualBits; + rc = CrBltInit(&cr_server.Blitter, &Ctx, true, true, NULL, &cr_server.TmpCtxDispatch); + if (RT_SUCCESS(rc)) + { + CRASSERT(CrBltIsInitialized(&cr_server.Blitter)); + } + else + { + crWarning("CrBltInit failed, rc %d", rc); + CRASSERT(!CrBltIsInitialized(&cr_server.Blitter)); + return NULL; + } + } + + if (!CrBltMuralGetCurrentInfo(&cr_server.Blitter)->Base.id) + { + CRMuralInfo *dummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + CR_BLITTER_WINDOW DummyInfo; + CRASSERT(dummy); + crServerVBoxBlitterWinInit(&DummyInfo, dummy); + CrBltMuralSetCurrentInfo(&cr_server.Blitter, &DummyInfo); + } + + return &cr_server.Blitter; +} + +PCR_BLITTER crServerVBoxBlitterGetInitialized() +{ + if (CrBltIsInitialized(&cr_server.Blitter)) + return &cr_server.Blitter; + return NULL; +} + + +int crServerVBoxBlitterTexInit(CRContext *ctx, CRMuralInfo *mural, PVBOXVR_TEXTURE pTex, GLboolean fDraw) +{ + CRTextureObj *tobj; + CRFramebufferObjectState *pBuf = &ctx->framebufferobject; + GLenum enmBuf; + CRFBOAttachmentPoint *pAp; + GLuint idx; + CRTextureLevel *tl; + CRFramebufferObject *pFBO = fDraw ? pBuf->drawFB : pBuf->readFB; + + if (!pFBO) + { + GLuint hwid; + + if (!mural->fRedirected) + return VERR_NOT_IMPLEMENTED; + + enmBuf = fDraw ? ctx->buffer.drawBuffer : ctx->buffer.readBuffer; + switch (enmBuf) + { + case GL_BACK: + case GL_BACK_RIGHT: + case GL_BACK_LEFT: + hwid = mural->aidColorTexs[CR_SERVER_FBO_BB_IDX(mural)]; + break; + case GL_FRONT: + case GL_FRONT_RIGHT: + case GL_FRONT_LEFT: + hwid = mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]; + break; + default: + crWarning("unsupported enum buf"); + return VERR_NOT_IMPLEMENTED; + break; + } + + if (!hwid) + { + crWarning("offscreen render tex hwid is null"); + return VERR_INVALID_STATE; + } + + pTex->width = mural->width; + pTex->height = mural->height; + pTex->target = GL_TEXTURE_2D; + pTex->hwid = hwid; + return VINF_SUCCESS; + } + + enmBuf = fDraw ? pFBO->drawbuffer[0] : pFBO->readbuffer; + idx = enmBuf - GL_COLOR_ATTACHMENT0_EXT; + if (idx >= CR_MAX_COLOR_ATTACHMENTS) + { + crWarning("idx is invalid %d, using 0", idx); + } + + pAp = &pFBO->color[idx]; + + if (!pAp->name) + { + crWarning("no collor draw attachment"); + return VERR_INVALID_STATE; + } + + if (pAp->level) + { + crWarning("non-zero level not implemented"); + return VERR_NOT_IMPLEMENTED; + } + + tobj = (CRTextureObj*)crHashtableSearch(ctx->shared->textureTable, pAp->name); + if (!tobj) + { + crWarning("no texture object found for name %d", pAp->name); + return VERR_INVALID_STATE; + } + + if (tobj->target != GL_TEXTURE_2D && tobj->target != GL_TEXTURE_RECTANGLE_NV) + { + crWarning("non-texture[rect|2d] not implemented"); + return VERR_NOT_IMPLEMENTED; + } + + CRASSERT(tobj->hwid); + + tl = tobj->level[0]; + pTex->width = tl->width; + pTex->height = tl->height; + pTex->target = tobj->target; + pTex->hwid = tobj->hwid; + + return VINF_SUCCESS; +} + +int crServerVBoxBlitterBlitCurrentCtx(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + PCR_BLITTER pBlitter; + CR_BLITTER_CONTEXT Ctx; + CRMuralInfo *mural; + CRContext *ctx = crStateGetCurrent(); + PVBOXVR_TEXTURE pDrawTex, pReadTex; + VBOXVR_TEXTURE DrawTex, ReadTex; + int rc; + GLuint idDrawFBO, idReadFBO; + CR_BLITTER_WINDOW BltInfo; + + if (mask != GL_COLOR_BUFFER_BIT) + { + crWarning("not supported blit mask %d", mask); + return VERR_NOT_IMPLEMENTED; + } + + if (!cr_server.curClient) + { + crWarning("no current client"); + return VERR_INVALID_STATE; + } + mural = cr_server.curClient->currentMural; + if (!mural) + { + crWarning("no current mural"); + return VERR_INVALID_STATE; + } + + rc = crServerVBoxBlitterTexInit(ctx, mural, &DrawTex, GL_TRUE); + if (RT_SUCCESS(rc)) + { + pDrawTex = &DrawTex; + } + else + { + crWarning("crServerVBoxBlitterTexInit failed for draw"); + return rc; + } + + rc = crServerVBoxBlitterTexInit(ctx, mural, &ReadTex, GL_FALSE); + if (RT_SUCCESS(rc)) + { + pReadTex = &ReadTex; + } + else + { +// crWarning("crServerVBoxBlitterTexInit failed for read"); + return rc; + } + + pBlitter = crServerVBoxBlitterGet(); + if (!pBlitter) + { + crWarning("crServerVBoxBlitterGet failed"); + return VERR_GENERAL_FAILURE; + } + + crServerVBoxBlitterWinInit(&BltInfo, mural); + + crServerVBoxBlitterCtxInit(&Ctx, cr_server.curClient->currentCtxInfo); + + CrBltMuralSetCurrentInfo(pBlitter, &BltInfo); + + idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer); + idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer); + + crStateSwitchPrepare(NULL, ctx, idDrawFBO, idReadFBO); + + rc = CrBltEnter(pBlitter); + if (RT_SUCCESS(rc)) + { + RTRECT ReadRect, DrawRect; + ReadRect.xLeft = srcX0; + ReadRect.yTop = srcY0; + ReadRect.xRight = srcX1; + ReadRect.yBottom = srcY1; + DrawRect.xLeft = dstX0; + DrawRect.yTop = dstY0; + DrawRect.xRight = dstX1; + DrawRect.yBottom = dstY1; + CrBltBlitTexTex(pBlitter, pReadTex, &ReadRect, pDrawTex, &DrawRect, 1, CRBLT_FLAGS_FROM_FILTER(filter)); + CrBltLeave(pBlitter); + } + else + { + crWarning("CrBltEnter failed rc %d", rc); + } + + crStateSwitchPostprocess(ctx, NULL, idDrawFBO, idReadFBO); + + return rc; +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchBlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { + CRContext *ctx = crStateGetCurrent(); + bool fTryBlitter = false; #ifdef CR_CHECK_BLITS // { SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; GLint rfb=0, dfb=0, dtex=0, dlev=-1, rtex=0, rlev=-1, rb=0, db=0, ppb=0, pub=0, vp[4], otex, dstw, dsth; GLint sdtex=0, srtex=0; GLenum dStatus, rStatus; - CRContext *ctx = crStateGetCurrent(); CRTextureObj *tobj = 0; CRTextureLevel *tl = 0; @@ -847,10 +1116,60 @@ crServerDispatchBlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint gl->BindTexture(GL_TEXTURE_2D, otex); #endif + if (srcY0 > srcY1) + { + /* work around Intel driver bug on Linux host */ + if (1 || dstY0 > dstY1) + { + /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */ + int32_t tmp = srcY0; + srcY0 = srcY1; + srcY1 = tmp; + tmp = dstY0; + dstY0 = dstY1; + dstY1 = tmp; + } + } + + if (srcX0 > srcX1) + { + if (dstX0 > dstX1) + { + /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */ + int32_t tmp = srcX0; + srcX0 = srcX1; + srcX1 = tmp; + tmp = dstX0; + dstX0 = dstX1; + dstX1 = tmp; + } + } + + if (cr_server.fBlitterMode) + { + fTryBlitter = true; + } + + if (fTryBlitter) + { + int rc = crServerVBoxBlitterBlitCurrentCtx(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + if (RT_SUCCESS(rc)) + goto my_exit; + } + + if (ctx->viewport.scissorTest) + cr_server.head_spu->dispatch_table.Disable(GL_SCISSOR_TEST); + cr_server.head_spu->dispatch_table.BlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + if (ctx->viewport.scissorTest) + cr_server.head_spu->dispatch_table.Enable(GL_SCISSOR_TEST); + + +my_exit: + //#ifdef CR_CHECK_BLITS // crDbgDumpTexImage2D("<== src tex:", GL_TEXTURE_2D, rtex, true); // crDbgDumpTexImage2D("<== dst tex:", GL_TEXTURE_2D, dtex, true); @@ -863,6 +1182,7 @@ crServerDispatchBlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint gl->BindTexture(GL_TEXTURE_2D, otex); crFree(img); #endif + return; } void SERVER_DISPATCH_APIENTRY crServerDispatchDrawBuffer( GLenum mode ) @@ -871,27 +1191,69 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchDrawBuffer( GLenum mode ) if (!crStateGetCurrent()->framebufferobject.drawFB) { - if (mode == GL_FRONT || mode == GL_FRONT_LEFT) + if (mode == GL_FRONT || mode == GL_FRONT_LEFT || mode == GL_FRONT_RIGHT) cr_server.curClient->currentMural->bFbDraw = GL_TRUE; - if (cr_server.curClient->currentMural->bUseFBO && crServerIsRedirectedToFBO() - && cr_server.curClient->currentMural->idFBO) + if (crServerIsRedirectedToFBO() + && cr_server.curClient->currentMural->aidFBOs[0]) { + CRMuralInfo *mural = cr_server.curClient->currentMural; + GLint iBufferNeeded = -1; switch (mode) { case GL_BACK: case GL_BACK_LEFT: + case GL_BACK_RIGHT: mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_FRONT: case GL_FRONT_LEFT: - crDebug("Setting GL_FRONT with FBO mode! (0x%x)", mode); + case GL_FRONT_RIGHT: + mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_FB_IDX(mural); + break; + case GL_NONE: + crDebug("DrawBuffer: GL_NONE"); + break; + case GL_AUX0: + crDebug("DrawBuffer: GL_AUX0"); + break; + case GL_AUX1: + crDebug("DrawBuffer: GL_AUX1"); + break; + case GL_AUX2: + crDebug("DrawBuffer: GL_AUX2"); + break; + case GL_AUX3: + crDebug("DrawBuffer: GL_AUX3"); + break; + case GL_LEFT: + crWarning("DrawBuffer: GL_LEFT not supported properly"); + mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); + break; + case GL_RIGHT: + crWarning("DrawBuffer: GL_RIGHT not supported properly"); + mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); + break; + case GL_FRONT_AND_BACK: + crWarning("DrawBuffer: GL_FRONT_AND_BACK not supported properly"); mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; default: - crWarning("unexpected mode! 0x%x", mode); + crWarning("DrawBuffer: unexpected mode! 0x%x", mode); + iBufferNeeded = mural->iCurDrawBuffer; break; } + + if (iBufferNeeded != mural->iCurDrawBuffer) + { + mural->iCurDrawBuffer = iBufferNeeded; + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, iBufferNeeded)); + } } } @@ -902,25 +1264,661 @@ void SERVER_DISPATCH_APIENTRY crServerDispatchReadBuffer( GLenum mode ) { crStateReadBuffer( mode ); - if (cr_server.curClient->currentMural->bUseFBO && crServerIsRedirectedToFBO() - && cr_server.curClient->currentMural->idFBO + if (crServerIsRedirectedToFBO() + && cr_server.curClient->currentMural->aidFBOs[0] && !crStateGetCurrent()->framebufferobject.readFB) { + CRMuralInfo *mural = cr_server.curClient->currentMural; + GLint iBufferNeeded = -1; switch (mode) { case GL_BACK: case GL_BACK_LEFT: + case GL_BACK_RIGHT: mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_FRONT: case GL_FRONT_LEFT: - crWarning("GL_FRONT not supported for FBO mode!"); + case GL_FRONT_RIGHT: mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_FB_IDX(mural); + break; + case GL_NONE: + crDebug("ReadBuffer: GL_NONE"); + break; + case GL_AUX0: + crDebug("ReadBuffer: GL_AUX0"); + break; + case GL_AUX1: + crDebug("ReadBuffer: GL_AUX1"); + break; + case GL_AUX2: + crDebug("ReadBuffer: GL_AUX2"); + break; + case GL_AUX3: + crDebug("ReadBuffer: GL_AUX3"); + break; + case GL_LEFT: + crWarning("ReadBuffer: GL_LEFT not supported properly"); + mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); + break; + case GL_RIGHT: + crWarning("ReadBuffer: GL_RIGHT not supported properly"); + mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); + break; + case GL_FRONT_AND_BACK: + crWarning("ReadBuffer: GL_FRONT_AND_BACK not supported properly"); + mode = GL_COLOR_ATTACHMENT0; + iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; default: - crWarning("unexpected mode! 0x%x", mode); + crWarning("ReadBuffer: unexpected mode! 0x%x", mode); + iBufferNeeded = mural->iCurDrawBuffer; break; } + + Assert(CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer)); + if (iBufferNeeded != mural->iCurReadBuffer) + { + mural->iCurReadBuffer = iBufferNeeded; + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, iBufferNeeded)); + } } cr_server.head_spu->dispatch_table.ReadBuffer( mode ); } + +GLenum SERVER_DISPATCH_APIENTRY crServerDispatchGetError( void ) +{ + GLenum retval, err; + CRContext *ctx = crStateGetCurrent(); + retval = ctx->error; + + err = cr_server.head_spu->dispatch_table.GetError(); + if (retval == GL_NO_ERROR) + retval = err; + else + ctx->error = GL_NO_ERROR; + + /* our impl has a single error flag, so we just loop here to reset all error flags to no_error */ + while (err != GL_NO_ERROR) + err = cr_server.head_spu->dispatch_table.GetError(); + + crServerReturnValue( &retval, sizeof(retval) ); + return retval; /* WILL PROBABLY BE IGNORED */ +} + +void SERVER_DISPATCH_APIENTRY +crServerMakeTmpCtxCurrent( GLint window, GLint nativeWindow, GLint context ) +{ + CRContext *pCtx = crStateGetCurrent(); + CRContext *pCurCtx = NULL; + GLuint idDrawFBO = 0, idReadFBO = 0; + int fDoPrePostProcess = 0; + + if (pCtx) + { + CRMuralInfo *pCurrentMural = cr_server.currentMural; + + pCurCtx = cr_server.currentCtxInfo ? cr_server.currentCtxInfo->pContext : cr_server.MainContextInfo.pContext; + Assert(pCurCtx == pCtx); + + if (!context) + { + if (pCurrentMural) + { + Assert(cr_server.currentCtxInfo); + context = cr_server.currentCtxInfo->SpuContext > 0 ? cr_server.currentCtxInfo->SpuContext : cr_server.MainContextInfo.SpuContext; + window = pCurrentMural->spuWindow; + } + else + { + CRMuralInfo * pDummy; + Assert(!cr_server.currentCtxInfo); + pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + context = cr_server.MainContextInfo.SpuContext; + window = pDummy->spuWindow; + } + + + fDoPrePostProcess = -1; + } + else + { + fDoPrePostProcess = 1; + } + + if (pCurrentMural) + { + idDrawFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurDrawBuffer); + idReadFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurReadBuffer); + } + else + { + idDrawFBO = 0; + idReadFBO = 0; + } + } + else + { + /* this is a GUI thread, so no need to do anything here */ + } + + if (fDoPrePostProcess > 0) + crStateSwitchPrepare(NULL, pCurCtx, idDrawFBO, idReadFBO); + + cr_server.head_spu->dispatch_table.MakeCurrent( window, nativeWindow, context); + + if (fDoPrePostProcess < 0) + crStateSwitchPostprocess(pCurCtx, NULL, idDrawFBO, idReadFBO); +} + +void crServerInitTmpCtxDispatch() +{ + MakeCurrentFunc_t pfnMakeCurrent; + + crSPUInitDispatchTable(&cr_server.TmpCtxDispatch); + crSPUCopyDispatchTable(&cr_server.TmpCtxDispatch, &cr_server.head_spu->dispatch_table); + cr_server.TmpCtxDispatch.MakeCurrent = crServerMakeTmpCtxCurrent; + + pfnMakeCurrent = crServerMakeTmpCtxCurrent; + cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_TMPCTX_MAKE_CURRENT, GL_BYTE, sizeof (void*), &pfnMakeCurrent); + +} + +/* dump stuff */ +#ifdef VBOX_WITH_CRSERVER_DUMPER + +/* first four bits are buffer dump config + * second four bits are texture dump config + * config flags: + * 1 - blit on enter + * 2 - blit on exit + * + * + * Example: + * + * 0x03 - dump buffer on enter and exit + * 0x22 - dump texture and buffer on exit */ + +int64_t g_CrDbgDumpPid = 0; +unsigned long g_CrDbgDumpEnabled = 0; +unsigned long g_CrDbgDumpDraw = 0 +#if 0 + | CR_SERVER_DUMP_F_COMPILE_SHADER + | CR_SERVER_DUMP_F_LINK_PROGRAM +#endif + ; +#if 0 + | CR_SERVER_DUMP_F_DRAW_BUFF_ENTER + | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE + | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER + | CR_SERVER_DUMP_F_DRAW_TEX_ENTER + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER + | CR_SERVER_DUMP_F_DRAW_STATE_ENTER + | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER + | CR_SERVER_DUMP_F_DRAWEL + | CR_SERVER_DUMP_F_SHADER_SOURCE + ; +#endif +unsigned long g_CrDbgDumpDrawFramesSettings = CR_SERVER_DUMP_F_DRAW_BUFF_ENTER + | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE + | CR_SERVER_DUMP_F_DRAW_TEX_ENTER + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER + | CR_SERVER_DUMP_F_COMPILE_SHADER + | CR_SERVER_DUMP_F_LINK_PROGRAM + | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER; +unsigned long g_CrDbgDumpDrawFramesAppliedSettings = 0; +unsigned long g_CrDbgDumpDrawFramesSavedInitSettings = 0; +unsigned long g_CrDbgDumpDrawFramesCount = 0; + +uint32_t g_CrDbgDumpDrawCount = 0; +uint32_t g_CrDbgDumpDumpOnCount = 10; +uint32_t g_CrDbgDumpDumpOnCountEnabled = 0; +uint32_t g_CrDbgDumpDumpOnCountPerform = 0; +uint32_t g_CrDbgDumpDrawFlags = CR_SERVER_DUMP_F_COMPILE_SHADER + | CR_SERVER_DUMP_F_SHADER_SOURCE + | CR_SERVER_DUMP_F_COMPILE_SHADER + | CR_SERVER_DUMP_F_LINK_PROGRAM + | CR_SERVER_DUMP_F_DRAW_BUFF_ENTER + | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE + | CR_SERVER_DUMP_F_DRAW_TEX_ENTER + | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER + | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER + | CR_SERVER_DUMP_F_DRAW_STATE_ENTER + | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER + | CR_SERVER_DUMP_F_DRAWEL + | CR_SERVER_DUMP_F_TEXPRESENT; + +void crServerDumpCheckTerm() +{ + if (!CrBltIsInitialized(&cr_server.RecorderBlitter)) + return; + + CrBltTerm(&cr_server.RecorderBlitter); +} + +int crServerDumpCheckInit() +{ + int rc; + CR_BLITTER_WINDOW BltWin; + CR_BLITTER_CONTEXT BltCtx; + CRMuralInfo *pBlitterMural; + + if (!CrBltIsInitialized(&cr_server.RecorderBlitter)) + { + pBlitterMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + if (!pBlitterMural) + { + crWarning("crServerGetDummyMural failed"); + return VERR_GENERAL_FAILURE; + } + + crServerVBoxBlitterWinInit(&BltWin, pBlitterMural); + crServerVBoxBlitterCtxInit(&BltCtx, &cr_server.MainContextInfo); + + rc = CrBltInit(&cr_server.RecorderBlitter, &BltCtx, true, true, NULL, &cr_server.TmpCtxDispatch); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltInit failed rc %d", rc); + return rc; + } + + rc = CrBltMuralSetCurrentInfo(&cr_server.RecorderBlitter, &BltWin); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltMuralSetCurrentInfo failed rc %d", rc); + return rc; + } + } + +#if 0 + crDmpDbgPrintInit(&cr_server.DbgPrintDumper); + cr_server.pDumper = &cr_server.DbgPrintDumper.Base; +#else + if (!crDmpHtmlIsInited(&cr_server.HtmlDumper)) + { + static int cCounter = 0; +// crDmpHtmlInit(&cr_server.HtmlDumper, "S:\\projects\\virtualbox\\3d\\dumps\\1", "index.html"); + crDmpHtmlInitF(&cr_server.HtmlDumper, "/Users/oracle-mac/vbox/dump/1", "index%d.html", cCounter); + cr_server.pDumper = &cr_server.HtmlDumper.Base; + ++cCounter; + } +#endif + + crRecInit(&cr_server.Recorder, &cr_server.RecorderBlitter, &cr_server.TmpCtxDispatch, cr_server.pDumper); + return VINF_SUCCESS; +} + +void crServerDumpShader(GLint id) +{ + CRContext *ctx = crStateGetCurrent(); + crRecDumpShader(&cr_server.Recorder, ctx, id, 0); +} + +void crServerDumpProgram(GLint id) +{ + CRContext *ctx = crStateGetCurrent(); + crRecDumpProgram(&cr_server.Recorder, ctx, id, 0); +} + +void crServerDumpCurrentProgram() +{ + CRContext *ctx = crStateGetCurrent(); + crRecDumpCurrentProgram(&cr_server.Recorder, ctx); +} + +void crServerDumpRecompileDumpCurrentProgram() +{ + crDmpStrF(cr_server.Recorder.pDumper, "==Dump(1)=="); + crServerRecompileCurrentProgram(); + crServerDumpCurrentProgramUniforms(); + crServerDumpCurrentProgramAttribs(); + crDmpStrF(cr_server.Recorder.pDumper, "Done Dump(1)"); + crServerRecompileCurrentProgram(); + crDmpStrF(cr_server.Recorder.pDumper, "Dump(2)"); + crServerRecompileCurrentProgram(); + crServerDumpCurrentProgramUniforms(); + crServerDumpCurrentProgramAttribs(); + crDmpStrF(cr_server.Recorder.pDumper, "Done Dump(2)"); +} + +void crServerRecompileCurrentProgram() +{ + CRContext *ctx = crStateGetCurrent(); + crRecRecompileCurrentProgram(&cr_server.Recorder, ctx); +} + +void crServerDumpCurrentProgramUniforms() +{ + CRContext *ctx = crStateGetCurrent(); + crDmpStrF(cr_server.Recorder.pDumper, "==Uniforms=="); + crRecDumpCurrentProgramUniforms(&cr_server.Recorder, ctx); + crDmpStrF(cr_server.Recorder.pDumper, "==Done Uniforms=="); +} + +void crServerDumpCurrentProgramAttribs() +{ + CRContext *ctx = crStateGetCurrent(); + crDmpStrF(cr_server.Recorder.pDumper, "==Attribs=="); + crRecDumpCurrentProgramAttribs(&cr_server.Recorder, ctx); + crDmpStrF(cr_server.Recorder.pDumper, "==Done Attribs=="); +} + +void crServerDumpState() +{ + CRContext *ctx = crStateGetCurrent(); + crRecDumpGlGetState(&cr_server.Recorder, ctx); + crRecDumpGlEnableState(&cr_server.Recorder, ctx); +} + +void crServerDumpDrawel(const char*pszFormat, ...) +{ + CRContext *ctx = crStateGetCurrent(); + va_list pArgList; + va_start(pArgList, pszFormat); + crRecDumpVertAttrV(&cr_server.Recorder, ctx, pszFormat, pArgList); + va_end(pArgList); +} + +void crServerDumpDrawelv(GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + CRContext *ctx = crStateGetCurrent(); + crRecDumpVertAttrv(&cr_server.Recorder, ctx, idx, pszElFormat, cbEl, pvVal, cVal); +} + +void crServerDumpBuffer(int idx) +{ + CRContextInfo *pCtxInfo = cr_server.currentCtxInfo; + CR_BLITTER_WINDOW BltWin; + CR_BLITTER_CONTEXT BltCtx; + CRContext *ctx = crStateGetCurrent(); + GLint idFBO; + GLint idTex; + VBOXVR_TEXTURE RedirTex; + int rc = crServerDumpCheckInit(); + idx = idx >= 0 ? idx : crServerMuralFBOIdxFromBufferName(cr_server.currentMural, pCtxInfo->pContext->buffer.drawBuffer); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerDumpCheckInit failed, rc %d", rc); + return; + } + + if (idx < 0) + { + crWarning("neg idx, unsupported"); + return; + } + + idFBO = CR_SERVER_FBO_FOR_IDX(cr_server.currentMural, idx); + idTex = CR_SERVER_FBO_TEX_FOR_IDX(cr_server.currentMural, idx); + + crServerVBoxBlitterWinInit(&BltWin, cr_server.currentMural); + crServerVBoxBlitterCtxInit(&BltCtx, pCtxInfo); + + RedirTex.width = cr_server.currentMural->fboWidth; + RedirTex.height = cr_server.currentMural->fboHeight; + RedirTex.target = GL_TEXTURE_2D; + RedirTex.hwid = idTex; + + crRecDumpBuffer(&cr_server.Recorder, ctx, &BltCtx, &BltWin, idFBO, idTex ? &RedirTex : NULL); +} + +void crServerDumpTexture(const VBOXVR_TEXTURE *pTex) +{ + CRContextInfo *pCtxInfo = cr_server.currentCtxInfo; + CR_BLITTER_WINDOW BltWin; + CR_BLITTER_CONTEXT BltCtx; + CRContext *ctx = crStateGetCurrent(); + int rc = crServerDumpCheckInit(); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerDumpCheckInit failed, rc %d", rc); + return; + } + + crServerVBoxBlitterWinInit(&BltWin, cr_server.currentMural); + crServerVBoxBlitterCtxInit(&BltCtx, pCtxInfo); + + crRecDumpTextureF(&cr_server.Recorder, pTex, &BltCtx, &BltWin, "Tex (%d x %d), hwid (%d) target %#x", pTex->width, pTex->height, pTex->hwid, pTex->target); +} + +void crServerDumpTextures() +{ + CRContextInfo *pCtxInfo = cr_server.currentCtxInfo; + CR_BLITTER_WINDOW BltWin; + CR_BLITTER_CONTEXT BltCtx; + CRContext *ctx = crStateGetCurrent(); + int rc = crServerDumpCheckInit(); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerDumpCheckInit failed, rc %d", rc); + return; + } + + crServerVBoxBlitterWinInit(&BltWin, cr_server.currentMural); + crServerVBoxBlitterCtxInit(&BltCtx, pCtxInfo); + + crRecDumpTextures(&cr_server.Recorder, ctx, &BltCtx, &BltWin); +} + +void crServerDumpFilterOpLeave(unsigned long event, CR_DUMPER *pDumper) +{ + if (CR_SERVER_DUMP_F_DRAW_LEAVE_ALL & event) + { + g_CrDbgDumpDumpOnCountPerform = 0; + } +} + +bool crServerDumpFilterOpEnter(unsigned long event, CR_DUMPER *pDumper) +{ + if ((CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER & event) + || (CR_SERVER_DUMP_F_TEXPRESENT & event)) + { + if (g_CrDbgDumpDumpOnCountEnabled == 1) + g_CrDbgDumpDumpOnCountEnabled = 2; + else if (g_CrDbgDumpDumpOnCountEnabled) + { + g_CrDbgDumpDumpOnCountEnabled = 0; + if (cr_server.pDumper == &cr_server.HtmlDumper.Base) + { + crDmpHtmlTerm(&cr_server.HtmlDumper); + cr_server.pDumper = NULL; + } + } + + g_CrDbgDumpDrawCount = 0; + } + else if (CR_SERVER_DUMP_F_DRAW_ENTER_ALL & event) + { + if (g_CrDbgDumpDumpOnCountEnabled == 2) + { + if (g_CrDbgDumpDumpOnCount == g_CrDbgDumpDrawCount) + { + g_CrDbgDumpDumpOnCountPerform = 1; + } + ++g_CrDbgDumpDrawCount; + } + } + if (g_CrDbgDumpDumpOnCountPerform) + { + if (g_CrDbgDumpDrawFlags & event) + return true; + } + return CR_SERVER_DUMP_DEFAULT_FILTER_OP(event); +} + +bool crServerDumpFilterDmp(unsigned long event, CR_DUMPER *pDumper) +{ + if (g_CrDbgDumpDumpOnCountPerform) + { + if (g_CrDbgDumpDrawFlags & event) + return true; + } + return CR_SERVER_DUMP_DEFAULT_FILTER_DMP(event); +} + +void crServerDumpFramesCheck() +{ + if (!g_CrDbgDumpDrawFramesCount) + return; + + if (!g_CrDbgDumpDrawFramesAppliedSettings) + { + if (!g_CrDbgDumpDrawFramesSettings) + { + crWarning("g_CrDbgDumpDrawFramesSettings is NULL, bump will not be started"); + g_CrDbgDumpDrawFramesCount = 0; + return; + } + + g_CrDbgDumpDrawFramesSavedInitSettings = g_CrDbgDumpDraw; + g_CrDbgDumpDrawFramesAppliedSettings = g_CrDbgDumpDrawFramesSettings; + g_CrDbgDumpDraw = g_CrDbgDumpDrawFramesSettings; + crDmpStrF(cr_server.Recorder.pDumper, "***Starting draw dump for %d frames, settings(0x%x)", g_CrDbgDumpDrawFramesCount, g_CrDbgDumpDraw); + return; + } + + --g_CrDbgDumpDrawFramesCount; + + if (!g_CrDbgDumpDrawFramesCount) + { + crDmpStrF(cr_server.Recorder.pDumper, "***Stop draw dump"); + g_CrDbgDumpDraw = g_CrDbgDumpDrawFramesSavedInitSettings; + g_CrDbgDumpDrawFramesAppliedSettings = 0; + } +} +#endif + +GLvoid crServerSpriteCoordReplEnable(GLboolean fEnable) +{ + CRContext *g = crStateGetCurrent(); + CRTextureState *t = &(g->texture); + GLuint curTextureUnit = t->curTextureUnit; + GLuint curTextureUnitRestore = curTextureUnit; + GLuint i; + + for (i = 0; i < g->limits.maxTextureUnits; ++i) + { + if (g->point.coordReplacement[i]) + { + if (i != curTextureUnit) + { + curTextureUnit = i; + cr_server.head_spu->dispatch_table.ActiveTextureARB( i + GL_TEXTURE0_ARB ); + } + + cr_server.head_spu->dispatch_table.TexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, (GLint)fEnable); + } + } + + if (curTextureUnit != curTextureUnitRestore) + { + cr_server.head_spu->dispatch_table.ActiveTextureARB( curTextureUnitRestore + GL_TEXTURE0_ARB ); + } +} + +GLvoid SERVER_DISPATCH_APIENTRY crServerDispatchDrawArrays(GLenum mode, GLint first, GLsizei count) +{ +#ifdef DEBUG + GLenum status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); + Assert(GL_FRAMEBUFFER_COMPLETE == status); +#endif + if (mode == GL_POINTS) + crServerSpriteCoordReplEnable(GL_TRUE); + CR_SERVER_DUMP_DRAW_ENTER(); + CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.DrawArrays(mode, first, count);); + CR_SERVER_DUMP_DRAW_LEAVE(); + if (mode == GL_POINTS) + crServerSpriteCoordReplEnable(GL_FALSE); +} + +GLvoid SERVER_DISPATCH_APIENTRY crServerDispatchDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices) +{ +#ifdef DEBUG + GLenum status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); + Assert(GL_FRAMEBUFFER_COMPLETE == status); +#endif + if (mode == GL_POINTS) + crServerSpriteCoordReplEnable(GL_TRUE); + CR_SERVER_DUMP_DRAW_ENTER(); + CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.DrawElements(mode, count, type, indices);); + CR_SERVER_DUMP_DRAW_LEAVE(); + if (mode == GL_POINTS) + crServerSpriteCoordReplEnable(GL_FALSE); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchEnd( void ) +{ + CRContext *g = crStateGetCurrent(); + GLenum mode = g->current.mode; + + crStateEnd(); + cr_server.head_spu->dispatch_table.End(); + + CR_SERVER_DUMP_DRAW_LEAVE(); + + if (mode == GL_POINTS) + crServerSpriteCoordReplEnable(GL_FALSE); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchBegin(GLenum mode) +{ +#ifdef DEBUG + CRContext *ctx = crStateGetCurrent(); + SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; + + if (ctx->program.vpProgramBinding) + { + AssertRelease(ctx->program.currentVertexProgram); + + if (ctx->program.currentVertexProgram->isARBprogram) + { + GLint pid=-1; + gl->GetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &pid); + + if (pid != ctx->program.currentVertexProgram->id) + { + crWarning("pid(%d) != ctx->program.currentVertexProgram->id(%d)", pid, ctx->program.currentVertexProgram->id); + } + AssertRelease(pid == ctx->program.currentVertexProgram->id); + } + else + { + GLint pid=-1; + + gl->GetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &pid); + if (pid != ctx->program.currentVertexProgram->id) + { + crWarning("pid(%d) != ctx->program.currentVertexProgram->id(%d)", pid, ctx->program.currentVertexProgram->id); + } + AssertRelease(pid == ctx->program.currentVertexProgram->id); + } + } + else if (ctx->glsl.activeProgram) + { + GLint pid=-1; + + gl->GetIntegerv(GL_CURRENT_PROGRAM, &pid); + crDebug("pid %i, state: id %i, hwid %i", pid, ctx->glsl.activeProgram->id, ctx->glsl.activeProgram->hwid); + if (pid != ctx->glsl.activeProgram->hwid) + { + crWarning("pid(%d) != ctx->glsl.activeProgram->hwid(%d)", pid, ctx->glsl.activeProgram->hwid); + } + AssertRelease(pid == ctx->glsl.activeProgram->hwid); + } +#endif + + if (mode == GL_POINTS) + crServerSpriteCoordReplEnable(GL_TRUE); + + CR_SERVER_DUMP_DRAW_ENTER(); + + crStateBegin(mode); + cr_server.head_spu->dispatch_table.Begin(mode); +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.c deleted file mode 100644 index f42ed0c7..00000000 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.c +++ /dev/null @@ -1,591 +0,0 @@ -/* $Id: server_muralfbo.c $ */ - -/** @file - * VBox crOpenGL: Window to FBO redirect support. - */ - -/* - * Copyright (C) 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; - * you can redistribute it and/or modify it under the terms of the GNU - * General Public License (GPL) as published by the Free Software - * Foundation, in version 2 as it comes in the "COPYING" file of the - * VirtualBox OSE distribution. VirtualBox OSE is distributed in the - * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. - */ - -#include "server.h" -#include "cr_string.h" -#include "cr_mem.h" -#include "render/renderspu.h" - -static int crServerGetPointScreen(GLint x, GLint y) -{ - int i; - - for (i=0; i<cr_server.screenCount; ++i) - { - if ((x>=cr_server.screen[i].x && x<cr_server.screen[i].x+(int)cr_server.screen[i].w) - && (y>=cr_server.screen[i].y && y<cr_server.screen[i].y+(int)cr_server.screen[i].h)) - { - return i; - } - } - - return -1; -} - -static GLboolean crServerMuralCoverScreen(CRMuralInfo *mural, int sId) -{ - return mural->gX < cr_server.screen[sId].x - && mural->gX+(int)mural->width > cr_server.screen[sId].x+(int)cr_server.screen[sId].w - && mural->gY < cr_server.screen[sId].y - && mural->gY+(int)mural->height > cr_server.screen[sId].y+(int)cr_server.screen[sId].h; -} - -/* Called when a new CRMuralInfo is created - * or when OutputRedirect status is changed. - */ -void crServerSetupOutputRedirect(CRMuralInfo *mural) -{ - /* Unset the previous redirect. */ - if (mural->pvOutputRedirectInstance) - { - cr_server.outputRedirect.CROREnd(mural->pvOutputRedirectInstance); - mural->pvOutputRedirectInstance = NULL; - } - - /* Setup a new redirect. */ - if (cr_server.bUseOutputRedirect) - { - /* Query supported formats. */ - uint32_t cbFormats = 4096; - char *pachFormats = (char *)crAlloc(cbFormats); - - if (pachFormats) - { - int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext, - 0 /* H3DOR_PROP_FORMATS */, // @todo from a header - pachFormats, cbFormats, &cbFormats); - if (RT_SUCCESS(rc)) - { - if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN")) - { - cr_server.outputRedirect.CRORBegin(cr_server.outputRedirect.pvContext, - &mural->pvOutputRedirectInstance, - "H3DOR_FMT_RGBA_TOPDOWN"); // @todo from a header - } - } - - crFree(pachFormats); - } - - /* If this is not NULL then there was a supported format. */ - if (mural->pvOutputRedirectInstance) - { - cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance, - mural->hX, mural->hY, - mural->width, mural->height); - // @todo the code assumes that RTRECT == four of GLInts - cr_server.outputRedirect.CRORVisibleRegion(mural->pvOutputRedirectInstance, - mural->cVisibleRects, (RTRECT *)mural->pVisibleRects); - } - } -} - -void crServerCheckMuralGeometry(CRMuralInfo *mural) -{ - int tlS, brS, trS, blS; - int overlappingScreenCount, primaryS, i; - - if (!mural->width || !mural->height) - return; - - if (cr_server.screenCount<2 && !cr_server.bForceOffscreenRendering) - { - CRScreenViewportInfo *pVieport = &cr_server.screenVieport[mural->screenId]; - CRASSERT(cr_server.screenCount>0); - - mural->hX = mural->gX-cr_server.screen[0].x; - mural->hY = mural->gY-cr_server.screen[0].y; - - cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX - pVieport->x, mural->hY - pVieport->y); - - return; - } - - tlS = crServerGetPointScreen(mural->gX, mural->gY); - brS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY+mural->height-1); - - if (tlS==brS && tlS>=0) - { - overlappingScreenCount = 1; - primaryS = tlS; - } - else - { - trS = crServerGetPointScreen(mural->gX+mural->width-1, mural->gY); - blS = crServerGetPointScreen(mural->gX, mural->gY+mural->height-1); - - primaryS = -1; overlappingScreenCount = 0; - for (i=0; i<cr_server.screenCount; ++i) - { - if ((i==tlS) || (i==brS) || (i==trS) || (i==blS) - || crServerMuralCoverScreen(mural, i)) - { - overlappingScreenCount++; - primaryS = primaryS<0 ? i:primaryS; - } - } - - if (!overlappingScreenCount) - { - primaryS = 0; - } - } - - if (primaryS!=mural->screenId) - { - mural->screenId = primaryS; - - renderspuSetWindowId(cr_server.screen[primaryS].winID); - renderspuReparentWindow(mural->spuWindow); - renderspuSetWindowId(cr_server.screen[0].winID); - } - - mural->hX = mural->gX-cr_server.screen[primaryS].x; - mural->hY = mural->gY-cr_server.screen[primaryS].y; - - if (overlappingScreenCount<2 && !cr_server.bForceOffscreenRendering) - { - CRScreenViewportInfo *pVieport = &cr_server.screenVieport[mural->screenId]; - - if (mural->bUseFBO) - { - crServerRedirMuralFBO(mural, GL_FALSE); - crServerDeleteMuralFBO(mural); - } - - cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX - pVieport->x, mural->hY - pVieport->y); - } - else - { - if (mural->spuWindow) - { - if (!mural->bUseFBO) - { - crServerRedirMuralFBO(mural, GL_TRUE); - } - else - { - if (mural->width!=mural->fboWidth - || mural->height!=mural->height) - { - crServerRedirMuralFBO(mural, GL_FALSE); - crServerDeleteMuralFBO(mural); - crServerRedirMuralFBO(mural, GL_TRUE); - } - } - } -#ifdef DEBUG_misha - else - { - Assert(!mural->bUseFBO); - } -#endif - - if (!mural->bUseFBO) - { - CRScreenViewportInfo *pVieport = &cr_server.screenVieport[mural->screenId]; - - cr_server.head_spu->dispatch_table.WindowPosition(mural->spuWindow, mural->hX - pVieport->x, mural->hY - pVieport->y); - } - } - - if (mural->pvOutputRedirectInstance) - { - cr_server.outputRedirect.CRORGeometry(mural->pvOutputRedirectInstance, - mural->hX, mural->hY, - mural->width, mural->height); - } -} - -GLboolean crServerSupportRedirMuralFBO(void) -{ - static GLboolean fInited = GL_FALSE; - static GLboolean fSupported = GL_FALSE; - if (!fInited) - { - const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS); - - fSupported = ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object") - || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object")) - && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two"); - fInited = GL_TRUE; - } - return fSupported; -} - -void crServerRedirMuralFBO(CRMuralInfo *mural, GLboolean redir) -{ - if (redir) - { - if (!crServerSupportRedirMuralFBO()) - { - crWarning("FBO not supported, can't redirect window output"); - return; - } - - cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, GL_FALSE); - - if (mural->idFBO==0) - { - crServerCreateMuralFBO(mural); - } - - if (!crStateGetCurrent()->framebufferobject.drawFB) - { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, mural->idFBO); - } - if (!crStateGetCurrent()->framebufferobject.readFB) - { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, mural->idFBO); - } - - if (cr_server.curClient && cr_server.curClient->currentMural == mural) - { - crStateGetCurrent()->buffer.width = 0; - crStateGetCurrent()->buffer.height = 0; - } - } - else - { - cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, mural->bVisible); - - if (mural->bUseFBO && crServerSupportRedirMuralFBO()) - { - if (!crStateGetCurrent()->framebufferobject.drawFB) - { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - } - if (!crStateGetCurrent()->framebufferobject.readFB) - { - cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - } - } - - if (cr_server.curClient && cr_server.curClient->currentMural == mural) - { - crStateGetCurrent()->buffer.width = mural->width; - crStateGetCurrent()->buffer.height = mural->height; - } - } - - mural->bUseFBO = redir; -} - -void crServerCreateMuralFBO(CRMuralInfo *mural) -{ - CRContext *ctx = crStateGetCurrent(); - GLuint uid; - GLenum status; - SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; - - CRASSERT(mural->idFBO==0); - - /*Color texture*/ - gl->GenTextures(1, &mural->idColorTex); - gl->BindTexture(GL_TEXTURE_2D, mural->idColorTex); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) - { - gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); - } - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height, - 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); - - /*Depth&Stencil*/ - gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB); - gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB); - gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, - mural->width, mural->height); - - /*FBO*/ - gl->GenFramebuffersEXT(1, &mural->idFBO); - gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->idFBO); - - gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, mural->idColorTex, 0); - gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, mural->idDepthStencilRB); - gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, mural->idDepthStencilRB); - - status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (status!=GL_FRAMEBUFFER_COMPLETE_EXT) - { - crWarning("FBO status(0x%x) isn't complete", status); - } - - mural->fboWidth = mural->width; - mural->fboHeight = mural->height; - - /*PBO*/ - if (cr_server.bUsePBOForReadback) - { - gl->GenBuffersARB(1, &mural->idPBO); - gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO); - gl->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, mural->width*mural->height*4, 0, GL_STREAM_READ_ARB); - gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid); - - if (!mural->idPBO) - { - crWarning("PBO create failed"); - } - } - - /*Restore gl state*/ - uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid; - gl->BindTexture(GL_TEXTURE_2D, uid); - - uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0; - gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, uid); - - uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0; - gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, uid); - - uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0; - gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER, uid); - - if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) - { - gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid); - } -} - -void crServerDeleteMuralFBO(CRMuralInfo *mural) -{ - CRASSERT(!mural->bUseFBO); - - if (mural->idFBO!=0) - { - cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->idColorTex); - cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB); - cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->idFBO); - - mural->idFBO = 0; - mural->idColorTex = 0; - mural->idDepthStencilRB = 0; - } - - if (mural->idPBO!=0) - { - CRASSERT(cr_server.bUsePBOForReadback); - cr_server.head_spu->dispatch_table.DeleteBuffersARB(1, &mural->idPBO); - mural->idPBO = 0; - } -} - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect) -{ - CRASSERT(a && b && rect); - - rect->x1 = MAX(a->x1, b->x1); - rect->x2 = MIN(a->x2, b->x2); - rect->y1 = MAX(a->y1, b->y1); - rect->y2 = MIN(a->y2, b->y2); - - return (rect->x2>rect->x1) && (rect->y2>rect->y1); -} - -static GLboolean crServerIntersectScreen(CRMuralInfo *mural, int sId, CRrecti *rect) -{ - rect->x1 = MAX(mural->gX, cr_server.screen[sId].x); - rect->x2 = MIN(mural->gX+(int)mural->fboWidth, cr_server.screen[sId].x+(int)cr_server.screen[sId].w); - rect->y1 = MAX(mural->gY, cr_server.screen[sId].y); - rect->y2 = MIN(mural->gY+(int)mural->fboHeight, cr_server.screen[sId].y+(int)cr_server.screen[sId].h); - - return (rect->x2>rect->x1) && (rect->y2>rect->y1); -} - -static void crServerCopySubImage(char *pDst, char* pSrc, CRrecti *pRect, int srcWidth, int srcHeight) -{ - int i; - int dstrowsize = 4*(pRect->x2-pRect->x1); - int srcrowsize = 4*srcWidth; - int height = pRect->y2-pRect->y1; - - pSrc += 4*pRect->x1 + srcrowsize*(srcHeight-1-pRect->y1); - - for (i=0; i<height; ++i) - { - crMemcpy(pDst, pSrc, dstrowsize); - - pSrc -= srcrowsize; - pDst += dstrowsize; - } -} - -static void crServerTransformRect(CRrecti *pDst, CRrecti *pSrc, int dx, int dy) -{ - pDst->x1 = pSrc->x1+dx; - pDst->x2 = pSrc->x2+dx; - pDst->y1 = pSrc->y1+dy; - pDst->y2 = pSrc->y2+dy; -} - -void crServerPresentFBO(CRMuralInfo *mural) -{ - char *pixels=NULL, *tmppixels; - GLuint uid; - int i, j; - CRrecti rect, rectwr, sectr; - GLboolean bUsePBO; - CRContext *ctx = crStateGetCurrent(); - - CRASSERT(cr_server.pfnPresentFBO); - - if (!mural->bVisible) - { - return; - } - - if (!mural->width || !mural->height) - { - return; - } - - if (cr_server.bUsePBOForReadback && !mural->idPBO) - { - crWarning("Mural doesn't have PBO even though bUsePBOForReadback is set!"); - } - - bUsePBO = cr_server.bUsePBOForReadback && mural->idPBO; - - cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, mural->idColorTex); - - if (bUsePBO) - { - CRASSERT(mural->idPBO); - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mural->idPBO); - } - else - { - if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB)) - { - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); - } - - pixels = crAlloc(4*mural->fboWidth*mural->fboHeight); - if (!pixels) - { - crWarning("Out of memory in crServerPresentFBO"); - return; - } - } - - /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ - cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixels); - - /*restore gl state*/ - uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid; - cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid); - - if (bUsePBO) - { - pixels = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); - if (!pixels) - { - crWarning("Failed to MapBuffer in crServerPresentFBO"); - return; - } - } - - for (i=0; i<cr_server.screenCount; ++i) - { - if (crServerIntersectScreen(mural, i, &rect)) - { - /* rect in window relative coords */ - crServerTransformRect(&rectwr, &rect, -mural->gX, -mural->gY); - - if (!mural->pVisibleRects) - { - /*we don't get any rects info for guest compiz windows, so we treat windows as visible unless explicitly received 0 visible rects*/ - if (!mural->bReceivedRects) - { - tmppixels = crAlloc(4*(rect.x2-rect.x1)*(rect.y2-rect.y1)); - if (!tmppixels) - { - crWarning("Out of memory in crServerPresentFBO"); - crFree(pixels); - return; - } - - crServerCopySubImage(tmppixels, pixels, &rectwr, mural->fboWidth, mural->fboHeight); - /*Note: pfnPresentFBO would free tmppixels*/ - cr_server.pfnPresentFBO(tmppixels, i, rect.x1-cr_server.screen[i].x, rect.y1-cr_server.screen[i].y, rect.x2-rect.x1, rect.y2-rect.y1); - } - } - else - { - for (j=0; j<mural->cVisibleRects; ++j) - { - if (crServerIntersectRect(&rectwr, (CRrecti*) &mural->pVisibleRects[4*j], §r)) - { - tmppixels = crAlloc(4*(sectr.x2-sectr.x1)*(sectr.y2-sectr.y1)); - if (!tmppixels) - { - crWarning("Out of memory in crServerPresentFBO"); - crFree(pixels); - return; - } - - crServerCopySubImage(tmppixels, pixels, §r, mural->fboWidth, mural->fboHeight); - /*Note: pfnPresentFBO would free tmppixels*/ - cr_server.pfnPresentFBO(tmppixels, i, - sectr.x1+mural->gX-cr_server.screen[i].x, - sectr.y1+mural->gY-cr_server.screen[i].y, - sectr.x2-sectr.x1, sectr.y2-sectr.y1); - } - } - } - } - } - - if (mural->pvOutputRedirectInstance) - { - /* @todo find out why presentfbo is not called but crorframe is called. */ - cr_server.outputRedirect.CRORFrame(mural->pvOutputRedirectInstance, - pixels, - 4 * mural->fboWidth * mural->fboHeight); - } - - if (bUsePBO) - { - cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid); - } - else - { - crFree(pixels); - if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB)) - { - cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid); - } - } -} - -GLboolean crServerIsRedirectedToFBO() -{ - return cr_server.curClient - && cr_server.curClient->currentMural - && cr_server.curClient->currentMural->bUseFBO; -} diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp new file mode 100644 index 00000000..10cdf5cf --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp @@ -0,0 +1,840 @@ +/* $Id: server_muralfbo.cpp $ */ + +/** @file + * VBox crOpenGL: Window to FBO redirect support. + */ + +/* + * Copyright (C) 2010-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 "server.h" +#include "cr_string.h" +#include "cr_mem.h" +#include "cr_vreg.h" +#include "render/renderspu.h" + +static void crServerRedirMuralFbSync(CRMuralInfo *mural); + +void crServerCheckMuralGeometry(CRMuralInfo *mural) +{ + if (!mural->CreateInfo.externalID) + return; + + CRASSERT(mural->spuWindow); + CRASSERT(mural->spuWindow != CR_RENDER_DEFAULT_WINDOW_ID); + + if (!mural->width || !mural->height + || mural->fboWidth != mural->width + || mural->fboHeight != mural->height) + { + crServerRedirMuralFbClear(mural); + crServerRedirMuralFBO(mural, false); + crServerDeleteMuralFBO(mural); + } + + if (!mural->width || !mural->height) + return; + + crServerRedirMuralFBO(mural, true); + crServerRedirMuralFbSync(mural); +} + +static void crServerCheckMuralGeometryCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo *pMI = (CRMuralInfo*) data1; + + if (!pMI->fRedirected || pMI == data2) + return; + + crServerCheckMuralGeometry(pMI); +} + + +void crServerCheckAllMuralGeometry(CRMuralInfo *pMI) +{ + CR_FBMAP Map; + int rc = CrPMgrHlpGlblUpdateBegin(&Map); + if (!RT_SUCCESS(rc)) + { + WARN(("CrPMgrHlpGlblUpdateBegin failed %d", rc)); + return; + } + + crHashtableWalk(cr_server.muralTable, crServerCheckMuralGeometryCB, pMI); + + if (pMI) + crServerCheckMuralGeometry(pMI); + + CrPMgrHlpGlblUpdateEnd(&Map); +} + +GLboolean crServerSupportRedirMuralFBO(void) +{ + static GLboolean fInited = GL_FALSE; + static GLboolean fSupported = GL_FALSE; + if (!fInited) + { + const GLubyte* pExt = cr_server.head_spu->dispatch_table.GetString(GL_REAL_EXTENSIONS); + + fSupported = ( NULL!=crStrstr((const char*)pExt, "GL_ARB_framebuffer_object") + || NULL!=crStrstr((const char*)pExt, "GL_EXT_framebuffer_object")) + && NULL!=crStrstr((const char*)pExt, "GL_ARB_texture_non_power_of_two"); + fInited = GL_TRUE; + } + return fSupported; +} + +static void crServerCreateMuralFBO(CRMuralInfo *mural); + +void crServerRedirMuralFbClear(CRMuralInfo *mural) +{ + uint32_t i; + for (i = 0; i < mural->cUsedFBDatas; ++i) + { + CR_FBDATA *pData = mural->apUsedFBDatas[i]; + int rc = CrFbUpdateBegin(pData->hFb); + if (RT_SUCCESS(rc)) + { + CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false); + CrFbUpdateEnd(pData->hFb); + } + else + WARN(("CrFbUpdateBegin failed rc %d", rc)); + } + mural->cUsedFBDatas = 0; + + for (i = 0; i < cr_server.screenCount; ++i) + { + GLuint j; + CR_FBDATA *pData = &mural->aFBDatas[i]; + if (!pData->hFb) + continue; + + CrFbEntryRelease(pData->hFb, pData->hFbEntry); + pData->hFbEntry = NULL; + + for (j = 0; j < mural->cBuffers; ++j) + { + CrTdRelease(pData->apTexDatas[j]); + pData->apTexDatas[j] = NULL; + } + + pData->hFb = NULL; + } +} + +static int crServerRedirMuralDbSyncFb(CRMuralInfo *mural, HCR_FRAMEBUFFER hFb, CR_FBDATA **ppData) +{ + CR_FBDATA *pData; + const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(hFb); + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb); + RTRECT FbRect = *CrVrScrCompositorRectGet(pCompositor); + RTRECT DefaultRegionsRect; + const RTRECT * pRegions; + uint32_t cRegions; + RTPOINT Pos; + RTRECT MuralRect; + int rc; + + CRASSERT(mural->fRedirected); + + *ppData = NULL; + + if (!mural->bVisible) + return VINF_SUCCESS; + + MuralRect.xLeft = mural->gX; + MuralRect.yTop = mural->gY; + MuralRect.xRight = MuralRect.xLeft + mural->width; + MuralRect.yBottom = MuralRect.yTop + mural->height; + + Pos.x = mural->gX - pScreenInfo->i32OriginX; + Pos.y = mural->gY - pScreenInfo->i32OriginY; + + VBoxRectTranslate(&FbRect, pScreenInfo->i32OriginX, pScreenInfo->i32OriginY); + + VBoxRectIntersect(&FbRect, &MuralRect); + + if (VBoxRectIsZero(&FbRect)) + return VINF_SUCCESS; + + if (mural->bReceivedRects) + { + pRegions = (const RTRECT*)mural->pVisibleRects; + cRegions = mural->cVisibleRects; + } + else + { + DefaultRegionsRect.xLeft = 0; + DefaultRegionsRect.yTop = 0; + DefaultRegionsRect.xRight = mural->width; + DefaultRegionsRect.yBottom = mural->height; + pRegions = &DefaultRegionsRect; + cRegions = 1; + } + + if (!cRegions) + return VINF_SUCCESS; + + pData = &mural->aFBDatas[pScreenInfo->u32ViewIndex]; + + if (!pData->hFb) + { + pData->hFb = hFb; + + for (uint32_t i = 0; i < mural->cBuffers; ++i) + { + VBOXVR_TEXTURE Tex; + Tex.width = mural->width; + Tex.height = mural->height; + Tex.hwid = mural->aidColorTexs[i]; + Tex.target = GL_TEXTURE_2D; + + pData->apTexDatas[i] = CrFbTexDataCreate(&Tex); + } + + rc = CrFbEntryCreateForTexData(hFb, pData->apTexDatas[CR_SERVER_FBO_FB_IDX(mural)], 0, &pData->hFbEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryCreateForTexData failed rc %d", rc)); + } + } + else + { + CRASSERT(pData->hFb == hFb); + } + + rc = CrFbUpdateBegin(hFb); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbUpdateBegin failed rc %d", rc)); + return rc; + } + + rc = CrFbEntryRegionsSet(hFb, pData->hFbEntry, &Pos, cRegions, pRegions, true); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryRegionsSet failed rc %d", rc)); + } + + CrFbUpdateEnd(hFb); + + const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry = CrFbEntryGetCompositorEntry(pData->hFbEntry); + if (CrVrScrCompositorEntryIsUsed(pCEntry)) + *ppData = pData; + + return rc; +} + +static void crServerRedirMuralFbSync(CRMuralInfo *mural) +{ + uint32_t i; + uint32_t cUsedFBs = 0; + HCR_FRAMEBUFFER ahUsedFbs[CR_MAX_GUEST_MONITORS]; + HCR_FRAMEBUFFER hFb; + + for (i = 0; i < mural->cUsedFBDatas; ++i) + { + CR_FBDATA *pData = mural->apUsedFBDatas[i]; + int rc = CrFbUpdateBegin(pData->hFb); + if (RT_SUCCESS(rc)) + { + ahUsedFbs[cUsedFBs] = pData->hFb; + CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false); + ++cUsedFBs; + } + else + WARN(("CrFbUpdateBegin failed rc %d", rc)); + } + mural->cUsedFBDatas = 0; + + if (!mural->width + || !mural->height + || !mural->bVisible + ) + goto end; + + CRASSERT(mural->fRedirected); + + for (hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + CR_FBDATA *pData = NULL; + int rc = crServerRedirMuralDbSyncFb(mural, hFb, &pData); + if (!RT_SUCCESS(rc)) + { + WARN(("crServerRedirMuralDbSyncFb failed %d", rc)); + continue; + } + + if (!pData) + continue; + + mural->apUsedFBDatas[mural->cUsedFBDatas] = pData; + ++mural->cUsedFBDatas; + } + +end: + + for (i = 0; i < cUsedFBs; ++i) + { + CrFbUpdateEnd(ahUsedFbs[i]); + } +} + +static void crVBoxServerMuralFbCleanCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo *pMI = (CRMuralInfo*) data1; + HCR_FRAMEBUFFER hFb = (HCR_FRAMEBUFFER)data2; + uint32_t i; + for (i = 0; i < pMI->cUsedFBDatas; ++i) + { + CR_FBDATA *pData = pMI->apUsedFBDatas[i]; + if (hFb != pData->hFb) + continue; + + CrFbEntryRegionsSet(pData->hFb, pData->hFbEntry, NULL, 0, NULL, false); + break; + } +} + +static void crVBoxServerMuralFbSetCB(unsigned long key, void *data1, void *data2) +{ + CRMuralInfo *pMI = (CRMuralInfo*) data1; + HCR_FRAMEBUFFER hFb = (HCR_FRAMEBUFFER)data2; + uint32_t i; + CR_FBDATA *pData = NULL; + bool fFbWasUsed = false; + + Assert(hFb); + + if (!pMI->fRedirected) + { + Assert(!pMI->cUsedFBDatas); + return; + } + + for (i = 0; i < pMI->cUsedFBDatas; ++i) + { + CR_FBDATA *pData = pMI->apUsedFBDatas[i]; + if (hFb != pData->hFb) + continue; + + fFbWasUsed = true; + break; + } + + if (CrFbIsEnabled(hFb)) + { + int rc = crServerRedirMuralDbSyncFb(pMI, hFb, &pData); + if (!RT_SUCCESS(rc)) + { + WARN(("crServerRedirMuralDbSyncFb failed %d", rc)); + pData = NULL; + } + } + + if (pData) + { + if (!fFbWasUsed) + { + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + for (i = 0; i < pMI->cUsedFBDatas; ++i) + { + CR_FBDATA *pData = pMI->apUsedFBDatas[i]; + uint32_t idCurScreen = CrFbGetScreenInfo(pData->hFb)->u32ViewIndex; + if (idCurScreen > idScreen) + break; + + Assert(idCurScreen != idScreen); + } + + for (int j = pMI->cUsedFBDatas; j > i; --j) + { + pMI->apUsedFBDatas[j] = pMI->apUsedFBDatas[j-1]; + } + + pMI->apUsedFBDatas[i] = pData; + ++pMI->cUsedFBDatas; + } + /* else - nothing to do */ + } + else + { + if (fFbWasUsed) + { + for (int j = i; j < pMI->cUsedFBDatas - 1; ++j) + { + pMI->apUsedFBDatas[j] = pMI->apUsedFBDatas[j+1]; + } + --pMI->cUsedFBDatas; + } + /* else - nothing to do */ + } +} + +void crVBoxServerMuralFbResizeEnd(HCR_FRAMEBUFFER hFb) +{ + crHashtableWalk(cr_server.muralTable, crVBoxServerMuralFbSetCB, hFb); +} + +void crVBoxServerMuralFbResizeBegin(HCR_FRAMEBUFFER hFb) +{ + crHashtableWalk(cr_server.muralTable, crVBoxServerMuralFbCleanCB, hFb); +} + + +static int crVBoxServerResizeScreen(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM) +{ + int rc; + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(pScreen->u32ViewIndex); + if (!hFb) + { + WARN(("CrPMgrFbGet failed")); + return VERR_INVALID_PARAMETER; + } + + rc = CrFbUpdateBegin(hFb); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbUpdateBegin failed %d", rc)); + return rc; + } + + crVBoxServerMuralFbResizeBegin(hFb); + + rc = CrFbResize(hFb, pScreen, pvVRAM); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbResize failed %d", rc)); + } + + crVBoxServerMuralFbResizeEnd(hFb); + + CrFbUpdateEnd(hFb); + + CrPMgrNotifyResize(hFb); + + return rc; +} + +DECLEXPORT(int) crVBoxServerNotifyResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM) +{ + int rc = crVBoxServerResizeScreen(pScreen, pvVRAM); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return VINF_SUCCESS; +} + +void crServerRedirMuralFBO(CRMuralInfo *mural, bool fEnabled) +{ + if (!mural->fRedirected == !fEnabled) + { + return; + } + + if (!mural->CreateInfo.externalID) + { + WARN(("trying to change redir setting for internal mural %d", mural->spuWindow)); + return; + } + + if (fEnabled) + { + if (!crServerSupportRedirMuralFBO()) + { + WARN(("FBO not supported, can't redirect window output")); + return; + } + + if (mural->aidFBOs[0]==0) + { + crServerCreateMuralFBO(mural); + } + + if (cr_server.curClient && cr_server.curClient->currentMural == mural) + { + if (!crStateGetCurrent()->framebufferobject.drawFB) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer)); + } + if (!crStateGetCurrent()->framebufferobject.readFB) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer)); + } + + crStateGetCurrent()->buffer.width = 0; + crStateGetCurrent()->buffer.height = 0; + } + } + else + { + if (cr_server.curClient && cr_server.curClient->currentMural == mural) + { + if (!crStateGetCurrent()->framebufferobject.drawFB) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); + } + if (!crStateGetCurrent()->framebufferobject.readFB) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); + } + + crStateGetCurrent()->buffer.width = mural->width; + crStateGetCurrent()->buffer.height = mural->height; + } + } + + mural->fRedirected = !!fEnabled; +} + +static void crServerCreateMuralFBO(CRMuralInfo *mural) +{ + CRContext *ctx = crStateGetCurrent(); + GLuint uid, i; + GLenum status; + SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; + CRContextInfo *pMuralContextInfo; + + CRASSERT(mural->aidFBOs[0]==0); + CRASSERT(mural->aidFBOs[1]==0); + + pMuralContextInfo = cr_server.currentCtxInfo; + if (!pMuralContextInfo) + { + /* happens on saved state load */ + CRASSERT(cr_server.MainContextInfo.SpuContext); + pMuralContextInfo = &cr_server.MainContextInfo; + cr_server.head_spu->dispatch_table.MakeCurrent(mural->spuWindow, 0, cr_server.MainContextInfo.SpuContext); + } + + if (pMuralContextInfo->CreateInfo.realVisualBits != mural->CreateInfo.realVisualBits) + { + WARN(("mural visual bits do not match with current context visual bits!")); + } + + mural->cBuffers = 2; + mural->iBbBuffer = 0; + /*Color texture*/ + + if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) + { + gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + } + + for (i = 0; i < mural->cBuffers; ++i) + { + gl->GenTextures(1, &mural->aidColorTexs[i]); + gl->BindTexture(GL_TEXTURE_2D, mural->aidColorTexs[i]); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mural->width, mural->height, + 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + } + + /*Depth&Stencil*/ + gl->GenRenderbuffersEXT(1, &mural->idDepthStencilRB); + gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, mural->idDepthStencilRB); + gl->RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, + mural->width, mural->height); + + /*FBO*/ + for (i = 0; i < mural->cBuffers; ++i) + { + gl->GenFramebuffersEXT(1, &mural->aidFBOs[i]); + gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, mural->aidFBOs[i]); + + gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, mural->aidColorTexs[i], 0); + gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, mural->idDepthStencilRB); + gl->FramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, mural->idDepthStencilRB); + + status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (status!=GL_FRAMEBUFFER_COMPLETE_EXT) + { + WARN(("FBO status(0x%x) isn't complete", status)); + } + } + + mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer); + mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer); + + mural->fboWidth = mural->width; + mural->fboHeight = mural->height; + + mural->iCurDrawBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.drawBuffer); + mural->iCurReadBuffer = crServerMuralFBOIdxFromBufferName(mural, ctx->buffer.readBuffer); + + /*Restore gl state*/ + uid = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid; + gl->BindTexture(GL_TEXTURE_2D, uid); + + uid = ctx->framebufferobject.renderbuffer ? ctx->framebufferobject.renderbuffer->hwid:0; + gl->BindRenderbufferEXT(GL_RENDERBUFFER_EXT, uid); + + uid = ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0; + gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, uid); + + uid = ctx->framebufferobject.readFB ? ctx->framebufferobject.readFB->hwid:0; + gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER, uid); + + if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) + { + gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid); + } + + if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB)) + { + gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid); + } + else + { + gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } + + CRASSERT(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]); +} + +void crServerDeleteMuralFBO(CRMuralInfo *mural) +{ + if (mural->aidFBOs[0]!=0) + { + GLuint i; + for (i = 0; i < mural->cBuffers; ++i) + { + cr_server.head_spu->dispatch_table.DeleteTextures(1, &mural->aidColorTexs[i]); + mural->aidColorTexs[i] = 0; + } + + cr_server.head_spu->dispatch_table.DeleteRenderbuffersEXT(1, &mural->idDepthStencilRB); + mural->idDepthStencilRB = 0; + + for (i = 0; i < mural->cBuffers; ++i) + { + cr_server.head_spu->dispatch_table.DeleteFramebuffersEXT(1, &mural->aidFBOs[i]); + mural->aidFBOs[i] = 0; + } + } + + mural->cBuffers = 0; +} + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +static GLboolean crServerIntersectRect(CRrecti *a, CRrecti *b, CRrecti *rect) +{ + CRASSERT(a && b && rect); + + rect->x1 = MAX(a->x1, b->x1); + rect->x2 = MIN(a->x2, b->x2); + rect->y1 = MAX(a->y1, b->y1); + rect->y2 = MIN(a->y2, b->y2); + + return (rect->x2>rect->x1) && (rect->y2>rect->y1); +} + +DECLEXPORT(void) crServerVBoxCompositionSetEnableStateGlobal(GLboolean fEnable) +{ +} + +DECLEXPORT(void) crServerVBoxScreenshotRelease(CR_SCREENSHOT *pScreenshot) +{ + if (pScreenshot->fDataAllocated) + { + RTMemFree(pScreenshot->Img.pvData); + pScreenshot->fDataAllocated = 0; + } +} + +DECLEXPORT(int) crServerVBoxScreenshotGet(uint32_t u32Screen, uint32_t width, uint32_t height, uint32_t pitch, void *pvBuffer, CR_SCREENSHOT *pScreenshot) +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u32Screen); + if (!hFb) + return VERR_INVALID_STATE; + + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + + if (!width) + width = pScreen->u32Width; + if (!height) + height = pScreen->u32Height; + if (!pitch) + pitch = pScreen->u32LineSize; + + if (CrFbHas3DData(hFb) + || pScreen->u32Width != width + || pScreen->u32Height != height + || pScreen->u32LineSize != pitch + || pScreen->u16BitsPerPixel != 32) + { + RTRECT SrcRect; + RTRECT DstRect; + + pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height; + if (!pvBuffer) + { + pScreenshot->Img.pvData = RTMemAlloc(pScreenshot->Img.cbData); + if (!pScreenshot->Img.pvData) + { + WARN(("RTMemAlloc failed")); + return VERR_NO_MEMORY; + } + pScreenshot->fDataAllocated = 1; + } + else + { + pScreenshot->Img.pvData = pvBuffer; + pScreenshot->fDataAllocated = 0; + } + + pScreenshot->Img.enmFormat = GL_BGRA; + pScreenshot->Img.width = width; + pScreenshot->Img.height = height; + pScreenshot->Img.bpp = 32; + pScreenshot->Img.pitch = pitch; + SrcRect.xLeft = 0; + SrcRect.yTop = 0; + SrcRect.xRight = pScreen->u32Width; + SrcRect.yBottom = pScreen->u32Height; + DstRect.xLeft = 0; + DstRect.yTop = 0; + DstRect.xRight = width; + DstRect.yBottom = height; + int rc = CrFbBltGetContents(hFb, &SrcRect, &DstRect, 1, &DstRect, &pScreenshot->Img); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbBltGetContents failed %d", rc)); + crServerVBoxScreenshotRelease(pScreenshot); + return rc; + } + } + else + { + pScreenshot->Img.cbData = pScreen->u32LineSize * pScreen->u32Height; + if (!pvBuffer) + pScreenshot->Img.pvData = CrFbGetVRAM(hFb); + else + { + pScreenshot->Img.pvData = pvBuffer; + memcpy(pvBuffer, CrFbGetVRAM(hFb), pScreenshot->Img.cbData); + } + pScreenshot->Img.enmFormat = GL_BGRA; + pScreenshot->Img.width = pScreen->u32Width; + pScreenshot->Img.height = pScreen->u32Height; + pScreenshot->Img.bpp = pScreen->u16BitsPerPixel; + pScreenshot->Img.pitch = pScreen->u32LineSize; + + pScreenshot->fDataAllocated = 0; + } + + pScreenshot->u32Screen = u32Screen; + + return VINF_SUCCESS; +} + +extern DECLEXPORT(int) crServerVBoxWindowsShow(bool fShow) +{ + return CrPMgrModeWinVisible(fShow); +} + +void crServerPresentFBO(CRMuralInfo *mural) +{ + uint32_t i; + for (i = 0; i < mural->cUsedFBDatas; ++i) + { + CR_FBDATA *pData = mural->apUsedFBDatas[i]; + int rc = CrFbUpdateBegin(pData->hFb); + if (RT_SUCCESS(rc)) + { + CrFbEntryTexDataUpdate(pData->hFb, pData->hFbEntry, pData->apTexDatas[CR_SERVER_FBO_FB_IDX(mural)]); + CrFbUpdateEnd(pData->hFb); + } + else + WARN(("CrFbUpdateBegin failed rc %d", rc)); + } +} + +GLboolean crServerIsRedirectedToFBO() +{ +#ifdef DEBUG_misha + Assert(cr_server.curClient); + if (cr_server.curClient) + { + Assert(cr_server.curClient->currentMural == cr_server.currentMural); + Assert(cr_server.curClient->currentCtxInfo == cr_server.currentCtxInfo); + } +#endif + return cr_server.curClient + && cr_server.curClient->currentMural + && cr_server.curClient->currentMural->fRedirected; +} + +GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer) +{ + switch (buffer) + { + case GL_FRONT: + case GL_FRONT_LEFT: + case GL_FRONT_RIGHT: + return CR_SERVER_FBO_FB_IDX(mural); + case GL_BACK: + case GL_BACK_LEFT: + case GL_BACK_RIGHT: + return CR_SERVER_FBO_BB_IDX(mural); + case GL_NONE: + case GL_AUX0: + case GL_AUX1: + case GL_AUX2: + case GL_AUX3: + case GL_LEFT: + case GL_RIGHT: + case GL_FRONT_AND_BACK: + return -1; + default: + WARN(("crServerMuralFBOIdxFromBufferName: invalid buffer passed 0x%x", buffer)); + return -2; + } +} + +void crServerMuralFBOSwapBuffers(CRMuralInfo *mural) +{ + CRContext *ctx = crStateGetCurrent(); + GLuint iOldCurDrawBuffer = mural->iCurDrawBuffer; + GLuint iOldCurReadBuffer = mural->iCurReadBuffer; + mural->iBbBuffer = ((mural->iBbBuffer + 1) % (mural->cBuffers)); + if (mural->iCurDrawBuffer >= 0) + mural->iCurDrawBuffer = ((mural->iCurDrawBuffer + 1) % (mural->cBuffers)); + if (mural->iCurReadBuffer >= 0) + mural->iCurReadBuffer = ((mural->iCurReadBuffer + 1) % (mural->cBuffers)); + Assert(iOldCurDrawBuffer != mural->iCurDrawBuffer || mural->cBuffers == 1 || mural->iCurDrawBuffer < 0); + Assert(iOldCurReadBuffer != mural->iCurReadBuffer || mural->cBuffers == 1 || mural->iCurReadBuffer < 0); + if (!ctx->framebufferobject.drawFB && iOldCurDrawBuffer != mural->iCurDrawBuffer) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer)); + } + if (!ctx->framebufferobject.readFB && iOldCurReadBuffer != mural->iCurReadBuffer) + { + cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer)); + } + Assert(mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]); +} + diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp new file mode 100644 index 00000000..e1dca828 --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp @@ -0,0 +1,4787 @@ +/* $Id: server_presenter.cpp $ */ + +/** @file + * Presenter API + */ + +/* + * Copyright (C) 2012-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_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "server_dispatch.h" +#include "server.h" +#include "cr_mem.h" +#include "cr_string.h" +#include <cr_vreg.h> +#include <cr_htable.h> +#include <cr_bmpscale.h> + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/asm.h> +#include <iprt/mem.h> +#include <iprt/list.h> + + +#ifdef DEBUG_misha +# define VBOXVDBG_MEMCACHE_DISABLE +#endif + +#ifndef VBOXVDBG_MEMCACHE_DISABLE +# include <iprt/memcache.h> +#endif + +#include "render/renderspu.h" + +class ICrFbDisplay +{ +public: + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) = 0; + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) = 0; + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) = 0; + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) = 0; + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) = 0; + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) = 0; + + virtual ~ICrFbDisplay() {} +}; + +class CrFbDisplayComposite; +class CrFbDisplayBase; +class CrFbDisplayWindow; +class CrFbDisplayWindowRootVr; +class CrFbDisplayVrdp; + +typedef struct CR_FRAMEBUFFER +{ + VBOXVR_SCR_COMPOSITOR Compositor; + struct VBVAINFOSCREEN ScreenInfo; + void *pvVram; + ICrFbDisplay *pDisplay; + RTLISTNODE EntriesList; + uint32_t cEntries; /* <- just for debugging */ + uint32_t cUpdating; + CRHTABLE SlotTable; +} CR_FRAMEBUFFER; + +typedef union CR_FBENTRY_FLAGS +{ + struct { + uint32_t fCreateNotified : 1; + uint32_t fInList : 1; + uint32_t Reserved : 30; + }; + uint32_t Value; +} CR_FBENTRY_FLAGS; + +typedef struct CR_FRAMEBUFFER_ENTRY +{ + VBOXVR_SCR_COMPOSITOR_ENTRY Entry; + RTLISTNODE Node; + uint32_t cRefs; + CR_FBENTRY_FLAGS Flags; + CRHTABLE HTable; +} CR_FRAMEBUFFER_ENTRY; + +typedef struct CR_FBTEX +{ + CR_TEXDATA Tex; + CRTextureObj *pTobj; +} CR_FBTEX; + +#define PCR_FBTEX_FROM_TEX(_pTex) ((CR_FBTEX*)((uint8_t*)(_pTex) - RT_OFFSETOF(CR_FBTEX, Tex))) +#define PCR_FRAMEBUFFER_FROM_COMPOSITOR(_pCompositor) ((CR_FRAMEBUFFER*)((uint8_t*)(_pCompositor) - RT_OFFSETOF(CR_FRAMEBUFFER, Compositor))) +#define PCR_FBENTRY_FROM_ENTRY(_pEntry) ((CR_FRAMEBUFFER_ENTRY*)((uint8_t*)(_pEntry) - RT_OFFSETOF(CR_FRAMEBUFFER_ENTRY, Entry))) + + +typedef struct CR_FBDISPLAY_INFO +{ + uint32_t u32Mode; + CrFbDisplayWindow *pDpWin; + CrFbDisplayWindowRootVr *pDpWinRootVr; + CrFbDisplayVrdp *pDpVrdp; + CrFbDisplayComposite *pDpComposite; +} CR_FBDISPLAY_INFO; + +typedef struct CR_PRESENTER_GLOBALS +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMEMCACHE FbEntryLookasideList; + RTMEMCACHE FbTexLookasideList; + RTMEMCACHE CEntryLookasideList; +#endif + uint32_t u32DisplayMode; + CRHashTable *pFbTexMap; + CR_FBDISPLAY_INFO aDisplayInfos[CR_MAX_GUEST_MONITORS]; + CR_FBMAP FramebufferInitMap; + CR_FRAMEBUFFER aFramebuffers[CR_MAX_GUEST_MONITORS]; + bool fWindowsForceHidden; + uint32_t cbTmpBuf; + void *pvTmpBuf; + uint32_t cbTmpBuf2; + void *pvTmpBuf2; +} CR_PRESENTER_GLOBALS; + +static CR_PRESENTER_GLOBALS g_CrPresenter; + +/* FRAMEBUFFER */ + +void CrFbInit(CR_FRAMEBUFFER *pFb, uint32_t idScreen) +{ + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = 1; + Rect.yBottom = 1; + memset(pFb, 0, sizeof (*pFb)); + pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED; + pFb->ScreenInfo.u32ViewIndex = idScreen; + CrVrScrCompositorInit(&pFb->Compositor, &Rect); + RTListInit(&pFb->EntriesList); + CrHTableCreate(&pFb->SlotTable, 0); +} + +bool CrFbIsEnabled(CR_FRAMEBUFFER *pFb) +{ + return !(pFb->ScreenInfo.u16Flags & VBVA_SCREEN_F_DISABLED); +} + +HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry); + +const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(CR_FRAMEBUFFER *pFb) +{ + return &pFb->Compositor; +} + +DECLINLINE(CR_FRAMEBUFFER*) CrFbFromCompositor(const struct VBOXVR_SCR_COMPOSITOR* pCompositor) +{ + return RT_FROM_MEMBER(pCompositor, CR_FRAMEBUFFER, Compositor); +} + +const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb) +{ + return &hFb->ScreenInfo; +} + +void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb) +{ + return hFb->pvVram; +} + +int CrFbUpdateBegin(CR_FRAMEBUFFER *pFb) +{ + ++pFb->cUpdating; + + if (pFb->cUpdating == 1) + { + if (pFb->pDisplay) + pFb->pDisplay->UpdateBegin(pFb); + } + + return VINF_SUCCESS; +} + +void CrFbUpdateEnd(CR_FRAMEBUFFER *pFb) +{ + if (!pFb->cUpdating) + { + WARN(("invalid UpdateEnd call!")); + return; + } + + --pFb->cUpdating; + + if (!pFb->cUpdating) + { + if (pFb->pDisplay) + pFb->pDisplay->UpdateEnd(pFb); + } +} + +bool CrFbIsUpdating(const CR_FRAMEBUFFER *pFb) +{ + return !!pFb->cUpdating; +} + +bool CrFbHas3DData(HCR_FRAMEBUFFER hFb) +{ + return !CrVrScrCompositorIsEmpty(&hFb->Compositor); +} + +static void crFbBltMem(uint8_t *pu8Src, int32_t cbSrcPitch, uint8_t *pu8Dst, int32_t cbDstPitch, uint32_t width, uint32_t height) +{ + uint32_t cbCopyRow = width * 4; + + for (uint32_t i = 0; i < height; ++i) + { + memcpy(pu8Dst, pu8Src, cbCopyRow); + + pu8Src += cbSrcPitch; + pu8Dst += cbDstPitch; + } +} + +static void crFbBltImg(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, CR_BLITTER_IMG *pDst) +{ + int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x; + int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y; + Assert(srcX >= 0); + Assert(srcY >= 0); + Assert(srcX < (int32_t)pSrc->width); + Assert(srcY < (int32_t)pSrc->height); + + int32_t dstX = pCopyRect->xLeft - pDstDataPoint->x; + int32_t dstY = pCopyRect->yTop - pDstDataPoint->y; + Assert(dstX >= 0); + Assert(dstY >= 0); + + uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4; + uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4; + + crFbBltMem(pu8Src, fSrcInvert ? -((int32_t)pSrc->pitch) : (int32_t)pSrc->pitch, pu8Dst, pDst->pitch, pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop); +} + +static void crFbBltImgScaled(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, float strX, float strY, CR_BLITTER_IMG *pDst) +{ + int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x; + int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y; + Assert(srcX >= 0); + Assert(srcY >= 0); + Assert(srcX < (int32_t)pSrc->width); + Assert(srcY < (int32_t)pSrc->height); + + RTPOINT ScaledDtsDataPoint; + RTRECT ScaledCopyRect; + + VBoxRectScaled(pCopyRect, strX, strY, &ScaledCopyRect); + ScaledDtsDataPoint.x = CR_FLOAT_RCAST(int32_t, strX * pDstDataPoint->x); + ScaledDtsDataPoint.y = CR_FLOAT_RCAST(int32_t, strY * pDstDataPoint->y); + + int32_t dstX = ScaledCopyRect.xLeft - ScaledDtsDataPoint.x; + int32_t dstY = ScaledCopyRect.yTop - ScaledDtsDataPoint.y; + Assert(dstX >= 0); + Assert(dstY >= 0); + + int32_t ScaledDstWidth = ScaledCopyRect.xRight - ScaledCopyRect.xLeft; + int32_t delta = (int32_t)pDst->width - dstX - ScaledDstWidth; + if (delta < 0) + ScaledDstWidth += delta; + + if (ScaledDstWidth <= 0) + { + LOG(("ScaledDstWidth <= 0")); + if (ScaledDstWidth < 0) + WARN(("dst width (%d) < 0", ScaledDstWidth)); + return; + } + + int32_t ScaledDstHeight = ScaledCopyRect.yBottom - ScaledCopyRect.yTop; + delta = (int32_t)pDst->height - dstY - ScaledDstHeight; + if (delta < 0) + ScaledDstHeight += delta; + + if (ScaledDstHeight <= 0) + { + LOG(("ScaledDstHeight <= 0")); + if (ScaledDstHeight < 0) + WARN(("dst height (%d) < 0", ScaledDstHeight)); + return; + } + + uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4; + uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4; + + CrBmpScale32(pu8Dst, pDst->pitch, + ScaledDstWidth, + ScaledDstHeight, + pu8Src, + fSrcInvert ? -((int32_t)pSrc->pitch) : (int32_t)pSrc->pitch, + pCopyRect->xRight - pCopyRect->xLeft, pCopyRect->yBottom - pCopyRect->yTop); +} + +static void crFbBltImgScaledRects(const CR_BLITTER_IMG *pSrc, const RTPOINT *pSrcDataPoint, bool fSrcInvert, const RTRECT *pCopyRect, const RTPOINT *pDstDataPoint, float strX, float strY, CR_BLITTER_IMG *pDst) +{ + int32_t srcX = pCopyRect->xLeft - pSrcDataPoint->x; + int32_t srcY = pCopyRect->yTop - pSrcDataPoint->y; + Assert(srcX >= 0); + Assert(srcY >= 0); + + RTRECT UnscaledCopyRect; + VBoxRectUnscaled(pCopyRect, strX, strY, &UnscaledCopyRect); + + srcX = CR_FLOAT_RCAST(int32_t, srcX / strX); + srcY = CR_FLOAT_RCAST(int32_t, srcY / strY); + + int32_t UnscaledSrcWidth = UnscaledCopyRect.xRight - UnscaledCopyRect.xLeft; + int32_t delta = (int32_t)pSrc->width - srcX - UnscaledSrcWidth; + if (delta < 0) + UnscaledSrcWidth += delta; + + if (UnscaledSrcWidth <= 0) + { + LOG(("UnscaledSrcWidth <= 0")); + if (UnscaledSrcWidth < 0) + WARN(("src width (%d) < 0", UnscaledSrcWidth)); + return; + } + + int32_t UnscaledSrcHeight = UnscaledCopyRect.yBottom - UnscaledCopyRect.yTop; + delta = (int32_t)pSrc->height - srcY - UnscaledSrcHeight; + if (delta < 0) + UnscaledSrcHeight += delta; + + if (UnscaledSrcHeight <= 0) + { + LOG(("UnscaledSrcHeight <= 0")); + if (UnscaledSrcHeight < 0) + WARN(("src height (%d) < 0", UnscaledSrcHeight)); + return; + } + + int32_t dstX = pCopyRect->xLeft - pDstDataPoint->x; + int32_t dstY = pCopyRect->yTop - pDstDataPoint->y; + Assert(dstX >= 0); + Assert(dstY >= 0); + + + uint8_t *pu8Src = ((uint8_t*)pSrc->pvData) + pSrc->pitch * (!fSrcInvert ? srcY : pSrc->height - srcY - 1) + srcX * 4; + uint8_t *pu8Dst = ((uint8_t*)pDst->pvData) + pDst->pitch * dstY + dstX * 4; + + CrBmpScale32(pu8Dst, pDst->pitch, + pCopyRect->xRight - pCopyRect->xLeft, + pCopyRect->yBottom - pCopyRect->yTop, + pu8Src, + fSrcInvert ? -pSrc->pitch : pSrc->pitch, + UnscaledSrcWidth, + UnscaledSrcHeight + ); +} + +static void crFbImgFromScreenVram(const VBVAINFOSCREEN *pScreen, void *pvVram, CR_BLITTER_IMG *pImg) +{ + pImg->pvData = pvVram; + pImg->cbData = pScreen->u32LineSize * pScreen->u32Height; + pImg->enmFormat = GL_BGRA; + pImg->width = pScreen->u32Width; + pImg->height = pScreen->u32Height; + pImg->bpp = pScreen->u16BitsPerPixel; + pImg->pitch = pScreen->u32LineSize; +} + +static void crFbImgFromFb(HCR_FRAMEBUFFER hFb, CR_BLITTER_IMG *pImg) +{ + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + void *pvVram = CrFbGetVRAM(hFb); + crFbImgFromScreenVram(pScreen, pvVram, pImg); +} + +static int crFbBltGetContentsDirect(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + VBOXVR_LIST List; + uint32_t c2DRects = 0; + CR_TEXDATA *pEnteredTex = NULL; + PCR_BLITTER pEnteredBlitter = NULL; + uint32_t width = 0, height = 0; + RTPOINT ScaledEntryPoint = {0}; + + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + int32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft; + int32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop; + int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft; + int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop; + + RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop}; + float strX = ((float)dstWidth) / srcWidth; + float strY = ((float)dstHeight) / srcHeight; + bool fScale = (dstWidth != srcWidth || dstHeight != srcHeight); + + const RTPOINT ZeroPoint = {0, 0}; + + VBoxVrListInit(&List); + int rc = VBoxVrListRectsAdd(&List, 1, CrVrScrCompositorRectGet(&hFb->Compositor), NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsAdd failed rc %d", rc)); + goto end; + } + + CrVrScrCompositorConstIterInit(&hFb->Compositor, &Iter); + + for(const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrVrScrCompositorConstIterNext(&Iter); + pEntry; + pEntry = CrVrScrCompositorConstIterNext(&Iter)) + { + uint32_t cRegions; + const RTRECT *pRegions; + rc = CrVrScrCompositorEntryRegionsGet(&hFb->Compositor, pEntry, &cRegions, NULL, NULL, &pRegions); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed rc %d", rc)); + goto end; + } + + rc = VBoxVrListRectsSubst(&List, cRegions, pRegions, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsSubst failed rc %d", rc)); + goto end; + } + + for (uint32_t j = 0; j < cRegions; ++j) + { + /* rects are in dst coordinates, + * while the pReg is in source coords + * convert */ + const RTRECT * pReg = &pRegions[j]; + RTRECT ScaledReg; + /* scale */ + VBoxRectScaled(pReg, strX, strY, &ScaledReg); + /* translate */ + VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop); + + for (uint32_t i = 0; i < cRects; ++i) + { + const RTRECT * pRect = &pRects[i]; + + RTRECT Intersection; + VBoxRectIntersected(pRect, &ScaledReg, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + const CR_BLITTER_IMG *pSrcImg; + + if (pEnteredTex != pTex) + { + if (!pEnteredBlitter) + { + pEnteredBlitter = CrTdBlitterGet(pTex); + rc = CrBltEnter(pEnteredBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed %d", rc)); + pEnteredBlitter = NULL; + goto end; + } + } + + if (pEnteredTex) + { + CrTdBltLeave(pEnteredTex); + + pEnteredTex = NULL; + + if (pEnteredBlitter != CrTdBlitterGet(pTex)) + { + WARN(("blitters not equal!")); + CrBltLeave(pEnteredBlitter); + + pEnteredBlitter = CrTdBlitterGet(pTex); + rc = CrBltEnter(pEnteredBlitter); + if (!RT_SUCCESS(rc)) + { + WARN(("CrBltEnter failed %d", rc)); + pEnteredBlitter = NULL; + goto end; + } + } + } + + rc = CrTdBltEnter(pTex); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltEnter failed %d", rc)); + goto end; + } + + pEnteredTex = pTex; + + const VBOXVR_TEXTURE *pVrTex = CrTdTexGet(pTex); + + width = CR_FLOAT_RCAST(uint32_t, strX * pVrTex->width); + height = CR_FLOAT_RCAST(uint32_t, strY * pVrTex->height); + ScaledEntryPoint.x = CR_FLOAT_RCAST(int32_t, strX * CrVrScrCompositorEntryRectGet(pEntry)->xLeft) + pDstRect->xLeft; + ScaledEntryPoint.y = CR_FLOAT_RCAST(int32_t, strY * CrVrScrCompositorEntryRectGet(pEntry)->yTop) + pDstRect->yTop; + } + + rc = CrTdBltDataAcquireScaled(pTex, GL_BGRA, false, width, height, &pSrcImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + goto end; + } + + bool fInvert = !(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS); + + crFbBltImg(pSrcImg, &ScaledEntryPoint, fInvert, &Intersection, &ZeroPoint, pImg); + + CrTdBltDataReleaseScaled(pTex, pSrcImg); + } + } + } + + c2DRects = VBoxVrListRectsCount(&List); + if (c2DRects) + { + if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); + + g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT); + g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2); + if (!g_CrPresenter.pvTmpBuf2) + { + WARN(("RTMemAlloc failed!")); + g_CrPresenter.cbTmpBuf2 = 0; + rc = VERR_NO_MEMORY; + goto end; + } + } + + RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2; + + rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsGet failed, rc %d", rc)); + goto end; + } + + const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor); + + CR_BLITTER_IMG FbImg; + + crFbImgFromFb(hFb, &FbImg); + + for (uint32_t j = 0; j < c2DRects; ++j) + { + const RTRECT * p2DRect = &p2DRects[j]; + RTRECT ScaledReg; + /* scale */ + VBoxRectScaled(p2DRect, strX, strY, &ScaledReg); + /* translate */ + VBoxRectTranslate(&ScaledReg, pDstRect->xLeft, pDstRect->yTop); + + for (uint32_t i = 0; i < cRects; ++i) + { + const RTRECT * pRect = &pRects[i]; + RTRECT Intersection; + + VBoxRectIntersected(pRect, &ScaledReg, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + if (!fScale) + crFbBltImg(&FbImg, &DstPoint, false, &Intersection, &ZeroPoint, pImg); + else + crFbBltImgScaledRects(&FbImg, &DstPoint, false, &Intersection, &ZeroPoint, strX, strY, pImg); + } + } + } + +end: + + if (pEnteredTex) + CrTdBltLeave(pEnteredTex); + + if (pEnteredBlitter) + CrBltLeave(pEnteredBlitter); + + VBoxVrListClear(&List); + + return rc; +} + +static int crFbBltGetContentsScaleCPU(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + int32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft; + int32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop; + int32_t dstWidth = pDstRect->xRight - pDstRect->xLeft; + int32_t dstHeight = pDstRect->yBottom - pDstRect->yTop; + + RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop}; + float strX = ((float)dstWidth) / srcWidth; + float strY = ((float)dstHeight) / srcHeight; + + RTRECT DstRect; + VBoxRectUnscaled(pDstRect, strX, strY, &DstRect); + DstRect.xRight = DstRect.xLeft + srcWidth; + DstRect.yBottom = DstRect.yTop + srcHeight; + + /* destination is bigger than the source, do 3D data stretching with CPU */ + CR_BLITTER_IMG Img; + Img.cbData = srcWidth * srcHeight * 4; + Img.pvData = RTMemAlloc(Img.cbData); + if (!Img.pvData) + { + WARN(("RTMemAlloc Failed")); + return VERR_NO_MEMORY; + } + Img.enmFormat = pImg->enmFormat; + Img.width = srcWidth; + Img.height = srcHeight; + Img.bpp = pImg->bpp; + Img.pitch = Img.width * 4; + + int rc = CrFbBltGetContents(hFb, pSrcRect, &DstRect, cRects, pRects, &Img); + if (RT_SUCCESS(rc)) + { + CrBmpScale32((uint8_t *)pImg->pvData, + pImg->pitch, + pImg->width, pImg->height, + (const uint8_t *)Img.pvData, + Img.pitch, + Img.width, Img.height); + } + else + WARN(("CrFbBltGetContents failed %d", rc)); + + RTMemFree(Img.pvData); + + return rc; + +} + +int CrFbBltGetContents(HCR_FRAMEBUFFER hFb, const RTRECT *pSrcRect, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + uint32_t srcWidth = pSrcRect->xRight - pSrcRect->xLeft; + uint32_t srcHeight = pSrcRect->yBottom - pSrcRect->yTop; + uint32_t dstWidth = pDstRect->xRight - pDstRect->xLeft; + uint32_t dstHeight = pDstRect->yBottom - pDstRect->yTop; + if ((srcWidth == dstWidth + && srcHeight == dstHeight) + || !CrFbHas3DData(hFb) + || (srcWidth * srcHeight > dstWidth * dstHeight)) + { + return crFbBltGetContentsDirect(hFb, pSrcRect, pDstRect, cRects, pRects, pImg); + } + + return crFbBltGetContentsScaleCPU(hFb, pSrcRect, pDstRect, cRects, pRects, pImg); +} + +#if 0 +static int crFbBltPutContentsVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pDstPoint, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg, float strX, float strY) +{ + const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor); + const RTPOINT ZeroPoint = {0}; + + uint32_t fbWidth = (pCompRect->xRight - pCompRect->xLeft); + uint32_t fbHeight = pCompRect->yBottom - pCompRect->yTop; + + uint32_t stretchedWidth = CR_FLOAT_RCAST(uint32_t, strX * fbWidth); + uint32_t stretchedHeight = CR_FLOAT_RCAST(uint32_t, strY * fbHeight); + + CR_BLITTER_IMG FbImg; + + bool fScale = fbWidth != stretchedWidth || fbHeight != stretchedHeight; + + crFbImgFromFb(hFb, &FbImg); + + RTRECT Intersection; + + for (uint32_t i = 0; i < cRects; ++i) + { + const RTRECT * pRect = &pRects[i]; + VBoxRectIntersected(pRect, pCompRect, &Intersection); + + if (VBoxRectIsZero(&Intersection)) + continue; + + if (!fScale) + crFbBltImg(pImg, pDstPoint, false, &Intersection, &ZeroPoint, &FbImg); + else + crFbBltImgScaled(pImg, pDstPoint, false, &Intersection, &ZeroPoint, strX, strY, &FbImg); + } + + return VINF_SUCCESS; +} + +int CrFbBltPutContents(HCR_FRAMEBUFFER hFb, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + RTPOINT DstPoint = {pDstRect->xLeft, pDstRect->yTop}; + float strX = ((float)pImg->width) / (pDstRect->xRight - pDstRect->xLeft); + float strY = ((float)pImg->height) / (pDstRect->yBottom - pDstRect->yTop); + + int rc = CrFbEntryRegionsAdd(hFb, NULL, const RTPOINT *pPos, cRects, pRects, true) + if (!hFb->cUpdating) + { + WARN(("not updating\n")); + return VERR_INVALID_STATE; + } +} + +int CrFbBltPutContentsNe(HCR_FRAMEBUFFER hFb, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg) +{ + uint32_t cCompRects; + const RTRECT *pCompRects; + int rc = CrVrScrCompositorRegionsGet(&hFb->Compositor, &cCompRects, NULL, NULL, &pCompRects); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc)); + return rc; + } + + bool fRegChanged = false; + for (uint32_t i = 0; i < cCompRects; ++i) + { + const RTRECT *pCompRect = pCompRects[i]; + for (uint32_t j = 0; j < cRects; ++j) + { + const RTRECT *pRect = pRects[j]; + if (VBoxRectIsIntersect(pCompRect, pRect)) + { + fRegChanged = true; + break; + } + } + } + + if (fRegChanged) + { + rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + rc = CrFbBltPutContents(hFb, pDstRect, cRects, pRects, pImg); + if (!RT_SUCCESS(rc)) + WARN(("CrFbBltPutContents failed rc %d", rc)); + CrFbUpdateEnd(hFb); + } + else + WARN(("CrFbUpdateBegin failed rc %d", rc)); + + return rc; + } + + return crFbBltPutContentsVram(HCR_FRAMEBUFFER hFb, const RTPOINT *pDstPoint, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg, float strX, float strY); + + const RTPOINT ZeroPoint = {0, 0}; + + c2DRects = VBoxVrListRectsCount(&List); + if (c2DRects) + { + if (g_CrPresenter.cbTmpBuf2 < c2DRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); + + g_CrPresenter.cbTmpBuf2 = (c2DRects + 10) * sizeof (RTRECT); + g_CrPresenter.pvTmpBuf2 = RTMemAlloc(g_CrPresenter.cbTmpBuf2); + if (!g_CrPresenter.pvTmpBuf2) + { + WARN(("RTMemAlloc failed!")); + g_CrPresenter.cbTmpBuf2 = 0; + rc = VERR_NO_MEMORY; + goto end; + } + } + + RTRECT *p2DRects = (RTRECT *)g_CrPresenter.pvTmpBuf2; + + rc = VBoxVrListRectsGet(&List, c2DRects, p2DRects); + if (!RT_SUCCESS(rc)) + { + WARN(("VBoxVrListRectsGet failed, rc %d", rc)); + goto end; + } + + RTPOINT Pos = {0}; + const RTRECT *pCompRect = CrVrScrCompositorRectGet(&hFb->Compositor); + + CR_BLITTER_IMG FbImg; + + crFbImgFromFb(hFb, &FbImg); + + for (uint32_t i = 0; i < cRects; ++i) + { + const RTRECT * pRect = &pRects[i]; + for (uint32_t j = 0; j < c2DRects; ++j) + { + const RTRECT * p2DRect = &p2DRects[j]; + RTRECT Intersection; + VBoxRectIntersected(pRect, p2DRect, &Intersection); + if (VBoxRectIsZero(&Intersection)) + continue; + + if (!fScale) + crFbBltImg(&FbImg, &ZeroPoint, false, &Intersection, &SrcPoint, pImg); + else + crFbBltImgScaled(&FbImg, &ZeroPoint, false, &Intersection, &SrcPoint, strX, strY, pImg); + } + } + } + +end: + + if (pEnteredTex) + CrTdBltLeave(pEnteredTex); + + if (pEnteredBlitter) + CrBltLeave(pEnteredBlitter); + + VBoxVrListClear(&List); + + return rc; +} +#endif + +int CrFbResize(CR_FRAMEBUFFER *pFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM) +{ + if (!pFb->cUpdating) + { + WARN(("no update in progress")); + return VERR_INVALID_STATE; + } + + if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED) + { + CrVrScrCompositorClear(&pFb->Compositor); + } + + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = pScreen->u32Width; + Rect.yBottom = pScreen->u32Height; + int rc = CrVrScrCompositorRectSet(&pFb->Compositor, &Rect, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRectSet failed rc %d", rc)); + return rc; + } + + pFb->ScreenInfo = *pScreen; + pFb->pvVram = pvVRAM; + + if (pFb->pDisplay) + pFb->pDisplay->FramebufferChanged(pFb); + + return VINF_SUCCESS; +} + +void CrFbTerm(CR_FRAMEBUFFER *pFb) +{ + if (pFb->cUpdating) + { + WARN(("update in progress")); + return; + } + uint32_t idScreen = pFb->ScreenInfo.u32ViewIndex; + + CrVrScrCompositorClear(&pFb->Compositor); + CrHTableDestroy(&pFb->SlotTable); + + Assert(RTListIsEmpty(&pFb->EntriesList)); + Assert(!pFb->cEntries); + + memset(pFb, 0, sizeof (*pFb)); + + pFb->ScreenInfo.u16Flags = VBVA_SCREEN_F_DISABLED; + pFb->ScreenInfo.u32ViewIndex = idScreen; +} + +ICrFbDisplay* CrFbDisplayGet(CR_FRAMEBUFFER *pFb) +{ + return pFb->pDisplay; +} + +int CrFbDisplaySet(CR_FRAMEBUFFER *pFb, ICrFbDisplay *pDisplay) +{ + if (pFb->cUpdating) + { + WARN(("update in progress")); + return VERR_INVALID_STATE; + } + + if (pFb->pDisplay == pDisplay) + return VINF_SUCCESS; + + pFb->pDisplay = pDisplay; + + return VINF_SUCCESS; +} + +#define CR_PMGR_MODE_WINDOW 0x1 +/* mutually exclusive with CR_PMGR_MODE_WINDOW */ +#define CR_PMGR_MODE_ROOTVR 0x2 +#define CR_PMGR_MODE_VRDP 0x4 +#define CR_PMGR_MODE_ALL 0x7 + +static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove); + +static CR_FBTEX* crFbTexAlloc() +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + return (CR_FBTEX*)RTMemCacheAlloc(g_CrPresenter.FbTexLookasideList); +#else + return (CR_FBTEX*)RTMemAlloc(sizeof (CR_FBTEX)); +#endif +} + +static void crFbTexFree(CR_FBTEX *pTex) +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.FbTexLookasideList, pTex); +#else + RTMemFree(pTex); +#endif +} + +static CR_FRAMEBUFFER_ENTRY* crFbEntryAlloc() +{ +#ifndef VBOXVDBG_MEMCACHE_DISABLE + return (CR_FRAMEBUFFER_ENTRY*)RTMemCacheAlloc(g_CrPresenter.FbEntryLookasideList); +#else + return (CR_FRAMEBUFFER_ENTRY*)RTMemAlloc(sizeof (CR_FRAMEBUFFER_ENTRY)); +#endif +} + +static void crFbEntryFree(CR_FRAMEBUFFER_ENTRY *pEntry) +{ + Assert(!CrVrScrCompositorEntryIsUsed(&pEntry->Entry)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.FbEntryLookasideList, pEntry); +#else + RTMemFree(pEntry); +#endif +} + +DECLCALLBACK(void) crFbTexRelease(CR_TEXDATA *pTex) +{ + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTex); + CRTextureObj *pTobj = pFbTex->pTobj; + + CrTdBltDataCleanupNe(pTex); + + if (pTobj) + { + CR_STATE_SHAREDOBJ_USAGE_CLEAR(pTobj, cr_server.MainContextInfo.pContext); + + crHashtableDelete(g_CrPresenter.pFbTexMap, pTobj->id, NULL); + + if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pTobj)) + { + CRSharedState *pShared = crStateGlobalSharedAcquire(); + + CRASSERT(pShared); + /* on the host side, we need to delete an ogl texture object here as well, which crStateDeleteTextureCallback will do + * in addition to calling crStateDeleteTextureObject to delete a state object */ + crHashtableDelete(pShared->textureTable, pTobj->id, crStateDeleteTextureCallback); + + crStateGlobalSharedRelease(); + } + + crStateGlobalSharedRelease(); + } + + crFbTexFree(pFbTex); +} + +void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased) +{ + PCR_BLITTER pBlitter = crServerVBoxBlitterGet(); + + CrTdInit(pFbTex, pTex, pBlitter, pfnTextureReleased); +} + +static CR_FBTEX* crFbTexCreate(const VBOXVR_TEXTURE *pTex) +{ + CR_FBTEX *pFbTex = crFbTexAlloc(); + if (!pFbTex) + { + WARN(("crFbTexAlloc failed!")); + return NULL; + } + + CrFbTexDataInit(&pFbTex->Tex, pTex, crFbTexRelease); + pFbTex->pTobj = NULL; + + return pFbTex; +} + + +CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex) +{ + CR_FBTEX *pFbTex = crFbTexCreate(pTex); + if (!pFbTex) + { + WARN(("crFbTexCreate failed!")); + return NULL; + } + + return &pFbTex->Tex; +} + +static CR_FBTEX* crFbTexAcquire(GLuint idTexture) +{ + CR_FBTEX *pFbTex = (CR_FBTEX *)crHashtableSearch(g_CrPresenter.pFbTexMap, idTexture); + if (pFbTex) + { + CrTdAddRef(&pFbTex->Tex); + return pFbTex; + } + + CRSharedState *pShared = crStateGlobalSharedAcquire(); + if (!pShared) + { + WARN(("pShared is null!")); + return NULL; + } + + CRTextureObj *pTobj = (CRTextureObj*)crHashtableSearch(pShared->textureTable, idTexture); + if (!pTobj) + { + LOG(("pTobj is null!")); + crStateGlobalSharedRelease(); + return NULL; + } + + Assert(pTobj->id == idTexture); + + GLuint hwid = crStateGetTextureObjHWID(pTobj); + if (!hwid) + { + WARN(("hwId is null!")); + crStateGlobalSharedRelease(); + return NULL; + } + + VBOXVR_TEXTURE Tex; + Tex.width = pTobj->level[0]->width; + Tex.height = pTobj->level[0]->height; + Tex.hwid = hwid; + Tex.target = pTobj->target; + + pFbTex = crFbTexCreate(&Tex); + if (!pFbTex) + { + WARN(("crFbTexCreate failed!")); + crStateGlobalSharedRelease(); + return NULL; + } + + CR_STATE_SHAREDOBJ_USAGE_SET(pTobj, cr_server.MainContextInfo.pContext); + + pFbTex->pTobj = pTobj; + + crHashtableAdd(g_CrPresenter.pFbTexMap, idTexture, pFbTex); + + return pFbTex; +} + +static void crFbEntryMarkDestroyed(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry) +{ + if (pEntry->Flags.fCreateNotified) + { + pEntry->Flags.fCreateNotified = 0; + if (pFb->pDisplay) + pFb->pDisplay->EntryDestroyed(pFb, pEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } +} + +static void crFbEntryDestroy(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry) +{ + crFbEntryMarkDestroyed(pFb, pEntry); + CrVrScrCompositorEntryCleanup(&pEntry->Entry); + CrHTableDestroy(&pEntry->HTable); + Assert(pFb->cEntries); + RTListNodeRemove(&pEntry->Node); + --pFb->cEntries; + crFbEntryFree(pEntry); +} + +DECLINLINE(uint32_t) crFbEntryAddRef(CR_FRAMEBUFFER_ENTRY* pEntry) +{ + return ++pEntry->cRefs; +} + +DECLINLINE(uint32_t) crFbEntryRelease(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY* pEntry) +{ + uint32_t cRefs = --pEntry->cRefs; + if (!cRefs) + crFbEntryDestroy(pFb, pEntry); + return cRefs; +} + +static DECLCALLBACK(void) crFbEntryReleased(const struct VBOXVR_SCR_COMPOSITOR *pCompositor, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry, struct VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacingEntry) +{ + CR_FRAMEBUFFER *pFb = PCR_FRAMEBUFFER_FROM_COMPOSITOR(pCompositor); + CR_FRAMEBUFFER_ENTRY *pFbEntry = PCR_FBENTRY_FROM_ENTRY(pEntry); + CR_FRAMEBUFFER_ENTRY *pFbReplacingEntry = pReplacingEntry ? PCR_FBENTRY_FROM_ENTRY(pReplacingEntry) : NULL; + if (pFbReplacingEntry) + { + /*replace operation implies the replaced entry gets auto-destroyed, + * while all its data gets moved to the *clean* replacing entry + * 1. ensure the replacing entry is cleaned up */ + crFbEntryMarkDestroyed(pFb, pFbReplacingEntry); + + CrHTableMoveTo(&pFbEntry->HTable, &pFbReplacingEntry->HTable); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry); + CR_TEXDATA *pReplacingTex = CrVrScrCompositorEntryTexGet(&pFbReplacingEntry->Entry); + + CrTdBltScaleCacheMoveTo(pTex, pReplacingTex); + + if (pFb->pDisplay) + pFb->pDisplay->EntryReplaced(pFb, pFbReplacingEntry, pFbEntry); + + CrTdBltDataInvalidateNe(pTex); + + /* 2. mark the replaced entry is destroyed */ + Assert(pFbEntry->Flags.fCreateNotified); + Assert(pFbEntry->Flags.fInList); + pFbEntry->Flags.fCreateNotified = 0; + pFbEntry->Flags.fInList = 0; + pFbReplacingEntry->Flags.fCreateNotified = 1; + pFbReplacingEntry->Flags.fInList = 1; + } + else + { + if (pFbEntry->Flags.fInList) + { + pFbEntry->Flags.fInList = 0; + if (pFb->pDisplay) + pFb->pDisplay->EntryRemoved(pFb, pFbEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pFbEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + } + + crFbEntryRelease(pFb, pFbEntry); +} + +static CR_FRAMEBUFFER_ENTRY* crFbEntryCreate(CR_FRAMEBUFFER *pFb, CR_TEXDATA* pTex, const RTRECT *pRect, uint32_t fFlags) +{ + CR_FRAMEBUFFER_ENTRY *pEntry = crFbEntryAlloc(); + if (!pEntry) + { + WARN(("crFbEntryAlloc failed!")); + return NULL; + } + + CrVrScrCompositorEntryInit(&pEntry->Entry, pRect, pTex, crFbEntryReleased); + CrVrScrCompositorEntryFlagsSet(&pEntry->Entry, fFlags); + pEntry->cRefs = 1; + pEntry->Flags.Value = 0; + CrHTableCreate(&pEntry->HTable, 0); + + RTListAppend(&pFb->EntriesList, &pEntry->Node); + ++pFb->cEntries; + + return pEntry; +} + +int CrFbEntryCreateForTexData(CR_FRAMEBUFFER *pFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry) +{ + RTRECT Rect; + Rect.xLeft = 0; + Rect.yTop = 0; + Rect.xRight = pTex->Tex.width; + Rect.yBottom = pTex->Tex.height; + CR_FRAMEBUFFER_ENTRY* pEntry = crFbEntryCreate(pFb, pTex, &Rect, fFlags); + if (!pEntry) + { + WARN(("crFbEntryCreate failed")); + return VERR_NO_MEMORY; + } + + *phEntry = pEntry; + return VINF_SUCCESS; +} + +int CrFbEntryTexDataUpdate(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex) +{ + if (!pFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + if (pTex) + CrVrScrCompositorEntryTexSet(&pEntry->Entry, pTex); + + if (CrVrScrCompositorEntryIsUsed(&pEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, pEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&pEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + + return VINF_SUCCESS; +} + + +int CrFbEntryCreateForTexId(CR_FRAMEBUFFER *pFb, GLuint idTexture, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry) +{ + CR_FBTEX* pFbTex = crFbTexAcquire(idTexture); + if (!pFbTex) + { + LOG(("crFbTexAcquire failed")); + return VERR_INVALID_PARAMETER; + } + + CR_TEXDATA* pTex = &pFbTex->Tex; + int rc = CrFbEntryCreateForTexData(pFb, pTex, fFlags, phEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryCreateForTexData failed rc %d", rc)); + } + + /*always release the tex, the CrFbEntryCreateForTexData will do incref as necessary */ + CrTdRelease(pTex); + return rc; +} + +void CrFbEntryAddRef(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + ++hEntry->cRefs; +} + +void CrFbEntryRelease(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) +{ + crFbEntryRelease(pFb, hEntry); +} + +int CrFbRegionsClear(HCR_FRAMEBUFFER hFb) +{ + if (!hFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + bool fChanged = false; + CrVrScrCompositorRegionsClear(&hFb->Compositor, &fChanged); + if (fChanged) + { + if (hFb->pDisplay) + hFb->pDisplay->RegionsChanged(hFb); + } + + return VINF_SUCCESS; +} + +int CrFbEntryRegionsAdd(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated) +{ + if (!pFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + uint32_t fChangeFlags = 0; + VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL; + VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry; + bool fEntryWasInList; + + if (hEntry) + { + crFbEntryAddRef(hEntry); + pNewEntry = &hEntry->Entry; + fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry); + + Assert(!hEntry->Flags.fInList == !fEntryWasInList); + } + else + { + pNewEntry = NULL; + fEntryWasInList = false; + } + + int rc = CrVrScrCompositorEntryRegionsAdd(&pFb->Compositor, hEntry ? &hEntry->Entry : NULL, pPos, cRegions, paRegions, fPosRelated, &pReplacedScrEntry, &fChangeFlags); + if (RT_SUCCESS(rc)) + { + if (fChangeFlags & VBOXVR_COMPOSITOR_CF_REGIONS_CHANGED) + { + if (!fEntryWasInList && pNewEntry) + { + Assert(CrVrScrCompositorEntryIsUsed(pNewEntry)); + if (!hEntry->Flags.fCreateNotified) + { + hEntry->Flags.fCreateNotified = 1; + if (pFb->pDisplay) + pFb->pDisplay->EntryCreated(pFb, hEntry); + } + +#ifdef DEBUG_misha + /* in theory hEntry->Flags.fInList can be set if entry is replaced, + * but then modified to fit the compositor rects, + * and so we get the regions changed notification as a result + * this should not generally happen though, so put an assertion to debug that situation */ + Assert(!hEntry->Flags.fInList); +#endif + if (!hEntry->Flags.fInList) + { + hEntry->Flags.fInList = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryAdded(pFb, hEntry); + } + } + if (pFb->pDisplay) + pFb->pDisplay->RegionsChanged(pFb); + + Assert(!pReplacedScrEntry); + } + else if (fChangeFlags & VBOXVR_COMPOSITOR_CF_ENTRY_REPLACED) + { + Assert(pReplacedScrEntry); + /* we have already processed that in a "release" callback */ + Assert(hEntry); + } + else + { + Assert(!fChangeFlags); + Assert(!pReplacedScrEntry); + } + + if (hEntry) + { + if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, hEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + } + } + else + WARN(("CrVrScrCompositorEntryRegionsAdd failed, rc %d", rc)); + + return rc; +} + +int CrFbEntryRegionsSet(CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated) +{ + if (!pFb->cUpdating) + { + WARN(("framebuffer not updating")); + return VERR_INVALID_STATE; + } + + bool fChanged = 0; + VBOXVR_SCR_COMPOSITOR_ENTRY *pReplacedScrEntry = NULL; + VBOXVR_SCR_COMPOSITOR_ENTRY *pNewEntry; + bool fEntryWasInList; + + if (hEntry) + { + crFbEntryAddRef(hEntry); + pNewEntry = &hEntry->Entry; + fEntryWasInList = CrVrScrCompositorEntryIsUsed(pNewEntry); + Assert(!hEntry->Flags.fInList == !fEntryWasInList); + } + else + { + pNewEntry = NULL; + fEntryWasInList = false; + } + + int rc = CrVrScrCompositorEntryRegionsSet(&pFb->Compositor, pNewEntry, pPos, cRegions, paRegions, fPosRelated, &fChanged); + if (RT_SUCCESS(rc)) + { + if (fChanged) + { + if (!fEntryWasInList && pNewEntry) + { + if (CrVrScrCompositorEntryIsUsed(pNewEntry)) + { + if (!hEntry->Flags.fCreateNotified) + { + hEntry->Flags.fCreateNotified = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryCreated(pFb, hEntry); + } + + Assert(!hEntry->Flags.fInList); + hEntry->Flags.fInList = 1; + + if (pFb->pDisplay) + pFb->pDisplay->EntryAdded(pFb, hEntry); + } + } + + if (pFb->pDisplay) + pFb->pDisplay->RegionsChanged(pFb); + } + + if (hEntry) + { + if (CrVrScrCompositorEntryIsUsed(&hEntry->Entry)) + { + if (pFb->pDisplay) + pFb->pDisplay->EntryTexChanged(pFb, hEntry); + + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(&hEntry->Entry); + if (pTex) + CrTdBltDataInvalidateNe(pTex); + } + } + } + else + WARN(("CrVrScrCompositorEntryRegionsSet failed, rc %d", rc)); + + return rc; +} + +const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry) +{ + return &hEntry->Entry; +} + +HCR_FRAMEBUFFER_ENTRY CrFbEntryFromCompositorEntry(const struct VBOXVR_SCR_COMPOSITOR_ENTRY* pCEntry) +{ + return RT_FROM_MEMBER(pCEntry, CR_FRAMEBUFFER_ENTRY, Entry); +} + +void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext) +{ + HCR_FRAMEBUFFER_ENTRY hEntry, hNext; + RTListForEachSafe(&hFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node) + { + if (hEntry->Flags.fCreateNotified) + { + if (!pfnVisitorCb(hFb, hEntry, pvContext)) + return; + } + } +} + + +CRHTABLE_HANDLE CrFbDDataAllocSlot(CR_FRAMEBUFFER *pFb) +{ + return CrHTablePut(&pFb->SlotTable, (void*)1); +} + +void CrFbDDataReleaseSlot(CR_FRAMEBUFFER *pFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext) +{ + HCR_FRAMEBUFFER_ENTRY hEntry, hNext; + RTListForEachSafe(&pFb->EntriesList, hEntry, hNext, CR_FRAMEBUFFER_ENTRY, Node) + { + if (CrFbDDataEntryGet(hEntry, hSlot)) + { + if (pfnReleaseCb) + pfnReleaseCb(pFb, hEntry, pvContext); + + CrFbDDataEntryClear(hEntry, hSlot); + } + } + + CrHTableRemove(&pFb->SlotTable, hSlot); +} + +int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData) +{ + return CrHTablePutToSlot(&hEntry->HTable, hSlot, pvData); +} + +void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot) +{ + return CrHTableRemove(&hEntry->HTable, hSlot); +} + +void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot) +{ + return CrHTableGet(&hEntry->HTable, hSlot); +} + +typedef union CR_FBDISPBASE_FLAGS +{ + struct { + uint32_t fRegionsShanged : 1; + uint32_t Reserved : 31; + }; + uint32_t u32Value; +} CR_FBDISPBASE_FLAGS; + +class CrFbDisplayBase : public ICrFbDisplay +{ +public: + CrFbDisplayBase() : + mpContainer(NULL), + mpFb(NULL), + mcUpdates(0), + mhSlot(CRHTABLE_HANDLE_INVALID) + { + mFlags.u32Value = 0; + } + + virtual bool isComposite() + { + return false; + } + + class CrFbDisplayComposite* getContainer() + { + return mpContainer; + } + + bool isInList() + { + return !!mpContainer; + } + + bool isUpdating() + { + return !!mcUpdates; + } + + int setRegionsChanged() + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + int setFramebuffer(struct CR_FRAMEBUFFER *pFb) + { + if (mcUpdates) + { + WARN(("trying to set framebuffer while update is in progress")); + return VERR_INVALID_STATE; + } + + if (mpFb == pFb) + return VINF_SUCCESS; + + int rc = setFramebufferBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpFb) + { + rc = fbCleanup(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + setFramebufferEnd(pFb); + return rc; + } + } + + mpFb = pFb; + + if (mpFb) + { + rc = fbSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + setFramebufferEnd(pFb); + return rc; + } + } + + setFramebufferEnd(pFb); + return VINF_SUCCESS; + } + + struct CR_FRAMEBUFFER* getFramebuffer() + { + return mpFb; + } + + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) + { + ++mcUpdates; + Assert(!mFlags.fRegionsShanged || mcUpdates > 1); + return VINF_SUCCESS; + } + + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) + { + --mcUpdates; + Assert(mcUpdates < UINT32_MAX/2); + if (!mcUpdates) + onUpdateEnd(); + } + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + return VINF_SUCCESS; + } + + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + mFlags.fRegionsShanged = 1; + return VINF_SUCCESS; + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + if (!mcUpdates) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + return VINF_SUCCESS; + } + + virtual ~CrFbDisplayBase(); + + /*@todo: move to protected and switch from RTLISTNODE*/ + RTLISTNODE mNode; + class CrFbDisplayComposite* mpContainer; +protected: + virtual void onUpdateEnd() + { + if (mFlags.fRegionsShanged) + { + mFlags.fRegionsShanged = 0; + if (getFramebuffer()) /*<-dont't do anything on cleanup*/ + ueRegions(); + } + } + + virtual void ueRegions() + { + } + + static DECLCALLBACK(bool) entriesCreateCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) + { + int rc = ((ICrFbDisplay*)(pvContext))->EntryCreated(hFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + } + return true; + } + + static DECLCALLBACK(bool) entriesDestroyCb(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) + { + int rc = ((ICrFbDisplay*)(pvContext))->EntryDestroyed(hFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + } + return true; + } + + int fbSynchAddAllEntries() + { + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + + CrVrScrCompositorConstIterInit(CrFbGetCompositor(mpFb), &Iter); + + int rc = VINF_SUCCESS; + + CrFbVisitCreatedEntries(mpFb, entriesCreateCb, this); + + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + + rc = EntryAdded(mpFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + EntryDestroyed(mpFb, hEntry); + break; + } + } + + return rc; + } + + int fbCleanupRemoveAllEntries() + { + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + + CrVrScrCompositorConstIterInit(CrFbGetCompositor(mpFb), &Iter); + + int rc = VINF_SUCCESS; + + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + rc = EntryRemoved(mpFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + break; + } + + CrFbVisitCreatedEntries(mpFb, entriesDestroyCb, this); + } + + return rc; + } + + virtual int setFramebufferBegin(struct CR_FRAMEBUFFER *pFb) + { + return UpdateBegin(pFb); + } + virtual void setFramebufferEnd(struct CR_FRAMEBUFFER *pFb) + { + UpdateEnd(pFb); + } + + static DECLCALLBACK(void) slotEntryReleaseCB(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext) + { + } + + virtual void slotRelease() + { + Assert(mhSlot); + CrFbDDataReleaseSlot(mpFb, mhSlot, slotEntryReleaseCB, this); + } + + virtual int fbCleanup() + { + if (mhSlot) + { + slotRelease(); + mhSlot = 0; + } + mpFb = NULL; + return VINF_SUCCESS; + } + + virtual int fbSync() + { + return VINF_SUCCESS; + } + + CRHTABLE_HANDLE slotGet() + { + if (!mhSlot) + { + if (mpFb) + mhSlot = CrFbDDataAllocSlot(mpFb); + } + + return mhSlot; + } + +private: + struct CR_FRAMEBUFFER *mpFb; + uint32_t mcUpdates; + CRHTABLE_HANDLE mhSlot; + CR_FBDISPBASE_FLAGS mFlags; +}; + +class CrFbDisplayComposite : public CrFbDisplayBase +{ +public: + CrFbDisplayComposite() : + mcDisplays(0) + { + RTListInit(&mDisplays); + } + + virtual bool isComposite() + { + return true; + } + + uint32_t getDisplayCount() + { + return mcDisplays; + } + + bool add(CrFbDisplayBase *pDisplay) + { + if (pDisplay->isInList()) + { + WARN(("entry in list already")); + return false; + } + + RTListAppend(&mDisplays, &pDisplay->mNode); + pDisplay->mpContainer = this; + pDisplay->setFramebuffer(getFramebuffer()); + ++mcDisplays; + return true; + } + + bool remove(CrFbDisplayBase *pDisplay, bool fCleanupDisplay = true) + { + if (pDisplay->getContainer() != this) + { + WARN(("invalid entry container")); + return false; + } + + RTListNodeRemove(&pDisplay->mNode); + pDisplay->mpContainer = NULL; + if (fCleanupDisplay) + pDisplay->setFramebuffer(NULL); + --mcDisplays; + return true; + } + + CrFbDisplayBase* first() + { + return RTListGetFirstCpp(&mDisplays, CrFbDisplayBase, mNode); + } + + CrFbDisplayBase* next(CrFbDisplayBase* pDisplay) + { + if (pDisplay->getContainer() != this) + { + WARN(("invalid entry container")); + return NULL; + } + + return RTListGetNextCpp(&mDisplays, pDisplay, CrFbDisplayBase, mNode); + } + + virtual int setFramebuffer(struct CR_FRAMEBUFFER *pFb) + { + CrFbDisplayBase::setFramebuffer(pFb); + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + pIter->setFramebuffer(pFb); + } + + return VINF_SUCCESS; + } + + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::UpdateBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + rc = pIter->UpdateBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) + { + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + pIter->UpdateEnd(pFb); + } + + CrFbDisplayBase::UpdateEnd(pFb); + } + + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + CrFbDisplayBase *pIter; + RTListForEachCpp(&mDisplays, pIter, CrFbDisplayBase, mNode) + { + int rc = pIter->FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + return VINF_SUCCESS; + } + + virtual ~CrFbDisplayComposite() + { + cleanup(); + } + + void cleanup(bool fCleanupDisplays = true) + { + CrFbDisplayBase *pIter, *pIterNext; + RTListForEachSafeCpp(&mDisplays, pIter, pIterNext, CrFbDisplayBase, mNode) + { + remove(pIter, fCleanupDisplays); + } + } +private: + RTLISTNODE mDisplays; + uint32_t mcDisplays; +}; + +typedef union CR_FBWIN_FLAGS +{ + struct { + uint32_t fVisible : 1; + uint32_t fDataPresented : 1; + uint32_t fForcePresentOnReenable : 1; + uint32_t fCompositoEntriesModified : 1; + uint32_t Reserved : 28; + }; + uint32_t Value; +} CR_FBWIN_FLAGS; + +class CrFbWindow +{ +public: + CrFbWindow(uint64_t parentId) : + mSpuWindow(0), + mpCompositor(NULL), + mcUpdates(0), + mxPos(0), + myPos(0), + mWidth(0), + mHeight(0), + mParentId(parentId) + { + mFlags.Value = 0; + } + + bool IsCreated() + { + return !!mSpuWindow; + } + + void Destroy() + { + CRASSERT(!mcUpdates); + + if (!mSpuWindow) + return; + + cr_server.head_spu->dispatch_table.WindowDestroy(mSpuWindow); + + mSpuWindow = 0; + mFlags.fDataPresented = 0; + } + + int Reparent(uint64_t parentId) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + uint64_t oldParentId = mParentId; + + mParentId = parentId; + + if (mSpuWindow) + { + if (oldParentId && !parentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, false); + + renderspuSetWindowId(mParentId); + renderspuReparentWindow(mSpuWindow); + renderspuSetWindowId(cr_server.screen[0].winID); + + if (parentId) + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); + + if (!oldParentId && parentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, true); + } + + return VINF_SUCCESS; + } + + int SetVisible(bool fVisible) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Vidible [%d]", fVisible)); + + if (!fVisible != !mFlags.fVisible) + { + mFlags.fVisible = fVisible; + if (mSpuWindow && mParentId) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, fVisible); + } + + return VINF_SUCCESS; + } + + int SetSize(uint32_t width, uint32_t height) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Size [%d ; %d]", width, height)); + + if (mWidth != width || mHeight != height) + { + mFlags.fCompositoEntriesModified = 1; + mWidth = width; + mHeight = height; + if (mSpuWindow) + cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, width, height); + } + + return VINF_SUCCESS; + } + + int SetPosition(int32_t x, int32_t y) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + LOG(("CrWIN: Pos [%d ; %d]", x, y)); +// always do WindowPosition to ensure window is adjusted properly +// if (x != mxPos || y != myPos) + { + mxPos = x; + myPos = y; + if (mSpuWindow) + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, x, y); + } + + return VINF_SUCCESS; + } + + int SetVisibleRegionsChanged() + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mFlags.fCompositoEntriesModified = 1; + return VINF_SUCCESS; + } + + int SetCompositor(const struct VBOXVR_SCR_COMPOSITOR * pCompositor) + { + if (!checkInitedUpdating()) + { + WARN(("err")); + return VERR_INVALID_STATE; + } + + mpCompositor = pCompositor; + mFlags.fCompositoEntriesModified = 1; + return VINF_SUCCESS; + } + + int UpdateBegin() + { + ++mcUpdates; + if (mcUpdates > 1) + return VINF_SUCCESS; + + Assert(!mFlags.fForcePresentOnReenable); +// Assert(!mFlags.fCompositoEntriesModified); + + if (mFlags.fDataPresented) + { + Assert(mSpuWindow); + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, NULL, NULL); + mFlags.fForcePresentOnReenable = isPresentNeeded(); + } + + return VINF_SUCCESS; + } + + void UpdateEnd() + { + --mcUpdates; + Assert(mcUpdates < UINT32_MAX/2); + if (mcUpdates) + return; + + checkRegions(); + + if (mSpuWindow) + { + bool fPresentNeeded = isPresentNeeded(); + if (fPresentNeeded || mFlags.fForcePresentOnReenable) + { + mFlags.fForcePresentOnReenable = false; + cr_server.head_spu->dispatch_table.VBoxPresentComposition(mSpuWindow, mpCompositor, NULL); + } + + /* even if the above branch is entered due to mFlags.fForcePresentOnReenable, + * the backend should clean up the compositor as soon as presentation is performed */ + mFlags.fDataPresented = fPresentNeeded; + } + else + { + Assert(!mFlags.fDataPresented); + Assert(!mFlags.fForcePresentOnReenable); + } + } + + uint64_t GetParentId() + { + return mParentId; + } + + int Create() + { + if (mSpuWindow) + { + //WARN(("window already created")); + return VINF_ALREADY_INITIALIZED; + } + + CRASSERT(cr_server.fVisualBitsDefault); + renderspuSetWindowId(mParentId); + mSpuWindow = cr_server.head_spu->dispatch_table.WindowCreate("", cr_server.fVisualBitsDefault); + renderspuSetWindowId(cr_server.screen[0].winID); + if (mSpuWindow < 0) { + WARN(("WindowCreate failed")); + return VERR_GENERAL_FAILURE; + } + + cr_server.head_spu->dispatch_table.WindowSize(mSpuWindow, mWidth, mHeight); + cr_server.head_spu->dispatch_table.WindowPosition(mSpuWindow, mxPos, myPos); + + checkRegions(); + + if (mParentId && mFlags.fVisible) + cr_server.head_spu->dispatch_table.WindowShow(mSpuWindow, true); + + return VINF_SUCCESS; + } + + ~CrFbWindow() + { + Destroy(); + } +protected: + void checkRegions() + { + if (!mSpuWindow) + return; + + if (!mFlags.fCompositoEntriesModified) + return; + + uint32_t cRects; + const RTRECT *pRects; + if (mpCompositor) + { + int rc = CrVrScrCompositorRegionsGet(mpCompositor, &cRects, NULL, &pRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorRegionsGet failed rc %d", rc)); + cRects = 0; + pRects = NULL; + } + } + else + { + cRects = 0; + pRects = NULL; + } + + cr_server.head_spu->dispatch_table.WindowVisibleRegion(mSpuWindow, cRects, (const GLint*)pRects); + + mFlags.fCompositoEntriesModified = 0; + } + + bool isPresentNeeded() + { + return mFlags.fVisible && mWidth && mHeight && mpCompositor && !CrVrScrCompositorIsEmpty(mpCompositor); + } + + bool checkInitedUpdating() + { + if (!mcUpdates) + { + WARN(("not updating")); + return false; + } + + return true; + } +private: + GLint mSpuWindow; + const struct VBOXVR_SCR_COMPOSITOR * mpCompositor; + uint32_t mcUpdates; + int32_t mxPos; + int32_t myPos; + uint32_t mWidth; + uint32_t mHeight; + CR_FBWIN_FLAGS mFlags; + uint64_t mParentId; +}; + +typedef union CR_FBDISPWINDOW_FLAGS +{ + struct { + uint32_t fNeVisible : 1; + uint32_t fNeForce : 1; + uint32_t Reserved : 30; + }; + uint32_t u32Value; +} CR_FBDISPWINDOW_FLAGS; +class CrFbDisplayWindow : public CrFbDisplayBase +{ +public: + CrFbDisplayWindow(CrFbWindow *pWindow, const RTRECT *pViewportRect) : + mpWindow(pWindow), + mViewportRect(*pViewportRect), + mu32Screen(~0) + { + mFlags.u32Value = 0; + CRASSERT(pWindow); + } + + virtual ~CrFbDisplayWindow() + { + if (mpWindow) + delete mpWindow; + } + + virtual int UpdateBegin(struct CR_FRAMEBUFFER *pFb) + { + int rc = mpWindow->UpdateBegin(); + if (RT_SUCCESS(rc)) + { + rc = CrFbDisplayBase::UpdateBegin(pFb); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + WARN(("err")); + } + else + WARN(("err")); + + return rc; + } + + virtual void UpdateEnd(struct CR_FRAMEBUFFER *pFb) + { + CrFbDisplayBase::UpdateEnd(pFb); + + mpWindow->UpdateEnd(); + } + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + if (mpWindow->GetParentId()) + { + rc = mpWindow->Create(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + } + + return VINF_SUCCESS; + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return screenChanged(); + } + + const RTRECT* getViewportRect() + { + return &mViewportRect; + } + + virtual int setViewportRect(const RTRECT *pViewportRect) + { + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + +// always call SetPosition to ensure window is adjustep properly +// if (pViewportRect->xLeft != mViewportRect.xLeft || pViewportRect->yTop != mViewportRect.yTop) + { + const RTRECT* pRect = getRect(); + int rc = mpWindow->SetPosition(pRect->xLeft - pViewportRect->xLeft, pRect->yTop - pViewportRect->yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("SetPosition failed")); + return rc; + } + } + + mViewportRect = *pViewportRect; + + return VINF_SUCCESS; + } + + virtual CrFbWindow * windowDetach() + { + if (isUpdating()) + { + WARN(("updating!")); + return NULL; + } + + CrFbWindow * pWindow = mpWindow; + if (mpWindow) + { + windowCleanup(); + mpWindow = NULL; + } + return pWindow; + } + + virtual CrFbWindow * windowAttach(CrFbWindow * pNewWindow) + { + if (isUpdating()) + { + WARN(("updating!")); + return NULL; + } + + CrFbWindow * pOld = mpWindow; + if (mpWindow) + windowDetach(); + + mpWindow = pNewWindow; + if (pNewWindow) + windowSync(); + + return mpWindow; + } + + virtual int reparent(uint64_t parentId) + { + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + + int rc = mpWindow->Reparent(parentId); + if (!RT_SUCCESS(rc)) + WARN(("window reparent failed")); + + mFlags.fNeForce = 1; + + return rc; + } + + virtual bool isVisible() + { + HCR_FRAMEBUFFER hFb = getFramebuffer(); + if (!hFb) + return false; + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(hFb); + return !CrVrScrCompositorIsEmpty(pCompositor); + } + + int winVisibilityChanged() + { + int rc = mpWindow->UpdateBegin(); + if (RT_SUCCESS(rc)) + { + rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); + if (!RT_SUCCESS(rc)) + WARN(("SetVisible failed, rc %d", rc)); + + mpWindow->UpdateEnd(); + } + else + WARN(("UpdateBegin failed, rc %d", rc)); + + return rc; + } + +protected: + virtual void onUpdateEnd() + { + CrFbDisplayBase::onUpdateEnd(); + bool fVisible = isVisible(); + if (mFlags.fNeVisible != fVisible || mFlags.fNeForce) + { + crVBoxServerNotifyEvent(mu32Screen, VBOX3D_NOTIFY_EVENT_TYPE_VISIBLE_3DDATA, fVisible ? (void*)1 : NULL); + mFlags.fNeVisible = fVisible; + mFlags.fNeForce = 0; + } + } + + virtual void ueRegions() + { + mpWindow->SetVisibleRegionsChanged(); + } + + virtual int screenChanged() + { + if (!isUpdating()) + { + WARN(("not updating!")); + return VERR_INVALID_STATE; + } + + if (CrFbIsEnabled(getFramebuffer())) + { + const RTRECT* pRect = getRect(); + int rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("SetComposition failed rc %d", rc)); + return rc; + } + + setRegionsChanged(); + + return mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop)); + } + + return mpWindow->SetVisible(false); + } + + virtual int windowSetCompositor(bool fSet) + { + if (fSet) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); + return mpWindow->SetCompositor(pCompositor); + } + return mpWindow->SetCompositor(NULL); + } + + virtual int windowCleanup() + { + int rc = mpWindow->UpdateBegin(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = mpWindow->SetVisible(false); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = windowSetCompositor(false); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + mpWindow->UpdateEnd(); + + return VINF_SUCCESS; + } + + virtual int fbCleanup() + { + int rc = windowCleanup(); + if (!RT_SUCCESS(rc)) + { + WARN(("windowCleanup failed")); + return rc; + } + return CrFbDisplayBase::fbCleanup(); + } + + virtual int windowSync() + { + const RTRECT* pRect = getRect(); + + int rc = mpWindow->UpdateBegin(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = windowSetCompositor(true); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = mpWindow->SetPosition(pRect->xLeft - mViewportRect.xLeft, pRect->yTop - mViewportRect.yTop); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = mpWindow->SetSize((uint32_t)(pRect->xRight - pRect->xLeft), (uint32_t)(pRect->yBottom - pRect->yTop)); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + rc = mpWindow->SetVisible(!g_CrPresenter.fWindowsForceHidden); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + mpWindow->UpdateEnd(); + return rc; + } + + mpWindow->UpdateEnd(); + + return rc; + } + + virtual int fbSync() + { + int rc = CrFbDisplayBase::fbSync(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + mu32Screen = CrFbGetScreenInfo(getFramebuffer())->u32ViewIndex; + + return windowSync(); + } + + virtual const struct RTRECT* getRect() + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(getFramebuffer()); + return CrVrScrCompositorRectGet(pCompositor); + } + + CrFbWindow* getWindow() {return mpWindow;} +private: + CrFbWindow *mpWindow; + RTRECT mViewportRect; + CR_FBDISPWINDOW_FLAGS mFlags; + uint32_t mu32Screen; +}; + +class CrFbDisplayWindowRootVr : public CrFbDisplayWindow +{ +public: + CrFbDisplayWindowRootVr(CrFbWindow *pWindow, const RTRECT *pViewportRect) : + CrFbDisplayWindow(pWindow, pViewportRect) + { + CrVrScrCompositorInit(&mCompositor, NULL); + } + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + Assert(!CrFbDDataEntryGet(hEntry, slotGet())); + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = entryAlloc(); + CrVrScrCompositorEntryInit(pMyEntry, CrVrScrCompositorEntryRectGet(pSrcEntry), CrVrScrCompositorEntryTexGet(pSrcEntry), NULL); + CrVrScrCompositorEntryFlagsSet(pMyEntry, CrVrScrCompositorEntryFlagsGet(pSrcEntry)); + rc = CrFbDDataEntryPut(hEntry, slotGet(), pMyEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbDDataEntryPut failed rc %d", rc)); + entryFree(pMyEntry); + return rc; + } + + return VINF_SUCCESS; + } + + virtual int EntryAdded(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryAdded(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + Assert(pMyEntry); + CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcEntry)); + + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayWindow::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcNewEntry = CrFbEntryGetCompositorEntry(hNewEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hNewEntry, slotGet()); + CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcNewEntry)); + + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + CrVrScrCompositorEntryTexSet(pMyEntry, CrVrScrCompositorEntryTexGet(pSrcEntry)); + + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + rc = CrVrScrCompositorEntryRegionsSet(&mCompositor, pMyEntry, NULL, 0, NULL, false, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return VINF_SUCCESS; + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayWindow::EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pSrcEntry = CrFbEntryGetCompositorEntry(hEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, slotGet()); + CrVrScrCompositorEntryCleanup(pMyEntry); + entryFree(pMyEntry); + + return VINF_SUCCESS; + } + + virtual int setViewportRect(const RTRECT *pViewportRect) + { + int rc = CrFbDisplayWindow::setViewportRect(pViewportRect); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = setRegionsChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return VINF_SUCCESS; + } + +protected: + virtual int windowSetCompositor(bool fSet) + { + if (fSet) + return getWindow()->SetCompositor(&mCompositor); + return getWindow()->SetCompositor(NULL); + } + + virtual void ueRegions() + { + synchCompositorRegions(); + } + + int compositorMarkUpdated() + { + CrVrScrCompositorClear(&mCompositor); + + int rc = CrVrScrCompositorRectSet(&mCompositor, CrVrScrCompositorRectGet(CrFbGetCompositor(getFramebuffer())), NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = setRegionsChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("screenChanged failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; + } + + virtual int screenChanged() + { + int rc = compositorMarkUpdated(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + rc = CrFbDisplayWindow::screenChanged(); + if (!RT_SUCCESS(rc)) + { + WARN(("screenChanged failed %d", rc)); + return rc; + } + + return VINF_SUCCESS; + } + + virtual const struct RTRECT* getRect() + { + return CrVrScrCompositorRectGet(&mCompositor); + } + + virtual int fbCleanup() + { + int rc = clearCompositor(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayWindow::fbCleanup(); + } + + virtual int fbSync() + { + int rc = synchCompositor(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayWindow::fbSync(); + } + + VBOXVR_SCR_COMPOSITOR_ENTRY* entryAlloc() + { +#ifndef VBOXVDBG_MEMCACHE_DISABLE + return (VBOXVR_SCR_COMPOSITOR_ENTRY*)RTMemCacheAlloc(g_CrPresenter.CEntryLookasideList); +#else + return (VBOXVR_SCR_COMPOSITOR_ENTRY*)RTMemAlloc(sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY)); +#endif + } + + void entryFree(VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry) + { + Assert(!CrVrScrCompositorEntryIsUsed(pEntry)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheFree(g_CrPresenter.CEntryLookasideList, pEntry); +#else + RTMemFree(pEntry); +#endif + } + + int synchCompositorRegions() + { + int rc; + + rootVrTranslateForPos(); + + /* ensure the rootvr compositor does not hold any data, + * i.e. cleanup all rootvr entries data */ + CrVrScrCompositorClear(&mCompositor); + + rc = CrVrScrCompositorIntersectedList(CrFbGetCompositor(getFramebuffer()), &cr_server.RootVr, &mCompositor, rootVrGetCEntry, this, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorIntersectedList failed, rc %d", rc)); + return rc; + } + + return getWindow()->SetVisibleRegionsChanged(); + } + + virtual int synchCompositor() + { + int rc = compositorMarkUpdated(); + if (!RT_SUCCESS(rc)) + { + WARN(("compositorMarkUpdated failed, rc %d", rc)); + return rc; + } + + rc = fbSynchAddAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("fbSynchAddAllEntries failed, rc %d", rc)); + return rc; + } + + return rc; + } + + virtual int clearCompositor() + { + return fbCleanupRemoveAllEntries(); + } + + void rootVrTranslateForPos() + { + const RTRECT *pRect = getViewportRect(); + const struct VBVAINFOSCREEN* pScreen = CrFbGetScreenInfo(getFramebuffer()); + int32_t x = pScreen->i32OriginX; + int32_t y = pScreen->i32OriginY; + int32_t dx = cr_server.RootVrCurPoint.x - x; + int32_t dy = cr_server.RootVrCurPoint.y - y; + + cr_server.RootVrCurPoint.x = x; + cr_server.RootVrCurPoint.y = y; + + VBoxVrListTranslate(&cr_server.RootVr, dx, dy); + } + + static DECLCALLBACK(VBOXVR_SCR_COMPOSITOR_ENTRY*) rootVrGetCEntry(const VBOXVR_SCR_COMPOSITOR_ENTRY*pEntry, void *pvContext) + { + CrFbDisplayWindowRootVr *pThis = (CrFbDisplayWindowRootVr*)pvContext; + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + VBOXVR_SCR_COMPOSITOR_ENTRY *pMyEntry = (VBOXVR_SCR_COMPOSITOR_ENTRY*)CrFbDDataEntryGet(hEntry, pThis->slotGet()); + Assert(!CrVrScrCompositorEntryIsUsed(pMyEntry)); + CrVrScrCompositorEntryRectSet(&pThis->mCompositor, pMyEntry, CrVrScrCompositorEntryRectGet(pEntry)); + return pMyEntry; + } +private: + VBOXVR_SCR_COMPOSITOR mCompositor; +}; + +class CrFbDisplayVrdp : public CrFbDisplayBase +{ +public: + CrFbDisplayVrdp() + { + memset(&mPos, 0, sizeof (mPos)); + } + + virtual int EntryCreated(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryCreated(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("EntryAdded failed rc %d", rc)); + return rc; + } + + Assert(!CrFbDDataEntryGet(hEntry, slotGet())); + rc = vrdpCreate(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("vrdpCreate failed rc %d", rc)); + return rc; + } + + return VINF_SUCCESS; + } + + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + int rc = CrFbDisplayBase::EntryReplaced(pFb, hNewEntry, hReplacedEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pReplacedEntry = CrFbEntryGetCompositorEntry(hReplacedEntry); + CR_TEXDATA *pReplacedTex = CrVrScrCompositorEntryTexGet(pReplacedEntry); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pNewEntry = CrFbEntryGetCompositorEntry(hNewEntry); + CR_TEXDATA *pNewTex = CrVrScrCompositorEntryTexGet(pNewEntry); + + CrTdBltDataInvalidateNe(pReplacedTex); + + rc = CrTdBltEnter(pNewTex); + if (RT_SUCCESS(rc)) + { + rc = vrdpFrame(hNewEntry); + CrTdBltLeave(pNewTex); + } + else + WARN(("CrTdBltEnter failed %d", rc)); + + return rc; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryTexChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + + rc = CrTdBltEnter(pTex); + if (RT_SUCCESS(rc)) + { + rc = vrdpFrame(hEntry); + CrTdBltLeave(pTex); + } + else + WARN(("CrTdBltEnter failed %d", rc)); + + return rc; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryRemoved(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + CrTdBltDataInvalidateNe(pTex); + + return vrdpRegions(pFb, hEntry); + } + + virtual int EntryDestroyed(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryDestroyed(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + vrdpDestroy(hEntry); + return VINF_SUCCESS; + } + + virtual int EntryPosChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + int rc = CrFbDisplayBase::EntryPosChanged(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + vrdpGeometry(hEntry); + + return VINF_SUCCESS; + } + + virtual int RegionsChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::RegionsChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return vrdpRegionsAll(pFb); + } + + virtual int FramebufferChanged(struct CR_FRAMEBUFFER *pFb) + { + int rc = CrFbDisplayBase::FramebufferChanged(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + syncPos(); + + rc = vrdpSyncEntryAll(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return vrdpRegionsAll(pFb); + } + +protected: + void syncPos() + { + const struct VBVAINFOSCREEN* pScreenInfo = CrFbGetScreenInfo(getFramebuffer()); + mPos.x = pScreenInfo->i32OriginX; + mPos.y = pScreenInfo->i32OriginY; + } + + virtual int fbCleanup() + { + int rc = fbCleanupRemoveAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayBase::fbCleanup(); + } + + virtual int fbSync() + { + syncPos(); + + int rc = fbSynchAddAllEntries(); + if (!RT_SUCCESS(rc)) + { + WARN(("err")); + return rc; + } + + return CrFbDisplayBase::fbSync(); + } +protected: + void vrdpDestroy(HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + cr_server.outputRedirect.CROREnd(pVrdp); + } + + void vrdpGeometry(HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + + cr_server.outputRedirect.CRORGeometry(pVrdp, + mPos.x + CrVrScrCompositorEntryRectGet(pEntry)->xLeft, + mPos.y + CrVrScrCompositorEntryRectGet(pEntry)->yTop, + CrVrScrCompositorEntryTexGet(pEntry)->Tex.width, + CrVrScrCompositorEntryTexGet(pEntry)->Tex.height); + } + + int vrdpRegions(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + uint32_t cRects; + const RTRECT *pRects; + + int rc = CrVrScrCompositorEntryRegionsGet(pCompositor, pEntry, &cRects, NULL, &pRects, NULL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrVrScrCompositorEntryRegionsGet failed, rc %d", rc)); + return rc; + } + + cr_server.outputRedirect.CRORVisibleRegion(pVrdp, cRects, pRects); + return VINF_SUCCESS; + } + + int vrdpFrame(HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp = CrFbDDataEntryGet(hEntry, slotGet()); + const VBOXVR_SCR_COMPOSITOR_ENTRY* pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTex = CrVrScrCompositorEntryTexGet(pEntry); + const CR_BLITTER_IMG *pImg; + CrTdBltDataInvalidateNe(pTex); + int rc = CrTdBltDataAcquire(pTex, GL_BGRA, !!(CrVrScrCompositorEntryFlagsGet(pEntry) & CRBLT_F_INVERT_SRC_YCOORDS), &pImg); + if (!RT_SUCCESS(rc)) + { + WARN(("CrTdBltDataAcquire failed rc %d", rc)); + return rc; + } + + cr_server.outputRedirect.CRORFrame(pVrdp, pImg->pvData, pImg->cbData); + CrTdBltDataRelease(pTex); + return VINF_SUCCESS; + } + + int vrdpRegionsAll(struct CR_FRAMEBUFFER *pFb) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(pCompositor, &Iter); + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + vrdpRegions(pFb, hEntry); + } + + return VINF_SUCCESS; + } + + int vrdpSynchEntry(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + vrdpGeometry(hEntry); + + return vrdpRegions(pFb, hEntry);; + } + + int vrdpSyncEntryAll(struct CR_FRAMEBUFFER *pFb) + { + const struct VBOXVR_SCR_COMPOSITOR* pCompositor = CrFbGetCompositor(pFb); + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(pCompositor, &Iter); + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + int rc = vrdpSynchEntry(pFb, hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("vrdpSynchEntry failed rc %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; + } + + int vrdpCreate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + void *pVrdp; + + /* Query supported formats. */ + uint32_t cbFormats = 4096; + char *pachFormats = (char *)crAlloc(cbFormats); + + if (!pachFormats) + { + WARN(("crAlloc failed")); + return VERR_NO_MEMORY; + } + + int rc = cr_server.outputRedirect.CRORContextProperty(cr_server.outputRedirect.pvContext, + 0 /* H3DOR_PROP_FORMATS */, // @todo from a header + pachFormats, cbFormats, &cbFormats); + if (RT_SUCCESS(rc)) + { + if (RTStrStr(pachFormats, "H3DOR_FMT_RGBA_TOPDOWN")) + { + cr_server.outputRedirect.CRORBegin(cr_server.outputRedirect.pvContext, + &pVrdp, + "H3DOR_FMT_RGBA_TOPDOWN"); // @todo from a header + + if (pVrdp) + { + rc = CrFbDDataEntryPut(hEntry, slotGet(), pVrdp); + if (RT_SUCCESS(rc)) + { + vrdpGeometry(hEntry); + vrdpRegions(hFb, hEntry); + //vrdpFrame(hEntry); + return VINF_SUCCESS; + } + else + WARN(("CrFbDDataEntryPut failed rc %d", rc)); + + cr_server.outputRedirect.CROREnd(pVrdp); + } + else + { + WARN(("CRORBegin failed")); + rc = VERR_GENERAL_FAILURE; + } + } + } + else + WARN(("CRORContextProperty failed rc %d", rc)); + + crFree(pachFormats); + + return rc; + } +private: + RTPOINT mPos; +}; + +CrFbDisplayBase::~CrFbDisplayBase() +{ + Assert(!mcUpdates); + + if (mpContainer) + mpContainer->remove(this); +} + + +#if 0 + + + + + +void crDbgDumpRect(uint32_t i, const RTRECT *pRect) +{ + crDebug("%d: (%d;%d) X (%d;%d)", i, pRect->xLeft, pRect->yTop, pRect->xRight, pRect->yBottom); +} + +void crDbgDumpRects(uint32_t cRects, const RTRECT *paRects) +{ + crDebug("Dumping rects (%d)", cRects); + for (uint32_t i = 0; i < cRects; ++i) + { + crDbgDumpRect(i, &paRects[i]); + } + crDebug("End Dumping rects (%d)", cRects); +} + +int crServerDisplaySaveState(PSSMHANDLE pSSM) +{ + int rc; + int cDisplays = 0, i; + for (i = 0; i < cr_server.screenCount; ++i) + { + if (ASMBitTest(cr_server.DisplaysInitMap, i) && !CrDpIsEmpty(&cr_server.aDispplays[i])) + ++cDisplays; + } + + rc = SSMR3PutS32(pSSM, cDisplays); + AssertRCReturn(rc, rc); + + if (!cDisplays) + return VINF_SUCCESS; + + rc = SSMR3PutS32(pSSM, cr_server.screenCount); + AssertRCReturn(rc, rc); + + for (i = 0; i < cr_server.screenCount; ++i) + { + rc = SSMR3PutS32(pSSM, cr_server.screen[i].x); + AssertRCReturn(rc, rc); + + rc = SSMR3PutS32(pSSM, cr_server.screen[i].y); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, cr_server.screen[i].w); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, cr_server.screen[i].h); + AssertRCReturn(rc, rc); + } + + for (i = 0; i < cr_server.screenCount; ++i) + { + if (ASMBitTest(cr_server.DisplaysInitMap, i) && !CrDpIsEmpty(&cr_server.aDispplays[i])) + { + rc = SSMR3PutS32(pSSM, i); + AssertRCReturn(rc, rc); + + rc = CrDpSaveState(&cr_server.aDispplays[i], pSSM); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +int crServerDisplayLoadState(PSSMHANDLE pSSM, uint32_t u32Version) +{ + +} +#endif + +class CrFbDisplayEntryDataMonitor : public CrFbDisplayBase +{ +public: + virtual int EntryReplaced(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hNewEntry, HCR_FRAMEBUFFER_ENTRY hReplacedEntry) + { + entryDataChanged(pFb, hReplacedEntry); + return VINF_SUCCESS; + } + + virtual int EntryTexChanged(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + entryDataChanged(pFb, hEntry); + return VINF_SUCCESS; + } + + virtual int EntryRemoved(struct CR_FRAMEBUFFER *pFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + entryDataChanged(pFb, hEntry); + return VINF_SUCCESS; + } +protected: + virtual void entryDataChanged(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry) + { + + } +}; + +int CrPMgrInit() +{ + int rc = VINF_SUCCESS; + memset(&g_CrPresenter, 0, sizeof (g_CrPresenter)); + g_CrPresenter.pFbTexMap = crAllocHashtable(); + if (g_CrPresenter.pFbTexMap) + { +#ifndef VBOXVDBG_MEMCACHE_DISABLE + rc = RTMemCacheCreate(&g_CrPresenter.FbEntryLookasideList, sizeof (CR_FRAMEBUFFER_ENTRY), + 0, /* size_t cbAlignment */ + UINT32_MAX, /* uint32_t cMaxObjects */ + NULL, /* PFNMEMCACHECTOR pfnCtor*/ + NULL, /* PFNMEMCACHEDTOR pfnDtor*/ + NULL, /* void *pvUser*/ + 0 /* uint32_t fFlags*/ + ); + if (RT_SUCCESS(rc)) + { + rc = RTMemCacheCreate(&g_CrPresenter.FbTexLookasideList, sizeof (CR_FBTEX), + 0, /* size_t cbAlignment */ + UINT32_MAX, /* uint32_t cMaxObjects */ + NULL, /* PFNMEMCACHECTOR pfnCtor*/ + NULL, /* PFNMEMCACHEDTOR pfnDtor*/ + NULL, /* void *pvUser*/ + 0 /* uint32_t fFlags*/ + ); + if (RT_SUCCESS(rc)) + { + rc = RTMemCacheCreate(&g_CrPresenter.CEntryLookasideList, sizeof (VBOXVR_SCR_COMPOSITOR_ENTRY), + 0, /* size_t cbAlignment */ + UINT32_MAX, /* uint32_t cMaxObjects */ + NULL, /* PFNMEMCACHECTOR pfnCtor*/ + NULL, /* PFNMEMCACHEDTOR pfnDtor*/ + NULL, /* void *pvUser*/ + 0 /* uint32_t fFlags*/ + ); + if (RT_SUCCESS(rc)) + { +#endif + rc = crPMgrModeModifyGlobal(CR_PMGR_MODE_WINDOW, 0); + if (RT_SUCCESS(rc)) + return VINF_SUCCESS; + else + WARN(("crPMgrModeModifyGlobal failed rc %d", rc)); +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); + + RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); + + RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList); + } + else + WARN(("RTMemCacheCreate failed rc %d", rc)); +#endif + } + else + { + WARN(("crAllocHashtable failed")); + rc = VERR_NO_MEMORY; + } + return rc; +} + +void CrPMgrTerm() +{ + crPMgrModeModifyGlobal(0, CR_PMGR_MODE_ALL); + + HCR_FRAMEBUFFER hFb; + + for (hFb = CrPMgrFbGetFirstInitialized(); + hFb; + hFb = CrPMgrFbGetNextInitialized(hFb)) + { + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CrFbDisplaySet(hFb, NULL); + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + + if (pInfo->pDpComposite) + delete pInfo->pDpComposite; + + Assert(!pInfo->pDpWin); + Assert(!pInfo->pDpWinRootVr); + Assert(!pInfo->pDpVrdp); + + CrFbTerm(hFb); + } + +#ifndef VBOXVDBG_MEMCACHE_DISABLE + RTMemCacheDestroy(g_CrPresenter.FbEntryLookasideList); + RTMemCacheDestroy(g_CrPresenter.FbTexLookasideList); + RTMemCacheDestroy(g_CrPresenter.CEntryLookasideList); +#endif + crFreeHashtable(g_CrPresenter.pFbTexMap, NULL); + + if (g_CrPresenter.pvTmpBuf) + RTMemFree(g_CrPresenter.pvTmpBuf); + + if (g_CrPresenter.pvTmpBuf2) + RTMemFree(g_CrPresenter.pvTmpBuf2); + + memset(&g_CrPresenter, 0, sizeof (g_CrPresenter)); +} + +HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return NULL; + } + + if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idScreen)) + { + CrFbInit(&g_CrPresenter.aFramebuffers[idScreen], idScreen); + CrFBmSetAtomic(&g_CrPresenter.FramebufferInitMap, idScreen); + } + else + Assert(g_CrPresenter.aFramebuffers[idScreen].ScreenInfo.u32ViewIndex == idScreen); + + return &g_CrPresenter.aFramebuffers[idScreen]; +} + +HCR_FRAMEBUFFER CrPMgrFbGetInitialized(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return NULL; + } + + if (!CrFBmIsSet(&g_CrPresenter.FramebufferInitMap, idScreen)) + { + return NULL; + } + else + Assert(g_CrPresenter.aFramebuffers[idScreen].ScreenInfo.u32ViewIndex == idScreen); + + return &g_CrPresenter.aFramebuffers[idScreen]; +} + +HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idScreen) +{ + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(idScreen); + + if(hFb && CrFbIsEnabled(hFb)) + return hFb; + + return NULL; +} + +static HCR_FRAMEBUFFER crPMgrFbGetNextEnabled(uint32_t i) +{ + for (;i < (uint32_t)cr_server.screenCount; ++i) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(i); + if (hFb) + return hFb; + } + + return NULL; +} + +static HCR_FRAMEBUFFER crPMgrFbGetNextInitialized(uint32_t i) +{ + for (;i < (uint32_t)cr_server.screenCount; ++i) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i); + if (hFb) + return hFb; + } + + return NULL; +} + +HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled() +{ + HCR_FRAMEBUFFER hFb = crPMgrFbGetNextEnabled(0); +// if (!hFb) +// WARN(("no enabled framebuffer found")); + return hFb; +} + +HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb) +{ + return crPMgrFbGetNextEnabled(hFb->ScreenInfo.u32ViewIndex+1); +} + +HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized() +{ + HCR_FRAMEBUFFER hFb = crPMgrFbGetNextInitialized(0); +// if (!hFb) +// WARN(("no initialized framebuffer found")); + return hFb; +} + +HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb) +{ + return crPMgrFbGetNextInitialized(hFb->ScreenInfo.u32ViewIndex+1); +} + +static uint32_t crPMgrModeAdjustVal(uint32_t u32Mode) +{ + u32Mode = CR_PMGR_MODE_ALL & u32Mode; + if (CR_PMGR_MODE_ROOTVR & u32Mode) + u32Mode &= ~CR_PMGR_MODE_WINDOW; + return u32Mode; +} + +int CrPMgrScreenChanged(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return VERR_INVALID_PARAMETER; + } + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pInfo->pDpWin) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(idScreen); + if (CrFbIsUpdating(hFb)) + { + WARN(("trying to update viewport while framebuffer is being updated")); + return VERR_INVALID_STATE; + } + + int rc = pInfo->pDpWin->UpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pInfo->pDpWin->reparent(cr_server.screen[idScreen].winID); + + pInfo->pDpWin->UpdateEnd(hFb); + } + else + WARN(("UpdateBegin failed %d", rc)); + } + + return VINF_SUCCESS; +} + +int CrPMgrViewportUpdate(uint32_t idScreen) +{ + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("invalid idScreen %d", idScreen)); + return VERR_INVALID_PARAMETER; + } + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + if (pInfo->pDpWin) + { + HCR_FRAMEBUFFER hFb = CrPMgrFbGet(idScreen); + if (CrFbIsUpdating(hFb)) + { + WARN(("trying to update viewport while framebuffer is being updated")); + return VERR_INVALID_STATE; + } + + int rc = pInfo->pDpWin->UpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pInfo->pDpWin->setViewportRect(&cr_server.screenVieport[idScreen].Rect); + pInfo->pDpWin->UpdateEnd(hFb); + } + else + WARN(("UpdateBegin failed %d", rc)); + } + + return VINF_SUCCESS; +} + +int CrPMgrModeModify(HCR_FRAMEBUFFER hFb, uint32_t u32ModeAdd, uint32_t u32ModeRemove) +{ + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + u32ModeRemove = ((u32ModeRemove | crPMgrModeAdjustVal(u32ModeRemove)) & CR_PMGR_MODE_ALL); + u32ModeAdd = crPMgrModeAdjustVal(u32ModeAdd); + u32ModeRemove &= pInfo->u32Mode; + u32ModeAdd &= ~(u32ModeRemove | pInfo->u32Mode); + uint32_t u32ModeResulting = ((pInfo->u32Mode | u32ModeAdd) & ~u32ModeRemove); + uint32_t u32Tmp = crPMgrModeAdjustVal(u32ModeResulting); + if (u32Tmp != u32ModeResulting) + { + u32ModeAdd |= (u32Tmp & ~u32ModeResulting); + u32ModeRemove |= (~u32Tmp & u32ModeResulting); + u32ModeResulting = u32Tmp; + Assert(u32ModeResulting == ((pInfo->u32Mode | u32ModeAdd) & ~u32ModeRemove)); + } + if (!u32ModeRemove && !u32ModeAdd) + return VINF_SUCCESS; + + if (!pInfo->pDpComposite) + { + pInfo->pDpComposite = new CrFbDisplayComposite(); + pInfo->pDpComposite->setFramebuffer(hFb); + } + + CrFbWindow * pOldWin = NULL; + + if (u32ModeRemove & CR_PMGR_MODE_ROOTVR) + { + CRASSERT(pInfo->pDpWinRootVr); + CRASSERT(pInfo->pDpWin == pInfo->pDpWinRootVr); + pInfo->pDpComposite->remove(pInfo->pDpWinRootVr); + pOldWin = pInfo->pDpWinRootVr->windowDetach(); + CRASSERT(pOldWin); + delete pInfo->pDpWinRootVr; + pInfo->pDpWinRootVr = NULL; + pInfo->pDpWin = NULL; + } + else if (u32ModeRemove & CR_PMGR_MODE_WINDOW) + { + CRASSERT(!pInfo->pDpWinRootVr); + CRASSERT(pInfo->pDpWin); + pInfo->pDpComposite->remove(pInfo->pDpWin); + pOldWin = pInfo->pDpWin->windowDetach(); + CRASSERT(pOldWin); + delete pInfo->pDpWin; + pInfo->pDpWin = NULL; + } + + if (u32ModeRemove & CR_PMGR_MODE_VRDP) + { + CRASSERT(pInfo->pDpVrdp); + if (pInfo->pDpComposite) + pInfo->pDpComposite->remove(pInfo->pDpVrdp); + else + CrFbDisplaySet(hFb, NULL); + + delete pInfo->pDpVrdp; + pInfo->pDpVrdp = NULL; + } + + CrFbDisplayBase *pDpToSet = NULL; + + if (u32ModeAdd & CR_PMGR_MODE_ROOTVR) + { + CRASSERT(!pInfo->pDpWin); + CRASSERT(!pInfo->pDpWinRootVr); + + if (!pOldWin) + pOldWin = new CrFbWindow(cr_server.screen[idScreen].winID); + + pInfo->pDpWinRootVr = new CrFbDisplayWindowRootVr(pOldWin, &cr_server.screenVieport[idScreen].Rect); + pOldWin = NULL; + pInfo->pDpWin = pInfo->pDpWinRootVr; + pInfo->pDpComposite->add(pInfo->pDpWinRootVr); + } + else if (u32ModeAdd & CR_PMGR_MODE_WINDOW) + { + CRASSERT(!pInfo->pDpWin); + CRASSERT(!pInfo->pDpWinRootVr); + + if (!pOldWin) + pOldWin = new CrFbWindow(cr_server.screen[idScreen].winID); + + pInfo->pDpWin = new CrFbDisplayWindow(pOldWin, &cr_server.screenVieport[idScreen].Rect); + pOldWin = NULL; + pInfo->pDpComposite->add(pInfo->pDpWin); + } + + if (u32ModeAdd & CR_PMGR_MODE_VRDP) + { + CRASSERT(!pInfo->pDpVrdp); + pInfo->pDpVrdp = new CrFbDisplayVrdp(); + pInfo->pDpComposite->add(pInfo->pDpVrdp); + } + + if (pInfo->pDpComposite->getDisplayCount() > 1) + { + ICrFbDisplay* pCur = CrFbDisplayGet(hFb); + if (pCur != (ICrFbDisplay*)pInfo->pDpComposite) + CrFbDisplaySet(hFb, pInfo->pDpComposite); + } + else + { + ICrFbDisplay* pCur = CrFbDisplayGet(hFb); + ICrFbDisplay* pFirst = pInfo->pDpComposite->first(); + if (pCur != pFirst) + CrFbDisplaySet(hFb, pFirst); + } + + if (pOldWin) + delete pOldWin; + + pInfo->u32Mode = u32ModeResulting; + + return VINF_SUCCESS; +} + +static int crPMgrModeModifyGlobal(uint32_t u32ModeAdd, uint32_t u32ModeRemove) +{ + g_CrPresenter.u32DisplayMode = (g_CrPresenter.u32DisplayMode | u32ModeAdd) & ~u32ModeRemove; + + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + CrPMgrModeModify(hFb, u32ModeAdd, u32ModeRemove); + } + + return VINF_SUCCESS; +} + +int CrPMgrModeVrdp(bool fEnable) +{ + uint32_t u32ModeAdd, u32ModeRemove; + if (fEnable) + { + u32ModeAdd = CR_PMGR_MODE_VRDP; + u32ModeRemove = 0; + } + else + { + u32ModeAdd = 0; + u32ModeRemove = CR_PMGR_MODE_VRDP; + } + return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove); +} + +int CrPMgrModeRootVr(bool fEnable) +{ + uint32_t u32ModeAdd, u32ModeRemove; + if (fEnable) + { + u32ModeAdd = CR_PMGR_MODE_ROOTVR; + u32ModeRemove = CR_PMGR_MODE_WINDOW; + } + else + { + u32ModeAdd = CR_PMGR_MODE_WINDOW; + u32ModeRemove = CR_PMGR_MODE_ROOTVR; + } + + return crPMgrModeModifyGlobal(u32ModeAdd, u32ModeRemove); +} + +int CrPMgrModeWinVisible(bool fEnable) +{ + if (!g_CrPresenter.fWindowsForceHidden == !!fEnable) + return VINF_SUCCESS; + + g_CrPresenter.fWindowsForceHidden = !fEnable; + + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + + if (pInfo->pDpWin) + pInfo->pDpWin->winVisibilityChanged(); + } + + return VINF_SUCCESS; +} + +int CrPMgrRootVrUpdate() +{ + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + uint32_t idScreen = CrFbGetScreenInfo(hFb)->u32ViewIndex; + CR_FBDISPLAY_INFO *pInfo = &g_CrPresenter.aDisplayInfos[idScreen]; + int rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + pInfo->pDpWinRootVr->RegionsChanged(hFb); + CrFbUpdateEnd(hFb); + } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + } + + return VINF_SUCCESS; +} + +/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */ +int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap) +{ + CrFBmInit(pMap); + for (HCR_FRAMEBUFFER hFb = CrPMgrFbGetFirstEnabled(); + hFb; + hFb = CrPMgrFbGetNextEnabled(hFb)) + { + int rc = CrFbUpdateBegin(hFb); + if (!RT_SUCCESS(rc)) + { + WARN(("UpdateBegin failed, rc %d", rc)); + for (HCR_FRAMEBUFFER hTmpFb = CrPMgrFbGetFirstEnabled(); + hFb != hTmpFb; + hTmpFb = CrPMgrFbGetNextEnabled(hTmpFb)) + { + CrFbUpdateEnd(hTmpFb); + CrFBmClear(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex); + } + return rc; + } + + CrFBmSet(pMap, CrFbGetScreenInfo(hFb)->u32ViewIndex); + } + + return VINF_SUCCESS; +} + +/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */ +void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap) +{ + for (uint32_t i = 0; i < (uint32_t)cr_server.screenCount; ++i) + { + if (!CrFBmIsSet(pMap, i)) + continue; + + HCR_FRAMEBUFFER hFb = CrPMgrFbGetInitialized(i); + CRASSERT(hFb); + CrFbUpdateEnd(hFb); + } +} + +/*client should notify the manager about the framebuffer resize via this function */ +int CrPMgrNotifyResize(HCR_FRAMEBUFFER hFb) +{ + int rc = VINF_SUCCESS; + if (CrFbIsEnabled(hFb)) + { + rc = CrPMgrModeModify(hFb, g_CrPresenter.u32DisplayMode, 0); + if (!RT_SUCCESS(rc)) + { + WARN(("CrPMgrModeModify failed rc %d", rc)); + return rc; + } + } + else + { + rc = CrPMgrModeModify(hFb, 0, CR_PMGR_MODE_ALL); + if (!RT_SUCCESS(rc)) + { + WARN(("CrPMgrModeModify failed rc %d", rc)); + return rc; + } + } + + return VINF_SUCCESS; +} + +int CrFbEntrySaveState(CR_FRAMEBUFFER *pFb, CR_FRAMEBUFFER_ENTRY *hEntry, PSSMHANDLE pSSM) +{ + const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + int rc = SSMR3PutU32(pSSM, pFbTex->pTobj->id); + AssertRCReturn(rc, rc); + uint32_t u32 = 0; + + u32 = CrVrScrCompositorEntryFlagsGet(pEntry); + rc = SSMR3PutU32(pSSM, u32); + AssertRCReturn(rc, rc); + + const RTRECT *pRect = CrVrScrCompositorEntryRectGet(pEntry); + + rc = SSMR3PutS32(pSSM, pRect->xLeft); + AssertRCReturn(rc, rc); + rc = SSMR3PutS32(pSSM, pRect->yTop); + AssertRCReturn(rc, rc); +#if 0 + rc = SSMR3PutS32(pSSM, pRect->xRight); + AssertRCReturn(rc, rc); + rc = SSMR3PutS32(pSSM, pRect->yBottom); + AssertRCReturn(rc, rc); +#endif + + rc = CrVrScrCompositorEntryRegionsGet(&pFb->Compositor, pEntry, &u32, NULL, NULL, &pRect); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, u32); + AssertRCReturn(rc, rc); + + if (u32) + { + rc = SSMR3PutMem(pSSM, pRect, u32 * sizeof (*pRect)); + AssertRCReturn(rc, rc); + } + return rc; +} + +int CrFbSaveState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM) +{ + VBOXVR_SCR_COMPOSITOR_CONST_ITERATOR Iter; + CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter); + const VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry; + uint32_t u32 = 0; + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CRASSERT(pTexData); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + if (pFbTex->pTobj) + ++u32; + } + + int rc = SSMR3PutU32(pSSM, u32); + AssertRCReturn(rc, rc); + + CrVrScrCompositorConstIterInit(&pFb->Compositor, &Iter); + + while ((pEntry = CrVrScrCompositorConstIterNext(&Iter)) != NULL) + { + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + if (pFbTex->pTobj) + { + HCR_FRAMEBUFFER_ENTRY hEntry = CrFbEntryFromCompositorEntry(pEntry); + rc = CrFbEntrySaveState(pFb, hEntry, pSSM); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +int CrPMgrSaveState(PSSMHANDLE pSSM) +{ + int rc; + int cDisplays = 0, i; + for (i = 0; i < cr_server.screenCount; ++i) + { + if (CrPMgrFbGetEnabled(i)) + ++cDisplays; + } + + rc = SSMR3PutS32(pSSM, cDisplays); + AssertRCReturn(rc, rc); + + if (!cDisplays) + return VINF_SUCCESS; + + rc = SSMR3PutS32(pSSM, cr_server.screenCount); + AssertRCReturn(rc, rc); + + for (i = 0; i < cr_server.screenCount; ++i) + { + CR_FRAMEBUFFER *hFb = CrPMgrFbGetEnabled(i); + if (hFb) + { + Assert(hFb->ScreenInfo.u32ViewIndex == i); + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32ViewIndex); + AssertRCReturn(rc, rc); + + rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginX); + AssertRCReturn(rc, rc); + + rc = SSMR3PutS32(pSSM, hFb->ScreenInfo.i32OriginY); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32StartOffset); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32LineSize); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Width); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, hFb->ScreenInfo.u32Height); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16BitsPerPixel); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU16(pSSM, hFb->ScreenInfo.u16Flags); + AssertRCReturn(rc, rc); + + rc = SSMR3PutU32(pSSM, (uint32_t)(((uintptr_t)hFb->pvVram) - ((uintptr_t)g_pvVRamBase))); + AssertRCReturn(rc, rc); + + rc = CrFbSaveState(hFb, pSSM); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +int CrFbEntryLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version) +{ + uint32_t texture; + int rc = SSMR3GetU32(pSSM, &texture); + AssertRCReturn(rc, rc); + + uint32_t fFlags; + rc = SSMR3GetU32(pSSM, &fFlags); + AssertRCReturn(rc, rc); + + + HCR_FRAMEBUFFER_ENTRY hEntry; + + rc = CrFbEntryCreateForTexId(pFb, texture, fFlags, &hEntry); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbEntryCreateForTexId Failed")); + return rc; + } + + Assert(hEntry); + + const struct VBOXVR_SCR_COMPOSITOR_ENTRY *pEntry = CrFbEntryGetCompositorEntry(hEntry); + CR_TEXDATA *pTexData = CrVrScrCompositorEntryTexGet(pEntry); + CR_FBTEX *pFbTex = PCR_FBTEX_FROM_TEX(pTexData); + + RTPOINT Point; + rc = SSMR3GetS32(pSSM, &Point.x); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &Point.y); + AssertRCReturn(rc, rc); + + uint32_t cRects; + rc = SSMR3GetU32(pSSM, &cRects); + AssertRCReturn(rc, rc); + + RTRECT * pRects = NULL; + if (cRects) + { + pRects = (RTRECT *)crAlloc(cRects * sizeof (*pRects)); + AssertReturn(pRects, VERR_NO_MEMORY); + + rc = SSMR3GetMem(pSSM, pRects, cRects * sizeof (*pRects)); + AssertRCReturn(rc, rc); + } + + rc = CrFbEntryRegionsSet(pFb, hEntry, &Point, cRects, pRects, false); + AssertRCReturn(rc, rc); + + if (pRects) + crFree(pRects); + + CrFbEntryRelease(pFb, hEntry); + + return VINF_SUCCESS; +} + +int CrFbLoadState(CR_FRAMEBUFFER *pFb, PSSMHANDLE pSSM, uint32_t version) +{ + uint32_t u32 = 0; + int rc = SSMR3GetU32(pSSM, &u32); + AssertRCReturn(rc, rc); + + if (!u32) + return VINF_SUCCESS; + + rc = CrFbUpdateBegin(pFb); + AssertRCReturn(rc, rc); + + for (uint32_t i = 0; i < u32; ++i) + { + rc = CrFbEntryLoadState(pFb, pSSM, version); + AssertRCReturn(rc, rc); + + } + + CrFbUpdateEnd(pFb); + + return VINF_SUCCESS; +} + +int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version) +{ + int rc; + int cDisplays, screenCount, i; + + rc = SSMR3GetS32(pSSM, &cDisplays); + AssertRCReturn(rc, rc); + + if (!cDisplays) + return VINF_SUCCESS; + + rc = SSMR3GetS32(pSSM, &screenCount); + AssertRCReturn(rc, rc); + + CRASSERT(screenCount == cr_server.screenCount); + + CRScreenInfo screen[CR_MAX_GUEST_MONITORS]; + + if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO) + { + for (i = 0; i < cr_server.screenCount; ++i) + { + rc = SSMR3GetS32(pSSM, &screen[i].x); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &screen[i].y); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &screen[i].w); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &screen[i].h); + AssertRCReturn(rc, rc); + } + } + + for (i = 0; i < cDisplays; ++i) + { + int iScreen; + + rc = SSMR3GetS32(pSSM, &iScreen); + AssertRCReturn(rc, rc); + + CR_FRAMEBUFFER *pFb = CrPMgrFbGet(iScreen); + Assert(pFb); + + rc = CrFbUpdateBegin(pFb); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbUpdateBegin failed %d", rc)); + return rc; + } + + VBVAINFOSCREEN Screen; + void *pvVRAM; + + Screen.u32ViewIndex = iScreen; + + if (version < SHCROGL_SSM_VERSION_WITH_FB_INFO) + { + memset(&Screen, 0, sizeof (Screen)); + Screen.u32LineSize = 4 * screen[iScreen].w; + Screen.u32Width = screen[iScreen].w; + Screen.u32Height = screen[iScreen].h; + Screen.u16BitsPerPixel = 4; + Screen.u16Flags = VBVA_SCREEN_F_ACTIVE; + + pvVRAM = g_pvVRamBase; + } + else + { + rc = SSMR3GetS32(pSSM, &Screen.i32OriginX); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &Screen.i32OriginY); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32StartOffset); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32LineSize); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32Width); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU32(pSSM, &Screen.u32Height); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU16(pSSM, &Screen.u16BitsPerPixel); + AssertRCReturn(rc, rc); + + rc = SSMR3GetU16(pSSM, &Screen.u16Flags); + AssertRCReturn(rc, rc); + + uint32_t offVram = 0; + rc = SSMR3GetU32(pSSM, &offVram); + AssertRCReturn(rc, rc); + + pvVRAM = (void*)(((uintptr_t)g_pvVRamBase) + offVram); + } + + crVBoxServerMuralFbResizeBegin(pFb); + + rc = CrFbResize(pFb, &Screen, pvVRAM); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbResize failed %d", rc)); + return rc; + } + + rc = CrFbLoadState(pFb, pSSM, version); + AssertRCReturn(rc, rc); + + crVBoxServerMuralFbResizeEnd(pFb); + + CrFbUpdateEnd(pFb); + + CrPMgrNotifyResize(pFb); + } + + return VINF_SUCCESS; +} + + +void SERVER_DISPATCH_APIENTRY +crServerDispatchVBoxTexPresent(GLuint texture, GLuint cfg, GLint xPos, GLint yPos, GLint cRects, const GLint *pRects) +{ + uint32_t idScreen = CR_PRESENT_GET_SCREEN(cfg); + if (idScreen >= CR_MAX_GUEST_MONITORS) + { + WARN(("Invalid guest screen")); + return; + } + + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(idScreen); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + return; + } + + HCR_FRAMEBUFFER_ENTRY hEntry; + int rc; + if (texture) + { + rc = CrFbEntryCreateForTexId(hFb, texture, (cfg & CR_PRESENT_FLAG_TEX_NONINVERT_YCOORD) ? 0 : CRBLT_F_INVERT_SRC_YCOORDS, &hEntry); + if (!RT_SUCCESS(rc)) + { + LOG(("CrFbEntryCreateForTexId Failed")); + return; + } + + Assert(hEntry); + +#if 0 + if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) + { + CR_SERVER_DUMP_TEXPRESENT(&pEntry->CEntry.Tex); + } +#endif + } + else + hEntry = NULL; + + rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + if (!(cfg & CR_PRESENT_FLAG_CLEAR_RECTS)) + { + RTPOINT Point = {xPos, yPos}; + rc = CrFbEntryRegionsAdd(hFb, hEntry, &Point, (uint32_t)cRects, (const RTRECT*)pRects, false); + } + else + { + CrFbRegionsClear(hFb); + } + + CrFbUpdateEnd(hFb); + } + else + { + WARN(("CrFbUpdateBegin Failed")); + } + + if (hEntry) + CrFbEntryRelease(hFb, hEntry); +} + +DECLINLINE(void) crVBoxPRectUnpack(const VBOXCMDVBVA_RECT *pVbvaRect, RTRECT *pRect) +{ + pRect->xLeft = pVbvaRect->xLeft; + pRect->yTop = pVbvaRect->yTop; + pRect->xRight = pVbvaRect->xRight; + pRect->yBottom = pVbvaRect->yBottom; +} + +DECLINLINE(void) crVBoxPRectUnpacks(const VBOXCMDVBVA_RECT *paVbvaRects, RTRECT *paRects, uint32_t cRects) +{ + uint32_t i = 0; + for (; i < cRects; ++i) + { + crVBoxPRectUnpack(&paVbvaRects[i], &paRects[i]); + } +} + +int32_t crVBoxServerCrCmdBltProcess(PVBOXCMDVBVA_HDR pCmd, uint32_t cbCmd) +{ + uint8_t u8Flags = pCmd->u8Flags; + if (u8Flags & (VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY | VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY)) + { + VBOXCMDVBVA_BLT_PRIMARY *pBlt = (VBOXCMDVBVA_BLT_PRIMARY*)pCmd; + uint8_t u8PrimaryID = pBlt->Hdr.u.u8PrimaryID; + HCR_FRAMEBUFFER hFb = CrPMgrFbGetEnabled(u8PrimaryID); + if (!hFb) + { + WARN(("request to present on disabled framebuffer, ignore")); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + + const VBOXCMDVBVA_RECT *pPRects = pBlt->aRects; + uint32_t cRects = (cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) / sizeof (VBOXCMDVBVA_RECT); + RTRECT *pRects; + if (g_CrPresenter.cbTmpBuf < cRects * sizeof (RTRECT)) + { + if (g_CrPresenter.pvTmpBuf) + RTMemFree(g_CrPresenter.pvTmpBuf); + + g_CrPresenter.cbTmpBuf = (cRects + 10) * sizeof (RTRECT); + g_CrPresenter.pvTmpBuf = RTMemAlloc(g_CrPresenter.cbTmpBuf); + if (!g_CrPresenter.pvTmpBuf) + { + WARN(("RTMemAlloc failed!")); + g_CrPresenter.cbTmpBuf = 0; + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + } + + pRects = (RTRECT *)g_CrPresenter.pvTmpBuf; + + crVBoxPRectUnpacks(pPRects, pRects, cRects); + + Assert(!((cbCmd - RT_OFFSETOF(VBOXCMDVBVA_BLT_PRIMARY, aRects)) % sizeof (VBOXCMDVBVA_RECT))); + + if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTPRIMARY) + { + if (!(u8Flags & VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY)) + { + /* blit to primary from non-primary */ + uint32_t texId; + if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTID) + { + /* TexPresent */ + texId = pBlt->alloc.u.id; + } + else + { + VBOXCMDVBVAOFFSET offVRAM = pBlt->alloc.u.offVRAM; + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + uint32_t cbScreen = pScreen->u32LineSize * pScreen->u32Height; + if (offVRAM >= g_cbVRam + || offVRAM + cbScreen >= g_cbVRam) + { + WARN(("invalid param")); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + + uint8_t *pu8Buf = g_pvVRamBase + offVRAM; + texId = 0; +// cr_server.CrCmdClientInfo.pfnCltScrUpdateBegin(cr_server.CrCmdClientInfo.hCltScr); + /*todo: notify VGA device to perform updates */ + } + + crServerDispatchVBoxTexPresent(texId, u8PrimaryID, pBlt->Pos.x, pBlt->Pos.y, cRects, (const GLint*)pRects); + } + else + { + /* blit from one primary to another primary, wow */ + WARN(("not implemented")); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + } + else + { + Assert(u8Flags & VBOXCMDVBVA_OPF_ALLOC_SRCPRIMARY); + /* blit from primary to non-primary */ + if (u8Flags & VBOXCMDVBVA_OPF_ALLOC_DSTID) + { + uint32_t texId = pBlt->alloc.u.id; + WARN(("not implemented")); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + else + { + VBOXCMDVBVAOFFSET offVRAM = pBlt->alloc.u.offVRAM; + const VBVAINFOSCREEN *pScreen = CrFbGetScreenInfo(hFb); + uint32_t cbScreen = pScreen->u32LineSize * pScreen->u32Height; + if (offVRAM >= g_cbVRam + || offVRAM + cbScreen >= g_cbVRam) + { + WARN(("invalid param")); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + + uint8_t *pu8Buf = g_pvVRamBase + offVRAM; + + RTRECT SrcRect; + SrcRect.xLeft = 0; + SrcRect.yTop = 0; + SrcRect.xRight = pScreen->u32Width; + SrcRect.yBottom = pScreen->u32Height; + RTRECT DstRect; + DstRect.xLeft = pBlt->Pos.x; + DstRect.yTop = pBlt->Pos.y; + DstRect.xRight = DstRect.xLeft + pScreen->u32Width; + DstRect.yBottom = DstRect.yTop + pScreen->u32Height; + CR_BLITTER_IMG Img; + crFbImgFromScreenVram(pScreen, pu8Buf, &Img); + int rc = CrFbBltGetContents(hFb, &SrcRect, &DstRect, cRects, pRects, &Img); + if (!RT_SUCCESS(rc)) + { + WARN(("CrFbBltGetContents failed %d", rc)); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + } + } + } + else + { + WARN(("not implemented")); + pCmd->u.i8Result = -1; + return VINF_SUCCESS; + } + + pCmd->u.i8Result = 0; + return VINF_SUCCESS; +} diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py index 69d09b60..11f2e77f 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py @@ -35,7 +35,7 @@ void crServerReturnValue( const void *payload, unsigned int payload_len ) rb = (CRMessageReadback *) crAlloc( msg_len ); rb->header.type = CR_MESSAGE_READBACK; - CRDBGPTR_PRINTWB(cr_server.curClient->conn->u32ClientID, &cr_server.writeback_ptr); + CRDBGPTR_PRINTRB(cr_server.curClient->conn->u32ClientID, &cr_server.writeback_ptr); CRDBGPTR_CHECKNZ(&cr_server.writeback_ptr); CRDBGPTR_CHECKNZ(&cr_server.return_ptr); crMemcpy( &(rb->writeback_ptr), &(cr_server.writeback_ptr), sizeof( rb->writeback_ptr ) ); diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp new file mode 100644 index 00000000..51c5d46f --- /dev/null +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp @@ -0,0 +1,755 @@ +/* $Id: server_rpw.cpp $ */ + +/** @file + * VBox crOpenGL: Read Pixels worker + */ + +/* + * Copyright (C) 2010-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 "server.h" +#include "cr_string.h" +#include "cr_mem.h" +#include "cr_vreg.h" +#include "render/renderspu.h" + +static void crServerRpwWorkerGpuSubmit(PRTLISTNODE pWorkList) +{ + CR_SERVER_RPW_ENTRY *pCurEntry; + RTListForEach(pWorkList, pCurEntry, CR_SERVER_RPW_ENTRY, WorkerWorkEntry) + { + cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, CR_SERVER_RPW_ENTRY_TEX(pCurEntry, Worker)); + + if (CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pCurEntry)) + { + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, CR_SERVER_RPW_ENTRY_PBO_CUR(pCurEntry)); + /*read the texture, note pixels are NULL for PBO case as it's offset in the buffer*/ + cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + CR_SERVER_RPW_ENTRY_PBO_FLIP(pCurEntry); + } + else + { + void *pvData = crAlloc(4*pCurEntry->Size.cx*pCurEntry->Size.cy); + if (pvData) + { + cr_server.head_spu->dispatch_table.GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pvData); + + pCurEntry->pfnData(pCurEntry, pvData); + + crFree(pvData); + } + else + { + crWarning("crAlloc failed"); + } + } + + cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, 0); + } +} + +static void crServerRpwWorkerGpuComplete(PRTLISTNODE pGpuSubmitedList) +{ + CR_SERVER_RPW_ENTRY *pCurEntry; + RTListForEach(pGpuSubmitedList, pCurEntry, CR_SERVER_RPW_ENTRY, GpuSubmittedEntry) + { + Assert(CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pCurEntry)); + + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, CR_SERVER_RPW_ENTRY_PBO_COMPLETED(pCurEntry)); + + void *pvData = cr_server.head_spu->dispatch_table.MapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY); + + pCurEntry->pfnData(pCurEntry, pvData); + + cr_server.head_spu->dispatch_table.UnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); + + cr_server.head_spu->dispatch_table.BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, pCurEntry->Size.cx*pCurEntry->Size.cy*4, 0, GL_STREAM_READ_ARB); + + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } +} + +static void crServerRpwWorkerGpuMarkGpuCompletedSubmitedLocked(PRTLISTNODE pGpuSubmitedList, PRTLISTNODE pWorkList) +{ + CR_SERVER_RPW_ENTRY *pCurEntry, *pNextEntry; + RTListForEachSafe(pGpuSubmitedList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, GpuSubmittedEntry) + { + CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pCurEntry, Gpu); + RTListNodeRemove(&pCurEntry->GpuSubmittedEntry); + } + + Assert(RTListIsEmpty(pGpuSubmitedList)); + + RTListForEachSafe(pWorkList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, WorkerWorkEntry) + { + Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pCurEntry, Worker)); + RTListNodeRemove(&pCurEntry->WorkerWorkEntry); + if (CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pCurEntry)) + { + /* PBO mode, put to the GPU submitted queue*/ + RTListAppend(pGpuSubmitedList, &pCurEntry->GpuSubmittedEntry); + CR_SERVER_RPW_ENTRY_TEX_PROMOTE(pCurEntry, Worker, Gpu); + } + else + { + /* no PBO, we are already done entry data processing, free it right away */ + Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pCurEntry, Gpu)); + CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pCurEntry, Worker); + } + } +} + +static void crServerRpwWorkerGetWorkLocked(CR_SERVER_RPW *pWorker, PRTLISTNODE pWorkList) +{ + CR_SERVER_RPW_ENTRY *pCurEntry, *pNextEntry; + RTListForEachSafe(&pWorker->WorkList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, WorkEntry) + { + RTListNodeRemove(&pCurEntry->WorkEntry); + RTListAppend(pWorkList, &pCurEntry->WorkerWorkEntry); + CR_SERVER_RPW_ENTRY_TEX_PROMOTE(pCurEntry, Submitted, Worker); + } +} + +static DECLCALLBACK(int) crServerRpwWorkerThread(RTTHREAD ThreadSelf, void *pvUser) +{ + CR_SERVER_RPW *pWorker = (CR_SERVER_RPW *)pvUser; + RTMSINTERVAL cWaitMillis = RT_INDEFINITE_WAIT; + RTLISTNODE WorkList, GpuSubmittedList; + CR_SERVER_RPW_CTL_TYPE enmCtlType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED; + CR_SERVER_RPW_ENTRY *pCtlEntry = NULL; + CRMuralInfo *pDummyMural = crServerGetDummyMural(pWorker->ctxVisBits); + bool fExit = false; + bool fForceComplete = false; + bool fNotifyCmdCompleted = false; + + CRASSERT(pDummyMural); + + int rc = RTSemEventSignal(pWorker->Ctl.hCompleteEvent); + if (!RT_SUCCESS(rc)) + { + crWarning("RTSemEventSignal failed rc %d", rc); + return rc; + } + + RTListInit(&WorkList); + RTListInit(&GpuSubmittedList); + + cr_server.head_spu->dispatch_table.MakeCurrent(pDummyMural->spuWindow, 0, pWorker->ctxId); + + rc = RTCritSectEnter(&pWorker->CritSect); + if (!RT_SUCCESS(rc)) + { + crWarning("RTCritSectEnter failed, rc %d", rc); + goto end; + } + + for (;;) + { + /* the crit sect is locked here */ + + if (pWorker->Ctl.enmType != CR_SERVER_RPW_CTL_TYPE_UNDEFINED) + { + enmCtlType = pWorker->Ctl.enmType; + pCtlEntry = pWorker->Ctl.pEntry; + pWorker->Ctl.enmType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED; + pWorker->Ctl.pEntry = NULL; + } + + crServerRpwWorkerGetWorkLocked(pWorker, &WorkList); + + RTCritSectLeave(&pWorker->CritSect); + + if (enmCtlType != CR_SERVER_RPW_CTL_TYPE_UNDEFINED) + { + switch (enmCtlType) + { + case CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE: + break; + case CR_SERVER_RPW_CTL_TYPE_TERM: + fExit = true; + break; + default: + crWarning("unexpected CtlType %d", enmCtlType); + break; + } + enmCtlType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED; + pCtlEntry = NULL; + fNotifyCmdCompleted = true; + } + + bool fNewItems = !RTListIsEmpty(&WorkList); + bool fCompleted = false; + + if (fNewItems) + { + crServerRpwWorkerGpuSubmit(&WorkList); + } + + if (!RTListIsEmpty(&GpuSubmittedList)) + { + if (fForceComplete || fNewItems) + { + crServerRpwWorkerGpuComplete(&GpuSubmittedList); + fForceComplete = false; + fCompleted = true; + } + } + + rc = RTCritSectEnter(&pWorker->CritSect); + if (!RT_SUCCESS(rc)) + { + crWarning("RTCritSectEnter failed, rc %d", rc); + break; + } + + /* fNewGpuItems means new entries arrived. WorkList contains new GPU submitted data + * fCompleted means completion was performed, GpuSubmittedList contains old GPU submitted data, + * which is now completed and should be released */ + if (fNewItems || fCompleted) + { + crServerRpwWorkerGpuMarkGpuCompletedSubmitedLocked(&GpuSubmittedList, &WorkList); + } + + if (fExit || !fNewItems) + { + RTCritSectLeave(&pWorker->CritSect); + + if (fNotifyCmdCompleted) + { + rc = RTSemEventSignal(pWorker->Ctl.hCompleteEvent); + if (!RT_SUCCESS(rc)) + { + crWarning("RTSemEventSignal failed rc %d", rc); + break; + } + fNotifyCmdCompleted = false; + } + + if (fExit) + break; + + if (!RTListIsEmpty(&GpuSubmittedList)) + cWaitMillis = 17; /* ~60Hz */ + else + cWaitMillis = RT_INDEFINITE_WAIT; + + rc = RTSemEventWait(pWorker->hSubmitEvent, cWaitMillis); + if (!RT_SUCCESS(rc) && rc != VERR_TIMEOUT) + { + crWarning("RTSemEventWait failed, rc %d", rc); + break; + } + + if (rc == VERR_TIMEOUT) + { + Assert(!RTListIsEmpty(&GpuSubmittedList)); + fForceComplete = true; + } + + rc = RTCritSectEnter(&pWorker->CritSect); + if (!RT_SUCCESS(rc)) + { + crWarning("RTCritSectEnter failed, rc %d", rc); + break; + } + } + } + +end: + cr_server.head_spu->dispatch_table.MakeCurrent(0, 0, 0); + + return rc; +} + +static int crServerRpwCtlNotify(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry) +{ + int rc = RTSemEventSignal(pWorker->hSubmitEvent); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventWait(pWorker->Ctl.hCompleteEvent, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + rc = pWorker->Ctl.rc; + if (!RT_SUCCESS(rc)) + { + crWarning("WdCtl command failed rc %d", rc); + } + } + else + { + crWarning("RTSemEventWait failed rc %d", rc); + } + } + else + { + int tmpRc; + crWarning("RTSemEventSignal failed rc %d", rc); + tmpRc = RTCritSectEnter(&pWorker->CritSect); + if (RT_SUCCESS(tmpRc)) + { + pWorker->Ctl.enmType = CR_SERVER_RPW_CTL_TYPE_UNDEFINED; + pWorker->Ctl.pEntry = NULL; + RTCritSectLeave(&pWorker->CritSect); + } + else + { + crWarning("RTSemEventSignal failed tmpRc %d", tmpRc); + } + } + + return rc; +} + +static int crServerRpwCtl(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_CTL_TYPE enmType, CR_SERVER_RPW_ENTRY *pEntry) +{ + int rc = RTCritSectEnter(&pWorker->CritSect); + if (RT_SUCCESS(rc)) + { + pWorker->Ctl.enmType = enmType; + pWorker->Ctl.pEntry = pEntry; + RTCritSectLeave(&pWorker->CritSect); + } + else + { + crWarning("RTCritSectEnter failed rc %d", rc); + return rc; + } + + rc = crServerRpwCtlNotify(pWorker, pEntry); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwCtlNotify failed rc %d", rc); + return rc; + } + return VINF_SUCCESS; +} + +int crServerRpwInit(CR_SERVER_RPW *pWorker) +{ + int rc; + + memset(pWorker, 0, sizeof (*pWorker)); + + RTListInit(&pWorker->WorkList); + + rc = RTCritSectInit(&pWorker->CritSect); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pWorker->hSubmitEvent); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pWorker->Ctl.hCompleteEvent); + if (RT_SUCCESS(rc)) + { + CRASSERT(cr_server.MainContextInfo.CreateInfo.realVisualBits); + CRASSERT(cr_server.MainContextInfo.SpuContext); + + pWorker->ctxId = cr_server.head_spu->dispatch_table.CreateContext("", cr_server.MainContextInfo.CreateInfo.realVisualBits, cr_server.MainContextInfo.SpuContext); + if (pWorker->ctxId) + { + CRMuralInfo *pDummyMural; + pWorker->ctxVisBits = cr_server.MainContextInfo.CreateInfo.realVisualBits; + pDummyMural = crServerGetDummyMural(pWorker->ctxVisBits); + if (pDummyMural) + { + /* since CreateContext does not actually create it on some platforms, e.g. on win, + * we need to do MakeCurrent to ensure it is created. + * There is some black magic in doing that to work around ogl driver bugs + * (i.e. we need to switch offscreen rendering off before doing make current) */ + CR_SERVER_CTX_SWITCH CtxSwitch; + + crServerCtxSwitchPrepare(&CtxSwitch, NULL); + + cr_server.head_spu->dispatch_table.Flush(); + + cr_server.head_spu->dispatch_table.MakeCurrent(pDummyMural->spuWindow, 0, pWorker->ctxId); + + if (cr_server.currentCtxInfo) + { + CRASSERT(cr_server.currentMural); + cr_server.head_spu->dispatch_table.MakeCurrent(cr_server.currentMural->spuWindow, 0, + cr_server.currentCtxInfo->SpuContext > 0 ? cr_server.currentCtxInfo->SpuContext : cr_server.MainContextInfo.SpuContext); + } + else + cr_server.head_spu->dispatch_table.MakeCurrent(CR_RENDER_DEFAULT_WINDOW_ID, 0, CR_RENDER_DEFAULT_CONTEXT_ID); + + crServerCtxSwitchPostprocess(&CtxSwitch); + + rc = RTThreadCreate(&pWorker->hThread, crServerRpwWorkerThread, pWorker, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "CrServerDw"); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventWait(pWorker->Ctl.hCompleteEvent, RT_INDEFINITE_WAIT); + if (RT_SUCCESS(rc)) + { + return VINF_SUCCESS; + } + else + { + crWarning("RTSemEventWait failed rc %d", rc); + } + } + else + { + crWarning("RTThreadCreate failed rc %d", rc); + } + } + else + { + crWarning("Failed to get dummy mural"); + rc = VERR_GENERAL_FAILURE; + } + cr_server.head_spu->dispatch_table.DestroyContext(pWorker->ctxId); + } + else + { + crWarning("CreateContext failed rc %d", rc); + } + + RTSemEventDestroy(pWorker->Ctl.hCompleteEvent); + } + else + { + crWarning("RTSemEventCreate failed rc %d", rc); + } + RTSemEventDestroy(pWorker->hSubmitEvent); + } + else + { + crWarning("RTSemEventCreate failed rc %d", rc); + } + + RTCritSectDelete(&pWorker->CritSect); + } + else + { + crWarning("RTCritSectInit failed rc %d", rc); + } + + return rc; +} + +int crServerRpwEntryResizeCleaned(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height) +{ + CRContext *pContext; + if (!width || !height) + { + return VINF_SUCCESS; + } + + if (!cr_server.currentCtxInfo) + { + CRMuralInfo *pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + if (!pDummy) + { + crWarning("crServerGetDummyMural failed"); + return VERR_GENERAL_FAILURE; + } + + + crServerPerformMakeCurrent(pDummy, &cr_server.MainContextInfo); + } + + Assert(width); + Assert(height); + + pContext = cr_server.currentCtxInfo->pContext; + + if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) + { + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + } + + for (int i = 0; i < 4; ++i) + { + cr_server.head_spu->dispatch_table.GenTextures(1, &pEntry->aidWorkerTexs[i]); + + cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, pEntry->aidWorkerTexs[i]); + cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + cr_server.head_spu->dispatch_table.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + cr_server.head_spu->dispatch_table.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, + 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL); + } + + pEntry->iTexDraw = -pEntry->iTexDraw; + + if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) + { + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pContext->bufferobject.unpackBuffer->hwid); + } + + if (cr_server.bUsePBOForReadback) + { + for (int i = 0; i < 2; ++i) + { + cr_server.head_spu->dispatch_table.GenBuffersARB(1, &pEntry->aidPBOs[i]); + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pEntry->aidPBOs[i]); + cr_server.head_spu->dispatch_table.BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, width*height*4, 0, GL_STREAM_READ_ARB); + } + + if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB)) + { + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pContext->bufferobject.packBuffer->hwid); + } + else + { + cr_server.head_spu->dispatch_table.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } + pEntry->iCurPBO = 0; + } + + + GLuint uid = pContext->texture.unit[pContext->texture.curTextureUnit].currentTexture2D->hwid; + cr_server.head_spu->dispatch_table.BindTexture(GL_TEXTURE_2D, uid); + + + pEntry->Size.cx = width; + pEntry->Size.cy = height; + + crServerRpwEntryDbgVerify(pEntry); + + return VINF_SUCCESS; +} + +int crServerRpwEntryCleanup(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry) +{ + if (!pEntry->Size.cx) + return VINF_SUCCESS; + + int rc = crServerRpwEntryCancel(pWorker, pEntry); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwEntryCancel failed rc %d", rc); + return rc; + } + + if (!cr_server.currentCtxInfo) + { + CRMuralInfo *pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + if (!pDummy) + { + crWarning("crServerGetDummyMural failed"); + return VERR_GENERAL_FAILURE; + } + + + crServerPerformMakeCurrent(pDummy, &cr_server.MainContextInfo); + } + + cr_server.head_spu->dispatch_table.DeleteTextures(4, pEntry->aidWorkerTexs); + + if (CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(pEntry)) + { + cr_server.head_spu->dispatch_table.DeleteBuffersARB(2, pEntry->aidPBOs); + memset(pEntry->aidPBOs, 0, sizeof (pEntry->aidPBOs)); + pEntry->iCurPBO = -1; + } + + memset(pEntry->aidWorkerTexs, 0, sizeof (pEntry->aidWorkerTexs)); + CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Submitted); + CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Worker); + CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Gpu); + pEntry->iTexDraw = -1; + pEntry->iTexSubmitted = -2; + pEntry->iTexWorker = -3; + pEntry->iTexGpu = -4; + pEntry->Size.cx = 0; + pEntry->Size.cy = 0; + return VINF_SUCCESS; +} + +int crServerRpwEntryResize(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height) +{ + if (!width || !height) + { + width = 0; + height = 0; + } + + if (width == pEntry->Size.cx && width == pEntry->Size.cy) + return VINF_SUCCESS; + + int rc = crServerRpwEntryCleanup(pWorker, pEntry); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwEntryCleanup failed rc %d", rc); + return rc; + } + + rc = crServerRpwEntryResizeCleaned(pWorker, pEntry, width, height); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwEntryResizeCleaned failed rc %d", rc); + } + return rc; +} + +int crServerRpwEntryInit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height, PFNCR_SERVER_RPW_DATA pfnData) +{ + memset(pEntry, 0, sizeof (*pEntry)); + + pEntry->iTexDraw = -1; + pEntry->iTexSubmitted = -2; + pEntry->iTexWorker = -3; + pEntry->iTexGpu = -4; + pEntry->iCurPBO = -1; + pEntry->pfnData = pfnData; + int rc = crServerRpwEntryResizeCleaned(pWorker, pEntry, width, height); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwEntryResizeCleaned failed rc %d", rc); + return rc; + } + return VINF_SUCCESS; +} + +int crServerRpwEntrySubmit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry) +{ + if (!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw)) + { + crWarning("submitting empty entry, ignoting"); + Assert(!pEntry->Size.cx); + Assert(!pEntry->Size.cy); + return VERR_INVALID_PARAMETER; + } + + Assert(pEntry->Size.cx); + Assert(pEntry->Size.cy); + + int rc = RTCritSectEnter(&pWorker->CritSect); + if (RT_SUCCESS(rc)) + { + Assert(pWorker->Ctl.enmType == CR_SERVER_RPW_CTL_TYPE_UNDEFINED); + if (!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Submitted)) + { + CR_SERVER_RPW_ENTRY_TEX_PROMOTE_KEEPVALID(pEntry, Draw, Submitted); + RTListAppend(&pWorker->WorkList, &pEntry->WorkEntry); + } + else + { + CR_SERVER_RPW_ENTRY_TEX_XCHG_VALID(pEntry, Draw, Submitted); + } + RTCritSectLeave(&pWorker->CritSect); + + RTSemEventSignal(pWorker->hSubmitEvent); + } + else + { + crWarning("RTCritSectEnter failed rc %d", rc); + return rc; + } + + return rc; +} + +static int crServerRpwEntryCancelCtl(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, CR_SERVER_RPW_CTL_TYPE enmType) +{ + if (CR_SERVER_RPW_CTL_TYPE_TERM == enmType && pEntry) + { + crWarning("Entry should be null for term request"); + pEntry = NULL; + } + + int rc = RTCritSectEnter(&pWorker->CritSect); + if (RT_SUCCESS(rc)) + { + if (pEntry) + { + if (CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Submitted)) + { + CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pEntry, Submitted); + RTListNodeRemove(&pEntry->WorkEntry); + } + + if (!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Worker) && !CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Gpu)) + { + /* can cancel it wight away */ + RTCritSectLeave(&pWorker->CritSect); + return VINF_SUCCESS; + } + } + else + { + CR_SERVER_RPW_ENTRY *pCurEntry, *pNextEntry; + RTListForEachSafe(&pWorker->WorkList, pCurEntry, pNextEntry, CR_SERVER_RPW_ENTRY, WorkEntry) + { + CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pCurEntry, Submitted); + CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(pEntry, Submitted); + RTListNodeRemove(&pCurEntry->WorkEntry); + } + } + pWorker->Ctl.enmType = enmType; + pWorker->Ctl.pEntry = pEntry; + RTCritSectLeave(&pWorker->CritSect); + } + else + { + crWarning("RTCritSectEnter failed rc %d", rc); + return rc; + } + + rc = crServerRpwCtlNotify(pWorker, pEntry); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwCtlNotify failed rc %d", rc); + } + return VINF_SUCCESS; +} + +int crServerRpwEntryWaitComplete(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry) +{ + int rc = crServerRpwCtl(pWorker, CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE, pEntry); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwCtl failed rc %d", rc); + } + return rc; +} + +int crServerRpwEntryCancel(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry) +{ + return crServerRpwEntryCancelCtl(pWorker, pEntry, CR_SERVER_RPW_CTL_TYPE_WAIT_COMPLETE); +} + +static int crServerRpwCtlTerm(CR_SERVER_RPW *pWorker) +{ + int rc = crServerRpwEntryCancelCtl(pWorker, NULL, CR_SERVER_RPW_CTL_TYPE_TERM); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwCtl failed rc %d", rc); + } + return rc; +} + +int crServerRpwTerm(CR_SERVER_RPW *pWorker) +{ + int rc = crServerRpwCtlTerm(pWorker); + if (!RT_SUCCESS(rc)) + { + crWarning("crServerRpwCtlTerm failed rc %d", rc); + return rc; + } + + rc = RTThreadWait(pWorker->hThread, RT_INDEFINITE_WAIT, NULL); + if (!RT_SUCCESS(rc)) + { + crWarning("RTThreadWait failed rc %d", rc); + return rc; + } + + RTSemEventDestroy(pWorker->Ctl.hCompleteEvent); + RTSemEventDestroy(pWorker->hSubmitEvent); + RTCritSectDelete(&pWorker->CritSect); + + return VINF_SUCCESS; +} diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py index 363ccb43..1698841f 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py @@ -74,31 +74,37 @@ for index in range(len(funcs)): { GLuint fboid; CRASSERT(tablesize/sizeof(%s)==1); - fboid = crStateFBOHWIDtoID((GLuint) *get_values); - if (cr_server.curClient->currentMural->bUseFBO - && crServerIsRedirectedToFBO() - && fboid==cr_server.curClient->currentMural->idFBO) + fboid = (GLuint) *get_values; + if (crServerIsRedirectedToFBO() + && (fboid==cr_server.curClient->currentMural->aidFBOs[0] + || fboid==cr_server.curClient->currentMural->aidFBOs[1])) { fboid = 0; } + else + { + fboid = crStateFBOHWIDtoID(fboid); + } *get_values = (%s) fboid; } else if (GL_READ_BUFFER==pname) { - if (cr_server.curClient->currentMural->bUseFBO && crServerIsRedirectedToFBO() - && cr_server.curClient->currentMural->idFBO + if (crServerIsRedirectedToFBO() + && CR_SERVER_FBO_FOR_IDX(cr_server.curClient->currentMural, cr_server.curClient->currentMural->iCurReadBuffer) && !crStateGetCurrent()->framebufferobject.readFB) { *get_values = (%s) crStateGetCurrent()->buffer.readBuffer; + Assert(crStateGetCurrent()->buffer.readBuffer == GL_BACK || crStateGetCurrent()->buffer.readBuffer == GL_FRONT); } } else if (GL_DRAW_BUFFER==pname) { - if (cr_server.curClient->currentMural->bUseFBO && crServerIsRedirectedToFBO() - && cr_server.curClient->currentMural->idFBO + if (crServerIsRedirectedToFBO() + && CR_SERVER_FBO_FOR_IDX(cr_server.curClient->currentMural, cr_server.curClient->currentMural->iCurDrawBuffer) && !crStateGetCurrent()->framebufferobject.drawFB) { *get_values = (%s) crStateGetCurrent()->buffer.drawBuffer; + Assert(crStateGetCurrent()->buffer.drawBuffer == GL_BACK || crStateGetCurrent()->buffer.drawBuffer == GL_FRONT); } } else if (GL_RENDERBUFFER_BINDING_EXT==pname) @@ -132,7 +138,14 @@ for index in range(len(funcs)): *get_values = (%s)CR_MAX_TEXTURE_UNITS; } } - """ % (types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index]) + else if (GL_MAX_VERTEX_ATTRIBS_ARB==pname) + { + if (CR_MAX_VERTEX_ATTRIBS < (GLuint)*get_values) + { + *get_values = (%s)CR_MAX_VERTEX_ATTRIBS; + } + } + """ % (types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index], types[index]) print '\tcrServerReturnValue( get_values, tablesize );' print '\tcrFree(get_values);' print '}\n' diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special index 7292626a..e2df4e91 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_special @@ -160,6 +160,7 @@ ProgramParameter4fNV ProgramParameter4dNV GetCompressedTexImageARB GenBuffersARB +DeleteBuffersARB GetBufferSubDataARB GetBufferPointervARB MapBufferARB @@ -248,3 +249,17 @@ BlitFramebufferEXT EndList DrawBuffer ReadBuffer +VBoxTexPresent +GetError +GetProgramiv +GetShaderiv +Begin +DrawArrays +DrawElements +End +TexEnvf +TexEnvfv +TexEnvi +TexEnviv +GetTexEnvfv +GetTexEnviv
\ No newline at end of file diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c index b5c8a5bf..29670790 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c @@ -84,7 +84,7 @@ void crServerAddToRunQueue( CRClient *client ) /* give this client a unique number if needed */ if (!client->number) { - client->number = crServerGenerateID(&cr_server.idsPool.freeClientID); + client->number = client->conn->u32ClientID; } crDebug("Adding client %p to the run queue", client); @@ -281,6 +281,28 @@ crServerDeleteClient( CRClient *client ) pNode->next = cr_server.pCleanupClient; cr_server.pCleanupClient = pNode; } + + if (!cr_server.numClients) + { + /* if no clients, the guest driver may be unloaded, + * and thus the visible regions situation might not be under control anymore, + * so cleanup the 3D framebuffer data here + * @todo: what really should happen is that guest driver on unload + * posts some request to host that would copy the current framebuffer 3D data to the 2D buffer + * (i.e. to the memory used by the standard IFramebuffer API) */ + HCR_FRAMEBUFFER hFb; + for (hFb = CrPMgrFbGetFirstEnabled(); hFb; hFb = CrPMgrFbGetNextEnabled(hFb)) + { + int rc = CrFbUpdateBegin(hFb); + if (RT_SUCCESS(rc)) + { + CrFbRegionsClear(hFb); + CrFbUpdateEnd(hFb); + } + else + WARN(("CrFbUpdateBegin failed %d", rc)); + } + } } /** @@ -441,7 +463,7 @@ crServerDispatchMessage(CRConnection *conn, CRMessage *msg) { uint32_t cbWriteback = pCmdData->cbWriteback; rc = crVBoxServerInternalClientRead(conn->pClient, (uint8_t*)pCmdData->pWriteback, &cbWriteback); - CRASSERT(rc == VINF_SUCCESS || rc == VERR_BUFFER_OVERFLOW); + Assert(rc == VINF_SUCCESS || rc == VERR_BUFFER_OVERFLOW); *pCmdData->pcbWriteback = cbWriteback; } VBOXCRHGSMI_CMD_CHECK_COMPLETE(pCmdData, rc); diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c index 392bcd20..8037ac66 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c @@ -136,3 +136,56 @@ CR_FUNC_IMAGE(TexImage2D, CR_FUNC_IMAGE(TexImage3D, (GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * pixels), (target, level, internalFormat, width, height, depth, border, format, type, realptr), pixels) + + +void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnvf( GLenum target, GLenum pname, GLfloat param ) +{ + crStateTexEnvf( target, pname, param ); + if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE) + CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnvf( target, pname, param );); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnvfv( GLenum target, GLenum pname, const GLfloat * params ) +{ + crStateTexEnvfv( target, pname, params ); + if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE) + CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnvfv( target, pname, params );); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnvi( GLenum target, GLenum pname, GLint param ) +{ + crStateTexEnvi( target, pname, param ); + if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE) + CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnvi( target, pname, param );); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchTexEnviv( GLenum target, GLenum pname, const GLint * params ) +{ + crStateTexEnviv( target, pname, params ); + if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE) + CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.TexEnviv( target, pname, params );); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchGetTexEnvfv( GLenum target, GLenum pname, GLfloat * params ) +{ + GLfloat local_params[4]; + (void) params; + if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE) + cr_server.head_spu->dispatch_table.GetTexEnvfv( target, pname, local_params ); + else + crStateGetTexEnvfv( target, pname, local_params ); + + crServerReturnValue( &(local_params[0]), crStateHlpComponentsCount(pname)*sizeof (GLfloat) ); +} + +void SERVER_DISPATCH_APIENTRY crServerDispatchGetTexEnviv( GLenum target, GLenum pname, GLint * params ) +{ + GLint local_params[4]; + (void) params; + if (GL_POINT_SPRITE != target && pname != GL_COORD_REPLACE) + cr_server.head_spu->dispatch_table.GetTexEnviv( target, pname, local_params ); + else + crStateGetTexEnviv( target, pname, local_params ); + + crServerReturnValue( &(local_params[0]), crStateHlpComponentsCount(pname)*sizeof (GLint) ); +} diff --git a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c index ce380be6..69351255 100644 --- a/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c +++ b/src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c @@ -10,21 +10,94 @@ #include "cr_rand.h" #include "cr_string.h" +#include "render/renderspu.h" + GLint SERVER_DISPATCH_APIENTRY crServerDispatchWindowCreate(const char *dpyName, GLint visBits) { return crServerDispatchWindowCreateEx(dpyName, visBits, -1); } +GLint crServerMuralInit(CRMuralInfo *mural, GLboolean fGuestWindow, GLint visBits, GLint preloadWinID) +{ + CRMuralInfo *defaultMural; + GLint dims[2]; + GLint windowID = -1; + GLint spuWindow = 0; + GLint realVisBits = visBits; + const char *dpyName = ""; -GLint -crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID) + crMemset(mural, 0, sizeof (*mural)); + + if (cr_server.fVisualBitsDefault) + realVisBits = cr_server.fVisualBitsDefault; + +#ifdef RT_OS_DARWIN + if (fGuestWindow) + { + CRMuralInfo *dummy = crServerGetDummyMural(visBits); + if (!dummy) + { + WARN(("crServerGetDummyMural failed")); + return -1; + } + spuWindow = dummy->spuWindow; + mural->fIsDummyRefference = GL_TRUE; + } + else +#endif + { + /* + * Have first SPU make a new window. + */ + spuWindow = cr_server.head_spu->dispatch_table.WindowCreate( dpyName, realVisBits ); + if (spuWindow < 0) { + return spuWindow; + } + mural->fIsDummyRefference = GL_FALSE; + } + + /* get initial window size */ + cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, spuWindow, GL_INT, 2, dims); + + defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0); + CRASSERT(defaultMural); + mural->gX = 0; + mural->gY = 0; + mural->width = dims[0]; + mural->height = dims[1]; + + mural->spuWindow = spuWindow; + mural->screenId = 0; + mural->fHasParentWindow = !!cr_server.screen[0].winID; + mural->bVisible = !cr_server.bWindowsInitiallyHidden; + + mural->cVisibleRects = 0; + mural->pVisibleRects = NULL; + mural->bReceivedRects = GL_FALSE; + + /* generate ID for this new window/mural (special-case for file conns) */ + if (cr_server.curClient && cr_server.curClient->conn->type == CR_FILE) + windowID = spuWindow; + else + windowID = preloadWinID<0 ? (GLint)crHashtableAllocKeys( cr_server.muralTable, 1 ) : preloadWinID; + + mural->CreateInfo.realVisualBits = realVisBits; + mural->CreateInfo.requestedVisualBits = visBits; + mural->CreateInfo.externalID = windowID; + mural->CreateInfo.pszDpyName = dpyName ? crStrdup(dpyName) : NULL; + + CR_STATE_SHAREDOBJ_USAGE_INIT(mural); + + return windowID; +} + +GLint crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID) { CRMuralInfo *mural; GLint windowID = -1; - GLint spuWindow; - GLint dims[2]; - CRCreateInfo_t *pCreateInfo; + + dpyName = ""; if (cr_server.sharedWindows) { int pos, j; @@ -54,58 +127,30 @@ crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preload } } - /* - * Have first SPU make a new window. - */ - spuWindow = cr_server.head_spu->dispatch_table.WindowCreate( dpyName, visBits ); - if (spuWindow < 0) { - crServerReturnValue( &spuWindow, sizeof(spuWindow) ); - return spuWindow; - } - - /* get initial window size */ - cr_server.head_spu->dispatch_table.GetChromiumParametervCR(GL_WINDOW_SIZE_CR, spuWindow, GL_INT, 2, dims); /* * Create a new mural for the new window. */ mural = (CRMuralInfo *) crCalloc(sizeof(CRMuralInfo)); - if (mural) { - CRMuralInfo *defaultMural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, 0); - CRASSERT(defaultMural); - mural->gX = 0; - mural->gY = 0; - mural->width = dims[0]; - mural->height = dims[1]; - - mural->spuWindow = spuWindow; - mural->screenId = 0; - mural->bVisible = GL_FALSE; - mural->bUseFBO = GL_FALSE; - - mural->cVisibleRects = 0; - mural->pVisibleRects = NULL; - mural->bReceivedRects = GL_FALSE; - - mural->pvOutputRedirectInstance = NULL; - - /* generate ID for this new window/mural (special-case for file conns) */ - if (cr_server.curClient && cr_server.curClient->conn->type == CR_FILE) - windowID = spuWindow; - else - windowID = preloadWinID<0 ? crServerGenerateID(&cr_server.idsPool.freeWindowID) : preloadWinID; - crHashtableAdd(cr_server.muralTable, windowID, mural); - - pCreateInfo = (CRCreateInfo_t *) crAlloc(sizeof(CRCreateInfo_t)); - pCreateInfo->pszDpyName = dpyName ? crStrdup(dpyName) : NULL; - pCreateInfo->visualBits = visBits; - crHashtableAdd(cr_server.pWindowCreateInfoTable, windowID, pCreateInfo); + if (!mural) + { + crWarning("crCalloc failed!"); + return -1; + } - crServerSetupOutputRedirect(mural); + windowID = crServerMuralInit(mural, GL_TRUE, visBits, preloadWinID); + if (windowID < 0) + { + crWarning("crServerMuralInit failed!"); + crServerReturnValue( &windowID, sizeof(windowID) ); + crFree(mural); + return windowID; } + crHashtableAdd(cr_server.muralTable, windowID, mural); + crDebug("CRServer: client %p created new window %d (SPU window %d)", - cr_server.curClient, windowID, spuWindow); + cr_server.curClient, windowID, mural->spuWindow); if (windowID != -1 && !cr_server.bIsInLoadingState) { int pos; @@ -117,6 +162,9 @@ crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preload } } + /* ensure we have a dummy mural created right away to avoid potential deadlocks on VM shutdown */ + crServerGetDummyMural(mural->CreateInfo.realVisualBits); + crServerReturnValue( &windowID, sizeof(windowID) ); return windowID; } @@ -137,6 +185,65 @@ static int crServerRemoveClientWindow(CRClient *pClient, GLint window) return false; } +void crServerMuralTerm(CRMuralInfo *mural) +{ + PCR_BLITTER pBlitter; + crServerRedirMuralFBO(mural, false); + crServerDeleteMuralFBO(mural); + + if (cr_server.currentMural == mural) + { + CRMuralInfo *dummyMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); + /* reset the current context to some dummy values to ensure render spu does not switch to a default "0" context, + * which might lead to muralFBO (offscreen rendering) gl entities being created in a scope of that context */ + cr_server.head_spu->dispatch_table.MakeCurrent(dummyMural->spuWindow, 0, cr_server.MainContextInfo.SpuContext); + cr_server.currentWindow = -1; + cr_server.currentMural = dummyMural; + } + else + { + CRASSERT(cr_server.currentWindow != mural->CreateInfo.externalID); + } + + pBlitter = crServerVBoxBlitterGetInitialized(); + if (pBlitter) + { + const CR_BLITTER_WINDOW * pWindow = CrBltMuralGetCurrentInfo(pBlitter); + if (pWindow && pWindow->Base.id == mural->spuWindow) + { + CRMuralInfo *dummy = crServerGetDummyMural(mural->CreateInfo.realVisualBits); + CR_BLITTER_WINDOW DummyInfo; + CRASSERT(dummy); + crServerVBoxBlitterWinInit(&DummyInfo, dummy); + CrBltMuralSetCurrentInfo(pBlitter, &DummyInfo); + } + } + + if (!mural->fIsDummyRefference) + cr_server.head_spu->dispatch_table.WindowDestroy( mural->spuWindow ); + + mural->spuWindow = 0; + + if (mural->pVisibleRects) + { + crFree(mural->pVisibleRects); + } + + if (mural->CreateInfo.pszDpyName) + crFree(mural->CreateInfo.pszDpyName); + + crServerRedirMuralFbClear(mural); +} + +static void crServerCleanupCtxMuralRefsCB(unsigned long key, void *data1, void *data2) +{ + CRContextInfo *ctxInfo = (CRContextInfo *) data1; + CRMuralInfo *mural = (CRMuralInfo *) data2; + + if (ctxInfo->currentMural == mural) + ctxInfo->currentMural = NULL; +} + void SERVER_DISPATCH_APIENTRY crServerDispatchWindowDestroy( GLint window ) { @@ -157,22 +264,13 @@ crServerDispatchWindowDestroy( GLint window ) return; } - if (mural->pvOutputRedirectInstance) - { - cr_server.outputRedirect.CROREnd(mural->pvOutputRedirectInstance); - mural->pvOutputRedirectInstance = NULL; - } + crDebug("CRServer: Destroying window %d (spu window %d)", window, mural->spuWindow); - if (cr_server.currentWindow == window) - { - cr_server.currentWindow = -1; - } + crHashtableWalk(cr_server.contextTable, crServerCleanupCtxMuralRefsCB, mural); - crServerRedirMuralFBO(mural, GL_FALSE); - crServerDeleteMuralFBO(mural); + crServerMuralTerm(mural); - crDebug("CRServer: Destroying window %d (spu window %d)", window, mural->spuWindow); - cr_server.head_spu->dispatch_table.WindowDestroy( mural->spuWindow ); + CRASSERT(cr_server.currentWindow != window); if (cr_server.curClient) { @@ -233,13 +331,29 @@ crServerDispatchWindowDestroy( GLint window ) pNode = pNode->next; } - crHashtableDelete(cr_server.pWindowCreateInfoTable, window, crServerCreateInfoDeleteCB); + crHashtableDelete(cr_server.muralTable, window, crFree); - if (mural->pVisibleRects) + crServerCheckAllMuralGeometry(NULL); +} + +GLboolean crServerMuralSize(CRMuralInfo *mural, GLint width, GLint height) +{ + if (mural->width == width && mural->height == height) + return GL_FALSE; + + mural->width = width; + mural->height = height; + + if (cr_server.curClient && cr_server.curClient->currentMural == mural + && !mural->fRedirected) { - crFree(mural->pVisibleRects); + crStateGetCurrent()->buffer.width = mural->width; + crStateGetCurrent()->buffer.height = mural->height; } - crHashtableDelete(cr_server.muralTable, window, crFree); + + crServerCheckAllMuralGeometry(mural); + + return GL_TRUE; } void SERVER_DISPATCH_APIENTRY @@ -256,60 +370,40 @@ crServerDispatchWindowSize( GLint window, GLint width, GLint height ) return; } - mural->width = width; - mural->height = height; + crServerMuralSize(mural, width, height); - if (cr_server.curClient && cr_server.curClient->currentMural == mural) + if (cr_server.currentMural == mural) { - crStateGetCurrent()->buffer.width = mural->width; - crStateGetCurrent()->buffer.height = mural->height; + crServerPerformMakeCurrent( mural, cr_server.currentCtxInfo ); } +} - crServerCheckMuralGeometry(mural); +void crServerMuralPosition(CRMuralInfo *mural, GLint x, GLint y) +{ + if (mural->gX == x && mural->gY == y) + return; - cr_server.head_spu->dispatch_table.WindowSize(mural->spuWindow, width, height); + mural->gX = x; + mural->gY = y; - /* Work-around Intel driver bug */ - CRASSERT(!cr_server.curClient - || !cr_server.curClient->currentMural - || cr_server.curClient->currentMural == mural); - if (cr_server.curClient && cr_server.curClient->currentMural == mural) - { - CRContextInfo * ctxInfo = cr_server.currentCtxInfo; - CRASSERT(ctxInfo); - crServerDispatchMakeCurrent(mural->spuWindow, 0, ctxInfo->CreateInfo.externalID); - } + crServerCheckAllMuralGeometry(mural); } - void SERVER_DISPATCH_APIENTRY crServerDispatchWindowPosition( GLint window, GLint x, GLint y ) { CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window); - /* crDebug("CRServer: Window %d pos %d, %d", window, x, y);*/ if (!mural) { #if EXTRA_WARN crWarning("CRServer: invalid window %d passed to WindowPosition()", window); #endif return; } - mural->gX = x; - mural->gY = y; - - crServerCheckMuralGeometry(mural); + crServerMuralPosition(mural, x, y); } -void SERVER_DISPATCH_APIENTRY -crServerDispatchWindowVisibleRegion( GLint window, GLint cRects, GLint *pRects ) +void crServerMuralVisibleRegion( CRMuralInfo *mural, GLint cRects, const GLint *pRects ) { - CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window); - if (!mural) { -#if EXTRA_WARN - crWarning("CRServer: invalid window %d passed to WindowVisibleRegion()", window); -#endif - return; - } - if (mural->pVisibleRects) { crFree(mural->pVisibleRects); @@ -328,17 +422,35 @@ crServerDispatchWindowVisibleRegion( GLint window, GLint cRects, GLint *pRects ) crMemcpy(mural->pVisibleRects, pRects, 4*sizeof(GLint)*cRects); } - cr_server.head_spu->dispatch_table.WindowVisibleRegion(mural->spuWindow, cRects, pRects); + crServerCheckAllMuralGeometry(mural); +} - if (mural->pvOutputRedirectInstance) - { - /* @todo the code assumes that RTRECT == four GLInts. */ - cr_server.outputRedirect.CRORVisibleRegion(mural->pvOutputRedirectInstance, - cRects, (RTRECT *)pRects); +void SERVER_DISPATCH_APIENTRY +crServerDispatchWindowVisibleRegion( GLint window, GLint cRects, const GLint *pRects ) +{ + CRMuralInfo *mural = (CRMuralInfo *) crHashtableSearch(cr_server.muralTable, window); + if (!mural) { +#if EXTRA_WARN + crWarning("CRServer: invalid window %d passed to WindowVisibleRegion()", window); +#endif + return; } + + crServerMuralVisibleRegion( mural, cRects, pRects ); } +void crServerMuralShow( CRMuralInfo *mural, GLint state ) +{ + if (!mural->bVisible == !state) + return; + mural->bVisible = !!state; + + if (mural->bVisible) + crServerCheckMuralGeometry(mural); + else + crServerCheckAllMuralGeometry(mural); +} void SERVER_DISPATCH_APIENTRY crServerDispatchWindowShow( GLint window, GLint state ) @@ -351,15 +463,9 @@ crServerDispatchWindowShow( GLint window, GLint state ) return; } - if (!mural->bUseFBO) - { - cr_server.head_spu->dispatch_table.WindowShow(mural->spuWindow, state); - } - - mural->bVisible = state; + crServerMuralShow( mural, state ); } - GLint crServerSPUWindowID(GLint serverWindow) { |
