1/* $Id: vbva.c,v 1.2 2020/10/22 20:47:23 thorpej Exp $ */ 2/** @file 3 * VirtualBox X11 Additions graphics driver 2D acceleration functions 4 */ 5 6/* 7 * Copyright (C) 2006-2017 Oracle Corporation 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28#if defined(IN_XF86_MODULE) && !defined(NO_ANSIC) 29# include "xf86_ansic.h" 30#endif 31#include "compiler.h" 32 33#include "vboxvideo_drv.h" 34 35#ifdef XORG_7X 36# include <stdlib.h> 37# include <string.h> 38#endif 39 40/************************************************************************** 41* Main functions * 42**************************************************************************/ 43 44/** 45 * Callback function called by the X server to tell us about dirty 46 * rectangles in the video buffer. 47 * 48 * @param pScrn pointer to the information structure for the current 49 * screen 50 * @param iRects Number of dirty rectangles to update 51 * @param aRects Array of structures containing the coordinates of the 52 * rectangles 53 */ 54void vbvxHandleDirtyRect(ScrnInfoPtr pScrn, int iRects, BoxPtr aRects) 55{ 56 VBVACMDHDR cmdHdr; 57 VBOXPtr pVBox; 58 int i; 59 unsigned j; 60 61 pVBox = pScrn->driverPrivate; 62 if (!pScrn->vtSema) 63 return; 64 65 for (j = 0; j < pVBox->cScreens; ++j) 66 { 67 /* Just continue quietly if VBVA is not currently active. */ 68 struct VBVABUFFER *pVBVA = pVBox->pScreens[j].aVbvaCtx.pVBVA; 69 if ( !pVBVA 70 || !(pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED)) 71 continue; 72 for (i = 0; i < iRects; ++i) 73 { 74 if ( aRects[i].x1 > pVBox->pScreens[j].aScreenLocation.x 75 + pVBox->pScreens[j].aScreenLocation.cx 76 || aRects[i].y1 > pVBox->pScreens[j].aScreenLocation.y 77 + pVBox->pScreens[j].aScreenLocation.cy 78 || aRects[i].x2 < pVBox->pScreens[j].aScreenLocation.x 79 || aRects[i].y2 < pVBox->pScreens[j].aScreenLocation.y) 80 continue; 81 cmdHdr.x = (int16_t)aRects[i].x1 - pVBox->pScreens[0].aScreenLocation.x; 82 cmdHdr.y = (int16_t)aRects[i].y1 - pVBox->pScreens[0].aScreenLocation.y; 83 cmdHdr.w = (uint16_t)(aRects[i].x2 - aRects[i].x1); 84 cmdHdr.h = (uint16_t)(aRects[i].y2 - aRects[i].y1); 85 86#if 0 87 TRACE_LOG("display=%u, x=%d, y=%d, w=%d, h=%d\n", 88 j, cmdHdr.x, cmdHdr.y, cmdHdr.w, cmdHdr.h); 89#endif 90 91 if (VBoxVBVABufferBeginUpdate(&pVBox->pScreens[j].aVbvaCtx, 92 &pVBox->guestCtx)) 93 { 94 VBoxVBVAWrite(&pVBox->pScreens[j].aVbvaCtx, &pVBox->guestCtx, &cmdHdr, 95 sizeof(cmdHdr)); 96 VBoxVBVABufferEndUpdate(&pVBox->pScreens[j].aVbvaCtx); 97 } 98 } 99 } 100} 101 102static DECLCALLBACK(void *) hgsmiEnvAlloc(void *pvEnv, HGSMISIZE cb) 103{ 104 RT_NOREF(pvEnv); 105 return calloc(1, cb); 106} 107 108static DECLCALLBACK(void) hgsmiEnvFree(void *pvEnv, void *pv) 109{ 110 RT_NOREF(pvEnv); 111 free(pv); 112} 113 114static HGSMIENV g_hgsmiEnv = 115{ 116 NULL, 117 hgsmiEnvAlloc, 118 hgsmiEnvFree 119}; 120 121/** 122 * Calculate the location in video RAM of and initialise the heap for guest to 123 * host messages. 124 */ 125void vbvxSetUpHGSMIHeapInGuest(VBOXPtr pVBox, uint32_t cbVRAM) 126{ 127 int rc; 128 uint32_t offVRAMBaseMapping, offGuestHeapMemory, cbGuestHeapMemory; 129 void *pvGuestHeapMemory; 130 131 VBoxHGSMIGetBaseMappingInfo(cbVRAM, &offVRAMBaseMapping, NULL, &offGuestHeapMemory, &cbGuestHeapMemory, NULL); 132 pvGuestHeapMemory = ((uint8_t *)pVBox->base) + offVRAMBaseMapping + offGuestHeapMemory; 133 rc = VBoxHGSMISetupGuestContext(&pVBox->guestCtx, pvGuestHeapMemory, cbGuestHeapMemory, 134 offVRAMBaseMapping + offGuestHeapMemory, &g_hgsmiEnv); 135 AssertMsg(RT_SUCCESS(rc), ("Failed to set up the guest-to-host message buffer heap, rc=%d\n", rc)); 136 pVBox->cbView = offVRAMBaseMapping; 137} 138 139/** Callback to fill in the view structures */ 140static DECLCALLBACK(int) vboxFillViewInfo(void *pvVBox, struct VBVAINFOVIEW *pViews, uint32_t cViews) 141{ 142 VBOXPtr pVBox = (VBOXPtr)pvVBox; 143 unsigned i; 144 for (i = 0; i < cViews; ++i) 145 { 146 pViews[i].u32ViewIndex = i; 147 pViews[i].u32ViewOffset = 0; 148 pViews[i].u32ViewSize = pVBox->cbView; 149 pViews[i].u32MaxScreenSize = pVBox->cbFBMax; 150 } 151 return VINF_SUCCESS; 152} 153 154/** 155 * Initialise VirtualBox's accelerated video extensions. 156 * 157 * @returns TRUE on success, FALSE on failure 158 */ 159static Bool vboxSetupVRAMVbva(VBOXPtr pVBox) 160{ 161 int rc = VINF_SUCCESS; 162 unsigned i; 163 164 pVBox->cbFBMax = pVBox->cbView; 165 for (i = 0; i < pVBox->cScreens; ++i) 166 { 167 pVBox->cbFBMax -= VBVA_MIN_BUFFER_SIZE; 168 pVBox->pScreens[i].aoffVBVABuffer = pVBox->cbFBMax; 169 TRACE_LOG("VBVA buffer offset for screen %u: 0x%lx\n", i, 170 (unsigned long) pVBox->cbFBMax); 171 VBoxVBVASetupBufferContext(&pVBox->pScreens[i].aVbvaCtx, 172 pVBox->pScreens[i].aoffVBVABuffer, 173 VBVA_MIN_BUFFER_SIZE); 174 } 175 TRACE_LOG("Maximum framebuffer size: %lu (0x%lx)\n", 176 (unsigned long) pVBox->cbFBMax, 177 (unsigned long) pVBox->cbFBMax); 178 rc = VBoxHGSMISendViewInfo(&pVBox->guestCtx, pVBox->cScreens, 179 vboxFillViewInfo, (void *)pVBox); 180 AssertMsg(RT_SUCCESS(rc), ("Failed to send the view information to the host, rc=%d\n", rc)); 181 return TRUE; 182} 183 184static Bool haveHGSMIModeHintAndCursorReportingInterface(VBOXPtr pVBox) 185{ 186 uint32_t fModeHintReporting, fCursorReporting; 187 188 return RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_MODE_HINT_REPORTING, &fModeHintReporting)) 189 && RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING, &fCursorReporting)) 190 && fModeHintReporting == VINF_SUCCESS 191 && fCursorReporting == VINF_SUCCESS; 192} 193 194static Bool hostHasScreenBlankingFlag(VBOXPtr pVBox) 195{ 196 uint32_t fScreenFlags; 197 198 return RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->guestCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, &fScreenFlags)) 199 && fScreenFlags & VBVA_SCREEN_F_BLANK; 200} 201 202/** 203 * Inform VBox that we will supply it with dirty rectangle information 204 * and install the dirty rectangle handler. 205 * 206 * @returns TRUE for success, FALSE for failure 207 * @param pScrn Pointer to a structure describing the X screen in use 208 */ 209Bool 210vboxEnableVbva(ScrnInfoPtr pScrn) 211{ 212 Bool rc = TRUE; 213 unsigned i; 214 VBOXPtr pVBox = pScrn->driverPrivate; 215 216 TRACE_ENTRY(); 217 if (!vboxSetupVRAMVbva(pVBox)) 218 return FALSE; 219 for (i = 0; i < pVBox->cScreens; ++i) 220 { 221 struct VBVABUFFER *pVBVA; 222 223 pVBVA = (struct VBVABUFFER *) ( ((uint8_t *)pVBox->base) 224 + pVBox->pScreens[i].aoffVBVABuffer); 225 if (!VBoxVBVAEnable(&pVBox->pScreens[i].aVbvaCtx, &pVBox->guestCtx, 226 pVBVA, i)) 227 rc = FALSE; 228 } 229 AssertMsg(rc, ("Failed to enable screen update reporting for at least one virtual monitor.\n")); 230 pVBox->fHaveHGSMIModeHints = haveHGSMIModeHintAndCursorReportingInterface(pVBox); 231 pVBox->fHostHasScreenBlankingFlag = hostHasScreenBlankingFlag(pVBox); 232 return rc; 233} 234 235/** 236 * Inform VBox that we will stop supplying it with dirty rectangle 237 * information. This function is intended to be called when an X 238 * virtual terminal is disabled, or the X server is terminated. 239 * 240 * @returns TRUE for success, FALSE for failure 241 * @param pScrn Pointer to a structure describing the X screen in use 242 */ 243void 244vboxDisableVbva(ScrnInfoPtr pScrn) 245{ 246 unsigned i; 247 VBOXPtr pVBox = pScrn->driverPrivate; 248 249 TRACE_ENTRY(); 250 for (i = 0; i < pVBox->cScreens; ++i) 251 VBoxVBVADisable(&pVBox->pScreens[i].aVbvaCtx, &pVBox->guestCtx, i); 252} 253