summaryrefslogtreecommitdiff
path: root/video
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /video
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'video')
-rw-r--r--video/KMDOD/KMDOD.sln28
-rw-r--r--video/KMDOD/ReadMe.md71
-rw-r--r--video/KMDOD/Sample/SampleDisplay.vcxproj198
-rw-r--r--video/KMDOD/Sample/SampleDisplay.vcxproj.Filters49
-rw-r--r--video/KMDOD/Sample/sampledisplay.infbin0 -> 5754 bytes
-rw-r--r--video/KMDOD/bdd.cxx856
-rw-r--r--video/KMDOD/bdd.hxx649
-rw-r--r--video/KMDOD/bdd_ddi.cxx579
-rw-r--r--video/KMDOD/bdd_dmm.cxx1083
-rw-r--r--video/KMDOD/bdd_errorlog.hxx84
-rw-r--r--video/KMDOD/bdd_util.cxx115
-rw-r--r--video/KMDOD/bltfuncs.cxx346
-rw-r--r--video/KMDOD/blthw.cxx556
-rw-r--r--video/KMDOD/memory.cxx78
-rw-r--r--video/KMDOD/sampledisplay.rc30
-rw-r--r--video/pixlib/PixLib.vcxproj151
-rw-r--r--video/pixlib/PixLib.vcxproj.Filters22
-rw-r--r--video/pixlib/ReadMe.md7
-rw-r--r--video/pixlib/pixel.cpp695
-rw-r--r--video/pixlib/pixel.hpp365
-rw-r--r--video/pixlib/pixlib.cpp8
-rw-r--r--video/pixlib/pixlib.sln28
22 files changed, 5998 insertions, 0 deletions
diff --git a/video/KMDOD/KMDOD.sln b/video/KMDOD/KMDOD.sln
new file mode 100644
index 00000000..3bc7a354
--- /dev/null
+++ b/video/KMDOD/KMDOD.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleDisplay", "Sample\SampleDisplay.vcxproj", "{1D4BAEF2-0892-4354-A6EB-546CF37110C9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|Win32.Build.0 = Debug|Win32
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|Win32.ActiveCfg = Release|Win32
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|Win32.Build.0 = Release|Win32
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|x64.ActiveCfg = Debug|x64
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Debug|x64.Build.0 = Debug|x64
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|x64.ActiveCfg = Release|x64
+ {1D4BAEF2-0892-4354-A6EB-546CF37110C9}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/video/KMDOD/ReadMe.md b/video/KMDOD/ReadMe.md
new file mode 100644
index 00000000..338abe7d
--- /dev/null
+++ b/video/KMDOD/ReadMe.md
@@ -0,0 +1,71 @@
+Kernel mode display-only miniport driver (KMDOD) sample
+=======================================================
+
+The kernel mode display-only miniport driver (KMDOD) sample implements most of the device driver interfaces (DDIs) that a display-only miniport driver should provide to the Windows Display Driver Model (WDDM). The code is useful to understand how to write a miniport driver for a display-only device, or how to develop a full WDDM driver.
+
+## Universal Compliant
+This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core.
+
+For more info on how a KMDOD works, see [Kernel Mode Display-Only Driver (KMDOD) Interface](http://msdn.microsoft.com/en-us/library/windows/hardware/jj673962). For more info on WDDM drivers, see [Windows Vista Display Driver Model (WDDM) Design Guide](http://msdn.microsoft.com/en-us/library/windows/hardware/ff570593).
+
+This code can also help you to understand the use and implementation of display-related DDIs. The INF file shows how to make a display miniport driver visible to other WDDM components.
+
+The sample can be installed on top of a VESA-capable graphics adapter, or on top of a graphics device that supports access to frame buffer memory through the Unified Extensible Firmware Interface (UEFI).
+
+The sample driver does not support the *sleep* power state. If it is placed in the sleep state, the driver will cause a system bugcheck to occur. There is no workaround available, by design.
+
+If the current display driver is not a WDDM 1.2 compliant driver, the sample driver might fail to install, with error code 43 displayed. The KMDOD driver is actually installed, but it cannot be started. The workaround for this issue is to switch to the Microsoft Basic Display Adapter Driver before installing the KMDOD sample driver, or simply to reboot your system after installing the KMDOD sample.
+
+Installation
+------------
+
+In Microsoft Visual Studio, press **F5** to build the sample and then deploy it to a target machine. For more info, see [Deploying a Driver to a Test Computer](http://msdn.microsoft.com/en-us/library/windows/hardware/hh454834).
+
+In some cases you might need to install the driver manually, as follows.
+
+1. Add the following files to the directory given by …\\[x64]\\C++\\Package:
+ - SampleDriver.cat
+ - SampleDriver.inf
+ - SampleDriver.sys
+ - SampleDriver.cer
+
+2. Unless you’ve provided a production certificate, you should manually install the SampleDriver.cer digital certificate with the following command:
+
+ `Certutil.exe -addstore root SampleDriver.cer`
+
+3. Then enable test signing by running the following BCDEdit command:
+
+ `Bcdedit.exe -set TESTSIGNING ON`
+
+ **Note**  After you change the TESTSIGNING boot configuration option, restart the computer for the change to take effect.
+
+ For more info, see [The TESTSIGNING Boot Configuration Option](http://msdn.microsoft.com/en-us/library/windows/hardware/ff553484).
+
+4. Manually install the driver using Device Manager, which is available from Control Panel.
+
+### ACPI-based GPUs
+
+To install the KMDOD sample driver on a GPU that is an Advanced Configuration and Power Interface (ACPI) device, add these lines to the `[MS]`, `[MS.NTamd64]`, and `[MS.NTarm]` sections of the Sampledisplay.inf file:
+
+<table>
+<colgroup>
+<col width="100%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th align="left">Text</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td align="left"><pre><code>&quot; Kernel mode display only sample driver &quot; = KDODSamp_Inst, ACPI\CLS_0003&amp;SUBCLS_0000
+&quot; Kernel mode display only sample driver &quot; = KDODSamp_Inst, ACPI\CLS_0003&amp;SUBCLS_0001
+&quot; Kernel mode display only sample driver &quot; = KDODSamp_Inst, ACPI\CLS_0003&amp;SUBCLS_0003</code></pre></td>
+</tr>
+</tbody>
+</table>
+
+This new code provides generic identifiers for ACPI hardware.
+
+You can optionally delete the original lines of code within these sections of the INF file.
+
diff --git a/video/KMDOD/Sample/SampleDisplay.vcxproj b/video/KMDOD/Sample/SampleDisplay.vcxproj
new file mode 100644
index 00000000..e90f3a1c
--- /dev/null
+++ b/video/KMDOD/Sample/SampleDisplay.vcxproj
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{1D4BAEF2-0892-4354-A6EB-546CF37110C9}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{747D8F94-A59D-430F-9355-8BCC82821140}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\displib.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);$(SDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>SampleDisplay</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>SampleDisplay</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>SampleDisplay</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>SampleDisplay</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\BDD.cxx" />
+ <ClCompile Include="..\BDD_DDI.cxx" />
+ <ClCompile Include="..\BDD_DMM.cxx" />
+ <ClCompile Include="..\BDD_Util.cxx" />
+ <ClCompile Include="..\BltFuncs.cxx" />
+ <ClCompile Include="..\BltHw.cxx" />
+ <ClCompile Include="..\memory.cxx" />
+ <ResourceCompile Include="..\sampledisplay.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/video/KMDOD/Sample/SampleDisplay.vcxproj.Filters b/video/KMDOD/Sample/SampleDisplay.vcxproj.Filters
new file mode 100644
index 00000000..fcad028c
--- /dev/null
+++ b/video/KMDOD/Sample/SampleDisplay.vcxproj.Filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{A6BB0B4D-C919-4D91-A64B-EEE3D2786FC8}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{859C600A-1FD2-4C7B-8AFF-0AC7726F84EC}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{7182D165-92F6-44B0-9AD8-B5DCF77CA59F}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{B6773450-64CD-4172-84AD-A2062E20181D}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\BDD.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\BDD_DDI.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\BDD_DMM.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\BDD_Util.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\BltFuncs.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\BltHw.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\memory.cxx">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\sampledisplay.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/video/KMDOD/Sample/sampledisplay.inf b/video/KMDOD/Sample/sampledisplay.inf
new file mode 100644
index 00000000..2efaa97a
--- /dev/null
+++ b/video/KMDOD/Sample/sampledisplay.inf
Binary files differ
diff --git a/video/KMDOD/bdd.cxx b/video/KMDOD/bdd.cxx
new file mode 100644
index 00000000..ce38f269
--- /dev/null
+++ b/video/KMDOD/bdd.cxx
@@ -0,0 +1,856 @@
+/******************************Module*Header*******************************\
+* Module Name: bdd.cxx
+*
+* Basic Display Driver functions implementation
+*
+*
+* Copyright (c) 2010 Microsoft Corporation
+\**************************************************************************/
+
+
+#include "BDD.hxx"
+
+#pragma code_seg("PAGE")
+
+
+BASIC_DISPLAY_DRIVER::BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pPhysicalDeviceObject),
+ m_MonitorPowerState(PowerDeviceD0),
+ m_AdapterPowerState(PowerDeviceD0)
+{
+ PAGED_CODE();
+ *((UINT*)&m_Flags) = 0;
+ m_Flags._LastFlag = TRUE;
+ RtlZeroMemory(&m_DxgkInterface, sizeof(m_DxgkInterface));
+ RtlZeroMemory(&m_StartInfo, sizeof(m_StartInfo));
+ RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
+ RtlZeroMemory(&m_DeviceInfo, sizeof(m_DeviceInfo));
+
+
+ for (UINT i=0;i<MAX_VIEWS;i++)
+ {
+ m_HardwareBlt[i].Initialize(this,i);
+ }
+}
+
+BASIC_DISPLAY_DRIVER::~BASIC_DISPLAY_DRIVER()
+{
+ PAGED_CODE();
+
+
+ CleanUp();
+}
+
+
+NTSTATUS BASIC_DISPLAY_DRIVER::StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pDxgkStartInfo != NULL);
+ BDD_ASSERT(pDxgkInterface != NULL);
+ BDD_ASSERT(pNumberOfViews != NULL);
+ BDD_ASSERT(pNumberOfChildren != NULL);
+
+ RtlCopyMemory(&m_StartInfo, pDxgkStartInfo, sizeof(m_StartInfo));
+ RtlCopyMemory(&m_DxgkInterface, pDxgkInterface, sizeof(m_DxgkInterface));
+ RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
+ m_CurrentModes[0].DispInfo.TargetId = D3DDDI_ID_UNINITIALIZED;
+
+ // Get device information from OS.
+ NTSTATUS Status = m_DxgkInterface.DxgkCbGetDeviceInformation(m_DxgkInterface.DeviceHandle, &m_DeviceInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ASSERTION1("DxgkCbGetDeviceInformation failed with status 0x%I64x",
+ Status);
+ return Status;
+ }
+
+ // Ignore return value, since it's not the end of the world if we failed to write these values to the registry
+ RegisterHWInfo();
+
+ // TODO: Uncomment the line below after updating the TODOs in the function CheckHardware
+// Status = CheckHardware();
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ // This sample driver only uses the frame buffer of the POST device. DxgkCbAcquirePostDisplayOwnership
+ // gives you the frame buffer address and ensures that no one else is drawing to it. Be sure to give it back!
+ Status = m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &(m_CurrentModes[0].DispInfo));
+ if (!NT_SUCCESS(Status) || m_CurrentModes[0].DispInfo.Width == 0)
+ {
+ // The most likely cause of failure is that the driver is simply not running on a POST device, or we are running
+ // after a pre-WDDM 1.2 driver. Since we can't draw anything, we should fail to start.
+ return STATUS_UNSUCCESSFUL;
+ }
+ m_Flags.DriverStarted = TRUE;
+ *pNumberOfViews = MAX_VIEWS;
+ *pNumberOfChildren = MAX_CHILDREN;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::StopDevice(VOID)
+{
+ PAGED_CODE();
+
+ CleanUp();
+
+ m_Flags.DriverStarted = FALSE;
+
+ return STATUS_SUCCESS;
+}
+
+VOID BASIC_DISPLAY_DRIVER::CleanUp()
+{
+ PAGED_CODE();
+
+ for (UINT Source = 0; Source < MAX_VIEWS; ++Source)
+ {
+ if (m_CurrentModes[Source].FrameBuffer.Ptr)
+ {
+ UnmapFrameBuffer(m_CurrentModes[Source].FrameBuffer.Ptr, m_CurrentModes[Source].DispInfo.Height * m_CurrentModes[Source].DispInfo.Pitch);
+ m_CurrentModes[Source].FrameBuffer.Ptr = NULL;
+ m_CurrentModes[Source].Flags.FrameBufferIsActive = FALSE;
+ }
+ }
+}
+
+
+NTSTATUS BASIC_DISPLAY_DRIVER::DispatchIoRequest(_In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pVideoRequestPacket != NULL);
+ BDD_ASSERT(VidPnSourceId < MAX_VIEWS);
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::SetPowerState(_In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType)
+{
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(ActionType);
+
+ BDD_ASSERT((HardwareUid < MAX_CHILDREN) || (HardwareUid == DISPLAY_ADAPTER_HW_ID));
+
+ if (HardwareUid == DISPLAY_ADAPTER_HW_ID)
+ {
+ if (DevicePowerState == PowerDeviceD0)
+ {
+
+ // When returning from D3 the device visibility defined to be off for all targets
+ if (m_AdapterPowerState == PowerDeviceD3)
+ {
+ DXGKARG_SETVIDPNSOURCEVISIBILITY Visibility;
+ Visibility.VidPnSourceId = D3DDDI_ID_ALL;
+ Visibility.Visible = FALSE;
+ SetVidPnSourceVisibility(&Visibility);
+ }
+ }
+
+ // Store new adapter power state
+ m_AdapterPowerState = DevicePowerState;
+
+ // There is nothing to do to specifically power up/down the display adapter
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ // TODO: This is where the specified monitor should be powered up/down
+ NOTHING;
+ return STATUS_SUCCESS;
+ }
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pChildRelations != NULL);
+
+ // The last DXGK_CHILD_DESCRIPTOR in the array of pChildRelations must remain zeroed out, so we subtract this from the count
+ ULONG ChildRelationsCount = (ChildRelationsSize / sizeof(DXGK_CHILD_DESCRIPTOR)) - 1;
+ BDD_ASSERT(ChildRelationsCount <= MAX_CHILDREN);
+
+ for (UINT ChildIndex = 0; ChildIndex < ChildRelationsCount; ++ChildIndex)
+ {
+ pChildRelations[ChildIndex].ChildDeviceType = TypeVideoOutput;
+ pChildRelations[ChildIndex].ChildCapabilities.HpdAwareness = HpdAwarenessInterruptible;
+ pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.InterfaceTechnology = m_CurrentModes[0].Flags.IsInternal ? D3DKMDT_VOT_INTERNAL : D3DKMDT_VOT_OTHER;
+ pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.MonitorOrientationAwareness = D3DKMDT_MOA_NONE;
+ pChildRelations[ChildIndex].ChildCapabilities.Type.VideoOutput.SupportsSdtvModes = FALSE;
+ // TODO: Replace 0 with the actual ACPI ID of the child device, if available
+ pChildRelations[ChildIndex].AcpiUid = 0;
+ pChildRelations[ChildIndex].ChildUid = ChildIndex;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly)
+{
+ PAGED_CODE();
+
+ UNREFERENCED_PARAMETER(NonDestructiveOnly);
+ BDD_ASSERT(pChildStatus != NULL);
+ BDD_ASSERT(pChildStatus->ChildUid < MAX_CHILDREN);
+
+ switch (pChildStatus->Type)
+ {
+ case StatusConnection:
+ {
+ // HpdAwarenessInterruptible was reported since HpdAwarenessNone is deprecated.
+ // However, BDD has no knowledge of HotPlug events, so just always return connected.
+ pChildStatus->HotPlug.Connected = IsDriverActive();
+ return STATUS_SUCCESS;
+ }
+
+ case StatusRotation:
+ {
+ // D3DKMDT_MOA_NONE was reported, so this should never be called
+ BDD_LOG_ERROR0("Child status being queried for StatusRotation even though D3DKMDT_MOA_NONE was reported");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ default:
+ {
+ BDD_LOG_WARNING1("Unknown pChildStatus->Type (0x%I64x) requested.", pChildStatus->Type);
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+}
+
+// EDID retrieval
+NTSTATUS BASIC_DISPLAY_DRIVER::QueryDeviceDescriptor(_In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pDeviceDescriptor != NULL);
+ BDD_ASSERT(ChildUid < MAX_CHILDREN);
+
+ // If we haven't successfully retrieved an EDID yet (invalid ones are ok, so long as it was retrieved)
+ if (!m_Flags.EDID_Attempted)
+ {
+ GetEdid(ChildUid);
+
+ }
+
+ if (!m_Flags.EDID_Retrieved || !m_Flags.EDID_ValidHeader || !m_Flags.EDID_ValidChecksum)
+ {
+ // Report no EDID if a valid one wasn't retrieved
+ return STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED;
+ }
+ else if (pDeviceDescriptor->DescriptorOffset == 0)
+ {
+ // Only the base block is supported
+ RtlCopyMemory(pDeviceDescriptor->DescriptorBuffer,
+ m_EDIDs[ChildUid],
+ min(pDeviceDescriptor->DescriptorLength, EDID_V1_BLOCK_SIZE));
+
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ return STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA;
+ }
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pQueryAdapterInfo != NULL);
+
+ switch (pQueryAdapterInfo->Type)
+ {
+ case DXGKQAITYPE_DRIVERCAPS:
+ {
+ if (pQueryAdapterInfo->OutputDataSize < sizeof(DXGK_DRIVERCAPS))
+ {
+ BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DRIVERCAPS) (0x%I64x)", pQueryAdapterInfo->OutputDataSize, sizeof(DXGK_DRIVERCAPS));
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ DXGK_DRIVERCAPS* pDriverCaps = (DXGK_DRIVERCAPS*)pQueryAdapterInfo->pOutputData;
+
+ // Nearly all fields must be initialized to zero, so zero out to start and then change those that are non-zero.
+ // Fields are zero since BDD is Display-Only and therefore does not support any of the render related fields.
+ // It also doesn't support hardware interrupts, gamma ramps, etc.
+ RtlZeroMemory(pDriverCaps, sizeof(DXGK_DRIVERCAPS));
+
+ pDriverCaps->WDDMVersion = DXGKDDI_WDDMv1_2;
+ pDriverCaps->HighestAcceptableAddress.QuadPart = -1;
+
+ pDriverCaps->SupportNonVGA = TRUE;
+ pDriverCaps->SupportSmoothRotation = TRUE;
+
+ return STATUS_SUCCESS;
+ }
+
+ case DXGKQAITYPE_DISPLAY_DRIVERCAPS_EXTENSION:
+ {
+ DXGK_DISPLAY_DRIVERCAPS_EXTENSION* pDriverDisplayCaps;
+
+ if (pQueryAdapterInfo->OutputDataSize < sizeof(*pDriverDisplayCaps))
+ {
+ BDD_LOG_ERROR2("pQueryAdapterInfo->OutputDataSize (0x%I64x) is smaller than sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION) (0x%I64x)",
+ pQueryAdapterInfo->OutputDataSize,
+ sizeof(DXGK_DISPLAY_DRIVERCAPS_EXTENSION));
+
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ pDriverDisplayCaps = (DXGK_DISPLAY_DRIVERCAPS_EXTENSION*)pQueryAdapterInfo->pOutputData;
+
+ // Reset all caps values
+ RtlZeroMemory(pDriverDisplayCaps, pQueryAdapterInfo->OutputDataSize);
+
+ // We claim to support virtual display mode.
+ pDriverDisplayCaps->VirtualModeSupport = 1;
+
+ return STATUS_SUCCESS;
+ }
+
+ default:
+ {
+ // BDD does not need to support any other adapter information types
+ BDD_LOG_WARNING1("Unknown QueryAdapterInfo Type (0x%I64x) requested", pQueryAdapterInfo->Type);
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+}
+
+
+NTSTATUS BASIC_DISPLAY_DRIVER::CheckHardware()
+{
+ PAGED_CODE();
+
+ NTSTATUS Status;
+ ULONG VendorID;
+ ULONG DeviceID;
+
+// TODO: If developing a driver for PCI based hardware, then use the second method to retrieve Vendor/Device IDs.
+// If developing for non-PCI based hardware (i.e. ACPI based hardware), use the first method to retrieve the IDs.
+#if 1 // ACPI-based device
+
+ // Get the Vendor & Device IDs on non-PCI system
+ ACPI_EVAL_INPUT_BUFFER_COMPLEX AcpiInputBuffer = {0};
+ AcpiInputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE;
+ AcpiInputBuffer.MethodNameAsUlong = ACPI_METHOD_HARDWARE_ID;
+ AcpiInputBuffer.Size = 0;
+ AcpiInputBuffer.ArgumentCount = 0;
+
+ BYTE OutputBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + 0x10];
+ RtlZeroMemory(OutputBuffer, sizeof(OutputBuffer));
+ ACPI_EVAL_OUTPUT_BUFFER* pAcpiOutputBuffer = reinterpret_cast<ACPI_EVAL_OUTPUT_BUFFER*>(&OutputBuffer);
+
+ Status = m_DxgkInterface.DxgkCbEvalAcpiMethod(m_DxgkInterface.DeviceHandle,
+ DISPLAY_ADAPTER_HW_ID,
+ &AcpiInputBuffer,
+ sizeof(AcpiInputBuffer),
+ pAcpiOutputBuffer,
+ sizeof(OutputBuffer));
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed to get hardware IDs with status 0x%I64x", Status);
+ return Status;
+ }
+
+ VendorID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[0];
+ DeviceID = ((ULONG*)(pAcpiOutputBuffer->Argument[0].Data))[1];
+
+#else // PCI-based device
+
+ // Get the Vendor & Device IDs on PCI system
+ PCI_COMMON_HEADER Header = {0};
+ ULONG BytesRead;
+
+ Status = m_DxgkInterface.DxgkCbReadDeviceSpace(m_DxgkInterface.DeviceHandle,
+ DXGK_WHICHSPACE_CONFIG,
+ &Header,
+ 0,
+ sizeof(Header),
+ &BytesRead);
+
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR1("DxgkCbReadDeviceSpace failed with status 0x%I64x", Status);
+ return Status;
+ }
+
+ VendorID = Header.VendorID;
+ DeviceID = Header.DeviceID;
+
+#endif
+
+ // TODO: Replace 0x1414 with your Vendor ID
+ if (VendorID == 0x1414)
+ {
+ switch (DeviceID)
+ {
+ // TODO: Replace the case statements below with the Device IDs supported by this driver
+ case 0x0000:
+ case 0xFFFF: return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_GRAPHICS_DRIVER_MISMATCH;
+}
+
+// Even though Sample Basic Display Driver does not support hardware cursors, and reports such
+// in QueryAdapterInfo. This function can still be called to set the pointer to not visible
+NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pSetPointerPosition != NULL);
+ BDD_ASSERT(pSetPointerPosition->VidPnSourceId < MAX_VIEWS);
+
+ if (!(pSetPointerPosition->Flags.Visible))
+ {
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ BDD_LOG_ASSERTION0("SetPointerPosition should never be called to set the pointer to visible since BDD doesn't support hardware cursors.");
+ return STATUS_UNSUCCESSFUL;
+ }
+}
+
+// Basic Sample Display Driver does not support hardware cursors, and reports such
+// in QueryAdapterInfo. Therefore this function should never be called.
+NTSTATUS BASIC_DISPLAY_DRIVER::SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pSetPointerShape != NULL);
+ BDD_LOG_ASSERTION0("SetPointerShape should never be called since BDD doesn't support hardware cursors.");
+
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS BASIC_DISPLAY_DRIVER::PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pPresentDisplayOnly != NULL);
+ BDD_ASSERT(pPresentDisplayOnly->VidPnSourceId < MAX_VIEWS);
+
+ if (pPresentDisplayOnly->BytesPerPixel < MIN_BYTES_PER_PIXEL_REPORTED)
+ {
+ // Only >=32bpp modes are reported, therefore this Present should never pass anything less than 4 bytes per pixel
+ BDD_LOG_ERROR1("pPresentDisplayOnly->BytesPerPixel is 0x%I64x, which is lower than the allowed.", pPresentDisplayOnly->BytesPerPixel);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // If it is in monitor off state or source is not supposed to be visible, don't present anything to the screen
+ if ((m_MonitorPowerState > PowerDeviceD0) ||
+ (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.SourceNotVisible))
+ {
+ return STATUS_SUCCESS;
+ }
+
+ // Present is only valid if the target is actively connected to this source
+ if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Flags.FrameBufferIsActive)
+ {
+
+ // If actual pixels are coming through, will need to completely zero out physical address next time in BlackOutScreen
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutStart.QuadPart = 0;
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].ZeroedOutEnd.QuadPart = 0;
+
+
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION RotationNeededByFb = pPresentDisplayOnly->Flags.Rotate ?
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Rotation :
+ D3DKMDT_VPPR_IDENTITY;
+ BYTE* pDst = (BYTE*)m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].FrameBuffer.Ptr;
+ UINT DstBitPerPixel = BPPFromPixelFormat(m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.ColorFormat);
+ if (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].Scaling == D3DKMDT_VPPS_CENTERED)
+ {
+ UINT CenterShift = (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Height -
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeHeight)*m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Pitch;
+ CenterShift += (m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].DispInfo.Width -
+ m_CurrentModes[pPresentDisplayOnly->VidPnSourceId].SrcModeWidth)*DstBitPerPixel/8;
+ pDst += (int)CenterShift/2;
+ }
+ return m_HardwareBlt[pPresentDisplayOnly->VidPnSourceId].ExecutePresentDisplayOnly(pDst,
+ DstBitPerPixel,
+ (BYTE*)pPresentDisplayOnly->pSource,
+ pPresentDisplayOnly->BytesPerPixel,
+ pPresentDisplayOnly->Pitch,
+ pPresentDisplayOnly->NumMoves,
+ pPresentDisplayOnly->pMoves,
+ pPresentDisplayOnly->NumDirtyRects,
+ pPresentDisplayOnly->pDirtyRect,
+ RotationNeededByFb);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(TargetId < MAX_CHILDREN);
+
+
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = FindSourceForTarget(TargetId, TRUE);
+
+ // In case BDD is the next driver to run, the monitor should not be off, since
+ // this could cause the BIOS to hang when the EDID is retrieved on Start.
+ if (m_MonitorPowerState > PowerDeviceD0)
+ {
+ SetPowerState(TargetId, PowerDeviceD0, PowerActionNone);
+ }
+
+ // The driver has to black out the display and ensure it is visible when releasing ownership
+ BlackOutScreen(SourceId);
+
+ *pDisplayInfo = m_CurrentModes[SourceId].DispInfo;
+
+ return StopDevice();
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pVidPnHWCaps != NULL);
+ BDD_ASSERT(pVidPnHWCaps->SourceId < MAX_VIEWS);
+ BDD_ASSERT(pVidPnHWCaps->TargetId < MAX_CHILDREN);
+
+ pVidPnHWCaps->VidPnHWCaps.DriverRotation = 1; // BDD does rotation in software
+ pVidPnHWCaps->VidPnHWCaps.DriverScaling = 0; // BDD does not support scaling
+ pVidPnHWCaps->VidPnHWCaps.DriverCloning = 0; // BDD does not support clone
+ pVidPnHWCaps->VidPnHWCaps.DriverColorConvert = 1; // BDD does color conversions in software
+ pVidPnHWCaps->VidPnHWCaps.DriverLinkedAdapaterOutput = 0; // BDD does not support linked adapters
+ pVidPnHWCaps->VidPnHWCaps.DriverRemoteDisplay = 0; // BDD does not support remote displays
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT_CHK(!m_Flags.EDID_Attempted);
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ RtlZeroMemory(m_EDIDs[TargetId], sizeof(m_EDIDs[TargetId]));
+
+
+ m_Flags.EDID_Attempted = TRUE;
+
+ return Status;
+}
+
+
+VOID BASIC_DISPLAY_DRIVER::BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
+{
+ PAGED_CODE();
+
+
+ UINT ScreenHeight = m_CurrentModes[SourceId].DispInfo.Height;
+ UINT ScreenPitch = m_CurrentModes[SourceId].DispInfo.Pitch;
+
+ PHYSICAL_ADDRESS NewPhysAddrStart = m_CurrentModes[SourceId].DispInfo.PhysicAddress;
+ PHYSICAL_ADDRESS NewPhysAddrEnd;
+ NewPhysAddrEnd.QuadPart = NewPhysAddrStart.QuadPart + (ScreenHeight * ScreenPitch);
+
+ if (m_CurrentModes[SourceId].Flags.FrameBufferIsActive)
+ {
+ BYTE* MappedAddr = reinterpret_cast<BYTE*>(m_CurrentModes[SourceId].FrameBuffer.Ptr);
+
+ // Zero any memory at the start that hasn't been zeroed recently
+ if (NewPhysAddrStart.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart)
+ {
+ if (NewPhysAddrEnd.QuadPart < m_CurrentModes[SourceId].ZeroedOutStart.QuadPart)
+ {
+ // No overlap
+ RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);
+ }
+ else
+ {
+ RtlZeroMemory(MappedAddr, (UINT)(m_CurrentModes[SourceId].ZeroedOutStart.QuadPart - NewPhysAddrStart.QuadPart));
+ }
+ }
+
+ // Zero any memory at the end that hasn't been zeroed recently
+ if (NewPhysAddrEnd.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)
+ {
+ if (NewPhysAddrStart.QuadPart > m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart)
+ {
+ // No overlap
+ // NOTE: When actual pixels were the most recent thing drawn, ZeroedOutStart & ZeroedOutEnd will both be 0
+ // and this is the path that will be used to black out the current screen.
+ RtlZeroMemory(MappedAddr, ScreenHeight * ScreenPitch);
+ }
+ else
+ {
+ RtlZeroMemory(MappedAddr, (UINT)(NewPhysAddrEnd.QuadPart - m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart));
+ }
+ }
+ }
+
+ m_CurrentModes[SourceId].ZeroedOutStart.QuadPart = NewPhysAddrStart.QuadPart;
+ m_CurrentModes[SourceId].ZeroedOutEnd.QuadPart = NewPhysAddrEnd.QuadPart;
+
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue)
+{
+ PAGED_CODE();
+
+ NTSTATUS Status;
+ ANSI_STRING AnsiStrValue;
+ UNICODE_STRING UnicodeStrValue;
+ UNICODE_STRING UnicodeStrValueName;
+
+ // ZwSetValueKey wants the ValueName as a UNICODE_STRING
+ RtlInitUnicodeString(&UnicodeStrValueName, pszwValueName);
+
+ // REG_SZ is for WCHARs, there is no equivalent for CHARs
+ // Use the ansi/unicode conversion functions to get from PSTR to PWSTR
+ RtlInitAnsiString(&AnsiStrValue, pszValue);
+ Status = RtlAnsiStringToUnicodeString(&UnicodeStrValue, &AnsiStrValue, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR1("RtlAnsiStringToUnicodeString failed with Status: 0x%I64x", Status);
+ return Status;
+ }
+
+ // Write the value to the registry
+ Status = ZwSetValueKey(DevInstRegKeyHandle,
+ &UnicodeStrValueName,
+ 0,
+ REG_SZ,
+ UnicodeStrValue.Buffer,
+ UnicodeStrValue.MaximumLength);
+
+ // Free the earlier allocated unicode string
+ RtlFreeUnicodeString(&UnicodeStrValue);
+
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR1("ZwSetValueKey failed with Status: 0x%I64x", Status);
+ }
+
+ return Status;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::RegisterHWInfo()
+{
+ PAGED_CODE();
+
+ NTSTATUS Status;
+
+ // TODO: Replace these strings with proper information
+ PCSTR StrHWInfoChipType = "Replace with the chip name";
+ PCSTR StrHWInfoDacType = "Replace with the DAC name or identifier (ID)";
+ PCSTR StrHWInfoAdapterString = "Replace with the name of the adapter";
+ PCSTR StrHWInfoBiosString = "Replace with information about the BIOS";
+
+ HANDLE DevInstRegKeyHandle;
+ Status = IoOpenDeviceRegistryKey(m_pPhysicalDevice, PLUGPLAY_REGKEY_DRIVER, KEY_SET_VALUE, &DevInstRegKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("IoOpenDeviceRegistryKey failed for PDO: 0x%I64x, Status: 0x%I64x", m_pPhysicalDevice, Status);
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.ChipType", StrHWInfoChipType);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.DacType", StrHWInfoDacType);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.AdapterString", StrHWInfoAdapterString);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ Status = WriteHWInfoStr(DevInstRegKeyHandle, L"HardwareInformation.BiosString", StrHWInfoBiosString);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ // MemorySize is a ULONG, unlike the others which are all strings
+ UNICODE_STRING ValueNameMemorySize;
+ RtlInitUnicodeString(&ValueNameMemorySize, L"HardwareInformation.MemorySize");
+ DWORD MemorySize = 0; // BDD has no access to video memory
+ Status = ZwSetValueKey(DevInstRegKeyHandle,
+ &ValueNameMemorySize,
+ 0,
+ REG_DWORD,
+ &MemorySize,
+ sizeof(MemorySize));
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR1("ZwSetValueKey for MemorySize failed with Status: 0x%I64x", Status);
+ return Status;
+ }
+
+ return Status;
+}
+
+//
+// Non-Paged Code
+//
+#pragma code_seg(push)
+#pragma code_seg()
+D3DDDI_VIDEO_PRESENT_SOURCE_ID BASIC_DISPLAY_DRIVER::FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero)
+{
+ UNREFERENCED_PARAMETER(TargetId);
+ BDD_ASSERT_CHK(TargetId < MAX_CHILDREN);
+
+ for (UINT SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)
+ {
+ if (m_CurrentModes[SourceId].FrameBuffer.Ptr != NULL)
+ {
+ return SourceId;
+ }
+ }
+
+ return DefaultToZero ? 0 : D3DDDI_ID_UNINITIALIZED;
+}
+
+VOID BASIC_DISPLAY_DRIVER::DpcRoutine(VOID)
+{
+ m_DxgkInterface.DxgkCbNotifyDpc((HANDLE)m_DxgkInterface.DeviceHandle);
+}
+
+BOOLEAN BASIC_DISPLAY_DRIVER::InterruptRoutine(_In_ ULONG MessageNumber)
+{
+ UNREFERENCED_PARAMETER(MessageNumber);
+
+ // BDD cannot handle interrupts
+ return FALSE;
+}
+
+VOID BASIC_DISPLAY_DRIVER::ResetDevice(VOID)
+{
+}
+
+// Must be Non-Paged, as it sets up the display for a bugcheck
+NTSTATUS BASIC_DISPLAY_DRIVER::SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* pWidth,
+ _Out_ UINT* pHeight,
+ _Out_ D3DDDIFORMAT* pColorFormat)
+{
+ UNREFERENCED_PARAMETER(Flags);
+
+ m_SystemDisplaySourceId = D3DDDI_ID_UNINITIALIZED;
+
+ BDD_ASSERT((TargetId < MAX_CHILDREN) || (TargetId == D3DDDI_ID_UNINITIALIZED));
+
+ // Find the frame buffer for displaying the bugcheck, if it was successfully mapped
+ if (TargetId == D3DDDI_ID_UNINITIALIZED)
+ {
+ for (UINT SourceIdx = 0; SourceIdx < MAX_VIEWS; ++SourceIdx)
+ {
+ if (m_CurrentModes[SourceIdx].FrameBuffer.Ptr != NULL)
+ {
+ m_SystemDisplaySourceId = SourceIdx;
+ break;
+ }
+ }
+ }
+ else
+ {
+ m_SystemDisplaySourceId = FindSourceForTarget(TargetId, FALSE);
+ }
+
+ if (m_SystemDisplaySourceId == D3DDDI_ID_UNINITIALIZED)
+ {
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if ((m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE90) ||
+ (m_CurrentModes[m_SystemDisplaySourceId].Rotation == D3DKMDT_VPPR_ROTATE270))
+ {
+ *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
+ *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
+ }
+ else
+ {
+ *pWidth = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
+ *pHeight = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
+ }
+
+ *pColorFormat = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat;
+
+
+ return STATUS_SUCCESS;
+}
+
+// Must be Non-Paged, as it is called to display the bugcheck screen
+VOID BASIC_DISPLAY_DRIVER::SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ INT PositionX,
+ _In_ INT PositionY)
+{
+
+ // Rect will be Offset by PositionX/Y in the src to reset it back to 0
+ RECT Rect;
+ Rect.left = PositionX;
+ Rect.top = PositionY;
+ Rect.right = Rect.left + SourceWidth;
+ Rect.bottom = Rect.top + SourceHeight;
+
+ // Set up destination blt info
+ BLT_INFO DstBltInfo;
+ DstBltInfo.pBits = m_CurrentModes[m_SystemDisplaySourceId].FrameBuffer.Ptr;
+ DstBltInfo.Pitch = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Pitch;
+ DstBltInfo.BitsPerPel = BPPFromPixelFormat(m_CurrentModes[m_SystemDisplaySourceId].DispInfo.ColorFormat);
+ DstBltInfo.Offset.x = 0;
+ DstBltInfo.Offset.y = 0;
+ DstBltInfo.Rotation = m_CurrentModes[m_SystemDisplaySourceId].Rotation;
+ DstBltInfo.Width = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Width;
+ DstBltInfo.Height = m_CurrentModes[m_SystemDisplaySourceId].DispInfo.Height;
+
+ // Set up source blt info
+ BLT_INFO SrcBltInfo;
+ SrcBltInfo.pBits = pSource;
+ SrcBltInfo.Pitch = SourceStride;
+ SrcBltInfo.BitsPerPel = 32;
+
+ SrcBltInfo.Offset.x = -PositionX;
+ SrcBltInfo.Offset.y = -PositionY;
+ SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;
+ SrcBltInfo.Width = SourceWidth;
+ SrcBltInfo.Height = SourceHeight;
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ &Rect);
+}
+
+#pragma code_seg(pop) // End Non-Paged Code
+
diff --git a/video/KMDOD/bdd.hxx b/video/KMDOD/bdd.hxx
new file mode 100644
index 00000000..68d435ba
--- /dev/null
+++ b/video/KMDOD/bdd.hxx
@@ -0,0 +1,649 @@
+/******************************Module*Header*******************************\
+* Module Name: BDD.hxx
+*
+* Basic Display Driver header file
+*
+*
+* Copyright (c) 2010 Microsoft Corporation
+\**************************************************************************/
+
+#ifndef _BDD_HXX_
+#define _BDD_HXX_
+
+extern "C"
+{
+ #define __CPLUSPLUS
+
+ // Standard C-runtime headers
+ #include <stddef.h>
+ #include <string.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ #include <initguid.h>
+
+ // NTOS headers
+ #include <ntddk.h>
+
+ #ifndef FAR
+ #define FAR
+ #endif
+
+ // Windows headers
+ #include <windef.h>
+ #include <winerror.h>
+
+ // Windows GDI headers
+ #include <wingdi.h>
+
+ // Windows DDI headers
+ #include <winddi.h>
+ #include <ntddvdeo.h>
+
+ #include <d3dkmddi.h>
+ #include <d3dkmthk.h>
+
+ #include <ntstrsafe.h>
+ #include <ntintsafe.h>
+
+ #include <dispmprt.h>
+};
+
+#define EDID_V1_BLOCK_SIZE 128
+
+#include "BDD_ErrorLog.hxx"
+
+#define MIN_WIDTH 640
+#define MIN_HEIGHT 480
+#define MIN_BITS_PER_PIXEL_ALLOWED 8
+#define MIN_BYTES_PER_PIXEL_REPORTED 4
+
+#define DEFAULT_WIDTH 1024
+#define DEFAULT_HEIGHT 768
+
+#define MAX_INVALID_INHERITED_WIDTH 1024
+#define MAX_INVALID_INHERITED_HEIGHT 768
+
+#define BITS_PER_BYTE 8
+
+typedef struct _BLT_INFO
+{
+ PVOID pBits;
+ UINT Pitch;
+ UINT BitsPerPel;
+ POINT Offset; // To unrotated top-left of dirty rects
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;
+ UINT Width; // For the unrotated image
+ UINT Height; // For the unrotated image
+} BLT_INFO;
+
+#define MAX_CHILDREN 1
+#define MAX_VIEWS 1
+
+typedef struct _BDD_FLAGS
+{
+ UINT DriverStarted : 1; // ( 1) 1 after StartDevice and 0 after StopDevice
+ UINT EDID_Retrieved : 1; // ( 2) EDID was successfully retrieved
+ UINT EDID_ValidChecksum : 1; // ( 3) Retrieved EDID has a valid checksum
+ UINT EDID_ValidHeader : 1; // ( 4) Retrieved EDID has a valid header
+ UINT EDID_Attempted : 1; // ( 5) 1 if an attempt was made to retrieve the EDID, successful or not
+
+ // IMPORTANT: All new flags must be added to just before _LastFlag (i.e. right above this comment), this allows different versions of diagnostics to still be useful.
+ UINT _LastFlag : 1; // ( 6) Always set to 1, is used to ensure that diagnostic version matches binary version
+ UINT Unused : 26;
+} BDD_FLAGS;
+
+// Represents the current mode, may not always be set (i.e. frame buffer mapped) if representing the mode passed in on single mode setups.
+typedef struct _CURRENT_BDD_MODE
+{
+ // The source mode currently set for HW Framebuffer
+ // For sample driver this info filled in StartDevice by the OS and never changed.
+ DXGK_DISPLAY_INFORMATION DispInfo;
+
+ // The rotation of the current mode. Rotation is performed in software during Present call
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;
+
+ D3DKMDT_VIDPN_PRESENT_PATH_SCALING Scaling;
+ // This mode might be different from one which are supported for HW frame buffer
+ // Scaling/displasment might be needed (if supported)
+ UINT SrcModeWidth;
+ UINT SrcModeHeight;
+
+ // Various boolean flags the struct uses
+ struct _CURRENT_BDD_MODE_FLAGS
+ {
+ UINT SourceNotVisible : 1; // 0 if source is visible
+ UINT FullscreenPresent : 1; // 0 if should use dirty rects for present
+ UINT FrameBufferIsActive : 1; // 0 if not currently active (i.e. target not connected to source)
+ UINT DoNotMapOrUnmap : 1; // 1 if the FrameBuffer should not be (un)mapped during normal execution
+ UINT IsInternal : 1; // 1 if it was determined (i.e. through ACPI) that an internal panel is being driven
+ UINT Unused : 27;
+ } Flags;
+
+ // The start and end of physical memory known to be all zeroes. Used to optimize the BlackOutScreen function to not write
+ // zeroes to memory already known to be zero. (Physical address is located in DispInfo)
+ PHYSICAL_ADDRESS ZeroedOutStart;
+ PHYSICAL_ADDRESS ZeroedOutEnd;
+
+ // Linear frame buffer pointer
+ // A union with a ULONG64 is used here to ensure this struct looks the same on 32bit and 64bit builds
+ // since the size of a VOID* changes depending on the build.
+ union
+ {
+ VOID* Ptr;
+ ULONG64 Force8Bytes;
+ } FrameBuffer;
+} CURRENT_BDD_MODE;
+
+class BASIC_DISPLAY_DRIVER;
+
+class BDD_HWBLT
+{
+public:
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SourceId;
+ BASIC_DISPLAY_DRIVER* m_DevExt;
+ BOOLEAN m_SynchExecution;
+ HANDLE m_hPresentWorkerThread;
+ PVOID m_pPresentWorkerThread;
+
+ // Events to contol thread execution
+ KEVENT m_hThreadStartupEvent;
+ KEVENT m_hThreadSuspendEvent;
+
+ BDD_HWBLT();
+
+ ~BDD_HWBLT();
+
+ void Initialize(_In_ BASIC_DISPLAY_DRIVER* DevExt, _In_ UINT IdSrc) { m_DevExt = DevExt; m_SourceId = IdSrc; }
+ void SetPresentWorkerThreadInfo(HANDLE hWorkerThread);
+ NTSTATUS ExecutePresentDisplayOnly(_In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* pMoves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* pDirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation);
+
+};
+
+class BASIC_DISPLAY_DRIVER
+{
+private:
+ DEVICE_OBJECT* m_pPhysicalDevice;
+ DXGKRNL_INTERFACE m_DxgkInterface;
+
+ // Information passed in by StartDevice DDI
+ DXGK_START_INFO m_StartInfo;
+
+
+ // Array of EDIDs, currently only supporting base block, hence EDID_V1_BLOCK_SIZE for size of each EDID
+ BYTE m_EDIDs[MAX_CHILDREN][EDID_V1_BLOCK_SIZE];
+
+ CURRENT_BDD_MODE m_CurrentModes[MAX_VIEWS];
+
+
+ BDD_HWBLT m_HardwareBlt[MAX_VIEWS];
+
+ // Current monitorpower state (this needs to be changed if MAX_CHILDREN != 1)
+ DEVICE_POWER_STATE m_MonitorPowerState;
+
+ // Current adapter power state
+ DEVICE_POWER_STATE m_AdapterPowerState;
+
+ // Source ID to be used by SystemDisplay functions
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID m_SystemDisplaySourceId;
+
+ // Various boolean flags the class uses
+ BDD_FLAGS m_Flags;
+
+ // Device information
+ DXGK_DEVICE_INFO m_DeviceInfo;
+
+public:
+ BASIC_DISPLAY_DRIVER(_In_ DEVICE_OBJECT* pPhysicalDeviceObject);
+ ~BASIC_DISPLAY_DRIVER();
+
+#pragma code_seg(push)
+#pragma code_seg()
+ BOOLEAN IsDriverActive() const
+ {
+ return m_Flags.DriverStarted;
+ }
+#pragma code_seg(pop)
+
+ NTSTATUS StartDevice(_In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren);
+
+ NTSTATUS StopDevice(VOID);
+
+ // Must be Non-Paged
+ VOID ResetDevice(VOID);
+
+
+ const CURRENT_BDD_MODE* GetCurrentMode(UINT SourceId) const
+ {
+ return (SourceId < MAX_VIEWS)?&m_CurrentModes[SourceId]:NULL;
+ }
+ const DXGKRNL_INTERFACE* GetDxgkInterface() const { return &m_DxgkInterface;}
+
+ // Not implemented since no IOCTLs currently handled.
+ NTSTATUS DispatchIoRequest(_In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket);
+
+ // Used to either turn off/on monitor (if possible), or mark that system is going into hibernate
+ NTSTATUS SetPowerState(_In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType);
+
+ // Report back child capabilities
+ NTSTATUS QueryChildRelations(_Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize);
+
+ NTSTATUS QueryChildStatus(_Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly);
+
+ // Return EDID if previously retrieved
+ NTSTATUS QueryDeviceDescriptor(_In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor);
+
+ // Must be Non-Paged
+ // BDD doesn't have interrupts, so just returns false
+ BOOLEAN InterruptRoutine(_In_ ULONG MessageNumber);
+
+ VOID DpcRoutine(VOID);
+
+ // Return DriverCaps, doesn't support other queries though
+ NTSTATUS QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo);
+
+ NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
+
+ NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
+
+ NTSTATUS PresentDisplayOnly(_In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly);
+
+ NTSTATUS IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn);
+
+ NTSTATUS RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn);
+
+ NTSTATUS RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology);
+
+ NTSTATUS RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);
+
+ NTSTATUS EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality);
+
+ NTSTATUS SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility);
+
+ NTSTATUS CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn);
+
+ NTSTATUS UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath);
+
+ NTSTATUS QueryVidPnHWCapability(_Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps);
+
+ // Part of PnPStop (PnP instance only), returns current mode information (which will be passed to fallback instance by dxgkrnl)
+ NTSTATUS StopDeviceAndReleasePostDisplayOwnership(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* pDisplayInfo);
+
+ // Must be Non-Paged
+ // Call to initialize as part of bugcheck
+ NTSTATUS SystemDisplayEnable(_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* pWidth,
+ _Out_ UINT* pHeight,
+ _Out_ D3DDDIFORMAT* pColorFormat);
+
+ // Must be Non-Paged
+ // Write out pixels as part of bugcheck
+ VOID SystemDisplayWrite(_In_reads_bytes_(SourceHeight * SourceStride) VOID* pSource,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ INT PositionX,
+ _In_ INT PositionY);
+
+
+private:
+ VOID CleanUp();
+
+ NTSTATUS CommonStart();
+
+ NTSTATUS GetEdid(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId);
+
+
+ // Given pixel format, give back the bits per pixel. Only supports pixel formats expected by BDD
+ // (i.e. the ones found below in PixelFormatFromBPP or that may come in from FallbackStart)
+ // This is because these two functions combine to allow BDD to store the bpp of a VBE mode in the
+ // ColorFormat field of a DispInfo
+ UINT BPPFromPixelFormat(D3DDDIFORMAT Format) const
+ {
+ switch (Format)
+ {
+ case D3DDDIFMT_UNKNOWN: return 0;
+ case D3DDDIFMT_P8: return 8;
+ case D3DDDIFMT_R5G6B5: return 16;
+ case D3DDDIFMT_R8G8B8: return 24;
+ case D3DDDIFMT_X8R8G8B8: // fall through
+ case D3DDDIFMT_A8R8G8B8: return 32;
+ default: BDD_LOG_ASSERTION1("Unknown D3DDDIFORMAT 0x%I64x", Format); return 0;
+ }
+ }
+
+ // Given bits per pixel, return the pixel format at the same bpp
+ D3DDDIFORMAT PixelFormatFromBPP(UINT BPP) const
+ {
+ switch (BPP)
+ {
+ case 8: return D3DDDIFMT_P8;
+ case 16: return D3DDDIFMT_R5G6B5;
+ case 24: return D3DDDIFMT_R8G8B8;
+ case 32: return D3DDDIFMT_X8R8G8B8;
+ default: BDD_LOG_ASSERTION1("A bit per pixel of 0x%I64x is not supported.", BPP); return D3DDDIFMT_UNKNOWN;
+ }
+ }
+
+ // These two functions make checks on the values of some of the fields of their respective structures to ensure
+ // that the specified fields are supported by BDD, i.e. gamma ramp must be D3DDDI_GAMMARAMP_DEFAULT
+ NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const;
+ NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const;
+
+ VOID BlackOutScreen(D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);
+
+ // Returns the index into gBddBiosData.BddModes of the VBE mode that matches the given VidPnSourceMode.
+ // If such a mode cannot be found, returns a number outside of [0, gBddBiosData.CountBddModes)
+ UINT FindMatchingVBEMode(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const;
+
+ // Must be Non-Paged
+ // Returns the SourceId that has TargetId as a valid frame buffer or D3DDDI_ID_UNINITIALIZED if no such SourceId exists
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID FindSourceForTarget(D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId, BOOLEAN DefaultToZero);
+
+ // Set the given source mode on the given path
+ NTSTATUS SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath);
+
+
+ // Add the current mode to the given monitor source mode set
+ NTSTATUS AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);
+
+
+ // Add the current mode to the given VidPn source mode set
+ NTSTATUS AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);
+
+ // Add the current mode (or the matching to pinned source mode) to the give VidPn target mode set
+ NTSTATUS AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,
+ D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,
+ _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId);
+
+ // Check that the hardware the driver is running on is hardware it is capable of driving.
+ NTSTATUS CheckHardware();
+
+ // Helper function for RegisterHWInfo
+ NTSTATUS WriteHWInfoStr(_In_ HANDLE DevInstRegKeyHandle, _In_ PCWSTR pszwValueName, _In_ PCSTR pszValue);
+
+ // Set the information in the registry as described here: http://msdn.microsoft.com/en-us/library/windows/hardware/ff569240(v=vs.85).aspx
+ NTSTATUS RegisterHWInfo();
+};
+
+//
+// Blt functions
+//
+
+// Must be Non-Paged
+VOID BltBits(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects);
+
+//
+// Driver Entry point
+//
+
+extern "C"
+DRIVER_INITIALIZE DriverEntry;
+
+//
+// PnP DDIs
+//
+
+VOID
+BddDdiUnload(VOID);
+
+// If uncommenting ENABLE_DXGK_SAL in the sources file, all the below function prototypes should be updated to use
+// the function typedef's from the header files. Additionally, annotations on the function definitions can be removed
+// as they are inherited from the prototype definition here. As an example the entire 4-line prototype for BddDdiAddDevice
+// is replaced by the single commented line below:
+// DXGKDDI_ADD_DEVICE BddDdiAddDevice;
+NTSTATUS
+BddDdiAddDevice(
+ _In_ DEVICE_OBJECT* pPhysicalDeviceObject,
+ _Outptr_ PVOID* ppDeviceContext);
+
+NTSTATUS
+BddDdiRemoveDevice(
+ _In_ VOID* pDeviceContext);
+
+NTSTATUS
+BddDdiStartDevice(
+ _In_ VOID* pDeviceContext,
+ _In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren);
+
+NTSTATUS
+BddDdiStopDevice(
+ _In_ VOID* pDeviceContext);
+
+VOID
+BddDdiResetDevice(
+ _In_ VOID* pDeviceContext);
+
+
+NTSTATUS
+BddDdiDispatchIoRequest(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket);
+
+NTSTATUS
+BddDdiSetPowerState(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType);
+
+NTSTATUS
+BddDdiQueryChildRelations(
+ _In_ VOID* pDeviceContext,
+ _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize);
+
+NTSTATUS
+BddDdiQueryChildStatus(
+ _In_ VOID* pDeviceContext,
+ _Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly);
+
+NTSTATUS
+BddDdiQueryDeviceDescriptor(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor);
+
+// Must be Non-Paged
+BOOLEAN
+BddDdiInterruptRoutine(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG MessageNumber);
+
+VOID
+BddDdiDpcRoutine(
+ _In_ VOID* pDeviceContext);
+
+//
+// WDDM Display Only Driver DDIs
+//
+
+NTSTATUS
+APIENTRY
+BddDdiQueryAdapterInfo(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo);
+
+NTSTATUS
+APIENTRY
+BddDdiSetPointerPosition(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
+
+NTSTATUS
+APIENTRY
+BddDdiSetPointerShape(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
+
+NTSTATUS
+APIENTRY
+BddDdiPresentDisplayOnly(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly);
+
+NTSTATUS
+APIENTRY
+BddDdiIsSupportedVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn);
+
+NTSTATUS
+APIENTRY
+BddDdiRecommendFunctionalVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn);
+
+NTSTATUS
+APIENTRY
+BddDdiRecommendVidPnTopology(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology);
+
+NTSTATUS
+APIENTRY
+BddDdiRecommendMonitorModes(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes);
+
+NTSTATUS
+APIENTRY
+BddDdiEnumVidPnCofuncModality(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality);
+
+NTSTATUS
+APIENTRY
+BddDdiSetVidPnSourceVisibility(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility);
+
+NTSTATUS
+APIENTRY
+BddDdiCommitVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn);
+
+NTSTATUS
+APIENTRY
+BddDdiUpdateActiveVidPnPresentPath(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath);
+
+NTSTATUS
+APIENTRY
+BddDdiQueryVidPnHWCapability(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps);
+
+NTSTATUS
+APIENTRY
+BddDdiStopDeviceAndReleasePostDisplayOwnership(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo);
+
+// Must be Non-Paged
+NTSTATUS
+APIENTRY
+BddDdiSystemDisplayEnable(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* Width,
+ _Out_ UINT* Height,
+ _Out_ D3DDDIFORMAT* ColorFormat);
+
+// Must be Non-Paged
+VOID
+APIENTRY
+BddDdiSystemDisplayWrite(
+ _In_ VOID* pDeviceContext,
+ _In_ VOID* Source,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ UINT PositionX,
+ _In_ UINT PositionY);
+
+//
+// Frame buffer map/unmap
+//
+
+NTSTATUS
+MapFrameBuffer(
+ _In_ PHYSICAL_ADDRESS PhysicalAddress,
+ _In_ ULONG Length,
+ _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress);
+
+NTSTATUS
+UnmapFrameBuffer(
+ _In_reads_bytes_(Length) VOID* VirtualAddress,
+ _In_ ULONG Length);
+
+
+BOOLEAN
+IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid);
+
+BOOLEAN
+IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid);
+
+//
+// Memory handling
+//
+
+// Defaulting the value of PoolType means that any call to new Foo()
+// will raise a compiler error for being ambiguous. This is to help keep
+// any calls to allocate memory from accidentally NOT going through
+// these functions.
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new(size_t Size, POOL_TYPE PoolType = PagedPool);
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType = PagedPool);
+void __cdecl operator delete(void* pObject);
+void __cdecl operator delete[](void* pObject);
+
+// Pool allocation tag for the Sample Display Driver. All allocations use this tag.
+#define BDDTAG 'DDBS'
+
+#endif // _BDD_HXX_
+
+
diff --git a/video/KMDOD/bdd_ddi.cxx b/video/KMDOD/bdd_ddi.cxx
new file mode 100644
index 00000000..5a53a3be
--- /dev/null
+++ b/video/KMDOD/bdd_ddi.cxx
@@ -0,0 +1,579 @@
+/******************************Module*Header*******************************\
+* Module Name: BDD_DDI.cxx
+*
+* Basic Display Driver DDI entry points redirects
+*
+*
+* Copyright (c) 2010 Microsoft Corporation
+\**************************************************************************/
+
+#include "BDD.hxx"
+
+
+#pragma code_seg(push)
+#pragma code_seg("INIT")
+// BEGIN: Init Code
+
+//
+// Driver Entry point
+//
+
+extern "C"
+NTSTATUS
+DriverEntry(
+ _In_ DRIVER_OBJECT* pDriverObject,
+ _In_ UNICODE_STRING* pRegistryPath)
+{
+ PAGED_CODE();
+
+
+ // Initialize DDI function pointers and dxgkrnl
+ KMDDOD_INITIALIZATION_DATA InitialData = {0};
+
+ InitialData.Version = DXGKDDI_INTERFACE_VERSION;
+
+ InitialData.DxgkDdiAddDevice = BddDdiAddDevice;
+ InitialData.DxgkDdiStartDevice = BddDdiStartDevice;
+ InitialData.DxgkDdiStopDevice = BddDdiStopDevice;
+ InitialData.DxgkDdiResetDevice = BddDdiResetDevice;
+ InitialData.DxgkDdiRemoveDevice = BddDdiRemoveDevice;
+ InitialData.DxgkDdiDispatchIoRequest = BddDdiDispatchIoRequest;
+ InitialData.DxgkDdiInterruptRoutine = BddDdiInterruptRoutine;
+ InitialData.DxgkDdiDpcRoutine = BddDdiDpcRoutine;
+ InitialData.DxgkDdiQueryChildRelations = BddDdiQueryChildRelations;
+ InitialData.DxgkDdiQueryChildStatus = BddDdiQueryChildStatus;
+ InitialData.DxgkDdiQueryDeviceDescriptor = BddDdiQueryDeviceDescriptor;
+ InitialData.DxgkDdiSetPowerState = BddDdiSetPowerState;
+ InitialData.DxgkDdiUnload = BddDdiUnload;
+ InitialData.DxgkDdiQueryAdapterInfo = BddDdiQueryAdapterInfo;
+ InitialData.DxgkDdiSetPointerPosition = BddDdiSetPointerPosition;
+ InitialData.DxgkDdiSetPointerShape = BddDdiSetPointerShape;
+ InitialData.DxgkDdiIsSupportedVidPn = BddDdiIsSupportedVidPn;
+ InitialData.DxgkDdiRecommendFunctionalVidPn = BddDdiRecommendFunctionalVidPn;
+ InitialData.DxgkDdiEnumVidPnCofuncModality = BddDdiEnumVidPnCofuncModality;
+ InitialData.DxgkDdiSetVidPnSourceVisibility = BddDdiSetVidPnSourceVisibility;
+ InitialData.DxgkDdiCommitVidPn = BddDdiCommitVidPn;
+ InitialData.DxgkDdiUpdateActiveVidPnPresentPath = BddDdiUpdateActiveVidPnPresentPath;
+ InitialData.DxgkDdiRecommendMonitorModes = BddDdiRecommendMonitorModes;
+ InitialData.DxgkDdiQueryVidPnHWCapability = BddDdiQueryVidPnHWCapability;
+ InitialData.DxgkDdiPresentDisplayOnly = BddDdiPresentDisplayOnly;
+ InitialData.DxgkDdiStopDeviceAndReleasePostDisplayOwnership = BddDdiStopDeviceAndReleasePostDisplayOwnership;
+ InitialData.DxgkDdiSystemDisplayEnable = BddDdiSystemDisplayEnable;
+ InitialData.DxgkDdiSystemDisplayWrite = BddDdiSystemDisplayWrite;
+
+ NTSTATUS Status = DxgkInitializeDisplayOnlyDriver(pDriverObject, pRegistryPath, &InitialData);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR1("DxgkInitializeDisplayOnlyDriver failed with Status: 0x%I64x", Status);
+ return Status;
+ }
+
+
+ return Status;
+}
+// END: Init Code
+#pragma code_seg(pop)
+
+#pragma code_seg(push)
+#pragma code_seg("PAGE")
+
+//
+// PnP DDIs
+//
+
+VOID
+BddDdiUnload(VOID)
+{
+ PAGED_CODE();
+}
+
+NTSTATUS
+BddDdiAddDevice(
+ _In_ DEVICE_OBJECT* pPhysicalDeviceObject,
+ _Outptr_ PVOID* ppDeviceContext)
+{
+ PAGED_CODE();
+
+ if ((pPhysicalDeviceObject == NULL) ||
+ (ppDeviceContext == NULL))
+ {
+ BDD_LOG_ERROR2("One of pPhysicalDeviceObject (0x%I64x), ppDeviceContext (0x%I64x) is NULL",
+ pPhysicalDeviceObject, ppDeviceContext);
+ return STATUS_INVALID_PARAMETER;
+ }
+ *ppDeviceContext = NULL;
+
+ BASIC_DISPLAY_DRIVER* pBDD = new(NonPagedPoolNx) BASIC_DISPLAY_DRIVER(pPhysicalDeviceObject);
+ if (pBDD == NULL)
+ {
+ BDD_LOG_LOW_RESOURCE0("pBDD failed to be allocated");
+ return STATUS_NO_MEMORY;
+ }
+
+ *ppDeviceContext = pBDD;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BddDdiRemoveDevice(
+ _In_ VOID* pDeviceContext)
+{
+ PAGED_CODE();
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+
+ if (pBDD)
+ {
+ delete pBDD;
+ pBDD = NULL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BddDdiStartDevice(
+ _In_ VOID* pDeviceContext,
+ _In_ DXGK_START_INFO* pDxgkStartInfo,
+ _In_ DXGKRNL_INTERFACE* pDxgkInterface,
+ _Out_ ULONG* pNumberOfViews,
+ _Out_ ULONG* pNumberOfChildren)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->StartDevice(pDxgkStartInfo, pDxgkInterface, pNumberOfViews, pNumberOfChildren);
+}
+
+NTSTATUS
+BddDdiStopDevice(
+ _In_ VOID* pDeviceContext)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->StopDevice();
+}
+
+
+NTSTATUS
+BddDdiDispatchIoRequest(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG VidPnSourceId,
+ _In_ VIDEO_REQUEST_PACKET* pVideoRequestPacket)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->DispatchIoRequest(VidPnSourceId, pVideoRequestPacket);
+}
+
+NTSTATUS
+BddDdiSetPowerState(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG HardwareUid,
+ _In_ DEVICE_POWER_STATE DevicePowerState,
+ _In_ POWER_ACTION ActionType)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ if (!pBDD->IsDriverActive())
+ {
+ // If the driver isn't active, SetPowerState can still be called, however in BDD's case
+ // this shouldn't do anything, as it could for instance be called on BDD Fallback after
+ // Fallback has been stopped and BDD PnP is being started. Fallback doesn't have control
+ // of the hardware in this case.
+ return STATUS_SUCCESS;
+ }
+ return pBDD->SetPowerState(HardwareUid, DevicePowerState, ActionType);
+}
+
+NTSTATUS
+BddDdiQueryChildRelations(
+ _In_ VOID* pDeviceContext,
+ _Out_writes_bytes_(ChildRelationsSize) DXGK_CHILD_DESCRIPTOR* pChildRelations,
+ _In_ ULONG ChildRelationsSize)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->QueryChildRelations(pChildRelations, ChildRelationsSize);
+}
+
+NTSTATUS
+BddDdiQueryChildStatus(
+ _In_ VOID* pDeviceContext,
+ _Inout_ DXGK_CHILD_STATUS* pChildStatus,
+ _In_ BOOLEAN NonDestructiveOnly)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->QueryChildStatus(pChildStatus, NonDestructiveOnly);
+}
+
+NTSTATUS
+BddDdiQueryDeviceDescriptor(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG ChildUid,
+ _Inout_ DXGK_DEVICE_DESCRIPTOR* pDeviceDescriptor)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ if (!pBDD->IsDriverActive())
+ {
+ // During stress testing of PnPStop, it is possible for BDD Fallback to get called to start then stop in quick succession.
+ // The first call queues a worker thread item indicating that it now has a child device, the second queues a worker thread
+ // item that it no longer has any child device. This function gets called based on the first worker thread item, but after
+ // the driver has been stopped. Therefore instead of asserting like other functions, we only warn.
+ BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->QueryDeviceDescriptor(ChildUid, pDeviceDescriptor);
+}
+
+
+//
+// WDDM Display Only Driver DDIs
+//
+
+NTSTATUS
+APIENTRY
+BddDdiQueryAdapterInfo(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAdapterInfo)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ return pBDD->QueryAdapterInfo(pQueryAdapterInfo);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiSetPointerPosition(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->SetPointerPosition(pSetPointerPosition);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiSetPointerShape(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->SetPointerShape(pSetPointerShape);
+}
+
+
+NTSTATUS
+APIENTRY
+BddDdiPresentDisplayOnly(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_PRESENT_DISPLAYONLY* pPresentDisplayOnly)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->PresentDisplayOnly(pPresentDisplayOnly);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiStopDeviceAndReleasePostDisplayOwnership(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _Out_ DXGK_DISPLAY_INFORMATION* DisplayInfo)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->StopDeviceAndReleasePostDisplayOwnership(TargetId, DisplayInfo);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiIsSupportedVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ // This path might hit because win32k/dxgport doesn't check that an adapter is active when taking the adapter lock.
+ // The adapter lock is the main thing BDD Fallback relies on to not be called while it's inactive. It is still a rare
+ // timing issue around PnpStart/Stop and isn't expected to have any effect on the stability of the system.
+ BDD_LOG_WARNING1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->IsSupportedVidPn(pIsSupportedVidPn);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiRecommendFunctionalVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->RecommendFunctionalVidPn(pRecommendFunctionalVidPn);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiRecommendVidPnTopology(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->RecommendVidPnTopology(pRecommendVidPnTopology);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiRecommendMonitorModes(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->RecommendMonitorModes(pRecommendMonitorModes);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiEnumVidPnCofuncModality(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->EnumVidPnCofuncModality(pEnumCofuncModality);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiSetVidPnSourceVisibility(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->SetVidPnSourceVisibility(pSetVidPnSourceVisibility);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiCommitVidPn(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->CommitVidPn(pCommitVidPn);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiUpdateActiveVidPnPresentPath(
+ _In_ CONST HANDLE hAdapter,
+ _In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->UpdateActiveVidPnPresentPath(pUpdateActiveVidPnPresentPath);
+}
+
+NTSTATUS
+APIENTRY
+BddDdiQueryVidPnHWCapability(
+ _In_ CONST HANDLE hAdapter,
+ _Inout_ DXGKARG_QUERYVIDPNHWCAPABILITY* pVidPnHWCaps)
+{
+ PAGED_CODE();
+ BDD_ASSERT_CHK(hAdapter != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(hAdapter);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return STATUS_UNSUCCESSFUL;
+ }
+ return pBDD->QueryVidPnHWCapability(pVidPnHWCaps);
+}
+//END: Paged Code
+#pragma code_seg(pop)
+
+#pragma code_seg(push)
+#pragma code_seg()
+// BEGIN: Non-Paged Code
+
+VOID
+BddDdiDpcRoutine(
+ _In_ VOID* pDeviceContext)
+{
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ if (!pBDD->IsDriverActive())
+ {
+ BDD_LOG_ASSERTION1("BDD (0x%I64x) is being called when not active!", pBDD);
+ return;
+ }
+ pBDD->DpcRoutine();
+}
+
+BOOLEAN
+BddDdiInterruptRoutine(
+ _In_ VOID* pDeviceContext,
+ _In_ ULONG MessageNumber)
+{
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->InterruptRoutine(MessageNumber);
+}
+
+VOID
+BddDdiResetDevice(
+ _In_ VOID* pDeviceContext)
+{
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ pBDD->ResetDevice();
+}
+
+NTSTATUS
+APIENTRY
+BddDdiSystemDisplayEnable(
+ _In_ VOID* pDeviceContext,
+ _In_ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId,
+ _In_ PDXGKARG_SYSTEM_DISPLAY_ENABLE_FLAGS Flags,
+ _Out_ UINT* Width,
+ _Out_ UINT* Height,
+ _Out_ D3DDDIFORMAT* ColorFormat)
+{
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ return pBDD->SystemDisplayEnable(TargetId, Flags, Width, Height, ColorFormat);
+}
+
+VOID
+APIENTRY
+BddDdiSystemDisplayWrite(
+ _In_ VOID* pDeviceContext,
+ _In_ VOID* Source,
+ _In_ UINT SourceWidth,
+ _In_ UINT SourceHeight,
+ _In_ UINT SourceStride,
+ _In_ UINT PositionX,
+ _In_ UINT PositionY)
+{
+ BDD_ASSERT_CHK(pDeviceContext != NULL);
+
+ BASIC_DISPLAY_DRIVER* pBDD = reinterpret_cast<BASIC_DISPLAY_DRIVER*>(pDeviceContext);
+ pBDD->SystemDisplayWrite(Source, SourceWidth, SourceHeight, SourceStride, PositionX, PositionY);
+}
+
+// END: Non-Paged Code
+#pragma code_seg(pop)
+
diff --git a/video/KMDOD/bdd_dmm.cxx b/video/KMDOD/bdd_dmm.cxx
new file mode 100644
index 00000000..95c59538
--- /dev/null
+++ b/video/KMDOD/bdd_dmm.cxx
@@ -0,0 +1,1083 @@
+/******************************Module*Header*******************************\
+* Module Name: bdd_dmm.hxx
+*
+* Basic Display Driver display-mode management (DMM) function implementations
+*
+*
+* Copyright (c) 2010 Microsoft Corporation
+\**************************************************************************/
+
+#include "BDD.hxx"
+
+#pragma code_seg("PAGE")
+
+// Display-Only Devices can only return display modes of D3DDDIFMT_A8R8G8B8.
+// Color conversion takes place if the app's fullscreen backbuffer has different format.
+// Full display drivers can add more if the hardware supports them.
+D3DDDIFORMAT gBddPixelFormats[] = {
+ D3DDDIFMT_A8R8G8B8
+};
+
+// TODO: Need to also check pinned modes and the path parameters, not just topology
+NTSTATUS BASIC_DISPLAY_DRIVER::IsSupportedVidPn(_Inout_ DXGKARG_ISSUPPORTEDVIDPN* pIsSupportedVidPn)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pIsSupportedVidPn != NULL);
+
+ if (pIsSupportedVidPn->hDesiredVidPn == 0)
+ {
+ // A null desired VidPn is supported
+ pIsSupportedVidPn->IsVidPnSupported = TRUE;
+ return STATUS_SUCCESS;
+ }
+
+ // Default to not supported, until shown it is supported
+ pIsSupportedVidPn->IsVidPnSupported = FALSE;
+
+ CONST DXGK_VIDPN_INTERFACE* pVidPnInterface;
+ NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pIsSupportedVidPn->hDesiredVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn);
+ return Status;
+ }
+
+ D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology;
+ CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface;
+ Status = pVidPnInterface->pfnGetTopology(pIsSupportedVidPn->hDesiredVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hDesiredVidPn = 0x%I64x", Status, pIsSupportedVidPn->hDesiredVidPn);
+ return Status;
+ }
+
+ // For every source in this topology, make sure they don't have more paths than there are targets
+ for (D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId = 0; SourceId < MAX_VIEWS; ++SourceId)
+ {
+ SIZE_T NumPathsFromSource = 0;
+ Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, SourceId, &NumPathsFromSource);
+ if (Status == STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY)
+ {
+ continue;
+ }
+ else if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnGetNumPathsFromSource failed with Status = 0x%I64x. hVidPnTopology = 0x%I64x, SourceId = 0x%I64x",
+ Status, hVidPnTopology, SourceId);
+ return Status;
+ }
+ else if (NumPathsFromSource > MAX_CHILDREN)
+ {
+ // This VidPn is not supported, which has already been set as the default
+ return STATUS_SUCCESS;
+ }
+ }
+
+ // All sources succeeded so this VidPn is supported
+ pIsSupportedVidPn->IsVidPnSupported = TRUE;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::RecommendFunctionalVidPn(_In_ CONST DXGKARG_RECOMMENDFUNCTIONALVIDPN* CONST pRecommendFunctionalVidPn)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pRecommendFunctionalVidPn == NULL);
+
+ return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::RecommendVidPnTopology(_In_ CONST DXGKARG_RECOMMENDVIDPNTOPOLOGY* CONST pRecommendVidPnTopology)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pRecommendVidPnTopology == NULL);
+
+ return STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::RecommendMonitorModes(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
+{
+ PAGED_CODE();
+
+ // This is always called to recommend modes for the monitor. The sample driver doesn't provide EDID for a monitor, so
+ // the OS prefills the list with default monitor modes. Since the required mode might not be in the list, it should
+ // be provided as a recommended mode.
+ return AddSingleMonitorMode(pRecommendMonitorModes);
+}
+
+// Tell DMM about all the modes, etc. that are supported
+NTSTATUS BASIC_DISPLAY_DRIVER::EnumVidPnCofuncModality(_In_ CONST DXGKARG_ENUMVIDPNCOFUNCMODALITY* CONST pEnumCofuncModality)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pEnumCofuncModality != NULL);
+
+ D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0;
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0;
+ D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet = 0;
+ CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
+ CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL;
+ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;
+ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface = NULL;
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL;
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPathTemp = NULL; // Used for AcquireNextPathInfo
+ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo = NULL;
+ CONST D3DKMDT_VIDPN_TARGET_MODE* pVidPnPinnedTargetModeInfo = NULL;
+
+ // Get the VidPn Interface so we can get the 'Source Mode Set', 'Target Mode Set' and 'VidPn Topology' interfaces
+ NTSTATUS Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pEnumCofuncModality->hConstrainingVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn);
+ return Status;
+ }
+
+ // Get the VidPn Topology interface so we can enumerate all paths
+ Status = pVidPnInterface->pfnGetTopology(pEnumCofuncModality->hConstrainingVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pEnumCofuncModality->hConstrainingVidPn);
+ return Status;
+ }
+
+ // Get the first path before we start looping through them
+ Status = pVidPnTopologyInterface->pfnAcquireFirstPathInfo(hVidPnTopology, &pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnAcquireFirstPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
+ return Status;
+ }
+
+ // Loop through all available paths.
+ while (Status != STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)
+ {
+ // Get the Source Mode Set interface so the pinned mode can be retrieved
+ Status = pVidPnInterface->pfnAcquireSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnSourceId,
+ &hVidPnSourceModeSet,
+ &pVidPnSourceModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId);
+ break;
+ }
+
+ // Get the pinned mode, needed when VidPnSource isn't pivot, and when VidPnTarget isn't pivot
+ Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pVidPnPinnedSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);
+ break;
+ }
+
+ // SOURCE MODES: If this source mode isn't the pivot point, do work on the source mode set
+ if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNSOURCE) &&
+ (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId)))
+ {
+ // If there's no pinned source add possible modes (otherwise they've already been added)
+ if (pVidPnPinnedSourceModeInfo == NULL)
+ {
+ // Release the acquired source mode set, since going to create a new one to put all modes in
+ Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ break;
+ }
+ hVidPnSourceModeSet = 0; // Successfully released it
+
+ // Create a new source mode set which will be added to the constraining VidPn with all the possible modes
+ Status = pVidPnInterface->pfnCreateNewSourceModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnSourceId,
+ &hVidPnSourceModeSet,
+ &pVidPnSourceModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnCreateNewSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId);
+ break;
+ }
+
+ // Add the appropriate modes to the source mode set
+ {
+ Status = AddSingleSourceMode(pVidPnSourceModeSetInterface, hVidPnSourceModeSet, pVidPnPresentPath->VidPnSourceId);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ // Give DMM back the source modes just populated
+ Status = pVidPnInterface->pfnAssignSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR4("pfnAssignSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, SourceId = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnSourceId, hVidPnSourceModeSet);
+ break;
+ }
+ hVidPnSourceModeSet = 0; // Successfully assigned it (equivalent to releasing it)
+ }
+ }// End: SOURCE MODES
+
+ // TARGET MODES: If this target mode isn't the pivot point, do work on the target mode set
+ if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_VIDPNTARGET) &&
+ (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
+ {
+ // Get the Target Mode Set interface so modes can be added if necessary
+ Status = pVidPnInterface->pfnAcquireTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnTargetId,
+ &hVidPnTargetModeSet,
+ &pVidPnTargetModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnAcquireTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId);
+ break;
+ }
+
+ Status = pVidPnTargetModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnTargetModeSet, &pVidPnPinnedTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet);
+ break;
+ }
+
+ // If there's no pinned target add possible modes (otherwise they've already been added)
+ if (pVidPnPinnedTargetModeInfo == NULL)
+ {
+ // Release the acquired target mode set, since going to create a new one to put all modes in
+ Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ break;
+ }
+ hVidPnTargetModeSet = 0; // Successfully released it
+
+ // Create a new target mode set which will be added to the constraining VidPn with all the possible modes
+ Status = pVidPnInterface->pfnCreateNewTargetModeSet(pEnumCofuncModality->hConstrainingVidPn,
+ pVidPnPresentPath->VidPnTargetId,
+ &hVidPnTargetModeSet,
+ &pVidPnTargetModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnCreateNewTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId);
+ break;
+ }
+
+ Status = AddSingleTargetMode(pVidPnTargetModeSetInterface, hVidPnTargetModeSet, pVidPnPinnedSourceModeInfo, pVidPnPresentPath->VidPnSourceId);
+
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ // Give DMM back the source modes just populated
+ Status = pVidPnInterface->pfnAssignTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR4("pfnAssignTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, TargetId = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, pVidPnPresentPath->VidPnTargetId, hVidPnTargetModeSet);
+ break;
+ }
+ hVidPnTargetModeSet = 0; // Successfully assigned it (equivalent to releasing it)
+ }
+ else
+ {
+ // Release the pinned target as there's no other work to do
+ Status = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnPinnedTargetModeInfo = 0x%I64x",
+ Status, hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
+ break;
+ }
+ pVidPnPinnedTargetModeInfo = NULL; // Successfully released it
+
+ // Release the acquired target mode set, since it is no longer needed
+ Status = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ASSERTION3("pfnReleaseTargetModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnTargetModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ break;
+ }
+ hVidPnTargetModeSet = 0; // Successfully released it
+ }
+ }// End: TARGET MODES
+
+ // Nothing else needs the pinned source mode so release it
+ if (pVidPnPinnedSourceModeInfo != NULL)
+ {
+ Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ASSERTION3("pfnReleaseModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnPinnedSourceModeInfo = 0x%I64x",
+ Status, hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
+ break;
+ }
+ pVidPnPinnedSourceModeInfo = NULL; // Successfully released it
+ }
+
+ // With the pinned source mode now released, if the source mode set hasn't been released, release that as well
+ if (hVidPnSourceModeSet != 0)
+ {
+ Status = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnReleaseSourceModeSet failed with Status = 0x%I64x, hConstrainingVidPn = 0x%I64x, hVidPnSourceModeSet = 0x%I64x",
+ Status, pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ break;
+ }
+ hVidPnSourceModeSet = 0; // Successfully released it
+ }
+
+ // If modifying support fields, need to modify a local version of a path structure since the retrieved one is const
+ D3DKMDT_VIDPN_PRESENT_PATH LocalVidPnPresentPath = *pVidPnPresentPath;
+ BOOLEAN SupportFieldsModified = FALSE;
+
+ // SCALING: If this path's scaling isn't the pivot point, do work on the scaling support
+ if (!((pEnumCofuncModality->EnumPivotType == D3DKMDT_EPT_SCALING) &&
+ (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&
+ (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
+ {
+ // If the scaling is unpinned, then modify the scaling support field
+ if (pVidPnPresentPath->ContentTransformation.Scaling == D3DKMDT_VPPS_UNPINNED)
+ {
+ // Identity and centered scaling are supported, but not any stretch modes
+ RtlZeroMemory(&(LocalVidPnPresentPath.ContentTransformation.ScalingSupport), sizeof(D3DKMDT_VIDPN_PRESENT_PATH_SCALING_SUPPORT));
+ LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Identity = 1;
+ LocalVidPnPresentPath.ContentTransformation.ScalingSupport.Centered = 1;
+ SupportFieldsModified = TRUE;
+ }
+ } // End: SCALING
+
+ // ROTATION: If this path's rotation isn't the pivot point, do work on the rotation support
+ if (!((pEnumCofuncModality->EnumPivotType != D3DKMDT_EPT_ROTATION) &&
+ (pEnumCofuncModality->EnumPivot.VidPnSourceId == pVidPnPresentPath->VidPnSourceId) &&
+ (pEnumCofuncModality->EnumPivot.VidPnTargetId == pVidPnPresentPath->VidPnTargetId)))
+ {
+ // If the rotation is unpinned, then modify the rotation support field
+ if (pVidPnPresentPath->ContentTransformation.Rotation == D3DKMDT_VPPR_UNPINNED)
+ {
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Identity = 1;
+ // Sample supports only Rotate90
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate90 = 1;
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate180 = 0;
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Rotate270 = 0;
+
+ // Since clone is not supported, should not support path-independent rotations
+ LocalVidPnPresentPath.ContentTransformation.RotationSupport.Offset0 = 1;
+
+ SupportFieldsModified = TRUE;
+ }
+ } // End: ROTATION
+
+ if (SupportFieldsModified)
+ {
+ // The correct path will be found by this function and the appropriate fields updated
+ Status = pVidPnTopologyInterface->pfnUpdatePathSupportInfo(hVidPnTopology, &LocalVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnUpdatePathSupportInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
+ break;
+ }
+ }
+
+ // Get the next path...
+ // (NOTE: This is the value of Status that will return STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET when it's time to quit the loop)
+ pVidPnPresentPathTemp = pVidPnPresentPath;
+ Status = pVidPnTopologyInterface->pfnAcquireNextPathInfo(hVidPnTopology, pVidPnPresentPathTemp, &pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnAcquireNextPathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", Status, hVidPnTopology, pVidPnPresentPathTemp);
+ break;
+ }
+
+ // ...and release the last path
+ NTSTATUS TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);
+ if (!NT_SUCCESS(TempStatus))
+ {
+ BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, pVidPnPresentPathTemp = 0x%I64x", TempStatus, hVidPnTopology, pVidPnPresentPathTemp);
+ Status = TempStatus;
+ break;
+ }
+ pVidPnPresentPathTemp = NULL; // Successfully released it
+ }// End: while loop for paths in topology
+
+ // If quit the while loop normally, set the return value to success
+ if (Status == STATUS_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET)
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ // Release any resources hanging around because the loop was quit early.
+ // Since in normal execution everything should be released by this point, TempStatus is initialized to a bogus error to be used as an
+ // assertion that if anything had to be released now (TempStatus changing) Status isn't successful.
+ NTSTATUS TempStatus = STATUS_NOT_FOUND;
+
+ if ((pVidPnSourceModeSetInterface != NULL) &&
+ (pVidPnPinnedSourceModeInfo != NULL))
+ {
+ TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnPinnedSourceModeInfo);
+ BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if ((pVidPnTargetModeSetInterface != NULL) &&
+ (pVidPnPinnedTargetModeInfo != NULL))
+ {
+ TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnPinnedTargetModeInfo);
+ BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (pVidPnPresentPath != NULL)
+ {
+ TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
+ BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (pVidPnPresentPathTemp != NULL)
+ {
+ TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPathTemp);
+ BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (hVidPnSourceModeSet != 0)
+ {
+ TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnSourceModeSet);
+ BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ if (hVidPnTargetModeSet != 0)
+ {
+ TempStatus = pVidPnInterface->pfnReleaseTargetModeSet(pEnumCofuncModality->hConstrainingVidPn, hVidPnTargetModeSet);
+ BDD_ASSERT_CHK(NT_SUCCESS(TempStatus));
+ }
+
+ BDD_ASSERT_CHK(TempStatus == STATUS_NOT_FOUND || Status != STATUS_SUCCESS);
+
+ return Status;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::SetVidPnSourceVisibility(_In_ CONST DXGKARG_SETVIDPNSOURCEVISIBILITY* pSetVidPnSourceVisibility)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pSetVidPnSourceVisibility != NULL);
+ BDD_ASSERT((pSetVidPnSourceVisibility->VidPnSourceId < MAX_VIEWS) ||
+ (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL));
+
+ UINT StartVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? 0 : pSetVidPnSourceVisibility->VidPnSourceId;
+ UINT MaxVidPnSourceId = (pSetVidPnSourceVisibility->VidPnSourceId == D3DDDI_ID_ALL) ? MAX_VIEWS : pSetVidPnSourceVisibility->VidPnSourceId + 1;
+
+ for (UINT SourceId = StartVidPnSourceId; SourceId < MaxVidPnSourceId; ++SourceId)
+ {
+ if (pSetVidPnSourceVisibility->Visible)
+ {
+ m_CurrentModes[SourceId].Flags.FullscreenPresent = TRUE;
+ }
+ else
+ {
+ BlackOutScreen(SourceId);
+ }
+
+ // Store current visibility so it can be dealt with during Present call
+ m_CurrentModes[SourceId].Flags.SourceNotVisible = !(pSetVidPnSourceVisibility->Visible);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+// NOTE: The value of pCommitVidPn->MonitorConnectivityChecks is ignored, since BDD is unable to recognize whether a monitor is connected or not
+// The value of pCommitVidPn->hPrimaryAllocation is also ignored, since BDD is a display only driver and does not deal with allocations
+NTSTATUS BASIC_DISPLAY_DRIVER::CommitVidPn(_In_ CONST DXGKARG_COMMITVIDPN* CONST pCommitVidPn)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pCommitVidPn != NULL);
+ BDD_ASSERT(pCommitVidPn->AffectedVidPnSourceId < MAX_VIEWS);
+
+ NTSTATUS Status;
+ SIZE_T NumPaths = 0;
+ D3DKMDT_HVIDPNTOPOLOGY hVidPnTopology = 0;
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet = 0;
+ CONST DXGK_VIDPN_INTERFACE* pVidPnInterface = NULL;
+ CONST DXGK_VIDPNTOPOLOGY_INTERFACE* pVidPnTopologyInterface = NULL;
+ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface = NULL;
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pVidPnPresentPath = NULL;
+ CONST D3DKMDT_VIDPN_SOURCE_MODE* pPinnedVidPnSourceModeInfo = NULL;
+
+ // Check this CommitVidPn is for the mode change notification when monitor is in power off state.
+ if (pCommitVidPn->Flags.PathPoweredOff)
+ {
+ // Ignore the commitVidPn call for the mode change notification when monitor is in power off state.
+ Status = STATUS_SUCCESS;
+ goto CommitVidPnExit;
+ }
+
+ // Get the VidPn Interface so we can get the 'Source Mode Set' and 'VidPn Topology' interfaces
+ Status = m_DxgkInterface.DxgkCbQueryVidPnInterface(pCommitVidPn->hFunctionalVidPn, DXGK_VIDPN_INTERFACE_VERSION_V1, &pVidPnInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("DxgkCbQueryVidPnInterface failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);
+ goto CommitVidPnExit;
+ }
+
+ // Get the VidPn Topology interface so can enumerate paths from source
+ Status = pVidPnInterface->pfnGetTopology(pCommitVidPn->hFunctionalVidPn, &hVidPnTopology, &pVidPnTopologyInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnGetTopology failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);
+ goto CommitVidPnExit;
+ }
+
+ // Find out the number of paths now, if it's 0 don't bother with source mode set and pinned mode, just clear current and then quit
+ Status = pVidPnTopologyInterface->pfnGetNumPaths(hVidPnTopology, &NumPaths);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnGetNumPaths failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
+ goto CommitVidPnExit;
+ }
+
+ if (NumPaths != 0)
+ {
+ // Get the Source Mode Set interface so we can get the pinned mode
+ Status = pVidPnInterface->pfnAcquireSourceModeSet(pCommitVidPn->hFunctionalVidPn,
+ pCommitVidPn->AffectedVidPnSourceId,
+ &hVidPnSourceModeSet,
+ &pVidPnSourceModeSetInterface);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnAcquireSourceModeSet failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x, SourceId = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn, pCommitVidPn->AffectedVidPnSourceId);
+ goto CommitVidPnExit;
+ }
+
+ // Get the mode that is being pinned
+ Status = pVidPnSourceModeSetInterface->pfnAcquirePinnedModeInfo(hVidPnSourceModeSet, &pPinnedVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnAcquirePinnedModeInfo failed with Status = 0x%I64x, hFunctionalVidPn = 0x%I64x", Status, pCommitVidPn->hFunctionalVidPn);
+ goto CommitVidPnExit;
+ }
+ }
+ else
+ {
+ // This will cause the successful quit below
+ pPinnedVidPnSourceModeInfo = NULL;
+ }
+
+ if (m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr &&
+ !m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.DoNotMapOrUnmap)
+ {
+ Status = UnmapFrameBuffer(m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr,
+ m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Pitch * m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].DispInfo.Height);
+ m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].FrameBuffer.Ptr = NULL;
+ m_CurrentModes[pCommitVidPn->AffectedVidPnSourceId].Flags.FrameBufferIsActive = FALSE;
+
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+ }
+
+ if (pPinnedVidPnSourceModeInfo == NULL)
+ {
+ // There is no mode to pin on this source, any old paths here have already been cleared
+ Status = STATUS_SUCCESS;
+ goto CommitVidPnExit;
+ }
+
+ Status = IsVidPnSourceModeFieldsValid(pPinnedVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+
+ // Get the number of paths from this source so we can loop through all paths
+ SIZE_T NumPathsFromSource = 0;
+ Status = pVidPnTopologyInterface->pfnGetNumPathsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, &NumPathsFromSource);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR2("pfnGetNumPathsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x", Status, hVidPnTopology);
+ goto CommitVidPnExit;
+ }
+
+ // Loop through all paths to set this mode
+ for (SIZE_T PathIndex = 0; PathIndex < NumPathsFromSource; ++PathIndex)
+ {
+ // Get the target id for this path
+ D3DDDI_VIDEO_PRESENT_TARGET_ID TargetId = D3DDDI_ID_UNINITIALIZED;
+ Status = pVidPnTopologyInterface->pfnEnumPathTargetsFromSource(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex, &TargetId);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR4("pfnEnumPathTargetsFromSource failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, PathIndex = 0x%I64x",
+ Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, PathIndex);
+ goto CommitVidPnExit;
+ }
+
+ // Get the actual path info
+ Status = pVidPnTopologyInterface->pfnAcquirePathInfo(hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId, &pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR4("pfnAcquirePathInfo failed with Status = 0x%I64x, hVidPnTopology = 0x%I64x, SourceId = 0x%I64x, TargetId = 0x%I64x",
+ Status, hVidPnTopology, pCommitVidPn->AffectedVidPnSourceId, TargetId);
+ goto CommitVidPnExit;
+ }
+
+ Status = IsVidPnPathFieldsValid(pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+
+ Status = SetSourceModeAndPath(pPinnedVidPnSourceModeInfo, pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ goto CommitVidPnExit;
+ }
+
+ Status = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
+ if (!NT_SUCCESS(Status))
+ {
+ BDD_LOG_ERROR3("pfnReleasePathInfo failed with Status = 0x%I64x, hVidPnTopoogy = 0x%I64x, pVidPnPresentPath = 0x%I64x",
+ Status, hVidPnTopology, pVidPnPresentPath);
+ goto CommitVidPnExit;
+ }
+ pVidPnPresentPath = NULL; // Successfully released it
+ }
+
+CommitVidPnExit:
+
+ NTSTATUS TempStatus;
+
+ if ((pVidPnSourceModeSetInterface != NULL) &&
+ (hVidPnSourceModeSet != 0) &&
+ (pPinnedVidPnSourceModeInfo != NULL))
+ {
+ TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pPinnedVidPnSourceModeInfo);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ }
+
+ if ((pVidPnInterface != NULL) &&
+ (pCommitVidPn->hFunctionalVidPn != 0) &&
+ (hVidPnSourceModeSet != 0))
+ {
+ TempStatus = pVidPnInterface->pfnReleaseSourceModeSet(pCommitVidPn->hFunctionalVidPn, hVidPnSourceModeSet);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ }
+
+ if ((pVidPnTopologyInterface != NULL) &&
+ (hVidPnTopology != 0) &&
+ (pVidPnPresentPath != NULL))
+ {
+ TempStatus = pVidPnTopologyInterface->pfnReleasePathInfo(hVidPnTopology, pVidPnPresentPath);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ }
+
+ return Status;
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::UpdateActiveVidPnPresentPath(_In_ CONST DXGKARG_UPDATEACTIVEVIDPNPRESENTPATH* CONST pUpdateActiveVidPnPresentPath)
+{
+ PAGED_CODE();
+
+ BDD_ASSERT(pUpdateActiveVidPnPresentPath != NULL);
+
+ NTSTATUS Status = IsVidPnPathFieldsValid(&(pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo));
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ // Mark the next present as fullscreen to make sure the full rotation comes through
+ m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Flags.FullscreenPresent = TRUE;
+
+ m_CurrentModes[pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.VidPnSourceId].Rotation = pUpdateActiveVidPnPresentPath->VidPnPresentPathInfo.ContentTransformation.Rotation;
+
+ return STATUS_SUCCESS;
+}
+
+//
+// Private BDD DMM functions
+//
+
+NTSTATUS BASIC_DISPLAY_DRIVER::SetSourceModeAndPath(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode,
+ CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath)
+{
+ PAGED_CODE();
+
+ CURRENT_BDD_MODE* pCurrentBddMode = &m_CurrentModes[pPath->VidPnSourceId];
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ pCurrentBddMode->Scaling = pPath->ContentTransformation.Scaling;
+ pCurrentBddMode->SrcModeWidth = pSourceMode->Format.Graphics.PrimSurfSize.cx;
+ pCurrentBddMode->SrcModeHeight = pSourceMode->Format.Graphics.PrimSurfSize.cy;
+ pCurrentBddMode->Rotation = pPath->ContentTransformation.Rotation;
+
+
+ if (!pCurrentBddMode->Flags.DoNotMapOrUnmap)
+ {
+ // Map the new frame buffer
+ BDD_ASSERT(pCurrentBddMode->FrameBuffer.Ptr == NULL);
+ Status = MapFrameBuffer(pCurrentBddMode->DispInfo.PhysicAddress,
+ pCurrentBddMode->DispInfo.Pitch * pCurrentBddMode->DispInfo.Height,
+ &(pCurrentBddMode->FrameBuffer.Ptr));
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+
+ pCurrentBddMode->Flags.FrameBufferIsActive = TRUE;
+ BlackOutScreen(pPath->VidPnSourceId);
+
+ // Mark that the next present should be fullscreen so the screen doesn't go from black to actual pixels one dirty rect at a time.
+ pCurrentBddMode->Flags.FullscreenPresent = TRUE;
+ }
+
+ return Status;
+}
+
+
+NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const
+{
+ PAGED_CODE();
+
+ if (pPath->VidPnSourceId >= MAX_VIEWS)
+ {
+ BDD_LOG_ERROR2("VidPnSourceId is 0x%I64x is too high (MAX_VIEWS is 0x%I64x)",
+ pPath->VidPnSourceId, MAX_VIEWS);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE;
+ }
+ else if (pPath->VidPnTargetId >= MAX_CHILDREN)
+ {
+ BDD_LOG_ERROR2("VidPnTargetId is 0x%I64x is too high (MAX_CHILDREN is 0x%I64x)",
+ pPath->VidPnTargetId, MAX_CHILDREN);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET;
+ }
+ else if (pPath->GammaRamp.Type != D3DDDI_GAMMARAMP_DEFAULT)
+ {
+ BDD_LOG_ERROR1("pPath contains a gamma ramp (0x%I64x)", pPath->GammaRamp.Type);
+ return STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED;
+ }
+ else if ((pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_IDENTITY) &&
+ (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_CENTERED) &&
+ (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_NOTSPECIFIED) &&
+ (pPath->ContentTransformation.Scaling != D3DKMDT_VPPS_UNINITIALIZED))
+ {
+ BDD_LOG_ERROR1("pPath contains a non-identity scaling (0x%I64x)", pPath->ContentTransformation.Scaling);
+ return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;
+ }
+ else if ((pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_IDENTITY) &&
+ (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_ROTATE90) &&
+ (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_NOTSPECIFIED) &&
+ (pPath->ContentTransformation.Rotation != D3DKMDT_VPPR_UNINITIALIZED))
+ {
+ BDD_LOG_ERROR1("pPath contains a not-supported rotation (0x%I64x)", pPath->ContentTransformation.Rotation);
+ return STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED;
+ }
+ else if ((pPath->VidPnTargetColorBasis != D3DKMDT_CB_SCRGB) &&
+ (pPath->VidPnTargetColorBasis != D3DKMDT_CB_UNINITIALIZED))
+ {
+ BDD_LOG_ERROR1("pPath has a non-linear RGB color basis (0x%I64x)", pPath->VidPnTargetColorBasis);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else
+ {
+ return STATUS_SUCCESS;
+ }
+}
+
+NTSTATUS BASIC_DISPLAY_DRIVER::IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const
+{
+ PAGED_CODE();
+
+ if (pSourceMode->Type != D3DKMDT_RMT_GRAPHICS)
+ {
+ BDD_LOG_ERROR1("pSourceMode is a non-graphics mode (0x%I64x)", pSourceMode->Type);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else if ((pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_SCRGB) &&
+ (pSourceMode->Format.Graphics.ColorBasis != D3DKMDT_CB_UNINITIALIZED))
+ {
+ BDD_LOG_ERROR1("pSourceMode has a non-linear RGB color basis (0x%I64x)", pSourceMode->Format.Graphics.ColorBasis);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else if (pSourceMode->Format.Graphics.PixelValueAccessMode != D3DKMDT_PVAM_DIRECT)
+ {
+ BDD_LOG_ERROR1("pSourceMode has a palettized access mode (0x%I64x)", pSourceMode->Format.Graphics.PixelValueAccessMode);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+ else
+ {
+ for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)
+ {
+ if (pSourceMode->Format.Graphics.PixelFormat == gBddPixelFormats[PelFmtIdx])
+ {
+ return STATUS_SUCCESS;
+ }
+ }
+
+ BDD_LOG_ERROR1("pSourceMode has an unknown pixel format (0x%I64x)", pSourceMode->Format.Graphics.PixelFormat);
+ return STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE;
+ }
+}
+
+
+
+// Add more mode from the table.
+struct SampleSourceMode
+{
+ UINT ModeWidth;
+ UINT ModeHeight;
+};
+
+// The driver will advertise all modes that fit within the actual required mode (see AddSingleSourceMode below)
+const static SampleSourceMode C_SampleSourceMode[] = {{800,600},{1024,768},{1152,864},{1280,800},{1280,1024},{1400,1050},{1600,1200},{1680,1050},{1920,1200}};
+const static UINT C_SampleSourceModeMax = sizeof(C_SampleSourceMode)/sizeof(C_SampleSourceMode[0]);
+
+NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleSourceMode(_In_ CONST DXGK_VIDPNSOURCEMODESET_INTERFACE* pVidPnSourceModeSetInterface,
+ D3DKMDT_HVIDPNSOURCEMODESET hVidPnSourceModeSet,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
+{
+ PAGED_CODE();
+
+ // There is only one source format supported by display-only drivers, but more can be added in a
+ // full WDDM driver if the hardware supports them
+ for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)
+ {
+ // Create new mode info that will be populated
+ D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;
+ NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);
+ return Status;
+ }
+
+ // Populate mode info with values from current mode and hard-coded values
+ // Always report 32 bpp format, this will be color converted during the present if the mode is < 32bpp
+ pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;
+ pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = m_CurrentModes[SourceId].DispInfo.Width;
+ pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = m_CurrentModes[SourceId].DispInfo.Height;
+ pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;
+ pVidPnSourceModeInfo->Format.Graphics.Stride = m_CurrentModes[SourceId].DispInfo.Pitch;
+ pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx];
+ pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;
+ pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;
+
+ // Add the mode to the source mode set
+ Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ NTSTATUS TempStatus = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ UNREFERENCED_PARAMETER(TempStatus);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ return Status;
+ }
+ }
+ }
+
+ UINT WidthMax = m_CurrentModes[SourceId].DispInfo.Width;
+ UINT HeightMax = m_CurrentModes[SourceId].DispInfo.Height;
+
+ // Add all predefined modes that fit within the bounds of the required (POST) mode
+ for (UINT ModeIndex = 0; ModeIndex < C_SampleSourceModeMax; ++ModeIndex)
+ {
+ if (C_SampleSourceMode[ModeIndex].ModeWidth > WidthMax)
+ {
+ break;
+ }
+ else if (C_SampleSourceMode[ModeIndex].ModeWidth == WidthMax)
+ {
+ if(C_SampleSourceMode[ModeIndex].ModeHeight >= HeightMax)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if(C_SampleSourceMode[ModeIndex].ModeHeight > HeightMax)
+ {
+ continue;
+ }
+ }
+
+ // There is only one source format supported by display-only drivers, but more can be added in a
+ // full WDDM driver if the hardware supports them
+ for (UINT PelFmtIdx = 0; PelFmtIdx < ARRAYSIZE(gBddPixelFormats); ++PelFmtIdx)
+ {
+ // Create new mode info that will be populated
+ D3DKMDT_VIDPN_SOURCE_MODE* pVidPnSourceModeInfo = NULL;
+ NTSTATUS Status = pVidPnSourceModeSetInterface->pfnCreateNewModeInfo(hVidPnSourceModeSet, &pVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, continuing to the next mode and trying again isn't going to be at all helpful, so return
+ // Also, mode doesn't need to be released since it was never created
+ BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x", Status, hVidPnSourceModeSet);
+ return Status;
+ }
+
+ // Populate mode info with values from mode at ModeIndex and hard-coded values
+ // Always report 32 bpp format, this will be color converted during the present if the mode at ModeIndex was < 32bpp
+ pVidPnSourceModeInfo->Type = D3DKMDT_RMT_GRAPHICS;
+ pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cx = C_SampleSourceMode[ModeIndex].ModeWidth;
+ pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize.cy = C_SampleSourceMode[ModeIndex].ModeHeight;
+ pVidPnSourceModeInfo->Format.Graphics.VisibleRegionSize = pVidPnSourceModeInfo->Format.Graphics.PrimSurfSize;
+ pVidPnSourceModeInfo->Format.Graphics.Stride = 4*C_SampleSourceMode[ModeIndex].ModeWidth;
+ pVidPnSourceModeInfo->Format.Graphics.PixelFormat = gBddPixelFormats[PelFmtIdx];
+ pVidPnSourceModeInfo->Format.Graphics.ColorBasis = D3DKMDT_CB_SCRGB;
+ pVidPnSourceModeInfo->Format.Graphics.PixelValueAccessMode = D3DKMDT_PVAM_DIRECT;
+
+ // Add the mode to the source mode set
+ Status = pVidPnSourceModeSetInterface->pfnAddMode(hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnSourceModeSet = 0x%I64x, pVidPnSourceModeInfo = 0x%I64x", Status, hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ }
+
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked, continue to next mode anyway
+ Status = pVidPnSourceModeSetInterface->pfnReleaseModeInfo(hVidPnSourceModeSet, pVidPnSourceModeInfo);
+ BDD_ASSERT_CHK(NT_SUCCESS(Status));
+ }
+ }
+ }
+
+
+ return STATUS_SUCCESS;
+}
+
+
+// Add the current mode information (acquired from the POST frame buffer) as the target mode.
+NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleTargetMode(_In_ CONST DXGK_VIDPNTARGETMODESET_INTERFACE* pVidPnTargetModeSetInterface,
+ D3DKMDT_HVIDPNTARGETMODESET hVidPnTargetModeSet,
+ _In_opt_ CONST D3DKMDT_VIDPN_SOURCE_MODE* pVidPnPinnedSourceModeInfo,
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceId)
+{
+ PAGED_CODE();
+
+ D3DKMDT_VIDPN_TARGET_MODE* pVidPnTargetModeInfo = NULL;
+ NTSTATUS Status = pVidPnTargetModeSetInterface->pfnCreateNewModeInfo(hVidPnTargetModeSet, &pVidPnTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x", Status, hVidPnTargetModeSet);
+ return Status;
+ }
+
+ pVidPnTargetModeInfo->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
+ UNREFERENCED_PARAMETER(pVidPnPinnedSourceModeInfo);
+ pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cx = m_CurrentModes[SourceId].DispInfo.Width;
+ pVidPnTargetModeInfo->VideoSignalInfo.TotalSize.cy = m_CurrentModes[SourceId].DispInfo.Height;
+ pVidPnTargetModeInfo->VideoSignalInfo.ActiveSize = pVidPnTargetModeInfo->VideoSignalInfo.TotalSize;
+ pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pVidPnTargetModeInfo->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;
+ // We add this as PREFERRED since it is the only supported target
+ pVidPnTargetModeInfo->Preference = D3DKMDT_MP_PREFERRED;
+
+ Status = pVidPnTargetModeSetInterface->pfnAddMode(hVidPnTargetModeSet, pVidPnTargetModeInfo);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hVidPnTargetModeSet = 0x%I64x, pVidPnTargetModeInfo = 0x%I64x", Status, hVidPnTargetModeSet, pVidPnTargetModeInfo);
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ NTSTATUS TempStatus = pVidPnTargetModeSetInterface->pfnReleaseModeInfo(hVidPnTargetModeSet, pVidPnTargetModeInfo);
+ UNREFERENCED_PARAMETER(TempStatus);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ return Status;
+ }
+ else
+ {
+ // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up
+ return STATUS_SUCCESS;
+ }
+}
+
+
+NTSTATUS BASIC_DISPLAY_DRIVER::AddSingleMonitorMode(_In_ CONST DXGKARG_RECOMMENDMONITORMODES* CONST pRecommendMonitorModes)
+{
+ PAGED_CODE();
+
+ D3DKMDT_MONITOR_SOURCE_MODE* pMonitorSourceMode = NULL;
+ NTSTATUS Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnCreateNewModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, &pMonitorSourceMode);
+ if (!NT_SUCCESS(Status))
+ {
+ // If failed to create a new mode info, mode doesn't need to be released since it was never created
+ BDD_LOG_ERROR2("pfnCreateNewModeInfo failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x", Status, pRecommendMonitorModes->hMonitorSourceModeSet);
+ return Status;
+ }
+
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID CorrespondingSourceId = FindSourceForTarget(pRecommendMonitorModes->VideoPresentTargetId, TRUE);
+
+ // Since we don't know the real monitor timing information, just use the current display mode (from the POST device) with unknown frequencies
+ pMonitorSourceMode->VideoSignalInfo.VideoStandard = D3DKMDT_VSS_OTHER;
+ pMonitorSourceMode->VideoSignalInfo.TotalSize.cx = m_CurrentModes[CorrespondingSourceId].DispInfo.Width;
+ pMonitorSourceMode->VideoSignalInfo.TotalSize.cy = m_CurrentModes[CorrespondingSourceId].DispInfo.Height;
+ pMonitorSourceMode->VideoSignalInfo.ActiveSize = pMonitorSourceMode->VideoSignalInfo.TotalSize;
+ pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.VSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Numerator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.HSyncFreq.Denominator = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.PixelRate = D3DKMDT_FREQUENCY_NOTSPECIFIED;
+ pMonitorSourceMode->VideoSignalInfo.ScanLineOrdering = D3DDDI_VSSLO_PROGRESSIVE;
+
+ // We set the preference to PREFERRED since this is the only supported mode
+ pMonitorSourceMode->Origin = D3DKMDT_MCO_DRIVER;
+ pMonitorSourceMode->Preference = D3DKMDT_MP_PREFERRED;
+ pMonitorSourceMode->ColorBasis = D3DKMDT_CB_SRGB;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.FirstChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.SecondChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.ThirdChannel = 8;
+ pMonitorSourceMode->ColorCoeffDynamicRanges.FourthChannel = 8;
+
+ Status = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnAddMode(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ if (!NT_SUCCESS(Status))
+ {
+ if (Status != STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET)
+ {
+ BDD_LOG_ERROR3("pfnAddMode failed with Status = 0x%I64x, hMonitorSourceModeSet = 0x%I64x, pMonitorSourceMode = 0x%I64x",
+ Status, pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
+ }
+
+ // If adding the mode failed, release the mode, if this doesn't work there is nothing that can be done, some memory will get leaked
+ NTSTATUS TempStatus = pRecommendMonitorModes->pMonitorSourceModeSetInterface->pfnReleaseModeInfo(pRecommendMonitorModes->hMonitorSourceModeSet, pMonitorSourceMode);
+ UNREFERENCED_PARAMETER(TempStatus);
+ NT_ASSERT(NT_SUCCESS(TempStatus));
+ return Status;
+ }
+ else
+ {
+ // If AddMode succeeded with something other than STATUS_SUCCESS treat it as such anyway when propagating up
+ return STATUS_SUCCESS;
+ }
+}
+
diff --git a/video/KMDOD/bdd_errorlog.hxx b/video/KMDOD/bdd_errorlog.hxx
new file mode 100644
index 00000000..f9c394f8
--- /dev/null
+++ b/video/KMDOD/bdd_errorlog.hxx
@@ -0,0 +1,84 @@
+/******************************Module*Header*******************************\
+* Module Name: BDD_ErrorLog.hxx
+*
+* Basic Display Driver Logging Macros
+*
+*
+* Copyright (c) 2010 Microsoft Corporation
+*
+\**************************************************************************/
+#ifndef _BDD_ERRORLOG_HXX_
+#define _BDD_ERRORLOG_HXX_
+
+#define BDD_LOG_ERROR0(Msg)
+#define BDD_LOG_ERROR1(Msg,Param1)
+#define BDD_LOG_ERROR2(Msg,Param1,Param2)
+#define BDD_LOG_ERROR3(Msg,Param1,Param2,Param3)
+#define BDD_LOG_ERROR4(Msg,Param1,Param2,Param3,Param4)
+#define BDD_LOG_ERROR5(Msg,Param1,Param2,Param3,Param4,Param5)
+
+//
+// Warnings
+//
+
+#define BDD_LOG_WARNING0(Msg)
+#define BDD_LOG_WARNING1(Msg,Param1)
+#define BDD_LOG_WARNING2(Msg,Param1,Param2)
+#define BDD_LOG_WARNING3(Msg,Param1,Param2,Param3)
+#define BDD_LOG_WARNING4(Msg,Param1,Param2,Param3,Param4)
+#define BDD_LOG_WARNING5(Msg,Param1,Param2,Param3,Param4,Param5)
+
+//
+// Events (i.e. low-frequency tracing)
+//
+
+#define BDD_LOG_EVENT0(Msg)
+#define BDD_LOG_EVENT1(Msg,Param1)
+#define BDD_LOG_EVENT2(Msg,Param1,Param2)
+#define BDD_LOG_EVENT3(Msg,Param1,Param2,Param3)
+#define BDD_LOG_EVENT4(Msg,Param1,Param2,Param3,Param4)
+#define BDD_LOG_EVENT5(Msg,Param1,Param2,Param3,Param4,Param5)
+
+//
+// Information (i.e. high-frequency tracing)
+//
+
+#define BDD_LOG_INFORMATION0(Msg)
+#define BDD_LOG_INFORMATION1(Msg,Param1)
+#define BDD_LOG_INFORMATION2(Msg,Param1,Param2)
+#define BDD_LOG_INFORMATION3(Msg,Param1,Param2,Param3)
+#define BDD_LOG_INFORMATION4(Msg,Param1,Param2,Param3,Param4)
+#define BDD_LOG_INFORMATION5(Msg,Param1,Param2,Param3,Param4,Param5)
+
+//
+// Low resource logging macros.
+//
+
+#define BDD_LOG_LOW_RESOURCE0(Msg)
+#define BDD_LOG_LOW_RESOURCE1(Msg,Param1)
+#define BDD_LOG_LOW_RESOURCE2(Msg,Param1,Param2)
+#define BDD_LOG_LOW_RESOURCE3(Msg,Param1,Param2,Param3)
+#define BDD_LOG_LOW_RESOURCE4(Msg,Param1,Param2,Param3,Param4)
+#define BDD_LOG_LOW_RESOURCE5(Msg,Param1,Param2,Param3,Param4,Param5)
+
+//
+// Assertion logging macros.
+//
+
+#define BDD_LOG_ASSERTION0(Msg) NT_ASSERT(FALSE)
+#define BDD_LOG_ASSERTION1(Msg,Param1) NT_ASSERT(FALSE)
+#define BDD_LOG_ASSERTION2(Msg,Param1,Param2) NT_ASSERT(FALSE)
+#define BDD_LOG_ASSERTION3(Msg,Param1,Param2,Param3) NT_ASSERT(FALSE)
+#define BDD_LOG_ASSERTION4(Msg,Param1,Param2,Param3,Param4) NT_ASSERT(FALSE)
+#define BDD_LOG_ASSERTION5(Msg,Param1,Param2,Param3,Param4,Param5) NT_ASSERT(FALSE)
+#define BDD_ASSERT(exp) {if (!(exp)) {BDD_LOG_ASSERTION0(#exp);}}
+
+#if DBG
+#define BDD_ASSERT_CHK(exp) BDD_ASSERT(exp)
+#else
+#define BDD_ASSERT_CHK(exp) {}
+#endif
+
+
+#endif //_BDD_ERRORLOG_HXX_
+
diff --git a/video/KMDOD/bdd_util.cxx b/video/KMDOD/bdd_util.cxx
new file mode 100644
index 00000000..a80dc4d1
--- /dev/null
+++ b/video/KMDOD/bdd_util.cxx
@@ -0,0 +1,115 @@
+/******************************Module*Header*******************************\
+* Module Name: bdd_util.cxx
+*
+* Basic Display Driver utility functions
+*
+* Created: 29-Mar-2011
+* Author: Amos Eshel [amosesh]
+*
+* Copyright (c) 2011 Microsoft Corporation
+\**************************************************************************/
+
+#include "BDD.hxx"
+
+
+#pragma code_seg("PAGE")
+
+//
+// EDID validation
+//
+
+BOOLEAN IsEdidHeaderValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid)
+{
+ PAGED_CODE();
+
+ static const UCHAR EDID1Header[8] = {0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0};
+ return memcmp(pEdid, EDID1Header, sizeof(EDID1Header)) == 0;
+}
+
+BOOLEAN IsEdidChecksumValid(_In_reads_bytes_(EDID_V1_BLOCK_SIZE) const BYTE* pEdid)
+{
+ PAGED_CODE();
+
+ BYTE CheckSum = 0;
+ for (const BYTE* pEdidStart = pEdid; pEdidStart < (pEdid + EDID_V1_BLOCK_SIZE); ++pEdidStart)
+ {
+ CheckSum += *pEdidStart;
+ }
+
+ return CheckSum == 0;
+}
+
+//
+// Frame buffer map/unmap
+//
+
+NTSTATUS
+MapFrameBuffer(
+ _In_ PHYSICAL_ADDRESS PhysicalAddress,
+ _In_ ULONG Length,
+ _Outptr_result_bytebuffer_(Length) VOID** VirtualAddress)
+{
+ PAGED_CODE();
+
+ //
+ // Check for parameters
+ //
+ if ((PhysicalAddress.QuadPart == (ULONGLONG)0) ||
+ (Length == 0) ||
+ (VirtualAddress == NULL))
+ {
+ BDD_LOG_ERROR3("One of PhysicalAddress.QuadPart (0x%I64x), Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0",
+ PhysicalAddress.QuadPart, Length, VirtualAddress);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ *VirtualAddress = MmMapIoSpace(PhysicalAddress,
+ Length,
+ MmWriteCombined);
+ if (*VirtualAddress == NULL)
+ {
+ // The underlying call to MmMapIoSpace failed. This may be because, MmWriteCombined
+ // isn't supported, so try again with MmNonCached
+
+ *VirtualAddress = MmMapIoSpace(PhysicalAddress,
+ Length,
+ MmNonCached);
+ if (*VirtualAddress == NULL)
+ {
+ BDD_LOG_LOW_RESOURCE1("MmMapIoSpace returned a NULL buffer when trying to allocate 0x%I64x bytes", Length);
+ return STATUS_NO_MEMORY;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+UnmapFrameBuffer(
+ _In_reads_bytes_(Length) VOID* VirtualAddress,
+ _In_ ULONG Length)
+{
+ PAGED_CODE();
+
+
+ //
+ // Check for parameters
+ //
+ if ((VirtualAddress == NULL) && (Length == 0))
+ {
+ // Allow this function to be called when there's no work to do, and treat as successful
+ return STATUS_SUCCESS;
+ }
+ else if ((VirtualAddress == NULL) || (Length == 0))
+ {
+ BDD_LOG_ERROR2("Only one of Length (0x%I64x), VirtualAddress (0x%I64x) is NULL or 0",
+ Length, VirtualAddress);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ MmUnmapIoSpace(VirtualAddress,
+ Length);
+
+ return STATUS_SUCCESS;
+}
+
diff --git a/video/KMDOD/bltfuncs.cxx b/video/KMDOD/bltfuncs.cxx
new file mode 100644
index 00000000..9df7ee6b
--- /dev/null
+++ b/video/KMDOD/bltfuncs.cxx
@@ -0,0 +1,346 @@
+/******************************Module*Header*******************************\
+ * Module Name: BltFuncs.cxx
+ *
+ * Basic Display Driver copying functionality
+ *
+ *
+ * Copyright (c) 2010 Microsoft Corporation
+\**************************************************************************/
+
+#include "BDD.hxx"
+
+// For the following macros, c must be a UCHAR.
+#define UPPER_6_BITS(c) (((c) & rMaskTable[6 - 1]) >> 2)
+#define UPPER_5_BITS(c) (((c) & rMaskTable[5 - 1]) >> 3)
+#define LOWER_6_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 6])
+#define LOWER_5_BITS(c) (((BYTE)(c)) & lMaskTable[BITS_PER_BYTE - 5])
+
+
+#define SHIFT_FOR_UPPER_5_IN_565 (6 + 5)
+#define SHIFT_FOR_MIDDLE_6_IN_565 (5)
+#define SHIFT_UPPER_5_IN_565_BACK ((BITS_PER_BYTE * 2) + (BITS_PER_BYTE - 5))
+#define SHIFT_MIDDLE_6_IN_565_BACK ((BITS_PER_BYTE * 1) + (BITS_PER_BYTE - 6))
+#define SHIFT_LOWER_5_IN_565_BACK ((BITS_PER_BYTE * 0) + (BITS_PER_BYTE - 5))
+
+// For the following macros, pPixel must be a BYTE* pointing to the start of a 32 bit pixel
+#define CONVERT_32BPP_TO_16BPP(pPixel) ((UPPER_5_BITS(pPixel[2]) << SHIFT_FOR_UPPER_5_IN_565) | \
+ (UPPER_6_BITS(pPixel[1]) << SHIFT_FOR_MIDDLE_6_IN_565) | \
+ (UPPER_5_BITS(pPixel[0])))
+
+// 8bpp is done with 6 levels per color channel since this gives true grays, even if it leaves 40 empty palette entries
+// The 6 levels per color is the reason for dividing below by 43 (43 * 6 == 258, closest multiple of 6 to 256)
+// It is also the reason for multiplying the red channel by 36 (== 6*6) and the green channel by 6, as this is the
+// equivalent to bit shifting in a 3:3:2 model. Changes to this must be reflected in vesasup.cxx with the Blues/Greens/Reds arrays
+#define CONVERT_32BPP_TO_8BPP(pPixel) (((pPixel[2] / 43) * 36) + \
+ ((pPixel[1] / 43) * 6) + \
+ ((pPixel[0] / 43)))
+
+// 4bpp is done with strict grayscale since this has been found to be usable
+// 30% of the red value, 59% of the green value, and 11% of the blue value is the standard way to convert true color to grayscale
+#define CONVERT_32BPP_TO_4BPP(pPixel) ((BYTE)(((pPixel[2] * 30) + \
+ (pPixel[1] * 59) + \
+ (pPixel[0] * 11)) / (100 * 16)))
+
+
+// For the following macro, Pixel must be a WORD representing a 16 bit pixel
+#define CONVERT_16BPP_TO_32BPP(Pixel) (((ULONG)LOWER_5_BITS((Pixel) >> SHIFT_FOR_UPPER_5_IN_565) << SHIFT_UPPER_5_IN_565_BACK) | \
+ ((ULONG)LOWER_6_BITS((Pixel) >> SHIFT_FOR_MIDDLE_6_IN_565) << SHIFT_MIDDLE_6_IN_565_BACK) | \
+ ((ULONG)LOWER_5_BITS((Pixel)) << SHIFT_LOWER_5_IN_565_BACK))
+
+#pragma code_seg(push)
+#pragma code_seg()
+// BEGIN: Non-Paged Code
+
+// Bit is 1 from Idx to end of byte, with bit count starting at high order
+BYTE lMaskTable[BITS_PER_BYTE] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+// Bit is 1 from Idx to start of byte, with bit count starting at high order
+BYTE rMaskTable[BITS_PER_BYTE] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
+
+// Bit of Idx is 1, with bit count starting at high order
+BYTE PixelMask[BITS_PER_BYTE] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
+
+/****************************Internal*Routine******************************\
+ * CopyBits32_32
+ *
+ *
+ * Copies rectangles from one surface to another. Both surfaces must have
+ * the same resolution.
+ *
+ * OffsetX, OffsetY - to add to the rectangle coordinates.
+ *
+ * Copied from %SDXROOT%\windows\Core\dxkernel\cdd\enable.cxx (CopySurfBits)
+ *
+\**************************************************************************/
+
+VOID CopyBits32_32(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ NT_ASSERT((pDst->BitsPerPel == 32) &&
+ (pSrc->BitsPerPel == 32));
+ NT_ASSERT((pDst->Rotation == D3DKMDT_VPPR_IDENTITY) &&
+ (pSrc->Rotation == D3DKMDT_VPPR_IDENTITY));
+
+ for (UINT iRect = 0; iRect < NumRects; iRect++)
+ {
+ CONST RECT* pRect = &pRects[iRect];
+
+ NT_ASSERT(pRect->right >= pRect->left);
+ NT_ASSERT(pRect->bottom >= pRect->top);
+
+ UINT NumPixels = pRect->right - pRect->left;
+ UINT NumRows = pRect->bottom - pRect->top;
+ UINT BytesToCopy = NumPixels * 4;
+ BYTE* pStartDst = ((BYTE*)pDst->pBits +
+ (pRect->top + pDst->Offset.y) * pDst->Pitch +
+ (pRect->left + pDst->Offset.x) * 4);
+ CONST BYTE* pStartSrc = ((BYTE*)pSrc->pBits +
+ (pRect->top + pSrc->Offset.y) * pSrc->Pitch +
+ (pRect->left + pSrc->Offset.x) * 4);
+
+ for (UINT i = 0; i < NumRows; ++i)
+ {
+ RtlCopyMemory(pStartDst, pStartSrc, BytesToCopy);
+ pStartDst += pDst->Pitch;
+ pStartSrc += pSrc->Pitch;
+ }
+ }
+}
+
+
+VOID GetPitches(_In_ CONST BLT_INFO* pBltInfo, _Out_ LONG* pPixelPitch, _Out_ LONG* pRowPitch)
+{
+ switch (pBltInfo->Rotation)
+ {
+ case D3DKMDT_VPPR_IDENTITY:
+ {
+ *pPixelPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ *pRowPitch = pBltInfo->Pitch;
+ return;
+ }
+ case D3DKMDT_VPPR_ROTATE90:
+ {
+ *pPixelPitch = -((LONG)pBltInfo->Pitch);
+ *pRowPitch = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ return;
+ }
+ case D3DKMDT_VPPR_ROTATE180:
+ {
+ *pPixelPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ *pRowPitch = -((LONG)pBltInfo->Pitch);
+ return;
+ }
+ case D3DKMDT_VPPR_ROTATE270:
+ {
+ *pPixelPitch = pBltInfo->Pitch;
+ *pRowPitch = -((LONG)pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ return;
+ }
+ default:
+ {
+ BDD_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation);
+ *pPixelPitch = 0;
+ *pRowPitch = 0;
+ return;
+ }
+ }
+}
+
+BYTE* GetRowStart(_In_ CONST BLT_INFO* pBltInfo, CONST RECT* pRect)
+{
+ BYTE* pRet = NULL;
+ LONG OffLeft = pRect->left + pBltInfo->Offset.x;
+ LONG OffTop = pRect->top + pBltInfo->Offset.y;
+ LONG BytesPerPixel = (pBltInfo->BitsPerPel / BITS_PER_BYTE);
+ switch (pBltInfo->Rotation)
+ {
+ case D3DKMDT_VPPR_IDENTITY:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ OffTop * pBltInfo->Pitch +
+ OffLeft * BytesPerPixel);
+ break;
+ }
+ case D3DKMDT_VPPR_ROTATE90:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ (pBltInfo->Height - 1 - OffLeft) * pBltInfo->Pitch +
+ OffTop * BytesPerPixel);
+ break;
+ }
+ case D3DKMDT_VPPR_ROTATE180:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ (pBltInfo->Height - 1 - OffTop) * pBltInfo->Pitch +
+ (pBltInfo->Width - 1 - OffLeft) * BytesPerPixel);
+ break;
+ }
+ case D3DKMDT_VPPR_ROTATE270:
+ {
+ pRet = ((BYTE*)pBltInfo->pBits +
+ OffLeft * pBltInfo->Pitch +
+ (pBltInfo->Width - 1 - OffTop) * BytesPerPixel);
+ break;
+ }
+ default:
+ {
+ BDD_LOG_ASSERTION1("Invalid rotation (0x%I64x) specified", pBltInfo->Rotation);
+ break;
+ }
+ }
+
+ return pRet;
+}
+
+/****************************Internal*Routine******************************\
+ * CopyBitsGeneric
+ *
+ *
+ * Blt function which can handle a rotated dst/src, offset rects in dst/src
+ * and bpp combinations of:
+ * dst | src
+ * 32 | 32 // For identity rotation this is much faster in CopyBits32_32
+ * 32 | 24
+ * 32 | 16
+ * 24 | 32
+ * 16 | 32
+ * 8 | 32
+ * 24 | 24 // untested
+ *
+\**************************************************************************/
+
+VOID CopyBitsGeneric(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ LONG DstPixelPitch = 0;
+ LONG DstRowPitch = 0;
+ LONG SrcPixelPitch = 0;
+ LONG SrcRowPitch = 0;
+
+ GetPitches(pDst, &DstPixelPitch, &DstRowPitch);
+ GetPitches(pSrc, &SrcPixelPitch, &SrcRowPitch);
+
+ for (UINT iRect = 0; iRect < NumRects; iRect++)
+ {
+ CONST RECT* pRect = &pRects[iRect];
+
+ NT_ASSERT(pRect->right >= pRect->left);
+ NT_ASSERT(pRect->bottom >= pRect->top);
+
+ UINT NumPixels = pRect->right - pRect->left;
+ UINT NumRows = pRect->bottom - pRect->top;
+
+ BYTE* pDstRow = GetRowStart(pDst, pRect);
+ CONST BYTE* pSrcRow = GetRowStart(pSrc, pRect);
+
+ for (UINT y=0; y < NumRows; y++)
+ {
+ BYTE* pDstPixel = pDstRow;
+ CONST BYTE* pSrcPixel = pSrcRow;
+
+ for (UINT x=0; x < NumPixels; x++)
+ {
+ if ((pDst->BitsPerPel == 24) ||
+ (pSrc->BitsPerPel == 24))
+ {
+ pDstPixel[0] = pSrcPixel[0];
+ pDstPixel[1] = pSrcPixel[1];
+ pDstPixel[2] = pSrcPixel[2];
+ // pPixel[3] is the alpha channel and is ignored for whichever of Src/Dst is 32bpp
+ }
+ else if (pDst->BitsPerPel == 32)
+ {
+ if (pSrc->BitsPerPel == 32)
+ {
+ UINT32* pDstPixelAs32 = (UINT32*)pDstPixel;
+ UINT32* pSrcPixelAs32 = (UINT32*)pSrcPixel;
+ *pDstPixelAs32 = *pSrcPixelAs32;
+ }
+ else if (pSrc->BitsPerPel == 16)
+ {
+ UINT32* pDstPixelAs32 = (UINT32*)pDstPixel;
+ UINT16* pSrcPixelAs16 = (UINT16*)pSrcPixel;
+
+ *pDstPixelAs32 = CONVERT_16BPP_TO_32BPP(*pSrcPixelAs16);
+ }
+ else
+ {
+ // Invalid pSrc->BitsPerPel on a pDst->BitsPerPel of 32
+ NT_ASSERT(FALSE);
+ }
+ }
+ else if (pDst->BitsPerPel == 16)
+ {
+ NT_ASSERT(pSrc->BitsPerPel == 32);
+
+ UINT16* pDstPixelAs16 = (UINT16*)pDstPixel;
+ *pDstPixelAs16 = CONVERT_32BPP_TO_16BPP(pSrcPixel);
+ }
+ else if (pDst->BitsPerPel == 8)
+ {
+ NT_ASSERT(pSrc->BitsPerPel == 32);
+
+ *pDstPixel = CONVERT_32BPP_TO_8BPP(pSrcPixel);
+ }
+ else
+ {
+ // Invalid pDst->BitsPerPel
+ NT_ASSERT(FALSE);
+ }
+ pDstPixel += DstPixelPitch;
+ pSrcPixel += SrcPixelPitch;
+ }
+
+ pDstRow += DstRowPitch;
+ pSrcRow += SrcRowPitch;
+ }
+ }
+}
+
+/****************************Internal*Routine******************************\
+ * BltBits
+ *
+ *
+ * Logic to decide which of the above functions to call based on Rotation/BPP
+ *
+\**************************************************************************/
+VOID BltBits(
+ BLT_INFO* pDst,
+ CONST BLT_INFO* pSrc,
+ UINT NumRects,
+ _In_reads_(NumRects) CONST RECT *pRects)
+{
+ // pSrc->pBits might be coming from user-mode. User-mode addresses when accessed by kernel need to be protected by a __try/__except.
+ // This usage is redundant in the sample driver since it is already being used for MmProbeAndLockPages. However, it is very important
+ // to have this in place and to make sure developers don't miss it, it is in these two locations.
+ __try
+ {
+ if (pDst->BitsPerPel == 32 &&
+ pSrc->BitsPerPel == 32 &&
+ pDst->Rotation == D3DKMDT_VPPR_IDENTITY &&
+ pSrc->Rotation == D3DKMDT_VPPR_IDENTITY)
+ {
+ // This is by far the most common copy function being called
+ CopyBits32_32(pDst, pSrc, NumRects, pRects);
+ }
+ else
+ {
+ CopyBitsGeneric(pDst, pSrc, NumRects, pRects);
+ }
+ }
+ #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BDD_LOG_ERROR2("Either dst (0x%I64x) or src (0x%I64x) bits encountered exception during access.", pDst->pBits, pSrc->pBits);
+ }
+}
+
+// END: Non-Paged Code
+#pragma code_seg(pop)
+
diff --git a/video/KMDOD/blthw.cxx b/video/KMDOD/blthw.cxx
new file mode 100644
index 00000000..2e6d2e5d
--- /dev/null
+++ b/video/KMDOD/blthw.cxx
@@ -0,0 +1,556 @@
+/******************************Module*Header*******************************\
+* Module Name: blthw.cxx
+*
+* Sample display driver functions for a HW blt simulation. This file is
+* only provided to simulate how a real hardware-accelerated display-only
+* driver functions, and should not be used in a real driver.
+*
+* Copyright (c) 2011 Microsoft Corporation
+\**************************************************************************/
+
+#include "BDD.hxx"
+
+typedef struct
+{
+ CONST DXGKRNL_INTERFACE* DxgkInterface;
+ DXGKARGCB_NOTIFY_INTERRUPT_DATA NotifyInterrupt;
+} SYNC_NOTIFY_INTERRUPT;
+
+KSYNCHRONIZE_ROUTINE SynchronizeVidSchNotifyInterrupt;
+
+BOOLEAN SynchronizeVidSchNotifyInterrupt(_In_opt_ PVOID params)
+{
+ // This routine is non-paged code called at the device interrupt level (DIRQL)
+ // to notify VidSch and schedule a DPC. It is meant as a demonstration of handling
+ // a real hardware interrupt, even though it is actually called from asynchronous
+ // present worker threads in this sample.
+ SYNC_NOTIFY_INTERRUPT* pParam = reinterpret_cast<SYNC_NOTIFY_INTERRUPT*>(params);
+
+ // The context is known to be non-NULL
+ __analysis_assume(pParam != NULL);
+
+ // Update driver information related to fences
+ switch(pParam->NotifyInterrupt.InterruptType)
+ {
+ case DXGK_INTERRUPT_DISPLAYONLY_VSYNC:
+ case DXGK_INTERRUPT_DISPLAYONLY_PRESENT_PROGRESS:
+ break;
+ default:
+ NT_ASSERT(FALSE);
+ return FALSE;
+ }
+
+ // Callback OS to report about the interrupt
+ pParam->DxgkInterface->DxgkCbNotifyInterrupt(pParam->DxgkInterface->DeviceHandle,&pParam->NotifyInterrupt);
+
+ // Now queue a DPC for this interrupt (to callback schedule at DCP level and let it do more work there)
+ // DxgkCbQueueDpc can return FALSE if there is already a DPC queued
+ // this is an acceptable condition
+ pParam->DxgkInterface->DxgkCbQueueDpc(pParam->DxgkInterface->DeviceHandle);
+
+ return TRUE;
+}
+
+#pragma code_seg("PAGE")
+
+KSTART_ROUTINE HwContextWorkerThread;
+
+struct DoPresentMemory
+{
+ PVOID DstAddr;
+ UINT DstStride;
+ ULONG DstBitPerPixel;
+ UINT SrcWidth;
+ UINT SrcHeight;
+ BYTE* SrcAddr;
+ LONG SrcPitch;
+ ULONG NumMoves; // in: Number of screen to screen moves
+ D3DKMT_MOVE_RECT* Moves; // in: Point to the list of moves
+ ULONG NumDirtyRects; // in: Number of direct rects
+ RECT* DirtyRect; // in: Point to the list of dirty rects
+ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation;
+ BOOLEAN SynchExecution;
+ D3DDDI_VIDEO_PRESENT_SOURCE_ID SourceID;
+ HANDLE hAdapter;
+ PMDL Mdl;
+ BDD_HWBLT* DisplaySource;
+};
+
+void
+HwExecutePresentDisplayOnly(
+ HANDLE Context);
+
+NTSTATUS
+StartHwBltPresentWorkerThread(
+ _In_ PKSTART_ROUTINE StartRoutine,
+ _In_ _When_(return==0, __drv_aliasesMem) PVOID StartContext)
+/*++
+
+ Routine Description:
+
+ This routine creates the worker thread to execute a single present
+ command. Creating a new thread on every asynchronous present is not
+ efficient, but this file is only meant as a simulation, not an example
+ of implementation.
+
+ Arguments:
+
+ StartRoutine - start routine
+ StartContext - start context
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ PAGED_CODE();
+
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+ HANDLE hWorkerThread = NULL;
+
+ // copy data from the context which is need here, as it will be deleted in separate thread
+ DoPresentMemory* ctx = reinterpret_cast<DoPresentMemory*>(StartContext);
+ BDD_HWBLT* displaySource = ctx->DisplaySource;
+
+ NTSTATUS Status = PsCreateSystemThread(
+ &hWorkerThread,
+ THREAD_ALL_ACCESS,
+ &ObjectAttributes,
+ NULL,
+ NULL,
+ StartRoutine,
+ StartContext);
+
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+
+ // wait for thread to start - infinite wait -
+ // need to make sure the tread is running before OS stars submitting the work items to it
+ KeWaitForSingleObject(&displaySource->m_hThreadStartupEvent, Executive, KernelMode, FALSE, NULL);
+
+ // Handle is passed to the parent object which must close it
+ displaySource->SetPresentWorkerThreadInfo(hWorkerThread);
+
+ // Resume context thread, this is done by setting the event the thread is waiting on
+ KeSetEvent(&displaySource->m_hThreadSuspendEvent, 0, FALSE);
+
+ return STATUS_PENDING;
+}
+
+BDD_HWBLT::BDD_HWBLT():m_DevExt (NULL),
+ m_SynchExecution(TRUE),
+ m_hPresentWorkerThread(NULL),
+ m_pPresentWorkerThread(NULL)
+{
+ PAGED_CODE();
+
+ KeInitializeEvent(&m_hThreadStartupEvent, NotificationEvent, FALSE);
+ KeInitializeEvent(&m_hThreadSuspendEvent, SynchronizationEvent, FALSE);
+
+}
+
+
+BDD_HWBLT::~BDD_HWBLT()
+/*++
+
+ Routine Description:
+
+ This routine waits on present worker thread to exit before
+ destroying the object
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ // make sure the worker thread has exited
+ SetPresentWorkerThreadInfo(NULL);
+}
+
+#pragma warning(push)
+#pragma warning(disable:26135) // The function doesn't lock anything
+
+void
+BDD_HWBLT::SetPresentWorkerThreadInfo(
+ HANDLE hWorkerThread)
+/*++
+
+ Routine Description:
+
+ The method is updating present worker information
+ It is called in following cases:
+ - In ExecutePresent to update worker thread information
+ - In Dtor to wait on worker thread to exit
+
+ Arguments:
+
+ hWorkerThread - handle of the present worker thread
+
+ Return Value:
+
+ None
+
+--*/
+{
+
+ PAGED_CODE();
+
+ if (m_pPresentWorkerThread)
+ {
+ // Wait for thread to exit
+ KeWaitForSingleObject(m_pPresentWorkerThread, Executive, KernelMode,
+ FALSE, NULL);
+ // Dereference thread object
+ ObDereferenceObject(m_pPresentWorkerThread);
+ m_pPresentWorkerThread = NULL;
+
+ NT_ASSERT(m_hPresentWorkerThread);
+ ZwClose(m_hPresentWorkerThread);
+ m_hPresentWorkerThread = NULL;
+ }
+
+ if (hWorkerThread)
+ {
+ // Make sure that thread's handle would be valid even if the thread exited
+ ObReferenceObjectByHandle(hWorkerThread, THREAD_ALL_ACCESS, NULL,
+ KernelMode, &m_pPresentWorkerThread, NULL);
+ NT_ASSERT(m_pPresentWorkerThread);
+ m_hPresentWorkerThread = hWorkerThread;
+ }
+
+}
+#pragma warning(pop)
+
+NTSTATUS
+BDD_HWBLT::ExecutePresentDisplayOnly(
+ _In_ BYTE* DstAddr,
+ _In_ UINT DstBitPerPixel,
+ _In_ BYTE* SrcAddr,
+ _In_ UINT SrcBytesPerPixel,
+ _In_ LONG SrcPitch,
+ _In_ ULONG NumMoves,
+ _In_ D3DKMT_MOVE_RECT* Moves,
+ _In_ ULONG NumDirtyRects,
+ _In_ RECT* DirtyRect,
+ _In_ D3DKMDT_VIDPN_PRESENT_PATH_ROTATION Rotation)
+/*++
+
+ Routine Description:
+
+ The method creates present worker thread and provides context
+ for it filled with present commands
+
+ Arguments:
+
+ DstAddr - address of destination surface
+ DstBitPerPixel - color depth of destination surface
+ SrcAddr - address of source surface
+ SrcBytesPerPixel - bytes per pixel of source surface
+ SrcPitch - source surface pitch (bytes in a row)
+ NumMoves - number of moves to be copied
+ Moves - moves' data
+ NumDirtyRects - number of rectangles to be copied
+ DirtyRect - rectangles' data
+ Rotation - roatation to be performed when executing copy
+ CallBack - callback for present worker thread to report execution status
+
+ Return Value:
+
+ Status
+
+--*/
+{
+
+ PAGED_CODE();
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ SIZE_T sizeMoves = NumMoves*sizeof(D3DKMT_MOVE_RECT);
+ SIZE_T sizeRects = NumDirtyRects*sizeof(RECT);
+ SIZE_T size = sizeof(DoPresentMemory) + sizeMoves + sizeRects;
+
+ DoPresentMemory* ctx = reinterpret_cast<DoPresentMemory*>
+ (new (PagedPool) BYTE[size]);
+
+ if (!ctx)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ RtlZeroMemory(ctx,size);
+
+ const CURRENT_BDD_MODE* pModeCur = m_DevExt->GetCurrentMode(m_SourceId);
+
+ ctx->DstAddr = DstAddr;
+ ctx->DstBitPerPixel = DstBitPerPixel;
+ ctx->DstStride = pModeCur->DispInfo.Pitch;
+ ctx->SrcWidth = pModeCur->SrcModeWidth;
+ ctx->SrcHeight = pModeCur->SrcModeHeight;
+ ctx->SrcAddr = NULL;
+ ctx->SrcPitch = SrcPitch;
+ ctx->Rotation = Rotation;
+ ctx->NumMoves = NumMoves;
+ ctx->Moves = Moves;
+ ctx->NumDirtyRects = NumDirtyRects;
+ ctx->DirtyRect = DirtyRect;
+ ctx->SourceID = m_SourceId;
+ ctx->hAdapter = m_DevExt;
+ ctx->Mdl = NULL;
+ ctx->DisplaySource = this;
+
+ // Alternate between synch and asynch execution, for demonstrating
+ // that a real hardware implementation can do either
+ m_SynchExecution = !m_SynchExecution;
+
+ ctx->SynchExecution = m_SynchExecution;
+
+ {
+ // Map Source into kernel space, as Blt will be executed by system worker thread
+ UINT sizeToMap = SrcBytesPerPixel*pModeCur->SrcModeWidth*pModeCur->SrcModeHeight;
+
+ PMDL mdl = IoAllocateMdl((PVOID)SrcAddr, sizeToMap, FALSE, FALSE, NULL);
+ if(!mdl)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KPROCESSOR_MODE AccessMode = static_cast<KPROCESSOR_MODE>(( SrcAddr <=
+ (BYTE* const) MM_USER_PROBE_ADDRESS)?UserMode:KernelMode);
+ __try
+ {
+ // Probe and lock the pages of this buffer in physical memory.
+ // We need only IoReadAccess.
+ MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
+ }
+ #pragma prefast(suppress: __WARNING_EXCEPTIONEXECUTEHANDLER, "try/except is only able to protect against user-mode errors and these are the only errors we try to catch here");
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = GetExceptionCode();
+ IoFreeMdl(mdl);
+ return Status;
+ }
+
+ // Map the physical pages described by the MDL into system space.
+ // Note: double mapping the buffer this way causes lot of system
+ // overhead for large size buffers.
+ ctx->SrcAddr = reinterpret_cast<BYTE*>
+ (MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ));
+
+ if(!ctx->SrcAddr) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ MmUnlockPages(mdl);
+ IoFreeMdl(mdl);
+ return Status;
+ }
+
+ // Save Mdl to unmap and unlock the pages in worker thread
+ ctx->Mdl = mdl;
+ }
+
+ BYTE* rects = reinterpret_cast<BYTE*>(ctx+1);
+
+ // copy moves and update pointer
+ if (Moves)
+ {
+ memcpy(rects,Moves,sizeMoves);
+ ctx->Moves = reinterpret_cast<D3DKMT_MOVE_RECT*>(rects);
+ rects += sizeMoves;
+ }
+
+ // copy dirty rects and update pointer
+ if (DirtyRect)
+ {
+ memcpy(rects,DirtyRect,sizeRects);
+ ctx->DirtyRect = reinterpret_cast<RECT*>(rects);
+ }
+
+
+ if (m_SynchExecution)
+ {
+ HwExecutePresentDisplayOnly((PVOID)ctx);
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ // Create a worker thread to perform the present asynchronously
+ // Ctx will be deleted in worker thread (on exit)
+ return StartHwBltPresentWorkerThread(HwContextWorkerThread,(PVOID)ctx);
+ }
+}
+
+
+void
+ReportPresentProgress(
+ _In_ HANDLE Adapter,
+ _In_ D3DDDI_VIDEO_PRESENT_SOURCE_ID VidPnSourceId,
+ _In_ BOOLEAN CompletedOrFailed)
+/*++
+
+ Routine Description:
+
+ This routine runs a fake interrupt routine in order to tell the OS about the present progress.
+
+ Arguments:
+
+ Adapter - Handle to the adapter (Device Extension)
+ VidPnSourceId - Video present source id for the callback
+ CompletedOrFailed - Present progress status for the source
+
+ Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ BASIC_DISPLAY_DRIVER* pDevExt =
+ reinterpret_cast<BASIC_DISPLAY_DRIVER*>(Adapter);
+
+ SYNC_NOTIFY_INTERRUPT SyncNotifyInterrupt = {};
+ SyncNotifyInterrupt.DxgkInterface = pDevExt->GetDxgkInterface();
+ SyncNotifyInterrupt.NotifyInterrupt.InterruptType = DXGK_INTERRUPT_DISPLAYONLY_PRESENT_PROGRESS;
+ SyncNotifyInterrupt.NotifyInterrupt.DisplayOnlyPresentProgress.VidPnSourceId = VidPnSourceId;
+
+ SyncNotifyInterrupt.NotifyInterrupt.DisplayOnlyPresentProgress.ProgressId =
+ (CompletedOrFailed)?DXGK_PRESENT_DISPLAYONLY_PROGRESS_ID_COMPLETE:
+ DXGK_PRESENT_DISPLAYONLY_PROGRESS_ID_FAILED;
+
+ // Execute the SynchronizeVidSchNotifyInterrupt function at the interrupt
+ // IRQL in order to fake a real present progress interrupt
+ BOOLEAN bRet = FALSE;
+ NT_VERIFY(NT_SUCCESS(pDevExt->GetDxgkInterface()->DxgkCbSynchronizeExecution(
+ pDevExt->GetDxgkInterface()->DeviceHandle,
+ (PKSYNCHRONIZE_ROUTINE)SynchronizeVidSchNotifyInterrupt,
+ (PVOID)&SyncNotifyInterrupt,0,&bRet)));
+ NT_ASSERT(bRet);
+}
+
+
+void
+HwContextWorkerThread(
+ HANDLE Context)
+{
+ PAGED_CODE();
+
+ DoPresentMemory* ctx = reinterpret_cast<DoPresentMemory*>(Context);
+ BDD_HWBLT* displaySource = ctx->DisplaySource;
+
+ // Signal event to indicate that the tread has started
+ KeSetEvent(&displaySource->m_hThreadStartupEvent, 0, FALSE);
+
+ // Suspend context thread, do this by waiting on the suspend event
+ KeWaitForSingleObject(&displaySource->m_hThreadSuspendEvent, Executive, KernelMode, FALSE, NULL);
+
+ HwExecutePresentDisplayOnly(Context);
+}
+
+
+void
+HwExecutePresentDisplayOnly(
+ HANDLE Context)
+/*++
+
+ Routine Description:
+
+ The routine executes present's commands and report progress to the OS
+
+ Arguments:
+
+ Context - Context with present's command
+
+ Return Value:
+
+ None
+
+--*/
+{
+ PAGED_CODE();
+
+ DoPresentMemory* ctx = reinterpret_cast<DoPresentMemory*>(Context);
+
+ // Set up destination blt info
+ BLT_INFO DstBltInfo;
+ DstBltInfo.pBits = ctx->DstAddr;
+ DstBltInfo.Pitch = ctx->DstStride;
+ DstBltInfo.BitsPerPel = ctx->DstBitPerPixel;
+ DstBltInfo.Offset.x = 0;
+ DstBltInfo.Offset.y = 0;
+ DstBltInfo.Rotation = ctx->Rotation;
+ DstBltInfo.Width = ctx->SrcWidth;
+ DstBltInfo.Height = ctx->SrcHeight;
+
+ // Set up source blt info
+ BLT_INFO SrcBltInfo;
+ SrcBltInfo.pBits = ctx->SrcAddr;
+ SrcBltInfo.Pitch = ctx->SrcPitch;
+ SrcBltInfo.BitsPerPel = 32;
+ SrcBltInfo.Offset.x = 0;
+ SrcBltInfo.Offset.y = 0;
+ SrcBltInfo.Rotation = D3DKMDT_VPPR_IDENTITY;
+ if (ctx->Rotation == D3DKMDT_VPPR_ROTATE90 ||
+ ctx->Rotation == D3DKMDT_VPPR_ROTATE270)
+ {
+ SrcBltInfo.Width = DstBltInfo.Height;
+ SrcBltInfo.Height = DstBltInfo.Width;
+ }
+ else
+ {
+ SrcBltInfo.Width = DstBltInfo.Width;
+ SrcBltInfo.Height = DstBltInfo.Height;
+ }
+
+
+ // Copy all the scroll rects from source image to video frame buffer.
+ for (UINT i = 0; i < ctx->NumMoves; i++)
+ {
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ &ctx->Moves[i].DestRect);
+ }
+
+ // Copy all the dirty rects from source image to video frame buffer.
+ for (UINT i = 0; i < ctx->NumDirtyRects; i++)
+ {
+
+ BltBits(&DstBltInfo,
+ &SrcBltInfo,
+ 1, // NumRects
+ &ctx->DirtyRect[i]);
+ }
+
+ // Unmap unmap and unlock the pages.
+ if (ctx->Mdl)
+ {
+ MmUnlockPages(ctx->Mdl);
+ IoFreeMdl(ctx->Mdl);
+ }
+
+ if(ctx->SynchExecution)
+ {
+ // This code simulates Blt executed synchronously
+ // nothing should be done here, just exit
+ ;
+ }
+ else
+ {
+ // TRUE == completed
+ // This code is emulates interrupt which HW should generate
+ ReportPresentProgress(ctx->hAdapter,ctx->SourceID,TRUE);
+ }
+
+ delete [] reinterpret_cast<BYTE*>(ctx);
+}
diff --git a/video/KMDOD/memory.cxx b/video/KMDOD/memory.cxx
new file mode 100644
index 00000000..e3b5b4a9
--- /dev/null
+++ b/video/KMDOD/memory.cxx
@@ -0,0 +1,78 @@
+/******************************Module*Header*******************************\
+* Module Name: bdd.h
+*
+* Basic Display Driver memory allocation, deletion, and tracking
+*
+*
+* Copyright (c) 2010 Microsoft Corporation
+\**************************************************************************/
+
+#include "BDD.hxx"
+
+#pragma code_seg("PAGE")
+
+//
+// New and delete operators
+//
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new(size_t Size, POOL_TYPE PoolType)
+{
+ PAGED_CODE();
+
+ Size = (Size != 0) ? Size : 1;
+
+ void* pObject = ExAllocatePoolWithTag(PoolType, Size, BDDTAG);
+
+#if DBG
+ if (pObject != NULL)
+ {
+ RtlFillMemory(pObject, Size, 0xCD);
+ }
+#endif // DBG
+
+ return pObject;
+}
+
+_When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+void* __cdecl operator new[](size_t Size, POOL_TYPE PoolType)
+{
+ PAGED_CODE();
+
+ Size = (Size != 0) ? Size : 1;
+
+ void* pObject = ExAllocatePoolWithTag(PoolType, Size, BDDTAG);
+
+#if DBG
+ if (pObject != NULL)
+ {
+ RtlFillMemory(pObject, Size, 0xCD);
+ }
+#endif // DBG
+
+ return pObject;
+}
+
+void __cdecl operator delete(void* pObject)
+{
+ PAGED_CODE();
+
+ if (pObject != NULL)
+ {
+ ExFreePool(pObject);
+ }
+}
+
+void __cdecl operator delete[](void* pObject)
+{
+ PAGED_CODE();
+
+ if (pObject != NULL)
+ {
+ ExFreePool(pObject);
+ }
+}
+
diff --git a/video/KMDOD/sampledisplay.rc b/video/KMDOD/sampledisplay.rc
new file mode 100644
index 00000000..f495476d
--- /dev/null
+++ b/video/KMDOD/sampledisplay.rc
@@ -0,0 +1,30 @@
+/*++
+
+Copyright (c) 2011 Microsoft Corporation
+
+Module Name:
+
+ SampleDisplay.rc
+
+Abstract:
+
+ This modules contains the version information for the Sample Display Driver
+
+Environment:
+
+ Kernel mode only
+
+--*/
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_DISPLAY
+#define VER_FILEDESCRIPTION_STR "Microsoft Sample Display Driver"
+#define VER_INTERNALNAME_STR "SampleDisplay.sys"
+#define VER_ORIGINALFILENAME_STR "SampleDisplay.sys"
+
+#define VER_LANGNEUTRAL
+#include "common.ver"
diff --git a/video/pixlib/PixLib.vcxproj b/video/pixlib/PixLib.vcxproj
new file mode 100644
index 00000000..422787ba
--- /dev/null
+++ b/video/pixlib/PixLib.vcxproj
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{81B1500C-93FF-426B-9F4E-AE70C8AC0E32}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>PixLib</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>PixLib</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>PixLib</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>PixLib</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories>
+ </Midl>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="pixlib.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/video/pixlib/PixLib.vcxproj.Filters b/video/pixlib/PixLib.vcxproj.Filters
new file mode 100644
index 00000000..48f6096a
--- /dev/null
+++ b/video/pixlib/PixLib.vcxproj.Filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{A8B745DE-6F64-4D24-9987-A54ECE81A482}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{826CC0FB-F174-4CEB-B426-B314EF20FC3D}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{AABC8FBD-8833-4320-AD01-F66555EFE527}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="pixlib.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/video/pixlib/ReadMe.md b/video/pixlib/ReadMe.md
new file mode 100644
index 00000000..b7667909
--- /dev/null
+++ b/video/pixlib/ReadMe.md
@@ -0,0 +1,7 @@
+PixLib sample
+=============
+
+The PixLib sample demonstrates how to implement the **CPixel** class for use by a display driver.
+
+For more information, see the WDK documentation topic, [CPixel Support Methods for Lightweight MIP Maps](http://msdn.microsoft.com/en-us/library/windows/hardware/ff540585).
+
diff --git a/video/pixlib/pixel.cpp b/video/pixlib/pixel.cpp
new file mode 100644
index 00000000..a1599e63
--- /dev/null
+++ b/video/pixlib/pixel.cpp
@@ -0,0 +1,695 @@
+/*==========================================================================;
+ *
+ * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
+ *
+ * File: pixel.cpp
+ * Content: Utility class for working with pixel formats
+ *
+ *
+ ***************************************************************************/
+
+#include "strsafe.h"
+#include "pixel.hpp"
+
+#ifndef DXPIXELVER
+#define DXPIXELVER 100
+#endif
+
+IHVFormatInfo *CPixel::m_pFormatList = 0;
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::Cleanup"
+void CPixel::Cleanup()
+{
+ while(m_pFormatList != 0)
+ {
+ IHVFormatInfo *t = m_pFormatList->m_pNext;
+ delete m_pFormatList;
+ m_pFormatList = t;
+ }
+}
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::BytesPerPixel"
+
+UINT CPixel::BytesPerPixel(D3DFORMAT Format)
+{
+ switch (DWORD(Format))
+ {
+ case D3DFMT_DXT1:
+ // Size is negative to indicate DXT; and indicates
+ // the size of the block
+ return (UINT)(-8);
+ case D3DFMT_DXT2:
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT4:
+ case D3DFMT_DXT5:
+ // Size is negative to indicate DXT; and indicates
+ // the size of the block
+ return (UINT)(-16);
+
+
+#if (DXPIXELVER > 8)
+ case D3DFMT_A32B32G32R32F:
+ return 16;
+
+ case D3DFMT_A16B16G16R16:
+ case D3DFMT_Q16W16V16U16:
+ case D3DFMT_A16B16G16R16F:
+ case D3DFMT_G32R32F:
+ case D3DFMT_MULTI2_ARGB8:
+ return 8;
+#endif
+
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_D32:
+ case D3DFMT_D24S8:
+ case D3DFMT_S8D24:
+ case D3DFMT_X8L8V8U8:
+ case D3DFMT_X4S4D24:
+ case D3DFMT_D24X4S4:
+ case D3DFMT_Q8W8V8U8:
+ case D3DFMT_V16U16:
+ case D3DFMT_A2W10V10U10:
+ case D3DFMT_A2B10G10R10:
+ case D3DFMT_A8B8G8R8:
+ case D3DFMT_X8B8G8R8:
+ case D3DFMT_G16R16:
+ case D3DFMT_D24X8:
+ case D3DFMT_X8D24:
+ case D3DFMT_W11V11U10:
+#if (DXPIXELVER > 8)
+ case D3DFMT_A2R10G10B10:
+ case D3DFMT_G16R16F:
+ case D3DFMT_R32F:
+ case D3DFMT_D32F_LOCKABLE:
+ case D3DFMT_D24FS8:
+ case D3DFMT_D32_LOCKABLE:
+#endif
+ return 4;
+
+ case D3DFMT_R8G8B8:
+ return 3;
+
+ case D3DFMT_R5G6B5:
+ case D3DFMT_X1R5G5B5:
+ case D3DFMT_A1R5G5B5:
+ case D3DFMT_A4R4G4B4:
+ case D3DFMT_A8L8:
+ case D3DFMT_V8U8:
+ case D3DFMT_L6V5U5:
+ case D3DFMT_D16:
+ case D3DFMT_D16_LOCKABLE:
+ case D3DFMT_D15S1:
+ case D3DFMT_S1D15:
+ case D3DFMT_A8P8:
+ case D3DFMT_A8R3G3B2:
+ case D3DFMT_UYVY:
+ case D3DFMT_YUY2:
+ case D3DFMT_X4R4G4B4:
+#if (DXPIXELVER > 8)
+ case D3DFMT_CxV8U8:
+ case D3DFMT_L16:
+ case D3DFMT_R16F:
+ case D3DFMT_R8G8_B8G8:
+ case D3DFMT_G8R8_G8B8:
+#endif
+ return 2;
+
+ case D3DFMT_P8:
+ case D3DFMT_L8:
+ case D3DFMT_R3G3B2:
+ case D3DFMT_A4L4:
+ case D3DFMT_A8:
+#if (DXPIXELVER > 8)
+ case D3DFMT_A1:
+ case D3DFMT_S8_LOCKABLE:
+#endif
+ return 1;
+
+ default:
+ return 0;
+ };
+}; // BytesPerPixel
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputePixelStride"
+
+UINT CPixel::ComputePixelStride(D3DFORMAT Format)
+{
+ UINT BPP = BytesPerPixel(Format);
+ if (BPP == 0)
+ {
+ for(IHVFormatInfo *p = m_pFormatList; p != 0; p = p->m_pNext)
+ {
+ if (p->m_Format == Format)
+ {
+ return p->m_BPP >> 3;
+ }
+ }
+ }
+ return BPP;
+}; // ComputePixelStride
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceStride"
+
+// Figure out a stride for a particular surface based on format and width
+inline UINT CPixel::ComputeSurfaceStride(UINT cpWidth, UINT cbPixel)
+{
+ UINT uStride = 0;
+ ComputeSurfaceStrideChecked(cpWidth, cbPixel, &uStride);
+ return uStride;
+}; // ComputeSurfaceStride
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceStrideChecked"
+
+// Figure out a stride for a particular surface based on format and width
+inline BOOL CPixel::ComputeSurfaceStrideChecked(UINT cpWidth, UINT cbPixel, UINT *pStride)
+{
+ // Figure out basic (linear) stride;
+ UINT64 u64Stride = (UINT64)cpWidth * (UINT64)cbPixel;
+
+ // Round up to multiple of 4 (for NT; but makes sense to maximize
+ // cache hits and reduce unaligned accesses)
+ //
+ // NOTE: Also necessary for UYVY and YUY2 formats that this round
+ // up by at least a multiple of 4.
+ u64Stride = (u64Stride + 3) & ~3; //safe since cbPixel cannot be 4G
+
+ if (u64Stride <= MAXALLOCSIZE)
+ {
+ *pStride = (UINT)u64Stride;
+ return TRUE;
+ }
+ return FALSE;
+}; // ComputeSurfaceStride
+
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceSize"
+
+UINT CPixel::ComputeSurfaceSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cbPixel)
+{
+ UINT uSize;
+ ComputeSurfaceSizeChecked(cpWidth, cpHeight, cbPixel, &uSize);
+ return uSize;
+} // ComputeSurfaceSize
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceSizeChecked"
+
+BOOL CPixel::ComputeSurfaceSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cbPixel,
+ UINT *pSize)
+
+{
+ UINT uStride;
+ UINT64 uSize64;
+ if (ComputeSurfaceStrideChecked(cpWidth, cbPixel, &uStride))
+ {
+ uSize64 = (UINT64)cpHeight * (UINT64)uStride;
+ if (uSize64 <= MAXALLOCSIZE)
+ {
+ *pSize = (UINT)uSize64;
+ return TRUE;
+ }
+ }
+
+ *pSize = 0U;
+ return FALSE;
+} // ComputeSurfaceSize
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeMipMapSize"
+
+UINT CPixel::ComputeMipMapSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cLevels,
+ D3DFORMAT Format)
+{
+ UINT uSize = 0; // initialize to zero to keep prefix happy win7: 185027
+ ComputeMipMapSizeChecked(cpWidth, cpHeight, cLevels, Format, &uSize);
+ return uSize;
+} // ComputeMipMapSize
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeMipMapSizeChecked"
+
+BOOL CPixel::ComputeMipMapSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cLevels,
+ D3DFORMAT Format,
+ UINT *pSize)
+{
+ UINT cbPixel = ComputePixelStride(Format);
+
+ // Adjust pixel->block if necessary
+ BOOL isDXT = IsDXT(cbPixel);
+ if (isDXT)
+ cbPixel *= (UINT)-1;
+
+ UINT64 cbSize = 0;
+ if (cpWidth > MAXALLOCSIZE-3 || cpHeight > MAXALLOCSIZE-3)
+ return FALSE;
+
+ for (UINT i = 0; i < cLevels; i++)
+ {
+ UINT cbMipSize;
+ // Figure out the size for
+ // each level of the mip-map
+ if (isDXT)
+ {
+ if (!ComputeSurfaceSizeChecked((cpWidth+3)/4, (cpHeight+3)/4, cbPixel, &cbMipSize))
+ return FALSE;
+ }
+ else
+ {
+ if (!ComputeSurfaceSizeChecked(cpWidth, cpHeight, cbPixel, &cbMipSize))
+ return FALSE;
+ }
+ cbSize += cbMipSize;
+ // Shrink width and height by half; clamp to 1 pixel
+ if (cpWidth > 1)
+ cpWidth >>= 1;
+ if (cpHeight > 1)
+ cpHeight >>= 1;
+ }
+ if (cbSize <= MAXALLOCSIZE)
+ {
+ *pSize = (UINT)cbSize;
+ return TRUE;
+ }
+ return FALSE;
+
+} // ComputeMipMapSize
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeMipVolumeSize"
+
+UINT CPixel::ComputeMipVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ UINT cLevels,
+ D3DFORMAT Format)
+{
+ UINT uSize = 0; // To keep prefix happy win7: 185029
+ ComputeMipVolumeSizeChecked(cpWidth, cpHeight, cpDepth, cLevels, Format, &uSize);
+ return uSize;
+} // ComputeMipVolumeSize
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeMipVolumeSizeChecked"
+
+BOOL CPixel::ComputeMipVolumeSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ UINT cLevels,
+ D3DFORMAT Format,
+ UINT *pSize)
+{
+ UINT cbPixel = ComputePixelStride(Format);
+
+ // Adjust pixel->block if necessary
+ BOOL isDXT = IsDXT(cbPixel);
+
+ if (isDXT)
+ cbPixel *= (UINT)-1;
+
+ UINT64 cbSize = 0;
+
+ if (cpWidth > MAXALLOCSIZE-3 || cpHeight > MAXALLOCSIZE-3 || cpDepth > MAXALLOCSIZE-3)
+ return FALSE;
+
+ for (UINT i = 0; i < cLevels; i++)
+ {
+ // Figure out the size for
+ // each level of the mip-volume
+ UINT Depth = cpDepth;
+ UINT64 cbLevelSize;
+ UINT cbSliceSize;
+ if (isDXT)
+ {
+ if (!ComputeSurfaceSizeChecked((cpWidth+3)/4, (cpHeight+3)/4, cbPixel, &cbSliceSize))
+ return FALSE;
+ }
+ else
+ {
+ if (!ComputeSurfaceSizeChecked(cpWidth, cpHeight, cbPixel, &cbSliceSize))
+ return FALSE;
+ }
+ cbLevelSize = (UINT64)Depth * (UINT64)cbSliceSize;
+ if (cbLevelSize > MAXALLOCSIZE)
+ return FALSE;
+ cbSize += cbLevelSize;
+
+ // Shrink width and height by half; clamp to 1 pixel
+ if (cpWidth > 1)
+ cpWidth >>= 1;
+ if (cpHeight > 1)
+ cpHeight >>= 1;
+ if (cpDepth > 1)
+ cpDepth >>= 1;
+ }
+
+ if (cbSize <= MAXALLOCSIZE)
+ {
+ *pSize = (UINT)cbSize;
+ return TRUE;
+ }
+ return FALSE;
+
+} // ComputeMipVolumeSize
+
+// Given a surface desc, a level, and pointer to
+// bits (pBits in the LockedRectData) and a sub-rect,
+// this will fill in the pLockedRectData structure
+void CPixel::ComputeMipMapOffset(const D3DSURFACE_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData)
+{
+ DXGASSERT(pBits != NULL);
+ DXGASSERT(pLockedRectData != NULL);
+ DXGASSERT(iLevel < 32);
+ DXGASSERT(pDescTopLevel != NULL);
+ DXGASSERT(0 != ComputePixelStride(pDescTopLevel->Format));
+ DXGASSERT(pDescTopLevel->Width > 0);
+ DXGASSERT(pDescTopLevel->Height > 0);
+
+ // CONSIDER: This is slow; and we can do a much better
+ // job for the non-compressed/wacky cases.
+ UINT cbOffset = 0;
+ UINT cbPixel = ComputePixelStride(pDescTopLevel->Format);
+ UINT cpWidth = pDescTopLevel->Width;
+ UINT cpHeight = pDescTopLevel->Height;
+
+ // Adjust pixel->block if necessary
+ BOOL isDXT = IsDXT(cbPixel);
+ if (isDXT)
+ cbPixel *= (UINT)-1;
+ BOOL OneBitPerPixelFormat = FALSE;
+#if (DXPIXELVER > 8)
+ OneBitPerPixelFormat = pDescTopLevel->Format == D3DFMT_A1;
+ if (OneBitPerPixelFormat)
+ {
+ cbPixel = 1;
+ }
+#endif
+ for (UINT i = 0; i < iLevel; i++)
+ {
+ if (isDXT)
+ cbOffset += ComputeSurfaceSize((cpWidth+3)/4, (cpHeight+3)/4, cbPixel);
+ else
+ if (OneBitPerPixelFormat)
+ cbOffset += ComputeSurfaceSize((cpWidth + 7) >> 3, cpHeight, cbPixel);
+ else
+ cbOffset += ComputeSurfaceSize(cpWidth, cpHeight, cbPixel);
+
+ // Shrink width and height by half; clamp to 1 pixel
+ if (cpWidth > 1)
+ cpWidth >>= 1;
+ if (cpHeight > 1)
+ cpHeight >>= 1;
+ }
+ if (isDXT)
+ cpWidth = (cpWidth+3)/4;
+ else
+ if (OneBitPerPixelFormat)
+ cpWidth = (cpWidth+7)/8;
+
+
+ // For DXTs, the pitch is the number of bytes
+ // for a single row of blocks; which is the same
+ // thing as the normal routine
+ pLockedRectData->Pitch = ComputeSurfaceStride(cpWidth,
+ cbPixel);
+ DXGASSERT(pLockedRectData->Pitch != 0);
+
+ // Don't adjust for Rect for DXT formats
+ if (pRect)
+ {
+ if (isDXT)
+ {
+ DXGASSERT((pRect->top & 3) == 0);
+ DXGASSERT((pRect->left & 3) == 0);
+ cbOffset += (pRect->top / 4) * pLockedRectData->Pitch +
+ (pRect->left / 4) * cbPixel;
+ }
+ else
+ if (OneBitPerPixelFormat)
+ {
+ // Assume that left is always 8 pixels aligned
+ cbOffset += pRect->top * pLockedRectData->Pitch +
+ (pRect->left >> 3);
+ }
+ else
+ {
+ cbOffset += pRect->top * pLockedRectData->Pitch +
+ pRect->left * cbPixel;
+ }
+ }
+
+ pLockedRectData->pBits = pBits + cbOffset;
+
+} // ComputeMipMapOffset
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeMipVolumeOffset"
+
+// MipVolume version of ComputeMipMapOffset
+void CPixel::ComputeMipVolumeOffset(const D3DVOLUME_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST D3DBOX *pBox,
+ D3DLOCKED_BOX *pLockedBoxData)
+{
+ DXGASSERT(pBits != NULL);
+ DXGASSERT(pLockedBoxData != NULL);
+ DXGASSERT(iLevel < 32);
+ DXGASSERT(pDescTopLevel != NULL);
+ DXGASSERT(0 != ComputePixelStride(pDescTopLevel->Format));
+ DXGASSERT(pDescTopLevel->Width > 0);
+ DXGASSERT(pDescTopLevel->Height > 0);
+ DXGASSERT(pDescTopLevel->Depth > 0);
+
+ UINT cbOffset = 0;
+ UINT cbPixel = ComputePixelStride(pDescTopLevel->Format);
+ UINT cpWidth = pDescTopLevel->Width;
+ UINT cpHeight = pDescTopLevel->Height;
+ UINT cpDepth = pDescTopLevel->Depth;
+
+ // Adjust pixel->block if necessary
+ BOOL isDXT = IsDXT(cbPixel);
+
+ if (isDXT)
+ cbPixel *= (UINT)-1;
+
+ for (UINT i = 0; i < iLevel; i++)
+ {
+ UINT Depth = cpDepth;
+ if (isDXT)
+ cbOffset += Depth * ComputeSurfaceSize((cpWidth+3)/4, (cpHeight+3)/4, cbPixel);
+ else
+ cbOffset += Depth * ComputeSurfaceSize(cpWidth, cpHeight, cbPixel);
+
+ // Shrink width and height by half; clamp to 1 pixel
+ if (cpWidth > 1)
+ cpWidth >>= 1;
+ if (cpHeight > 1)
+ cpHeight >>= 1;
+ if (cpDepth > 1)
+ cpDepth >>= 1;
+ }
+
+ if (isDXT)
+ {
+ cpWidth = (cpWidth+3)/4;
+ cpHeight = (cpHeight+3)/4;
+ }
+
+ // For DXTs, the row pitch is the number of bytes
+ // for a single row of blocks; which is the same
+ // thing as the normal routine
+ pLockedBoxData->RowPitch = ComputeSurfaceStride(cpWidth,
+ cbPixel);
+ DXGASSERT(pLockedBoxData->RowPitch != 0);
+
+ // For DXVs the slice pitch is the number of bytes
+ // for a single plane of blocks; which is the same thing
+ // as the normal routine
+ pLockedBoxData->SlicePitch = ComputeSurfaceSize(cpWidth,
+ cpHeight,
+ cbPixel);
+ DXGASSERT(pLockedBoxData->SlicePitch != 0);
+
+ // Adjust for Box
+ if (pBox)
+ {
+ UINT iStride = pLockedBoxData->RowPitch;
+ UINT iSlice = pLockedBoxData->SlicePitch;
+ if (isDXT)
+ {
+ cbOffset += (pBox->Front) * iSlice;
+
+ DXGASSERT((pBox->Top & 3) == 0);
+ DXGASSERT((pBox->Left & 3) == 0);
+ cbOffset += (pBox->Top / 4) * iStride +
+ (pBox->Left / 4) * cbPixel;
+ }
+ else
+ {
+ cbOffset += pBox->Front * iSlice +
+ pBox->Top * iStride +
+ pBox->Left * cbPixel;
+ }
+ }
+
+ pLockedBoxData->pBits = pBits + cbOffset;
+
+} // ComputeMipVolumeOffset
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::Register"
+
+HRESULT CPixel::Register(D3DFORMAT Format, DWORD BPP)
+{
+ DXGASSERT(BPP != 0);
+
+ // Do not register duplicates
+ IHVFormatInfo *p;
+ for(p = m_pFormatList; p != 0; p = p->m_pNext)
+ {
+ if (p->m_Format == Format)
+ {
+ return S_OK;
+ }
+ }
+
+ // Not found, add to registry.
+ // This allocation will be leaked, but since
+ // we don't expect to have a large number of
+ // IHV formats, the leak is not a big deal.
+ // Also, the leak will be immediately recovered
+ // upon process exit.
+ IHVFormatInfo *p2 = new IHVFormatInfo;
+ if (p2 == 0)
+ {
+ return E_OUTOFMEMORY;
+ }
+ p2->m_Format = Format;
+ p2->m_BPP = BPP;
+ p2->m_pNext = m_pFormatList;
+ m_pFormatList = p2;
+
+ return S_OK;
+}
+
+
+extern "C" UINT CPixel__ComputeSurfaceSize(UINT cpWidth,
+ UINT cpHeight,
+ D3DFORMAT Format)
+{
+ return CPixel::ComputeSurfaceSize(cpWidth, cpHeight, Format);
+}
+
+extern "C" UINT CPixel__ComputeVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ D3DFORMAT Format)
+{
+ return CPixel::ComputeVolumeSize(cpWidth, cpHeight, cpDepth, Format);
+}
+
+extern "C" UINT CPixel__ComputeMipMapSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cLevels,
+ D3DFORMAT Format)
+{
+ return CPixel::ComputeMipMapSize(cpWidth, cpHeight, cLevels, Format);
+}
+
+extern "C" UINT CPixel__ComputeMipVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ UINT cLevels,
+ D3DFORMAT Format)
+{
+ return CPixel::ComputeMipVolumeSize(cpWidth, cpHeight, cpDepth, cLevels, Format);
+}
+
+extern "C" void CPixel__ComputeMipMapOffset(const D3DSURFACE_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData)
+{
+ CPixel::ComputeMipMapOffset(pDescTopLevel, iLevel, pBits, pRect, pLockedRectData);
+}
+
+extern "C" void CPixel__ComputeMipVolumeOffset(const D3DVOLUME_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST D3DBOX *pBox,
+ D3DLOCKED_BOX *pLockedBoxData)
+{
+ CPixel::ComputeMipVolumeOffset(pDescTopLevel, iLevel, pBits, pBox, pLockedBoxData);
+}
+
+extern "C" void CPixel__ComputeSurfaceOffset(const D3DSURFACE_DESC *pDesc,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData)
+{
+ CPixel::ComputeSurfaceOffset(pDesc, pBits, pRect, pLockedRectData);
+}
+
+extern "C" UINT CPixel__ComputePixelStride(D3DFORMAT Format)
+{
+ return CPixel::ComputePixelStride(Format);
+}
+
+extern "C" void CPixel__AdjustForDXT(UINT *pcpWidth,
+ UINT *pcpHeight,
+ UINT *pcbPixel)
+{
+ CPixel::AdjustForDXT(pcpWidth, pcpHeight, pcbPixel);
+}
+
+extern "C" BOOL CPixel__IsDXT(D3DFORMAT Format)
+{
+ return CPixel::IsDXT(Format);
+}
+
+extern "C" UINT CPixel__BytesPerPixel(D3DFORMAT Format)
+{
+ return CPixel::BytesPerPixel(Format);
+}
+
+extern "C" HRESULT CPixel__Register(D3DFORMAT Format, DWORD BPP)
+{
+ return CPixel::Register(Format, BPP);
+}
+
+extern "C" void CPixel__Cleanup()
+{
+ CPixel::Cleanup();
+}
+
+extern "C" UINT CPixel__ComputeSurfaceStride(UINT cpWidth, UINT cbPixel)
+{
+ return CPixel::ComputeSurfaceStride(cpWidth, cbPixel);
+}
+
+
+// End of file : pixel.cpp
+
diff --git a/video/pixlib/pixel.hpp b/video/pixlib/pixel.hpp
new file mode 100644
index 00000000..a23a79f6
--- /dev/null
+++ b/video/pixlib/pixel.hpp
@@ -0,0 +1,365 @@
+/*==========================================================================;
+ *
+ * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
+ *
+ * File: pixel.hpp
+ * Content: Utility class for working with pixel formats
+ *
+ *
+ ***************************************************************************/
+
+#ifdef __cplusplus
+
+#ifndef __PIXEL_HPP_CPP__
+#define __PIXEL_HPP_CPP__
+
+#ifndef DXPIXELVER
+#define DXPIXELVER 100
+#endif
+
+#ifndef DXGASSERT
+#define DXGASSERT( x ) _Analysis_assume_( x );
+#endif
+
+struct IHVFormatInfo
+{
+ D3DFORMAT m_Format;
+ DWORD m_BPP;
+ IHVFormatInfo *m_pNext;
+};
+
+//2GB max allocation size
+#define MAXALLOCSIZE 0x80000000
+
+// This is a utility class that implements useful helpers for
+// allocating and accessing various pixel formats. All methods
+// are static and hence should be accessed as follows:
+// e.g. CPixel::LockOffset(...)
+//
+
+class CPixel
+{
+public:
+ // Allocate helpers
+
+ // Determine the amount of memory that is needed to
+ // allocate various things..
+ static UINT ComputeSurfaceSize(UINT cpWidth,
+ UINT cpHeight,
+ D3DFORMAT Format);
+
+ static UINT ComputeVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ D3DFORMAT Format);
+
+
+ static UINT ComputeMipMapSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cLevels,
+ D3DFORMAT Format);
+
+ static UINT ComputeMipVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ UINT cLevels,
+ D3DFORMAT Format);
+
+ static BOOL ComputeSurfaceSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ D3DFORMAT Format,
+ UINT *pSize);
+
+ static BOOL ComputeVolumeSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ D3DFORMAT Format,
+ UINT *pSize);
+
+
+ static BOOL ComputeMipMapSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cLevels,
+ D3DFORMAT Format,
+ UINT *pSize);
+
+ static BOOL ComputeMipVolumeSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ UINT cLevels,
+ D3DFORMAT Format,
+ UINT *pSize);
+
+
+ // Lock helpers
+
+ // Given a surface desc, a level, and pointer to
+ // bits (pBits in the LockedRectData) and a sub-rect,
+ // this will fill in the pLockedRectData structure
+ static void ComputeMipMapOffset(const D3DSURFACE_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData);
+
+ // MipVolume version of ComputeMipMapOffset
+ static void ComputeMipVolumeOffset(const D3DVOLUME_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST D3DBOX *pBox,
+ D3DLOCKED_BOX *pLockedBoxData);
+
+ // Surface version of ComputeMipMapOffset
+ static void ComputeSurfaceOffset(const D3DSURFACE_DESC *pDesc,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData);
+
+ // Pixel Stride will return negative for DXT formats
+ // Call AdjustForDXT to work with things at the block level
+ static UINT ComputePixelStride(D3DFORMAT Format);
+
+ // This will adjust cbPixel
+ // to pixels per block; and width and height will
+ // be adjusted to pixels. Assumes the IsDXT(cbPixel).
+ static void AdjustForDXT(UINT *pcpWidth,
+ UINT *pcpHeight,
+ UINT *pcbPixel);
+
+ // returns TRUE if cbPixel is "negative" i.e. DXT/V group
+ static BOOL IsDXT(UINT cbPixel);
+
+ // returns TRUE if format is one of the DXT/V group
+ static BOOL IsDXT(D3DFORMAT Format);
+
+ static UINT BytesPerPixel(D3DFORMAT Format);
+
+ // Register format for later lookup
+ static HRESULT Register(D3DFORMAT Format, DWORD BPP);
+
+ // Cleanup registry
+ static void Cleanup();
+
+ static UINT ComputeSurfaceStride(UINT cpWidth, UINT cbPixel);
+
+ static BOOL ComputeSurfaceStrideChecked(UINT cpWidth, UINT cbPixel, UINT *pStride);
+
+
+private:
+ // Internal functions
+
+ static UINT ComputeSurfaceSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cbPixel);
+
+ static BOOL ComputeSurfaceSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ UINT cbPixel,
+ UINT *pSize);
+
+
+ static IHVFormatInfo *m_pFormatList;
+
+}; // CPixel
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceOffset"
+
+inline void CPixel::ComputeSurfaceOffset(const D3DSURFACE_DESC *pDesc,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData)
+{
+ ComputeMipMapOffset(pDesc, 0, pBits, pRect, pLockedRectData);
+} // ComputeSurfaceOffset
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceSize"
+
+inline UINT CPixel::ComputeSurfaceSize(UINT cpWidth,
+ UINT cpHeight,
+ D3DFORMAT Format)
+{
+ UINT uSize = 0; // initialize to zero to keep prefix happy win7: 185026
+ ComputeSurfaceSizeChecked(cpWidth, cpHeight, Format, &uSize);
+ return uSize;
+} // ComputeSurfaceSize
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeSurfaceSizeChecked"
+
+inline BOOL CPixel::ComputeSurfaceSizeChecked(UINT cpWidth,
+ UINT cpHeight,
+ D3DFORMAT Format,
+ UINT *uSize)
+{
+ UINT cbPixel = ComputePixelStride(Format);
+
+ // Adjust pixel->block if necessary
+ BOOL isDXT = IsDXT(cbPixel);
+ if (isDXT)
+ {
+ AdjustForDXT(&cpWidth, &cpHeight, &cbPixel);
+ }
+#if (DXPIXELVER > 8)
+ else
+ if (Format == D3DFMT_A1)
+ {
+ cpWidth = (cpWidth + 7) >> 3;
+ cbPixel = 1;
+ }
+#endif
+
+ return ComputeSurfaceSizeChecked(cpWidth,
+ cpHeight,
+ cbPixel,
+ uSize);
+} // ComputeSurfaceSize
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::AdjustForDXT"
+inline void CPixel::AdjustForDXT(UINT *pcpWidth,
+ UINT *pcpHeight,
+ UINT *pcbPixel)
+{
+ DXGASSERT(pcbPixel);
+ DXGASSERT(pcpWidth);
+ DXGASSERT(pcpHeight);
+ DXGASSERT(IsDXT(*pcbPixel));
+
+ // Adjust width and height for DXT formats to be in blocks
+ // instead of pixels. Blocks are 4x4 pixels.
+ *pcpWidth = (*pcpWidth + 3) / 4;
+ *pcpHeight = (*pcpHeight + 3) / 4;
+
+ // Negate the pcbPixel to determine bytes per block
+ *pcbPixel *= (UINT)-1;
+
+ // We only know of two DXT formats right now...
+ DXGASSERT(*pcbPixel == 8 || *pcbPixel == 16);
+
+} // CPixel::AdjustForDXT
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::ComputeVolumeSize"
+
+inline UINT CPixel::ComputeVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ D3DFORMAT Format)
+{
+ UINT cbPixel = ComputePixelStride(Format);
+
+ if (IsDXT(cbPixel))
+ {
+ AdjustForDXT(&cpWidth, &cpHeight, &cbPixel);
+ }
+
+ return cpDepth * ComputeSurfaceSize(cpWidth, cpHeight, cbPixel);
+} // ComputeVolumeSize
+
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::IsDXT(cbPixel)"
+
+// returns TRUE if cbPixel is "negative"
+inline BOOL CPixel::IsDXT(UINT cbPixel)
+{
+ if (((INT)cbPixel) < 0)
+ return TRUE;
+ else
+ return FALSE;
+} // IsDXT
+
+#undef DPF_MODNAME
+#define DPF_MODNAME "CPixel::IsDXT(format)"
+
+// returns TRUE if this is a linear format
+// i.e. DXT or DXV
+inline BOOL CPixel::IsDXT(D3DFORMAT Format)
+{
+ // CONSIDER: This is a duplication of Requires4x4 function
+ switch (Format)
+ {
+ // normal DXTs
+ case D3DFMT_DXT1:
+ case D3DFMT_DXT2:
+ case D3DFMT_DXT3:
+ case D3DFMT_DXT4:
+ case D3DFMT_DXT5:
+ return TRUE;
+ }
+
+ return FALSE;
+} // IsDXT
+
+
+#endif // __PIXEL_HPP_CPP__
+
+#else
+
+#ifndef __PIXEL_HPP_C__
+#define __PIXEL_HPP_C__
+
+UINT CPixel__ComputeSurfaceSize(UINT cpWidth,
+ UINT cpHeight,
+ D3DFORMAT Format);
+
+UINT CPixel__ComputeVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ D3DFORMAT Format);
+
+UINT CPixel__ComputeMipMapSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cLevels,
+ D3DFORMAT Format);
+
+UINT CPixel__ComputeMipVolumeSize(UINT cpWidth,
+ UINT cpHeight,
+ UINT cpDepth,
+ UINT cLevels,
+ D3DFORMAT Format);
+
+void CPixel__ComputeMipMapOffset(const D3DSURFACE_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData);
+
+void CPixel__ComputeMipVolumeOffset(const D3DVOLUME_DESC *pDescTopLevel,
+ UINT iLevel,
+ BYTE *pBits,
+ CONST D3DBOX *pBox,
+ D3DLOCKED_BOX *pLockedBoxData);
+
+void CPixel__ComputeSurfaceOffset(const D3DSURFACE_DESC *pDesc,
+ BYTE *pBits,
+ CONST RECT *pRect,
+ D3DLOCKED_RECT *pLockedRectData);
+
+UINT CPixel__ComputePixelStride(D3DFORMAT Format);
+
+void CPixel__AdjustForDXT(UINT *pcpWidth,
+ UINT *pcpHeight,
+ UINT *pcbPixel);
+
+BOOL CPixel__IsDXT(D3DFORMAT Format);
+
+UINT CPixel__BytesPerPixel(D3DFORMAT Format);
+
+HRESULT CPixel__Register(D3DFORMAT Format, DWORD BPP);
+
+void CPixel__Cleanup();
+
+UINT CPixel__ComputeSurfaceStride(UINT cpWidth, UINT cbPixel);
+
+
+#endif // __PIXEL_HPP_C__
+
+#endif
+
+
diff --git a/video/pixlib/pixlib.cpp b/video/pixlib/pixlib.cpp
new file mode 100644
index 00000000..df761641
--- /dev/null
+++ b/video/pixlib/pixlib.cpp
@@ -0,0 +1,8 @@
+
+#include "d3d9.h"
+#include "ddraw.h"
+#include "dx95type.h"
+#include "d3dnthal.h"
+
+#include "pixel.cpp"
+
diff --git a/video/pixlib/pixlib.sln b/video/pixlib/pixlib.sln
new file mode 100644
index 00000000..4be1ce6b
--- /dev/null
+++ b/video/pixlib/pixlib.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PixLib", "PixLib.vcxproj", "{4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|Win32.Build.0 = Debug|Win32
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|Win32.ActiveCfg = Release|Win32
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|Win32.Build.0 = Release|Win32
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|x64.ActiveCfg = Debug|x64
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Debug|x64.Build.0 = Debug|x64
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|x64.ActiveCfg = Release|x64
+ {4E06B3AB-DFAD-4F48-8936-FFF04466B8EA}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal