summaryrefslogtreecommitdiff
path: root/xddm/display/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'xddm/display/driver.c')
-rw-r--r--xddm/display/driver.c1590
1 files changed, 1590 insertions, 0 deletions
diff --git a/xddm/display/driver.c b/xddm/display/driver.c
new file mode 100644
index 0000000..d7fdbf7
--- /dev/null
+++ b/xddm/display/driver.c
@@ -0,0 +1,1590 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This software is licensed under the GNU General Public License,
+ version 2 (GPLv2) (see COPYING for details), subject to the
+ following clarification.
+
+ With respect to binaries built using the Microsoft(R) Windows
+ Driver Kit (WDK), GPLv2 does not extend to any code contained in or
+ derived from the WDK ("WDK Code"). As to WDK Code, by using or
+ distributing such binaries you agree to be bound by the Microsoft
+ Software License Terms for the WDK. All WDK Code is considered by
+ the GPLv2 licensors to qualify for the special exception stated in
+ section 3 of GPLv2 (commonly known as the system library
+ exception).
+
+ There is NO WARRANTY for this software, express or implied,
+ including the implied warranties of NON-INFRINGEMENT, TITLE,
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+*/
+
+#include "stddef.h"
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "os_dep.h"
+
+#include "winerror.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "winddi.h"
+#include "devioctl.h"
+#include "ntddvdeo.h"
+
+#include "qxldd.h"
+#include "utils.h"
+#include "mspace.h"
+#include "res.h"
+#include "surface.h"
+
+#define DEVICE_NAME L"qxldd"
+
+#define QXLDD_DEBUG_PREFIX "qxldd: "
+
+static DRVFN drv_calls[] = {
+ {INDEX_DrvDisableDriver, (PFN)DrvDisableDriver},
+ {INDEX_DrvEscape, (PFN)DrvEscape},
+ {INDEX_DrvEnablePDEV, (PFN)DrvEnablePDEV},
+ {INDEX_DrvDisablePDEV, (PFN)DrvDisablePDEV},
+ {INDEX_DrvCompletePDEV, (PFN)DrvCompletePDEV},
+ {INDEX_DrvEnableSurface, (PFN)DrvEnableSurface},
+ {INDEX_DrvDisableSurface, (PFN)DrvDisableSurface},
+ {INDEX_DrvAssertMode, (PFN)DrvAssertMode},
+ {INDEX_DrvGetModes, (PFN)DrvGetModes},
+ {INDEX_DrvSynchronize, (PFN)DrvSynchronize},
+ {INDEX_DrvCopyBits, (PFN)DrvCopyBits},
+ {INDEX_DrvBitBlt, (PFN)DrvBitBlt},
+ {INDEX_DrvTextOut, (PFN)DrvTextOut},
+ {INDEX_DrvStrokePath, (PFN)DrvStrokePath},
+ {INDEX_DrvRealizeBrush, (PFN)DrvRealizeBrush},
+ {INDEX_DrvSetPointerShape, (PFN)DrvSetPointerShape},
+ {INDEX_DrvMovePointer, (PFN)DrvMovePointer},
+ {INDEX_DrvStretchBlt, (PFN)DrvStretchBlt},
+ {INDEX_DrvStretchBltROP, (PFN)DrvStretchBltROP},
+ {INDEX_DrvTransparentBlt, (PFN)DrvTransparentBlt},
+ {INDEX_DrvAlphaBlend, (PFN)DrvAlphaBlend},
+ {INDEX_DrvCreateDeviceBitmap, (PFN)DrvCreateDeviceBitmap},
+ {INDEX_DrvDeleteDeviceBitmap, (PFN)DrvDeleteDeviceBitmap},
+
+#ifdef CALL_TEST
+ {INDEX_DrvFillPath, (PFN)DrvFillPath},
+ {INDEX_DrvGradientFill, (PFN)DrvGradientFill},
+ {INDEX_DrvLineTo, (PFN)DrvLineTo},
+ {INDEX_DrvPlgBlt, (PFN)DrvPlgBlt},
+ {INDEX_DrvStrokeAndFillPath, (PFN)DrvStrokeAndFillPath},
+#endif
+};
+
+#ifdef CALL_TEST
+
+typedef struct CallCounter {
+ const char *name;
+ BOOL effective;
+} CallCounterInfo;
+
+static CallCounterInfo counters_info[NUM_CALL_COUNTERS] = {
+ { "DrvCopyBits", FALSE},
+ { "DrvBitBlt", TRUE},
+ { "DrvTextOut", TRUE},
+ { "DrvStrokePath", TRUE},
+ { "DrvStretchBlt", FALSE},
+ { "DrvStretchBltROP", TRUE},
+ { "TransparentBlt", FALSE},
+ { "DrvAlphaBlend", FALSE},
+
+ { "DrvFillPath", FALSE},
+ { "DrvGradientFill", FALSE},
+ { "DrvLineTo", FALSE},
+ { "DrvPlgBlt", FALSE},
+ { "DrvStrokeAndFillPath", FALSE},
+};
+
+#endif
+
+#define DBG_LEVEL 0
+
+void DebugPrintV(PDev *pdev, const char *message, va_list ap)
+{
+ if (pdev && pdev->log_buf) {
+ EngAcquireSemaphore(pdev->print_sem);
+ _snprintf(pdev->log_buf, QXL_LOG_BUF_SIZE, QXLDD_DEBUG_PREFIX);
+ _vsnprintf(pdev->log_buf + strlen(QXLDD_DEBUG_PREFIX),
+ QXL_LOG_BUF_SIZE - strlen(QXLDD_DEBUG_PREFIX), message, ap);
+ sync_io(pdev, pdev->log_port, 0);
+ EngReleaseSemaphore(pdev->print_sem);
+ } else {
+ EngDebugPrint(QXLDD_DEBUG_PREFIX, (PCHAR)message, ap);
+ }
+}
+
+void DebugPrint(PDev *pdev, int level, const char *message, ...)
+{
+ va_list ap;
+
+ if (level > (pdev && pdev->log_level ? (int)*pdev->log_level : DBG_LEVEL)) {
+ return;
+ }
+ va_start(ap, message);
+ DebugPrintV(pdev, message, ap);
+ va_end(ap);
+}
+
+#define DRIVER_VERSION 1
+#define OS_VERSION_MAJOR 5
+#define OS_VERSION_MINOR 0
+#define MK_GDIINFO_VERSION(os_major, os_minor, drv_vers) \
+ ((drv_vers) | ((os_minor) << 8) | ((os_major) << 12))
+
+
+GDIINFO gdi_default = {
+ MK_GDIINFO_VERSION(OS_VERSION_MAJOR, OS_VERSION_MINOR, DRIVER_VERSION),
+ DT_RASDISPLAY,
+ 0, //ulHorzSize
+ 0, //ulVertSize
+ 0, //ulHorzRes
+ 0, //ulVertRes
+ 0, //cBitsPixel
+ 0, //cPlanes
+ 0, //ulNumColors
+ 0, //flRaster
+ 0, //ulLogPixelsX
+ 0, //ulLogPixelsY
+ TC_RA_ABLE, //flTextCaps
+ 0, //ulDACRed
+ 0, //ulDACGreen
+ 0, //ulDACBlue
+ 0x0024, //ulAspectX
+ 0x0024, //ulAspectY
+ 0x0033, //ulAspectXY
+ 1, //xStyleStep
+ 1, //yStyleSte;
+ 3, //denStyleStep
+ { 0, 0}, //ptlPhysOffset
+ { 0, 0}, //szlPhysSize
+ 0, //ulNumPalReg
+
+ { //ciDevice
+ { 6700, 3300, 0}, //Red
+ { 2100, 7100, 0}, //Green
+ { 1400, 800, 0}, //Blue
+ { 1750, 3950, 0}, //Cyan
+ { 4050, 2050, 0}, //Magenta
+ { 4400, 5200, 0}, //Yellow
+ { 3127, 3290, 0}, //AlignmentWhite
+ 20000, //RedGamma
+ 20000, //GreenGamma
+ 20000, //BlueGamma
+ 0, 0, 0, 0, 0, 0 //No dye correction for raster displays
+ },
+
+ 0, //ulDevicePelsDPI
+ PRIMARY_ORDER_CBA, //ulPrimaryOrder
+ HT_PATSIZE_4x4_M, //ulHTPatternSize
+ HT_FORMAT_8BPP, //ulHTOutputFormat
+ HT_FLAG_ADDITIVE_PRIMS, //flHTFlags
+ 0, //ulVRefresh
+ 0, //ulPanningHorzRes
+ 0, //ulPanningVertRes
+ 0, //ulBltAlignment
+ //more
+};
+
+#define SYSTM_LOGFONT {16, 7, 0, 0, 700, 0, 0, 0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,\
+ CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,\
+ VARIABLE_PITCH | FF_DONTCARE, L"System"}
+#define HELVE_LOGFONT {12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,\
+ CLIP_STROKE_PRECIS, PROOF_QUALITY,\
+ VARIABLE_PITCH | FF_DONTCARE, L"MS Sans Serif"}
+#define COURI_LOGFONT {12, 9, 0, 0, 400, 0, 0, 0, ANSI_CHARSET,OUT_DEFAULT_PRECIS,\
+ CLIP_STROKE_PRECIS,PROOF_QUALITY,\
+ FIXED_PITCH | FF_DONTCARE, L"Courier"}
+
+DEVINFO dev_default = {
+ GCAPS_ARBRUSHOPAQUE | GCAPS_ARBRUSHTEXT | GCAPS_ASYNCMOVE | /* GCAPS_BEZIERS | */
+ GCAPS_GRAY16 | GCAPS_OPAQUERECT |
+ GCAPS_WINDINGFILL /*| GCAPS_LAYERED*/,
+ SYSTM_LOGFONT, //lfDefaultFont
+ HELVE_LOGFONT, //lfAnsiVarFont
+ COURI_LOGFONT, //lfAnsiFixFont
+ 0, //cFonts
+ 0, //iDitherFormat
+ 0, //cxDither
+ 0, //cyDither
+ 0, //hpalDefault
+#if (WINVER >= 0x0501)
+ GCAPS2_MOUSETRAILS |
+#endif
+ GCAPS2_ALPHACURSOR,
+};
+
+static BOOL PrepareHardware(PDev *pdev);
+
+static void mspace_print(void *user_data, char *format, ...)
+{
+ PDev *pdev = (PDev *)user_data;
+ va_list ap;
+
+ va_start(ap, format);
+ DebugPrintV(pdev, format, ap);
+ va_end(ap);
+}
+
+static void mspace_abort(void *user_data)
+{
+ mspace_print(user_data, "mspace abort");
+ EngDebugBreak();
+}
+
+BOOL DrvEnableDriver(ULONG engine_version, ULONG enable_data_size, PDRVENABLEDATA enable_data)
+{
+ DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+ enable_data->iDriverVersion = DDI_DRIVER_VERSION_NT5;
+ enable_data->c = sizeof(drv_calls) / sizeof(DRVFN);
+ enable_data->pdrvfn = drv_calls;
+ mspace_set_abort_func(mspace_abort);
+ mspace_set_print_func(mspace_print);
+ ResInitGlobals();
+#ifndef _WIN64
+ CheckAndSetSSE2();
+#endif
+ DEBUG_PRINT((NULL, 1, "%s: end\n", __FUNCTION__));
+ return TRUE;
+}
+
+ULONG DrvEscape(SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn,
+ ULONG cjOut, PVOID pvOut)
+{
+ PDev* pdev = pso ? (PDev*)pso->dhpdev : NULL;
+ int RetVal = -1;
+
+ switch (iEsc) {
+ case QXL_ESCAPE_SET_CUSTOM_DISPLAY: {
+ ULONG length;
+
+ DEBUG_PRINT((pdev, 1, "set custom display %p\n", pdev));
+ if (pdev == NULL)
+ break;
+
+ if (EngDeviceIoControl(pdev->driver, IOCTL_QXL_SET_CUSTOM_DISPLAY,
+ pvIn, cjIn, NULL, 0, &length)) {
+ DEBUG_PRINT((pdev, 0, "%s: IOCTL_QXL_SET_CUSTOM_DISPLAY failed\n", __FUNCTION__));
+ break;
+ }
+ RetVal = 1;
+ break;
+ }
+ default:
+ DEBUG_PRINT((NULL, 1, "%s: unhandled escape code %d\n", __FUNCTION__, iEsc));
+ RetVal = 0;
+ }
+
+ DEBUG_PRINT((NULL, 1, "%s: end\n", __FUNCTION__));
+ return RetVal;
+}
+
+VOID DrvDisableDriver(VOID)
+{
+ DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+ ResDestroyGlobals();
+}
+
+DWORD GetAvailableModes(HANDLE driver, PVIDEO_MODE_INFORMATION *mode_info,
+ DWORD *mode_info_size)
+{
+ ULONG n;
+ VIDEO_NUM_MODES modes;
+ PVIDEO_MODE_INFORMATION info;
+
+ DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+ if (EngDeviceIoControl(driver, IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, NULL, 0,
+ &modes, sizeof(VIDEO_NUM_MODES), &n)) {
+ DEBUG_PRINT((NULL, 0, "%s: query num modes failed\n", __FUNCTION__));
+ return 0;
+ }
+
+ info = (PVIDEO_MODE_INFORMATION)EngAllocMem(FL_ZERO_MEMORY,
+ modes.NumModes * modes.ModeInformationLength,
+ ALLOC_TAG);
+ if (!info) {
+ DEBUG_PRINT((NULL, 0, "%s: memory allocation failed\n", __FUNCTION__));
+ return 0;
+ }
+
+ if (EngDeviceIoControl(driver, IOCTL_VIDEO_QUERY_AVAIL_MODES, NULL, 0, info,
+ modes.NumModes * modes.ModeInformationLength, &n)) {
+ DEBUG_PRINT((NULL, 0, "%s: query modes failed\n", __FUNCTION__));
+ EngFreeMem(info);
+ return 0;
+ }
+
+ *mode_info = info;
+ *mode_info_size = modes.ModeInformationLength;
+
+ n = modes.NumModes;
+ while ( n-- ) {
+ if ( (info->NumberOfPlanes != 1 ) ||!(info->AttributeFlags & VIDEO_MODE_GRAPHICS)
+ ||((info->BitsPerPlane != 16) && (info->BitsPerPlane != 32))) {
+
+ DEBUG_PRINT((NULL, 1, "%s: unsuported mode rejecting miniport mode\n", __FUNCTION__));
+ DEBUG_PRINT((NULL, 1, " width = %li height = %li\n",
+ info->VisScreenWidth, info->VisScreenHeight));
+ DEBUG_PRINT((NULL, 1, " bpp = %li freq = %li\n",
+ info->BitsPerPlane * info->NumberOfPlanes, info->Frequency));
+ info->Length = 0;
+ }
+
+ info = (PVIDEO_MODE_INFORMATION) (((PUCHAR)info) + modes.ModeInformationLength);
+ }
+ DEBUG_PRINT((NULL, 1, "%s: OK num modes %lu\n", __FUNCTION__, modes.NumModes));
+ return modes.NumModes;
+}
+
+BOOL InitializeModeFields(PDev *pdev, GDIINFO *gdi_info, DEVINFO *dev_info,
+ DEVMODEW *dev_mode)
+{
+ ULONG n_modes;
+ PVIDEO_MODE_INFORMATION video_buff;
+ PVIDEO_MODE_INFORMATION selected_mode;
+ PVIDEO_MODE_INFORMATION video_mode;
+ VIDEO_MODE_INFORMATION vmi;
+ ULONG video_mode_size;
+
+ DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+ n_modes = GetAvailableModes(pdev->driver, &video_buff, &video_mode_size);
+ if ( n_modes == 0 ) {
+ DEBUG_PRINT((NULL, 0, "%s: get available modes failed\n", __FUNCTION__));
+ return FALSE;
+ }
+
+#if (WINVER < 0x0501)
+ DEBUG_PRINT((NULL, 1, "%s: req mode: fields %u bits %u w %u h %u frequency %u\n",
+ __FUNCTION__,
+ dev_mode->dmFields,
+ dev_mode->dmBitsPerPel,
+ dev_mode->dmPelsWidth,
+ dev_mode->dmPelsHeight,
+ dev_mode->dmDisplayFrequency));
+#else
+ DEBUG_PRINT((NULL, 1, "%s: req mode: fields %u bits %u w %u h %u frequency %u orientation %u\n",
+ __FUNCTION__,
+ dev_mode->dmFields,
+ dev_mode->dmBitsPerPel,
+ dev_mode->dmPelsWidth,
+ dev_mode->dmPelsHeight,
+ dev_mode->dmDisplayFrequency,
+ dev_mode->dmDisplayOrientation));
+#endif
+
+
+ selected_mode = NULL;
+ video_mode = video_buff;
+
+ while (n_modes--) {
+ if ( video_mode->Length != 0 ) {
+ DEBUG_PRINT((NULL, 1, "%s: check width = %li height = %li\n",
+ __FUNCTION__,
+ video_mode->VisScreenWidth,
+ video_mode->VisScreenHeight));
+ DEBUG_PRINT((NULL, 1, " bpp = %li freq = %li\n",
+ video_mode->BitsPerPlane * video_mode->NumberOfPlanes,
+ video_mode->Frequency));
+
+ if ( (video_mode->VisScreenWidth == dev_mode->dmPelsWidth)
+ && (video_mode->VisScreenHeight == dev_mode->dmPelsHeight)
+ && (video_mode->BitsPerPlane * video_mode->NumberOfPlanes
+ == dev_mode->dmBitsPerPel)
+ && (video_mode->Frequency == dev_mode->dmDisplayFrequency)
+#if (WINVER >= 0x0501)
+ && (video_mode->DriverSpecificAttributeFlags
+ == dev_mode->dmDisplayOrientation)
+#endif
+ ) {
+ selected_mode = video_mode;
+ DEBUG_PRINT((NULL, 1, "%s: found\n", __FUNCTION__));
+ break;
+ }
+ }
+ video_mode = (PVIDEO_MODE_INFORMATION)(((PUCHAR)video_mode) + video_mode_size);
+ }
+
+ if (!selected_mode) {
+ DEBUG_PRINT((NULL, 0, "%s: not found\n"));
+ EngFreeMem(video_buff);
+ return FALSE;
+ }
+
+ vmi = *selected_mode;
+ EngFreeMem(video_buff);
+
+ pdev->video_mode_index = vmi.ModeIndex;
+ pdev->resolution.cx = vmi.VisScreenWidth;
+ pdev->resolution.cy = vmi.VisScreenHeight;
+ pdev->max_bitmap_size = pdev->resolution.cx * pdev->resolution.cy;
+ pdev->max_bitmap_size += pdev->max_bitmap_size / 2;
+ pdev->stride = vmi.ScreenStride;
+
+ *gdi_info = gdi_default;
+
+ gdi_info->ulHorzSize = vmi.XMillimeter;
+ gdi_info->ulVertSize = vmi.YMillimeter;
+ gdi_info->ulHorzRes = vmi.VisScreenWidth;
+ gdi_info->ulVertRes = vmi.VisScreenHeight;
+ gdi_info->cBitsPixel = vmi.BitsPerPlane;
+ gdi_info->cPlanes = vmi.NumberOfPlanes;
+ gdi_info->ulVRefresh = vmi.Frequency;
+ gdi_info->ulDACRed = vmi.NumberRedBits;
+ gdi_info->ulDACGreen = vmi.NumberGreenBits;
+ gdi_info->ulDACBlue = vmi.NumberBlueBits;
+ gdi_info->ulLogPixelsX = dev_mode->dmLogPixels;
+ gdi_info->ulLogPixelsY = dev_mode->dmLogPixels;
+
+ *dev_info = dev_default;
+
+ switch ( vmi.BitsPerPlane ) {
+ case 16:
+ pdev->bitmap_format = BMF_16BPP;
+ pdev->red_mask = vmi.RedMask;
+ pdev->green_mask = vmi.GreenMask;
+ pdev->blue_mask = vmi.BlueMask;
+
+ gdi_info->ulNumColors = (ULONG)-1;
+ gdi_info->ulNumPalReg = 0;
+ gdi_info->ulHTOutputFormat = HT_FORMAT_16BPP;
+
+ dev_info->iDitherFormat = BMF_16BPP;
+ break;
+ case 32:
+ pdev->bitmap_format = BMF_32BPP;
+ pdev->red_mask = vmi.RedMask;
+ pdev->green_mask = vmi.GreenMask;
+ pdev->blue_mask = vmi.BlueMask;
+
+ gdi_info->ulNumColors = (ULONG)-1;
+ gdi_info->ulNumPalReg = 0;
+ gdi_info->ulHTOutputFormat = HT_FORMAT_32BPP;
+
+ dev_info->iDitherFormat = BMF_32BPP;
+ break;
+ default:
+ DEBUG_PRINT((NULL, 0, "%s: bit depth not supported\n", __FUNCTION__));
+ return FALSE;
+ }
+ DEBUG_PRINT((NULL, 1, "%s: exit\n", __FUNCTION__));
+ return TRUE;
+}
+
+void DestroyPalette(PDev *pdev)
+{
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+ if (pdev->palette) {
+ EngDeletePalette(pdev->palette);
+ pdev->palette = NULL;
+ }
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+BOOL InitPalette(PDev *pdev, DEVINFO *dev_info)
+{
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+ if ((pdev->palette = EngCreatePalette(PAL_BITFIELDS, 0, NULL,
+ pdev->red_mask,
+ pdev->green_mask,
+ pdev->blue_mask)) == NULL) {
+ DEBUG_PRINT((NULL, 0, "%s: create palette failed\n", __FUNCTION__));
+ return FALSE;
+ }
+ dev_info->hpalDefault = pdev->palette;
+
+ DEBUG_PRINT((NULL, 1, "%s: OK\n", __FUNCTION__));
+ return TRUE;
+}
+
+DHPDEV DrvEnablePDEV(DEVMODEW *dev_mode, PWSTR ignore1, ULONG ignore2, HSURF *ignore3,
+ ULONG dev_caps_size, ULONG *dev_caps, ULONG dev_inf_size,
+ DEVINFO *in_dev_info, HDEV gdi_dev, PWSTR device_name, HANDLE driver)
+{
+ PDev *pdev;
+ GDIINFO gdi_info;
+ DEVINFO dev_info;
+
+ DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+ if (!(pdev = (PDev*)EngAllocMem(FL_ZERO_MEMORY, sizeof(PDev), ALLOC_TAG))) {
+ DEBUG_PRINT((NULL, 0, "%s: pdev alloc failed\n", __FUNCTION__));
+ return NULL;
+ }
+
+ RtlZeroMemory(&gdi_info, sizeof(GDIINFO));
+ RtlCopyMemory(&gdi_info, dev_caps, MIN(dev_caps_size, sizeof(GDIINFO)));
+
+ RtlZeroMemory(&dev_info, sizeof(DEVINFO));
+ RtlCopyMemory(&dev_info, in_dev_info, MIN(dev_inf_size, sizeof(DEVINFO)));
+
+ pdev->driver = driver;
+
+ if (!InitializeModeFields(pdev, &gdi_info, &dev_info, dev_mode)) {
+ DEBUG_PRINT((NULL, 0, "%s: init mode failed\n", __FUNCTION__));
+ goto err1;
+ }
+
+ if (!InitPalette(pdev, &dev_info)) {
+ DEBUG_PRINT((NULL, 0, "%s: init palet failed\n", __FUNCTION__));
+ goto err1;
+ }
+
+ if (!ResInit(pdev)) {
+ DEBUG_PRINT((NULL, 0, "%s: init res failed\n", __FUNCTION__));
+ goto err2;
+ }
+
+ RtlCopyMemory(dev_caps, &gdi_info, dev_caps_size);
+ RtlCopyMemory(in_dev_info, &dev_info, dev_inf_size);
+
+ pdev->enabled = TRUE; /* assume no operations before a DrvEnablePDEV. */
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+ return(DHPDEV)pdev;
+
+err2:
+ DestroyPalette(pdev);
+
+err1:
+ EngFreeMem(pdev);
+
+ return NULL;
+}
+
+#ifdef DBG
+static void DebugCountAliveSurfaces(PDev *pdev)
+{
+ UINT32 i;
+ SurfaceInfo *surface_info;
+ int total = 0;
+ int of_pdev = 0;
+ int no_surf_obj = 0;
+
+ for (i = 0 ; i < pdev->n_surfaces; ++i) {
+ surface_info = GetSurfaceInfo(pdev, i);
+ if (surface_info->draw_area.base_mem != NULL) {
+ total++;
+ // all should belong to the same pdev
+ if (surface_info->u.pdev == pdev) {
+ of_pdev++;
+ if (surface_info->draw_area.surf_obj == NULL) {
+ no_surf_obj++;
+ }
+ }
+ }
+ }
+ DEBUG_PRINT((pdev, 1, "%s: %p: %d / %d / %d (total,pdev,no_surf_obj)\n", __FUNCTION__, pdev,
+ total, of_pdev, no_surf_obj));
+}
+#else
+static void DebugCountAliveSurfaces(PDev *pdev)
+{
+}
+#endif
+
+VOID DrvDisablePDEV(DHPDEV in_pdev)
+{
+ PDev* pdev = (PDev*)in_pdev;
+
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+ ResDestroy(pdev);
+ DestroyPalette(pdev);
+ EngFreeMem(pdev);
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+VOID DrvCompletePDEV(DHPDEV in_pdev, HDEV gdi_dev)
+{
+ PDev* pdev = (PDev*)in_pdev;
+
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+ pdev->eng = gdi_dev;
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+static VOID HideMouse(PDev *pdev)
+{
+ QXLCursorCmd *cursor_cmd;
+
+ cursor_cmd = CursorCmd(pdev);
+ cursor_cmd->type = QXL_CURSOR_HIDE;
+
+ PushCursorCmd(pdev, cursor_cmd);
+}
+
+static VOID CreatePrimarySurface(PDev *pdev, UINT32 depth, UINT32 format,
+ UINT32 width, UINT32 height, INT32 stride,
+ QXLPHYSICAL phys_mem)
+{
+ pdev->primary_surface_create->format = format;
+ pdev->primary_surface_create->width = width;
+ pdev->primary_surface_create->height = height;
+ pdev->primary_surface_create->stride = -stride;
+ pdev->primary_surface_create->mem = phys_mem;
+
+ pdev->primary_surface_create->flags = 0;
+ pdev->primary_surface_create->type = QXL_SURF_TYPE_PRIMARY;
+
+ async_io(pdev, ASYNCABLE_CREATE_PRIMARY, 0);
+}
+
+static void DestroyPrimarySurface(PDev *pdev, int hide_mouse)
+{
+ if (hide_mouse) {
+ HideMouse(pdev);
+ }
+ async_io(pdev, ASYNCABLE_DESTROY_PRIMARY, 0);
+}
+
+static void DestroyAllSurfaces(PDev *pdev)
+{
+ HideMouse(pdev);
+ async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
+}
+
+BOOL SetHardwareMode(PDev *pdev)
+{
+ VIDEO_MODE_INFORMATION video_info;
+ DWORD length;
+
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx mode %lu\n", __FUNCTION__, pdev, pdev->video_mode_index));
+
+ if (EngDeviceIoControl(pdev->driver, IOCTL_VIDEO_SET_CURRENT_MODE,
+ &pdev->video_mode_index, sizeof(DWORD),
+ NULL, 0, &length)) {
+ DEBUG_PRINT((NULL, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx OK\n", __FUNCTION__, pdev));
+ return TRUE;
+}
+
+static VOID UpdateMainSlot(PDev *pdev, MemSlot *slot)
+{
+ QXLPHYSICAL high_bits;
+
+
+ pdev->mem_slots[pdev->main_mem_slot].slot = *slot;
+
+ high_bits = pdev->main_mem_slot << pdev->slot_gen_bits;
+ high_bits |= slot->generation;
+ high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
+ pdev->mem_slots[pdev->main_mem_slot].high_bits = high_bits;
+
+ pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
+}
+
+static void RemoveVRamSlot(PDev *pdev)
+{
+ sync_io(pdev, pdev->memslot_del_port, pdev->vram_mem_slot);
+ pdev->vram_slot_initialized = FALSE;
+}
+
+static BOOLEAN CreateVRamSlot(PDev *pdev)
+{
+ QXLMemSlot *slot;
+ UINT64 high_bits;
+ UINT8 slot_id = pdev->main_mem_slot + 1;
+
+ if (slot_id >= pdev->num_mem_slot) {
+ return FALSE;
+ }
+
+ pdev->va_slot_mask = (~(QXLPHYSICAL)0) >> (pdev->slot_id_bits + pdev->slot_gen_bits);
+
+
+ *pdev->ram_slot_start = pdev->fb_phys;
+ *pdev->ram_slot_end = pdev->fb_phys + pdev->fb_size;
+
+ async_io(pdev, ASYNCABLE_MEMSLOT_ADD, slot_id);
+
+ pdev->vram_mem_slot = slot_id;
+
+ pdev->mem_slots[slot_id].slot.generation = *pdev->slots_generation;
+ pdev->mem_slots[slot_id].slot.start_phys_addr = pdev->fb_phys;
+ pdev->mem_slots[slot_id].slot.end_phys_addr = pdev->fb_phys + pdev->fb_size;
+ pdev->mem_slots[slot_id].slot.start_virt_addr = (UINT64)pdev->fb;
+ pdev->mem_slots[slot_id].slot.end_virt_addr = (UINT64)pdev->fb + pdev->fb_size;
+
+ high_bits = slot_id << pdev->slot_gen_bits;
+ high_bits |= pdev->mem_slots[slot_id].slot.generation;
+ high_bits <<= (64 - (pdev->slot_gen_bits + pdev->slot_id_bits));
+ pdev->mem_slots[slot_id].high_bits = high_bits;
+
+ pdev->vram_slot_initialized = TRUE;
+
+ return TRUE;
+}
+
+static BOOL PrepareHardware(PDev *pdev)
+{
+ VIDEO_MEMORY video_mem;
+ VIDEO_MEMORY_INFORMATION video_mem_Info;
+ DWORD length;
+ QXLDriverInfo dev_info;
+ QXLPHYSICAL high_bits;
+
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+ if (!SetHardwareMode(pdev)) {
+ DEBUG_PRINT((pdev, 0, "%s: set mode failed, 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+
+ if (EngDeviceIoControl( pdev->driver, IOCTL_QXL_GET_INFO, NULL,
+ 0, &dev_info, sizeof(QXLDriverInfo), &length) ) {
+ DEBUG_PRINT((pdev, 0, "%s: get qxl info failed, 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+
+ if (dev_info.version != QXL_DRIVER_INFO_VERSION) {
+ DEBUG_PRINT((pdev, 0, "%s: get qxl info mismatch, 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+
+ pdev->pci_revision = dev_info.pci_revision;
+ pdev->use_async = (pdev->pci_revision >= QXL_REVISION_STABLE_V10);
+ pdev->cmd_ring = dev_info.cmd_ring;
+ pdev->cursor_ring = dev_info.cursor_ring;
+ pdev->release_ring = dev_info.release_ring;
+ pdev->notify_cmd_port = dev_info.notify_cmd_port;
+ pdev->notify_cursor_port = dev_info.notify_cursor_port;
+ pdev->notify_oom_port = dev_info.notify_oom_port;
+
+ pdev->asyncable[ASYNCABLE_UPDATE_AREA][ASYNC] = dev_info.update_area_async_port;
+ pdev->asyncable[ASYNCABLE_UPDATE_AREA][SYNC] = dev_info.update_area_port;
+ pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][ASYNC] = dev_info.memslot_add_async_port;
+ pdev->asyncable[ASYNCABLE_MEMSLOT_ADD][SYNC] = dev_info.memslot_add_port;
+ pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][ASYNC] = dev_info.create_primary_async_port;
+ pdev->asyncable[ASYNCABLE_CREATE_PRIMARY][SYNC] = dev_info.create_primary_port;
+ pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][ASYNC] = dev_info.destroy_primary_async_port;
+ pdev->asyncable[ASYNCABLE_DESTROY_PRIMARY][SYNC] = dev_info.destroy_primary_port;
+ pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][ASYNC] = dev_info.destroy_surface_async_port;
+ pdev->asyncable[ASYNCABLE_DESTROY_SURFACE][SYNC] = dev_info.destroy_surface_wait_port;
+ pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][ASYNC] = dev_info.destroy_all_surfaces_async_port;
+ pdev->asyncable[ASYNCABLE_DESTROY_ALL_SURFACES][SYNC] = dev_info.destroy_all_surfaces_port;
+ pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][ASYNC] = dev_info.flush_surfaces_async_port;
+ pdev->asyncable[ASYNCABLE_FLUSH_SURFACES][SYNC] = NULL;
+
+ pdev->display_event = dev_info.display_event;
+ pdev->cursor_event = dev_info.cursor_event;
+ pdev->sleep_event = dev_info.sleep_event;
+ pdev->io_cmd_event = dev_info.io_cmd_event;
+#if (WINVER < 0x0501)
+ pdev->WaitForEvent = dev_info.WaitForEvent;
+#endif
+
+ pdev->num_io_pages = dev_info.num_pages;
+ pdev->io_pages_virt = dev_info.io_pages_virt;
+ pdev->io_pages_phys = dev_info.io_pages_phys;
+
+ pdev->dev_update_id = dev_info.update_id;
+
+ pdev->update_area = dev_info.update_area;
+ pdev->update_surface = dev_info.update_surface;
+
+ pdev->mm_clock = dev_info.mm_clock;
+
+ pdev->compression_level = dev_info.compression_level;
+
+ pdev->log_port = dev_info.log_port;
+ pdev->log_buf = dev_info.log_buf;
+ pdev->log_level = dev_info.log_level;
+
+ pdev->n_surfaces = dev_info.n_surfaces;
+
+ pdev->mem_slots = EngAllocMem(FL_ZERO_MEMORY, sizeof(PMemSlot) * dev_info.num_mem_slot,
+ ALLOC_TAG);
+ if (!pdev->mem_slots) {
+ DEBUG_PRINT((pdev, 0, "%s: mem slots alloc failed, 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+
+ pdev->slots_generation = dev_info.slots_generation;
+ pdev->ram_slot_start = dev_info.ram_slot_start;
+ pdev->ram_slot_end = dev_info.ram_slot_end;
+ pdev->slot_id_bits = dev_info.slot_id_bits;
+ pdev->slot_gen_bits = dev_info.slot_gen_bits;
+ pdev->main_mem_slot = dev_info.main_mem_slot_id;
+ pdev->num_mem_slot = dev_info.num_mem_slot;
+
+ UpdateMainSlot(pdev, &dev_info.main_mem_slot);
+
+ video_mem.RequestedVirtualAddress = NULL;
+
+ if (EngDeviceIoControl( pdev->driver, IOCTL_VIDEO_MAP_VIDEO_MEMORY, &video_mem,
+ sizeof(VIDEO_MEMORY), &video_mem_Info,
+ sizeof(video_mem_Info), &length) ) {
+ DEBUG_PRINT((pdev, 0, "%s: mapping failed, 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx vals 0x%lx %ul\n", __FUNCTION__, pdev,
+ video_mem_Info.FrameBufferBase, video_mem_Info.FrameBufferLength));
+ pdev->fb = (BYTE*)video_mem_Info.FrameBufferBase;
+ pdev->fb_size = video_mem_Info.FrameBufferLength;
+ pdev->fb_phys = dev_info.fb_phys;
+
+ pdev->memslot_del_port = dev_info.memslot_del_port;
+
+ pdev->flush_release_port = dev_info.flush_release_port;
+
+ pdev->primary_memory_start = dev_info.surface0_area;
+ pdev->primary_memory_size = dev_info.surface0_area_size;
+
+ pdev->primary_surface_create = dev_info.primary_surface_create;
+
+ pdev->dev_id = dev_info.dev_id;
+
+ pdev->create_non_primary_surfaces = dev_info.create_non_primary_surfaces;
+ DEBUG_PRINT((pdev, 1, "%s: create_non_primary_surfaces = %d\n", __FUNCTION__,
+ pdev->create_non_primary_surfaces));
+
+ CreateVRamSlot(pdev);
+
+ DEBUG_PRINT((NULL, 1, "%s: 0x%lx exit: 0x%lx %ul\n", __FUNCTION__, pdev,
+ pdev->fb, pdev->fb_size));
+ return TRUE;
+}
+
+static VOID UnmapFB(PDev *pdev)
+{
+ VIDEO_MEMORY video_mem;
+ DWORD length;
+
+ if (!pdev->fb) {
+ return;
+ }
+
+ video_mem.RequestedVirtualAddress = pdev->fb;
+ pdev->fb = 0;
+ pdev->fb_size = 0;
+ if (EngDeviceIoControl(pdev->driver,
+ IOCTL_VIDEO_UNMAP_VIDEO_MEMORY,
+ &video_mem,
+ sizeof(video_mem),
+ NULL,
+ 0,
+ &length)) {
+ DEBUG_PRINT((NULL, 0, "%s: unmpap failed, 0x%lx\n", __FUNCTION__, pdev));
+ }
+}
+
+VOID EnableQXLPrimarySurface(PDev *pdev)
+{
+ UINT32 depth, format;
+
+ switch (pdev->bitmap_format) {
+ case BMF_8BPP:
+ PANIC(pdev, "bad formart type 8bpp\n");
+ case BMF_16BPP:
+ depth = 16;
+ format = SPICE_SURFACE_FMT_16_555;
+ break;
+ case BMF_24BPP:
+ case BMF_32BPP:
+ depth = 32;
+ format = SPICE_SURFACE_FMT_32_xRGB;
+ break;
+ default:
+ PANIC(pdev, "bad formart type\n");
+ };
+
+ CreatePrimarySurface(pdev, depth, format,
+ pdev->resolution.cx, pdev->resolution.cy,
+ pdev->stride, pdev->surf_phys);
+ pdev->surf_enable = TRUE;
+}
+
+HSURF DrvEnableSurface(DHPDEV in_pdev)
+{
+ PDev *pdev;
+ HSURF surf;
+ DWORD length;
+ QXLPHYSICAL phys_mem;
+ UINT8 *base_mem;
+
+ pdev = (PDev*)in_pdev;
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, in_pdev));
+
+ if (!PrepareHardware(pdev)) {
+ return FALSE;
+ }
+ InitResources(pdev);
+
+ if (!(surf = (HSURF)CreateDeviceBitmap(pdev, pdev->resolution, pdev->bitmap_format, &phys_mem,
+ &base_mem, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0))) {
+ DEBUG_PRINT((pdev, 0, "%s: create device surface failed, 0x%lx\n",
+ __FUNCTION__, pdev));
+ goto err;
+ }
+
+ DEBUG_PRINT((pdev, 1, "%s: EngModifySurface(0x%lx, 0x%lx, 0, MS_NOTSYSTEMMEMORY, "
+ "0x%lx, 0x%lx, %lu, NULL)\n",
+ __FUNCTION__,
+ surf,
+ pdev->eng,
+ pdev,
+ pdev->fb,
+ pdev->stride));
+
+ pdev->surf = surf;
+ pdev->surf_phys = phys_mem;
+ pdev->surf_base = base_mem;
+
+ EnableQXLPrimarySurface(pdev);
+
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+ return surf;
+
+err:
+ DrvDisableSurface((DHPDEV)pdev);
+ DEBUG_PRINT((pdev, 0, "%s: 0x%lx err\n", __FUNCTION__, pdev));
+ return NULL;
+}
+
+VOID DisableQXLPrimarySurface(PDev *pdev, int hide_mouse)
+{
+ DrawArea drawarea;
+
+ if (pdev->surf_enable) {
+ DestroyPrimarySurface(pdev, hide_mouse);
+ pdev->surf_enable = FALSE;
+ }
+}
+
+VOID DisableQXLAllSurfaces(PDev *pdev)
+{
+ DestroyAllSurfaces(pdev);
+}
+
+VOID DrvDisableSurface(DHPDEV in_pdev)
+{
+ PDev *pdev = (PDev*)in_pdev;
+ DrawArea drawarea;
+
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+ // Don't destroy the primary - it's destroyed by destroy_all_surfaces
+ // at AssertModeDisable. Also, msdn specifically mentions DrvDisableSurface
+ // should not touch the hardware, that should be done just via DrvAssertMode
+ // (http://msdn.microsoft.com/en-us/library/ff556200%28VS.85%29.aspx)
+ pdev->surf_enable = FALSE;
+ UnmapFB(pdev);
+
+ if (pdev->surf) {
+ DeleteDeviceBitmap(pdev, 0, DEVICE_BITMAP_ALLOCATION_TYPE_SURF0);
+ EngDeleteSurface(pdev->surf);
+ pdev->surf = NULL;
+ }
+
+ if (pdev->mem_slots) {
+ EngFreeMem(pdev->mem_slots);
+ pdev->mem_slots = NULL;
+ }
+
+ DebugCountAliveSurfaces(pdev);
+ ClearResources(pdev);
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit\n", __FUNCTION__, pdev));
+}
+
+static void FlushSurfaces(PDev *pdev)
+{
+ UINT32 surface_id;
+ SurfaceInfo *surface_info;
+ SURFOBJ *surf_obj;
+ RECTL area = {0, 0, 0, 0};
+
+ if (pdev->pci_revision < QXL_REVISION_STABLE_V10) {
+ DEBUG_PRINT((pdev, 1, "%s: revision too old for QXL_IO_FLUSH_SURFACES\n", __FUNCTION__));
+ for (surface_id = pdev->n_surfaces - 1; surface_id > 0 ; --surface_id) {
+ surface_info = GetSurfaceInfo(pdev, surface_id);
+
+ if (!surface_info->draw_area.base_mem) {
+ continue;
+ }
+ surf_obj = surface_info->draw_area.surf_obj;
+ if (!surf_obj) {
+ continue;
+ }
+ area.right = surf_obj->sizlBitmap.cx;
+ area.bottom = surf_obj->sizlBitmap.cy;
+ UpdateArea(pdev,&area, surface_id);
+ }
+ } else {
+ async_io(pdev, ASYNCABLE_FLUSH_SURFACES, 0);
+ }
+}
+
+static BOOL FlushRelease(PDev *pdev)
+{
+ if (pdev->pci_revision< QXL_REVISION_STABLE_V10) {
+ DWORD length;
+
+ DEBUG_PRINT((pdev, 1, "%s: revision too old for QXL_IO_FLUSH_RELEASE\n", __FUNCTION__));
+ if (EngDeviceIoControl(pdev->driver, IOCTL_VIDEO_RESET_DEVICE,
+ NULL, 0, NULL, 0, &length)) {
+ DEBUG_PRINT((NULL, 0, "%s: reset failed 0x%lx\n", __FUNCTION__, pdev));
+ return FALSE;
+ }
+ } else {
+ /* Free release ring contents */
+ ReleaseCacheDeviceMemoryResources(pdev);
+ EmptyReleaseRing(pdev);
+ /* Get the last free list onto the release ring */
+ sync_io(pdev, pdev->flush_release_port, 0);
+ DEBUG_PRINT((pdev, 4, "%s after FLUSH_RELEASE\n", __FUNCTION__));
+ /* And release that. mspace allocators should be clean after. */
+ EmptyReleaseRing(pdev);
+ }
+ return TRUE;
+}
+
+static BOOL AssertModeDisable(PDev *pdev)
+{
+ DEBUG_PRINT((pdev, 3, "%s entry\n", __FUNCTION__));
+ /* flush command ring and update all surfaces */
+ FlushSurfaces(pdev);
+ DebugCountAliveSurfaces(pdev);
+ /*
+ * this call is redundant for
+ * pci_revision < QXL_REVISION_STABLE_V10, due to the
+ * IOCTL_VIDEO_RESET_DEVICE in FlushRelease. However,
+ * MoveAllSurfacesToRam depends on destroy_all_surfaces
+ * in case of failure.
+ * TODO: make MoveAllSurfacesToRam send destroy_surface
+ * commands instead of create_surface commands in case
+ * of failure
+ */
+ async_io(pdev, ASYNCABLE_DESTROY_ALL_SURFACES, 0);
+ /* move all surfaces from device to system memory */
+ if (!MoveAllSurfacesToRam(pdev)) {
+ EnableQXLPrimarySurface(pdev);
+ return FALSE;
+ }
+ if (!FlushRelease(pdev)) {
+ return FALSE;
+ }
+ RemoveVRamSlot(pdev);
+ DebugCountAliveSurfaces(pdev);
+ DEBUG_PRINT((pdev, 4, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
+ pdev->cmd_ring->prod, pdev->cmd_ring->cons,
+ pdev->cursor_ring->prod, pdev->cursor_ring->cons,
+ pdev->release_ring->prod, pdev->release_ring->cons,
+ pdev->free_outputs));
+ DEBUG_PRINT((pdev, 3, "%s exit\n", __FUNCTION__));
+ return TRUE;
+}
+
+static void AssertModeEnable(PDev *pdev)
+{
+ InitDeviceMemoryResources(pdev);
+ DEBUG_PRINT((pdev, 3, "%s: [%d,%d] [%d,%d] [%d,%d] %lx\n", __FUNCTION__,
+ pdev->cmd_ring->prod, pdev->cmd_ring->cons,
+ pdev->cursor_ring->prod, pdev->cursor_ring->cons,
+ pdev->release_ring->prod, pdev->release_ring->cons,
+ pdev->free_outputs));
+ EnableQXLPrimarySurface(pdev);
+ CreateVRamSlot(pdev);
+ DebugCountAliveSurfaces(pdev);
+ MoveAllSurfacesToVideoRam(pdev);
+ DebugCountAliveSurfaces(pdev);
+}
+
+BOOL DrvAssertMode(DHPDEV in_pdev, BOOL enable)
+{
+ PDev* pdev = (PDev*)in_pdev;
+ BOOL ret = TRUE;
+
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx revision %d enable %d\n", __FUNCTION__, pdev, pdev->pci_revision, enable));
+ if (pdev->enabled == enable) {
+ DEBUG_PRINT((pdev, 1, "%s: called twice with same argument (%d)\n", __FUNCTION__,
+ enable));
+ return TRUE;
+ }
+ pdev->enabled = enable;
+ if (enable) {
+ AssertModeEnable(pdev);
+ } else {
+ ret = AssertModeDisable(pdev);
+ if (!ret) {
+ pdev->enabled = !enable;
+ }
+ }
+ DEBUG_PRINT((pdev, 1, "%s: 0x%lx exit %d\n", __FUNCTION__, pdev, enable));
+ return ret;
+}
+
+ULONG DrvGetModes(HANDLE driver, ULONG dev_modes_size, DEVMODEW *dev_modes)
+{
+ PVIDEO_MODE_INFORMATION video_modes;
+ PVIDEO_MODE_INFORMATION curr_video_mode;
+ DWORD mode_size;
+ DWORD output_size;
+ DWORD n_modes;
+
+ DEBUG_PRINT((NULL, 1, "%s\n", __FUNCTION__));
+
+ n_modes = GetAvailableModes(driver, &video_modes, &mode_size);
+
+ if (!n_modes) {
+ DEBUG_PRINT((NULL, 0, "%s: get available modes failed\n", __FUNCTION__));
+ return 0;
+ }
+
+ if (!dev_modes) {
+ DEBUG_PRINT((NULL, 1, "%s: query size\n", __FUNCTION__));
+ output_size = n_modes * sizeof(DEVMODEW);
+ goto out;
+ }
+
+ if (dev_modes_size < n_modes * sizeof(DEVMODEW)) {
+ DEBUG_PRINT((NULL, 0, "%s: buf to small\n", __FUNCTION__));
+ output_size = 0;
+ goto out;
+ }
+
+ output_size = 0;
+ curr_video_mode = video_modes;
+ do {
+ if (curr_video_mode->Length != 0) {
+ RtlZeroMemory(dev_modes, sizeof(DEVMODEW));
+ ASSERT(NULL, sizeof(DEVICE_NAME) < sizeof(dev_modes->dmDeviceName));
+ RtlCopyMemory(dev_modes->dmDeviceName, DEVICE_NAME, sizeof(DEVICE_NAME));
+ dev_modes->dmSpecVersion = DM_SPECVERSION;
+ dev_modes->dmDriverVersion = DM_SPECVERSION;
+ dev_modes->dmSize = sizeof(DEVMODEW);
+ dev_modes->dmBitsPerPel = curr_video_mode->NumberOfPlanes *
+ curr_video_mode->BitsPerPlane;
+ dev_modes->dmPelsWidth = curr_video_mode->VisScreenWidth;
+ dev_modes->dmPelsHeight = curr_video_mode->VisScreenHeight;
+ dev_modes->dmDisplayFrequency = curr_video_mode->Frequency;
+ dev_modes->dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+ DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS;
+#if (WINVER >= 0x0501)
+ dev_modes->dmDisplayOrientation = curr_video_mode->DriverSpecificAttributeFlags;
+ dev_modes->dmFields |= DM_DISPLAYORIENTATION;
+#endif
+
+ DEBUG_PRINT((NULL, 1, "%s: mode: w %u h %u bits %u frequency %u\n",
+ __FUNCTION__,
+ dev_modes->dmPelsWidth,
+ dev_modes->dmPelsHeight,
+ dev_modes->dmBitsPerPel,
+ dev_modes->dmDisplayFrequency));
+#if (WINVER >= 0x0501)
+ DEBUG_PRINT((NULL, 1, " orientation %u\n",
+ dev_modes->dmDisplayOrientation));
+#endif
+ output_size += sizeof(DEVMODEW);
+ dev_modes++;
+ }
+ curr_video_mode = (PVIDEO_MODE_INFORMATION)(((PUCHAR)curr_video_mode) + mode_size);
+ } while (--n_modes);
+
+ out:
+
+ EngFreeMem(video_modes);
+ DEBUG_PRINT((NULL, 1, "%s: exit %u\n", __FUNCTION__, output_size));
+ return output_size;
+}
+
+VOID DrvSynchronize(DHPDEV in_pdev, RECTL *ignored)
+{
+ PDev* pdev = (PDev*)in_pdev;
+ int notify;
+
+ DEBUG_PRINT((pdev, 3, "%s: 0x%lx\n", __FUNCTION__, pdev));
+
+ DEBUG_PRINT((pdev, 4, "%s: 0x%lx done\n", __FUNCTION__, pdev));
+}
+
+char *BitmapFormatToStr(int format)
+{
+ switch (format) {
+ case BMF_1BPP:
+ return "BMF_1BPP";
+ case BMF_4BPP:
+ return "BMF_4BPP";
+ case BMF_8BPP:
+ return "BMF_8BPP";
+ case BMF_16BPP:
+ return "BMF_16BPP";
+ case BMF_24BPP:
+ return "BMF_24BPP";
+ case BMF_32BPP:
+ return "BMF_32BPP";
+ case BMF_4RLE:
+ return "BMF_4RLE";
+ case BMF_8RLE:
+ return "BMF_8RLE";
+ case BMF_JPEG:
+ return "BMF_JPEG";
+ case BMF_PNG:
+ return "BMF_PNG";
+ default:
+ return "?";
+ }
+}
+
+char *BitmapTypeToStr(int type)
+{
+ switch (type) {
+ case STYPE_BITMAP:
+ return "STYPE_BITMAP";
+ case STYPE_DEVICE:
+ return "STYPE_DEVICE";
+ case STYPE_DEVBITMAP:
+ return "STYPE_DEVBITMAP";
+ default:
+ return "?";
+ }
+}
+
+#include "rop.h"
+#include "utils.h"
+#include "res.h"
+
+FIX FlotaToFixed(FLOATL val, FLOATL scale)
+{
+ FLOATOBJ float_obj;
+ FIX ret;
+
+ FLOATOBJ_SetFloat(&float_obj, val);
+ FLOATOBJ_MulFloat(&float_obj, scale);
+
+ ret = FLOATOBJ_GetLong(&float_obj) << 4;
+ FLOATOBJ_MulLong(&float_obj, 16);
+ ret |= (0x0f & FLOATOBJ_GetLong(&float_obj));
+ return ret;
+}
+
+static BOOL GetCosmeticAttr(PDev *pdev, QXLDrawable *drawable, QXLLineAttr *q_line_attr,
+ LINEATTRS *line_attr)
+{
+ q_line_attr->join_style = JOIN_MITER;
+ q_line_attr->end_style = ENDCAP_BUTT;
+ q_line_attr->width = 1 << 4;
+ q_line_attr->miter_limit = 0;
+
+ if (line_attr->fl & LA_STYLED) {
+ PFLOAT_LONG src_style = line_attr->pstyle;
+ FIX *style;
+ FIX *end;
+ UINT32 nseg;
+
+ q_line_attr->flags = (UINT8)(line_attr->fl & (LA_STYLED | LA_STARTGAP));
+ nseg = (line_attr->fl & LA_ALTERNATE) ? 2 : line_attr->cstyle;
+ if ( nseg > 100) {
+ return FALSE;
+ }
+
+ if (!(style = (FIX *)QXLGetBuf(pdev, drawable, &q_line_attr->style,
+ nseg * sizeof(UINT32)))) {
+ return FALSE;
+ }
+
+ if (line_attr->fl & LA_ALTERNATE) {
+ style[0] = style[1] = 1 << 4;
+ } else {
+ for ( end = style + nseg; style < end; style++, src_style++) {
+ *style = (*src_style).l << 4;
+ }
+ }
+ q_line_attr->style_nseg = (UINT8)nseg;
+ } else {
+ q_line_attr->flags = 0;
+ q_line_attr->style_nseg = 0;
+ q_line_attr->style = 0;
+ }
+ return TRUE;
+}
+
+BOOL APIENTRY DrvStrokePath(SURFOBJ *surf, PATHOBJ *path, CLIPOBJ *clip, XFORMOBJ *width_transform,
+ BRUSHOBJ *brush, POINTL *brush_pos, LINEATTRS *line_attr,
+ MIX mix /*rop*/)
+{
+ QXLDrawable *drawable;
+ RECTFX fx_area;
+ RECTL area;
+ PDev *pdev;
+ ROP3Info *fore_rop;
+ ROP3Info *back_rop;
+ BOOL h_or_v_line;
+
+ if (!(pdev = (PDev *)surf->dhpdev)) {
+ DEBUG_PRINT((NULL, 0, "%s: err no pdev\n", __FUNCTION__));
+ return TRUE;
+ }
+
+ PUNT_IF_DISABLED(pdev);
+
+ CountCall(pdev, CALL_COUNTER_STROKE_PATH);
+
+ DEBUG_PRINT((pdev, 3, "%s\n", __FUNCTION__));
+ ASSERT(pdev, surf && path && line_attr && clip);
+
+
+ if (line_attr->fl & (LA_STYLED | LA_ALTERNATE | LA_GEOMETRIC)) { //for now
+ // punt back to GDI result in infinite recursion
+ //return EngStrokePath(surf, path, clip, width_transform, brush, brush_pos, line_attr, mix);
+ }
+
+ ASSERT(pdev, (line_attr->fl & LA_GEOMETRIC) == 0); /* We should not get these */
+
+ PATHOBJ_vGetBounds(path, &fx_area);
+ FXToRect(&area, &fx_area);
+
+ h_or_v_line = area.bottom == area.top + 1 || area.right == area.left + 1;
+
+ if (clip) {
+ if (clip->iDComplexity == DC_TRIVIAL) {
+ clip = NULL;
+ } else {
+ SectRect(&clip->rclBounds, &area, &area);
+ if (IsEmptyRect(&area)) {
+ DEBUG_PRINT((pdev, 1, "%s: empty rect after clip\n", __FUNCTION__));
+ return TRUE;
+ }
+ }
+ }
+
+ if (!(drawable = Drawable(pdev, QXL_DRAW_STROKE, &area, clip, GetSurfaceId(surf)))) {
+ return FALSE;
+ }
+
+ fore_rop = &rops2[(mix - 1) & 0x0f];
+ back_rop = &rops2[((mix >> 8) - 1) & 0x0f];
+
+ if (!((fore_rop->flags | back_rop->flags) & ROP3_BRUSH)) {
+ drawable->u.stroke.brush.type = SPICE_BRUSH_TYPE_NONE;
+ } else if (!QXLGetBrush(pdev, drawable, &drawable->u.stroke.brush, brush, brush_pos,
+ &drawable->surfaces_dest[0], &drawable->surfaces_rects[0])) {
+ goto err;
+ }
+
+ if (!QXLGetPath(pdev, drawable, &drawable->u.stroke.path, path)) {
+ goto err;
+ }
+ // DrvStrokePath only draws foreground pixels, unless you support dotted
+ // lines, so you only care about the low-order byte.
+ drawable->u.stroke.fore_mode = fore_rop->method_data;
+ drawable->u.stroke.back_mode = back_rop->method_data;
+
+ drawable->effect = (h_or_v_line) ? QXL_EFFECT_OPAQUE: QXL_EFFECT_BLEND;
+
+ if (!GetCosmeticAttr(pdev, drawable, &drawable->u.stroke.attr, line_attr)) {
+ goto err;
+ }
+
+ if (drawable->u.stroke.attr.flags & LA_STYLED) {
+ drawable->effect = (fore_rop->effect == back_rop->effect) ? fore_rop->effect :
+ QXL_EFFECT_BLEND;
+ } else {
+ drawable->effect = fore_rop->effect;
+ }
+
+ if (drawable->effect == QXL_EFFECT_OPAQUE && !h_or_v_line) {
+ drawable->effect = QXL_EFFECT_OPAQUE_BRUSH;
+ }
+
+ PushDrawable(pdev, drawable);
+ DEBUG_PRINT((pdev, 4, "%s: done\n", __FUNCTION__));
+ return TRUE;
+
+err:
+ ReleaseOutput(pdev, drawable->release_info.id);
+ return FALSE;
+}
+
+HBITMAP APIENTRY DrvCreateDeviceBitmap(DHPDEV dhpdev, SIZEL size, ULONG format)
+{
+ PDev *pdev;
+ UINT8 *base_mem;
+ UINT32 surface_id;
+ QXLPHYSICAL phys_mem;
+ HBITMAP hbitmap;
+
+ pdev = (PDev *)dhpdev;
+
+ if (!pdev->create_non_primary_surfaces) {
+ return FALSE;
+ }
+
+ if (!pdev->vram_slot_initialized || pdev->bitmap_format != format || pdev->fb == 0) {
+ DEBUG_PRINT((pdev, 3, "%s failed: %p: slot_initialized %d, format(%d,%d), fb %p\n",
+ __FUNCTION__, pdev, pdev->vram_slot_initialized,
+ pdev->bitmap_format, format, pdev->fb));
+ return 0;
+ }
+
+ PUNT_IF_DISABLED(pdev);
+
+ surface_id = GetFreeSurface(pdev);
+ if (!surface_id) {
+ DEBUG_PRINT((pdev, 3, "%s:%p GetFreeSurface failed\n", __FUNCTION__, pdev));
+ goto out_error;
+ }
+ DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
+
+ hbitmap = CreateDeviceBitmap(pdev, size, pdev->bitmap_format, &phys_mem, &base_mem, surface_id,
+ DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+ if (!hbitmap) {
+ DEBUG_PRINT((pdev, 3, "%s:%p CreateDeviceBitmap failed\n", __FUNCTION__, pdev));
+ goto out_error2;
+ }
+
+ return hbitmap;
+
+ // to optimize the failure case
+out_error2:
+ FreeSurfaceInfo(pdev, surface_id);
+out_error:
+ return 0;
+}
+
+VOID APIENTRY DrvDeleteDeviceBitmap(DHSURF dhsurf)
+{
+ UINT32 surface_id;
+ SurfaceInfo *surface;
+ PDev *pdev;
+
+ surface = (SurfaceInfo *)dhsurf;
+ surface_id = GetSurfaceIdFromInfo(surface);
+ pdev = surface->u.pdev;
+
+ DEBUG_PRINT((pdev, 3, "%s: %p: %d\n", __FUNCTION__, pdev, surface_id));
+
+ ASSERT(pdev, surface_id < pdev->n_surfaces);
+
+ DeleteDeviceBitmap(surface->u.pdev, surface_id,
+ surface->copy ? DEVICE_BITMAP_ALLOCATION_TYPE_RAM
+ : DEVICE_BITMAP_ALLOCATION_TYPE_VRAM);
+}
+
+#ifdef CALL_TEST
+
+void CountCall(PDev *pdev, int counter)
+{
+ if (pdev->count_calls) {
+ int i;
+
+ pdev->call_counters[counter]++;
+ if((++pdev->total_calls % 500) == 0) {
+ DEBUG_PRINT((pdev, 0, "total eng calls is %u\n", pdev->total_calls));
+ for (i = 0; i < NUM_CALL_COUNTERS; i++) {
+ DEBUG_PRINT((pdev, 0, "%s count is %u\n",
+ counters_info[i].name, pdev->call_counters[i]));
+ }
+ }
+ pdev->count_calls = FALSE;
+ } else if (counters_info[counter].effective) {
+ pdev->count_calls = TRUE;
+ }
+}
+
+BOOL APIENTRY DrvFillPath(
+ SURFOBJ *pso,
+ PATHOBJ *ppo,
+ CLIPOBJ *pco,
+ BRUSHOBJ *pbo,
+ POINTL *pptlBrushOrg,
+ MIX mix,
+ FLONG flOptions)
+{
+ PDev *pdev;
+
+ pdev = (PDev *)pso->dhpdev;
+ CountCall(pdev, CALL_COUNTER_FILL_PATH);
+
+ return EngFillPath(pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions);
+}
+
+BOOL APIENTRY DrvGradientFill(
+ SURFOBJ *psoDest,
+ CLIPOBJ *pco,
+ XLATEOBJ *pxlo,
+ TRIVERTEX *pVertex,
+ ULONG nVertex,
+ PVOID pMesh,
+ ULONG nMesh,
+ RECTL *prclExtents,
+ POINTL *pptlDitherOrg,
+ ULONG ulMode)
+{
+ PDev *pdev;
+
+ pdev = (PDev *)psoDest->dhpdev;
+ CountCall(pdev, CALL_COUNTER_GRADIENT_FILL);
+ return EngGradientFill(psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents,
+ pptlDitherOrg, ulMode);
+}
+
+BOOL APIENTRY DrvLineTo(
+ SURFOBJ *pso,
+ CLIPOBJ *pco,
+ BRUSHOBJ *pbo,
+ LONG x1,
+ LONG y1,
+ LONG x2,
+ LONG y2,
+ RECTL *prclBounds,
+ MIX mix)
+{
+ PDev *pdev;
+
+ pdev = (PDev *)pso->dhpdev;
+ CountCall(pdev, CALL_COUNTER_LINE_TO);
+ return EngLineTo(pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix);
+}
+
+BOOL APIENTRY DrvPlgBlt(
+ SURFOBJ *psoTrg,
+ SURFOBJ *psoSrc,
+ SURFOBJ *psoMsk,
+ CLIPOBJ *pco,
+ XLATEOBJ *pxlo,
+ COLORADJUSTMENT *pca,
+ POINTL *pptlBrushOrg,
+ POINTFIX *pptfx,
+ RECTL *prcl,
+ POINTL *pptl,
+ ULONG iMode)
+{
+ if (psoSrc->iType == STYPE_BITMAP) {
+ PDev *pdev;
+
+ ASSERT(NULL, psoTrg && psoTrg->iType != STYPE_BITMAP && psoTrg->dhpdev);
+ pdev = (PDev *)psoTrg->dhpdev;
+ CountCall(pdev, CALL_COUNTER_PLG_BLT);
+ }
+ return EngPlgBlt(psoTrg, psoSrc, psoMsk, pco, pxlo, pca, pptlBrushOrg, pptfx, prcl, pptl,
+ iMode);
+}
+
+BOOL APIENTRY DrvStrokeAndFillPath(
+ SURFOBJ *pso,
+ PATHOBJ *ppo,
+ CLIPOBJ *pco,
+ XFORMOBJ *pxo,
+ BRUSHOBJ *pboStroke,
+ LINEATTRS *plineattrs,
+ BRUSHOBJ *pboFill,
+ POINTL *pptlBrushOrg,
+ MIX mixFill,
+ FLONG flOptions)
+{
+ PDev *pdev = (PDev *)pso->dhpdev;
+ CountCall(pdev, CALL_COUNTER_STROKE_AND_FILL_PATH);
+ return EngStrokeAndFillPath(pso, ppo, pco, pxo, pboStroke, plineattrs, pboFill, pptlBrushOrg,
+ mixFill, flOptions);
+}
+
+#endif