summaryrefslogtreecommitdiff
path: root/src/VBox/HostServices/SharedOpenGL/crserverlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostServices/SharedOpenGL/crserverlib')
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/get_components.py144
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/get_sizes.py40
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server.h585
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_bufferobject.c14
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_clear.c52
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_config.c129
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_context.c264
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch.py11
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_dispatch_header.py13
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_framebuffer.c59
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_get.py4
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_getshaders.c38
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_glsl.c55
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_lists.c41
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_main.c2411
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_misc.c1062
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.c591
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_muralfbo.cpp840
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_presenter.cpp4787
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_retval.py2
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_rpw.cpp755
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_simpleget.py31
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_special15
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_stream.c26
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_texture.c53
-rw-r--r--src/VBox/HostServices/SharedOpenGL/crserverlib/server_window.c328
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], &sectr))
- {
- 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, &sectr, 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)
{