71 m_Framebuffer(
nullptr),
72 m_CommandRegion(
nullptr),
73 m_pFramebuffer(
nullptr),
80 m_CommandRegionSize(0),
82 m_HardwareAccepted(
false),
86 m_ProviderRegistered(
false),
87 m_ShutdownComplete(
false) {}
96 if (!initialiseHardwareLocked()) {
97 disableHardwareLocked();
103 if (!m_pFramebuffer || !m_pProvider) {
104 markOfflineLocked(
"could not allocate provider state");
108 m_pProvider->pDisplay =
this;
109 m_pProvider->pFramebuffer = m_pFramebuffer;
110 m_pProvider->maxWidth = m_MaxWidth;
111 m_pProvider->maxHeight = m_MaxHeight;
112 m_pProvider->maxTextWidth = 0;
113 m_pProvider->maxTextHeight = 0;
114 m_pProvider->maxDepth = 32;
115 m_pProvider->bHardwareAccel = m_Capabilities & SVGA_CAP_RECT_COPY;
120 if (!registerProvider()) {
122 markOfflineLocked(
"could not register with the graphics service");
130 str.assign(
"vmware-gfx", 11);
134 str.assign(
"vmware guest tools, graphics card", 34);
141 if (!availableLocked())
144 sm.width = readRegisterLocked(SVGA_REG_WIDTH);
145 sm.height = readRegisterLocked(SVGA_REG_HEIGHT);
146 sm.pf.
nBpp = readRegisterLocked(SVGA_REG_BITS_PER_PIXEL);
148 const uint32_t redMask = readRegisterLocked(SVGA_REG_RED_MASK);
149 const uint32_t greenMask = readRegisterLocked(SVGA_REG_GREEN_MASK);
150 const uint32_t blueMask = readRegisterLocked(SVGA_REG_BLUE_MASK);
151 sm.pf2 = pixelFormat(sm.pf.
nBpp, redMask, greenMask, blueMask);
152 sm.bytesPerPixel = (sm.pf.
nBpp + 7) / 8;
153 sm.bytesPerLine = readRegisterLocked(SVGA_REG_BYTES_PER_LINE);
161 if (!availableLocked())
164 for (
size_t i = 0; i < ModeCount; ++i) {
166 pMode->id = g_Modes[i].id;
167 pMode->width = g_Modes[i].width;
168 pMode->height = g_Modes[i].height;
169 pMode->pf2 = g_Modes[i].format;
180 if (!availableLocked())
184 disableDisplayLocked();
188 if (!setModeLocked(sm.width, sm.height, Graphics::bitsPerPixel(sm.pf2)))
200 const bool available = availableLocked();
202 disableDisplayLocked();
209 if (!availableLocked())
211 disableDisplayLocked();
222 if (!availableLocked())
225 if (width > m_MaxWidth)
227 if (height > m_MaxHeight)
228 height = m_MaxHeight;
229 return setModeLocked(width, height, bpp);
232 bool redraw(
size_t x,
size_t y,
size_t width,
size_t height) {
236 if (!availableLocked() || !m_FifoRunning || !m_pFramebuffer)
239 const size_t screenWidth = m_pFramebuffer->getWidth();
240 const size_t screenHeight = m_pFramebuffer->getHeight();
241 if ((x >= screenWidth) || (y >= screenHeight))
243 if (width > (screenWidth - x))
244 width = screenWidth - x;
245 if (height > (screenHeight - y))
246 height = screenHeight - y;
247 if (!width || !height)
250 const uint32_t command[] = {SVGA_CMD_UPDATE,
static_cast<uint32_t
>(x),
static_cast<uint32_t
>(y),
251 static_cast<uint32_t
>(width),
static_cast<uint32_t
>(height)};
252 return submitFifoLocked(command,
sizeof(command) /
sizeof(command[0]));
255 bool copy(
size_t sourceX,
size_t sourceY,
size_t destinationX,
size_t destinationY,
size_t width,
256 size_t height,
bool softwareFallback) {
260 if (!availableLocked() || !m_pFramebuffer || !m_pFramebuffer->getActive())
263 const size_t screenWidth = m_pFramebuffer->getWidth();
264 const size_t screenHeight = m_pFramebuffer->getHeight();
265 if ((sourceX >= screenWidth) || (destinationX >= screenWidth) || (sourceY >= screenHeight) ||
266 (destinationY >= screenHeight))
269 if (width > (screenWidth - sourceX))
270 width = screenWidth - sourceX;
271 if (width > (screenWidth - destinationX))
272 width = screenWidth - destinationX;
273 if (height > (screenHeight - sourceY))
274 height = screenHeight - sourceY;
275 if (height > (screenHeight - destinationY))
276 height = screenHeight - destinationY;
277 if (!width || !height)
280 if (m_FifoRunning && (m_Capabilities & SVGA_CAP_RECT_COPY)) {
281 const uint32_t command[] = {SVGA_CMD_RECT_COPY,
282 static_cast<uint32_t
>(sourceX),
283 static_cast<uint32_t
>(sourceY),
284 static_cast<uint32_t
>(destinationX),
285 static_cast<uint32_t
>(destinationY),
286 static_cast<uint32_t
>(width),
287 static_cast<uint32_t
>(height)};
288 if (submitFifoLocked(command,
sizeof(command) /
sizeof(command[0])))
290 if (!availableLocked())
294 if (!softwareFallback)
296 m_pFramebuffer->softwareCopy(sourceX, sourceY, destinationX, destinationY, width, height);
303 :
Framebuffer(), m_CallbackOperations(), m_pDisplay(pDisplay) {
304 setFramebuffer(framebuffer);
309 void closeCallbacks() {
310 m_CallbackOperations.
close();
314 m_CallbackOperations.
wait();
315 m_pDisplay =
nullptr;
320 virtual void hwRedraw(
size_t x = ~0UL,
size_t y = ~0UL,
size_t width = ~0UL,
321 size_t height = ~0UL) {
325 if (!m_CallbackOperations.
tryAcquire(callback))
333 m_pDisplay->redraw(x, y, width, height);
336 virtual void copy(
size_t sourceX,
size_t sourceY,
size_t destinationX,
size_t destinationY,
337 size_t width,
size_t height,
bool bLowestCall =
true) {
341 if (!m_CallbackOperations.
tryAcquire(callback))
344 m_pDisplay->copy(sourceX, sourceY, destinationX, destinationY, width, height, bLowestCall);
347 void softwareCopy(
size_t sourceX,
size_t sourceY,
size_t destinationX,
size_t destinationY,
348 size_t width,
size_t height) {
349 swCopy(sourceX, sourceY, destinationX, destinationY, width, height);
358 bool availableLocked()
const {
359 return m_Online && !m_Stopping;
362 static Graphics::PixelFormat pixelFormat(
size_t bpp, uint32_t redMask, uint32_t greenMask,
366 return redMask > blueMask ? Graphics::Bits24_Rgb : Graphics::Bits24_Bgr;
368 if ((redMask == greenMask) && (greenMask == blueMask)) {
369 return blueMask == 0xF ? Graphics::Bits16_Argb : Graphics::Bits16_Rgb555;
371 return Graphics::Bits16_Rgb565;
373 return Graphics::Bits32_Argb;
377 bool initialiseHardwareLocked() {
379 WARNING(
"vmware-gfx has an incomplete PCI BAR set");
384 WARNING(
"vmware-gfx has no register I/O BAR");
389 if (!m_pIo || !(*m_pIo)) {
390 WARNING(
"vmware-gfx has no usable register I/O BAR");
394 writeRegisterLocked(SVGA_REG_ID, SVGA_MAKE_ID(2));
395 if (readRegisterLocked(SVGA_REG_ID) != SVGA_MAKE_ID(2)) {
396 WARNING(
"vmware-gfx is not a compatible SVGA2 device");
399 m_HardwareAccepted =
true;
401 const uintptr_t fbBase = readRegisterLocked(SVGA_REG_FB_START);
402 const size_t vramSize = readRegisterLocked(SVGA_REG_VRAM_SIZE);
403 const size_t framebufferSize = readRegisterLocked(SVGA_REG_FB_SIZE);
404 const uintptr_t commandBase = readRegisterLocked(SVGA_REG_MEM_START);
405 const size_t commandSize = readRegisterLocked(SVGA_REG_MEM_SIZE);
406 m_Capabilities = readRegisterLocked(SVGA_REG_CAPABILITIES);
407 m_MaxWidth = readRegisterLocked(SVGA_REG_MAX_WIDTH);
408 m_MaxHeight = readRegisterLocked(SVGA_REG_MAX_HEIGHT);
417 pFramebufferAddress = pAddress;
419 pCommandAddress = pAddress;
422 if (!pFramebufferAddress || !pCommandAddress || (pFramebufferAddress == pCommandAddress) ||
423 !pFramebufferAddress->
m_Io || !pCommandAddress->
m_Io || !m_MaxWidth || !m_MaxHeight ||
424 !commandSize || (commandSize > pCommandAddress->
m_Size) ||
425 (commandSize >
static_cast<size_t>(~
static_cast<uint32_t
>(0)))) {
426 WARNING(
"vmware-gfx reported an invalid framebuffer/FIFO layout");
432 m_FramebufferSize = pFramebufferAddress->
m_Size;
433 if (framebufferSize && (framebufferSize < m_FramebufferSize))
434 m_FramebufferSize = framebufferSize;
435 m_CommandRegionSize = commandSize;
436 if (!m_FramebufferSize) {
437 WARNING(
"vmware-gfx reported an empty framebuffer aperture");
443 pFramebufferAddress->
map(m_FramebufferSize,
true,
true);
444 if (!m_Framebuffer->
virtualAddress() || (m_Framebuffer->
size() < m_FramebufferSize)) {
445 WARNING(
"vmware-gfx could not map its framebuffer aperture");
449 pCommandAddress->
map(m_CommandRegionSize);
450 if (!m_CommandRegion->
virtualAddress() || (m_CommandRegion->
size() < m_CommandRegionSize)) {
451 WARNING(
"vmware-gfx could not map its FIFO aperture");
455 uint32_t fifoMin = 4 *
sizeof(uint32_t);
456 const uint32_t fifoMax =
static_cast<uint32_t
>(commandSize) & ~
static_cast<uint32_t
>(3);
457 if (m_Capabilities & SVGA_CAP_EXTENDED_FIFO) {
458 const size_t fifoRegisters = readRegisterLocked(SVGA_REG_MEM_REGS);
459 if ((fifoRegisters < SVGA_FIFO_NUM_REGS) ||
460 (fifoRegisters > (
static_cast<size_t>(~
static_cast<uint32_t
>(0)) /
sizeof(uint32_t)))) {
461 WARNING(
"vmware-gfx reported an invalid extended FIFO header");
464 fifoMin =
static_cast<uint32_t
>(fifoRegisters *
sizeof(uint32_t));
467 if ((fifoMax <= fifoMin) || ((fifoMax - fifoMin) < MinimumFifoBytes)) {
468 WARNING(
"vmware-gfx FIFO is too small for supported commands");
471 m_FifoHeaderBytes = fifoMin;
473 disableDisplayLocked();
474 volatile uint32_t* fifo = fifoLocked();
475 fifo[SVGA_FIFO_MIN] = fifoMin;
476 fifo[SVGA_FIFO_MAX] = fifoMax;
477 fifo[SVGA_FIFO_NEXT_CMD] = fifoMin;
478 fifo[SVGA_FIFO_STOP] = fifoMin;
479 asm volatile(
"" : : :
"memory");
481 writeRegisterLocked(SVGA_REG_GUEST_ID, 0x500A);
482 NOTICE(
"vmware-gfx found, caps=" <<
Hex << m_Capabilities <<
", maximum resolution is " <<
Dec
483 << m_MaxWidth <<
"x" << m_MaxHeight <<
Hex);
484 NOTICE(
"vmware-gfx framebuffer at " <<
Hex << fbBase <<
" - " << (fbBase + vramSize)
485 <<
", command FIFO at " << commandBase);
486 if (m_Capabilities & SVGA_CAP_EXTENDED_FIFO) {
487 NOTICE(
"vmware-gfx using extended fifo, caps=" << fifo[SVGA_FIFO_CAPABILITIES]
488 <<
", flags=" << fifo[SVGA_FIFO_FLAGS]);
494 bool registerProvider() {
499 sizeof(*m_pProvider)))
503 m_ProviderRegistered =
true;
507 void unregisterProvider() {
511 if (!m_ProviderRegistered)
513 pProvider = m_pProvider;
520 sizeof(*pProvider))) {
521 panic(
"vmware-gfx could not withdraw its graphics provider");
525 m_ProviderRegistered =
false;
528 bool setModeLocked(
size_t width,
size_t height,
size_t bpp) {
529 if (!availableLocked() || !width || !height || !bpp || (width > m_MaxWidth) ||
530 (height > m_MaxHeight) || (bpp > 32))
533 if (m_FifoRunning && !syncFifoLocked()) {
534 markOfflineLocked(
"timed out draining FIFO before a mode change");
538 writeRegisterLocked(SVGA_REG_CONFIG_DONE, 0);
539 m_FifoRunning =
false;
540 writeRegisterLocked(SVGA_REG_ENABLE, 1);
541 writeRegisterLocked(SVGA_REG_WIDTH,
static_cast<uint32_t
>(width));
542 writeRegisterLocked(SVGA_REG_HEIGHT,
static_cast<uint32_t
>(height));
543 writeRegisterLocked(SVGA_REG_BITS_PER_PIXEL,
static_cast<uint32_t
>(bpp));
545 const size_t actualWidth = readRegisterLocked(SVGA_REG_WIDTH);
546 const size_t actualHeight = readRegisterLocked(SVGA_REG_HEIGHT);
547 const size_t actualDepth = readRegisterLocked(SVGA_REG_DEPTH);
548 const size_t fbOffset = readRegisterLocked(SVGA_REG_FB_OFFSET);
549 const uintptr_t fbBase = readRegisterLocked(SVGA_REG_FB_START);
550 const uint32_t redMask = readRegisterLocked(SVGA_REG_RED_MASK);
551 const uint32_t greenMask = readRegisterLocked(SVGA_REG_GREEN_MASK);
552 const uint32_t blueMask = readRegisterLocked(SVGA_REG_BLUE_MASK);
553 const size_t bytesPerLine = readRegisterLocked(SVGA_REG_BYTES_PER_LINE);
555 if (!actualWidth || !actualHeight || !bytesPerLine || (actualWidth > m_MaxWidth) ||
556 (actualHeight > m_MaxHeight) ||
557 (actualWidth > ((~
static_cast<size_t>(0) - 7) /
static_cast<size_t>(bpp))) ||
558 (bytesPerLine < ((actualWidth * bpp + 7) / 8)) ||
559 (actualHeight > (~
static_cast<size_t>(0) / bytesPerLine))) {
560 markOfflineLocked(
"device returned an invalid mode layout");
564 const size_t framebufferBytes = actualHeight * bytesPerLine;
565 if ((fbOffset > m_FramebufferSize) || (framebufferBytes > (m_FramebufferSize - fbOffset))) {
566 markOfflineLocked(
"mode exceeds the framebuffer aperture");
570 const size_t requiredMapping = fbOffset + framebufferBytes;
572 markOfflineLocked(
"could not map the complete framebuffer mode");
576 m_pFramebuffer->setWidth(actualWidth);
577 m_pFramebuffer->setHeight(actualHeight);
578 m_pFramebuffer->setBytesPerPixel((bpp + 7) / 8);
579 m_pFramebuffer->setBytesPerLine(bytesPerLine);
580 m_pFramebuffer->setFormat(pixelFormat(bpp, redMask, greenMask, blueMask));
581 m_pFramebuffer->setXPos(0);
582 m_pFramebuffer->setYPos(0);
583 m_pFramebuffer->setParent(
nullptr);
584 m_pFramebuffer->setFramebuffer(
reinterpret_cast<uintptr_t
>(m_Framebuffer->
virtualAddress()) +
586 m_pFramebuffer->setActive(
true);
587 m_pFramebuffer->
rect(0, 0, actualWidth, actualHeight, 0);
589 asm volatile(
"" : : :
"memory");
590 writeRegisterLocked(SVGA_REG_CONFIG_DONE, 1);
591 m_FifoRunning =
true;
592 NOTICE(
"vmware-gfx entered mode " <<
Dec << actualWidth <<
"x" << actualHeight <<
"x"
593 << actualDepth <<
Hex <<
", mode framebuffer is "
594 << (fbBase + fbOffset));
598 bool submitFifoLocked(
const uint32_t* pCommand,
size_t words) {
599 if (!availableLocked() || !m_FifoRunning || !pCommand || (words > LargestCommandWords))
603 if (!prepareFifoLocked(words, layout))
606 volatile uint32_t* fifo = fifoLocked();
607 uint32_t next = layout.next;
608 for (
size_t i = 0; i < words; ++i) {
609 fifo[next /
sizeof(uint32_t)] = pCommand[i];
610 next +=
sizeof(uint32_t);
611 if (next == layout.max)
616 asm volatile(
"" : : :
"memory");
617 fifo[SVGA_FIFO_NEXT_CMD] = next;
618 asm volatile(
"" : : :
"memory");
623 layout = readFifoLayoutLocked();
624 if (!VmwareSvgaState::valid(layout, m_FifoHeaderBytes, m_CommandRegionSize)) {
625 markOfflineLocked(
"device returned an invalid FIFO cursor");
628 if (VmwareSvgaState::canFit(layout, words))
631 if (!syncFifoLocked()) {
632 markOfflineLocked(
"timed out waiting for FIFO space");
636 layout = readFifoLayoutLocked();
637 if (!VmwareSvgaState::valid(layout, m_FifoHeaderBytes, m_CommandRegionSize) ||
638 !VmwareSvgaState::canFit(layout, words)) {
639 markOfflineLocked(
"FIFO remained full after a completed sync");
645 bool syncFifoLocked() {
646 writeRegisterLocked(SVGA_REG_SYNC, 1);
648 while (readRegisterLocked(SVGA_REG_BUSY)) {
649 if (!budget.keepPolling(Time::getTicks()))
657 volatile uint32_t* fifo = fifoLocked();
658 return {fifo[SVGA_FIFO_MIN], fifo[SVGA_FIFO_MAX], fifo[SVGA_FIFO_NEXT_CMD],
659 fifo[SVGA_FIFO_STOP]};
662 volatile uint32_t* fifoLocked()
const {
663 return reinterpret_cast<volatile uint32_t*
>(m_CommandRegion->
virtualAddress());
666 uint32_t readRegisterLocked(
size_t offset)
const {
667 m_pIo->
write32(
static_cast<uint32_t
>(offset), SVGA_INDEX_PORT);
668 return m_pIo->
read32(SVGA_VALUE_PORT);
671 void writeRegisterLocked(
size_t offset, uint32_t value)
const {
672 m_pIo->
write32(
static_cast<uint32_t
>(offset), SVGA_INDEX_PORT);
673 m_pIo->
write32(value, SVGA_VALUE_PORT);
676 void disableDisplayLocked() {
677 if (!m_HardwareAccepted)
679 writeRegisterLocked(SVGA_REG_CONFIG_DONE, 0);
680 writeRegisterLocked(SVGA_REG_ENABLE, 0);
681 m_FifoRunning =
false;
683 m_pFramebuffer->setActive(
false);
686 void disableHardwareLocked() {
687 disableDisplayLocked();
691 void markOfflineLocked(
const char* reason) {
692 WARNING(
"vmware-gfx offline: " << reason);
693 disableHardwareLocked();
699 VmwareFramebuffer* m_pFramebuffer;
702 uint32_t m_Capabilities;
705 size_t m_FramebufferSize;
706 size_t m_CommandRegionSize;
707 size_t m_FifoHeaderBytes;
708 bool m_HardwareAccepted;
712 bool m_ProviderRegistered;
713 bool m_ShutdownComplete;