mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-06 20:58:37 +01:00
[d3d9] Implement Direct3D9 Frontend (#1275)
Co-authored-by: Philip Rebohle <philip.rebohle@tu-dortmund.de> Co-authored-by: Robin Kertels <robin.kertels@gmail.com> Co-authored-by: pchome <pchome@users.noreply.github.com> Co-authored-by: Christopher Egert <cme3000@gmail.com> Co-authored-by: Derek Lesho <dereklesho52@Gmail.com> Co-authored-by: Luis Cáceres <lacaceres97@gmail.com> Co-authored-by: Nelson Chen <crazysim@gmail.com> Co-authored-by: Edmondo Tommasina <edmondo.tommasina@gmail.com> Co-authored-by: Riesi <riesi@opentrash.com> Co-authored-by: gbMichelle <gbmichelle.dev@gmail.com>
This commit is contained in:
parent
566fb84abd
commit
54ed8f0bb0
118 changed files with 28889 additions and 3 deletions
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
6
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -9,7 +9,10 @@ assignees: ''
|
|||
|
||||
Please describe your issue as accurately as possible. If you run into a problem with a binary release, make sure to test with latest `master` as well.
|
||||
|
||||
**Important:** When reporting an issue with a specific game or application, such as crashes or rendering issues, please include log files and a D3D11 Apitrace (see https://github.com/apitrace/apitrace) so that the issue can be reproduced. In order to create a trace, run `wine apitrace.exe trace -a dxgi YOURGAME.exe`. DO NOT use DXVK together with apitrace!
|
||||
**Important:** When reporting an issue with a specific game or application, such as crashes or rendering issues, please include log files and a D3D11/D3D9 Apitrace (see https://github.com/apitrace/apitrace) so that the issue can be reproduced.
|
||||
In order to create a trace for **D3D11/D3D10**: Run `wine apitrace.exe trace -a dxgi YOURGAME.exe`.
|
||||
In order to create a trace for **D3D9**: Follow https://github.com/Joshua-Ashton/d9vk/wiki/Making-a-Trace.
|
||||
DO NOT use DXVK together with apitrace!
|
||||
|
||||
### Software information
|
||||
Name of the game, settings used etc.
|
||||
|
@ -24,5 +27,6 @@ Name of the game, settings used etc.
|
|||
- Put a link here
|
||||
|
||||
### Log files
|
||||
- d3d9.log:
|
||||
- d3d11.log:
|
||||
- dxgi.log:
|
||||
|
|
1
LICENSE
1
LICENSE
|
@ -1,4 +1,5 @@
|
|||
Copyright (c) 2017-2019 Philip Rebohle
|
||||
Copyright (c) 2019 Joshua Ashton
|
||||
|
||||
zlib/libpng license
|
||||
|
||||
|
|
112
dxvk.conf
112
dxvk.conf
|
@ -6,6 +6,7 @@
|
|||
# Supported values: True, False
|
||||
|
||||
# dxgi.deferSurfaceCreation = False
|
||||
# d3d9.deferSurfaceCreation = False
|
||||
|
||||
|
||||
# Enforce a stricter maximum frame latency. Overrides the application
|
||||
|
@ -15,6 +16,7 @@
|
|||
# Supported values : 0 - 16
|
||||
|
||||
# dxgi.maxFrameLatency = 0
|
||||
# d3d9.maxFrameLatency = 0
|
||||
|
||||
|
||||
# Override PCI vendor and device IDs reported to the application. Can
|
||||
|
@ -25,6 +27,9 @@
|
|||
# dxgi.customDeviceId = 0000
|
||||
# dxgi.customVendorId = 0000
|
||||
|
||||
# d3d9.customDeviceId = 0000
|
||||
# d3d9.customVendorId = 0000
|
||||
|
||||
|
||||
# Report Nvidia GPUs as AMD GPUs by default. This is enabled by default
|
||||
# to work around issues with NVAPI, but may cause issues in some games.
|
||||
|
@ -60,7 +65,8 @@
|
|||
#
|
||||
# Supported values: Any non-negative number
|
||||
|
||||
# dxgi.syncInterval = -1
|
||||
# dxgi.syncInterval = -1
|
||||
# d3d9.presentInterval = -1
|
||||
|
||||
|
||||
# Performs range check on dynamically indexed constant buffers in shaders.
|
||||
|
@ -115,6 +121,7 @@
|
|||
# Supported values: Any number between 0 and 16
|
||||
|
||||
# d3d11.samplerAnisotropy = -1
|
||||
# d3d9.samplerAnisotropy = -1
|
||||
|
||||
|
||||
# Replaces NaN outputs from fragment shaders with zeroes for floating
|
||||
|
@ -179,3 +186,106 @@
|
|||
# ignored. The syntax is identical.
|
||||
|
||||
# dxvk.hud =
|
||||
|
||||
|
||||
# Reported shader model
|
||||
#
|
||||
# The shader model to state that we support in the device
|
||||
# capabilities that the applicatation queries.
|
||||
#
|
||||
# Supported values:
|
||||
# - 1: Shader Model 1
|
||||
# - 2: Shader Model 2
|
||||
# - 3: Shader Model 3
|
||||
|
||||
# d3d9.shaderModel = 3
|
||||
|
||||
|
||||
# Evict Managed on Unlock
|
||||
#
|
||||
# Decides whether we should evict managed resources from
|
||||
# system memory when they are unlocked entirely.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.evictManagedOnUnlock = False
|
||||
|
||||
|
||||
# DPI Awareness
|
||||
#
|
||||
# Decides whether we should call SetProcessDPIAware on device
|
||||
# creation. Helps avoid upscaling blur in modern Windows on
|
||||
# Hi-DPI screens/devices.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.dpiAware = True
|
||||
|
||||
|
||||
# Strict Constant Copies
|
||||
#
|
||||
# Decides whether we should always copy defined constants to
|
||||
# the UBO when relative addresssing is used, or only when the
|
||||
# relative addressing starts a defined constant.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.strictConstantCopies = False
|
||||
|
||||
|
||||
# Strict Pow
|
||||
#
|
||||
# Decides whether we have an opSelect for handling pow(0,0) = 0
|
||||
# otherwise it becomes undefined.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.strictPow = True
|
||||
|
||||
|
||||
# Lenient Clear
|
||||
#
|
||||
# Decides whether or not we fastpath clear anyway if we are close enough to
|
||||
# clearing a full render target.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.lenientClear = False
|
||||
|
||||
|
||||
# Max available memory
|
||||
#
|
||||
# Changes the max initial value used in tracking and GetAvailableTextureMem
|
||||
# Value in Megabytes
|
||||
#
|
||||
# Supported values:
|
||||
# - Any int32_t
|
||||
|
||||
# d3d9.maxAvailableMemory = 4096
|
||||
|
||||
|
||||
# Force enable/disable floating point quirk emulation
|
||||
#
|
||||
# Force toggle anything * 0 emulation
|
||||
# Tristate
|
||||
# Supported values:
|
||||
# - True/False
|
||||
|
||||
# d3d9.floatEmulation =
|
||||
|
||||
|
||||
# Enable dialog box mode
|
||||
#
|
||||
# Changes the default state of dialog box mode.
|
||||
# *Disables* exclusive fullscreen when enabled.
|
||||
#
|
||||
# Supported values:
|
||||
# - True, False: Always enable / disable
|
||||
|
||||
# d3d9.enableDialogMode = False
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ if dxvk_winelib
|
|||
endif
|
||||
wrc = find_program('wrc')
|
||||
lib_vulkan = declare_dependency(link_args: [ '-lwinevulkan' ])
|
||||
lib_d3d9 = declare_dependency(link_args: [ '-ld3d9' ])
|
||||
lib_d3d11 = declare_dependency(link_args: [ '-ld3d11' ])
|
||||
lib_dxgi = declare_dependency(link_args: [ '-ldxgi' ])
|
||||
lib_d3dcompiler_43 = declare_dependency(link_args: [ '-L'+dxvk_library_path, '-ld3dcompiler_43' ])
|
||||
|
@ -63,6 +64,7 @@ else
|
|||
endif
|
||||
|
||||
lib_vulkan = dxvk_compiler.find_library('vulkan-1', dirs : dxvk_library_path)
|
||||
lib_d3d9 = dxvk_compiler.find_library('d3d9')
|
||||
lib_d3d11 = dxvk_compiler.find_library('d3d11')
|
||||
lib_dxgi = dxvk_compiler.find_library('dxgi')
|
||||
lib_d3dcompiler_43 = dxvk_compiler.find_library('d3dcompiler_43', dirs : dxvk_library_path)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
option('enable_tests', type : 'boolean', value : false)
|
||||
option('enable_dxgi', type : 'boolean', value : true, description: 'Build DXGI')
|
||||
option('enable_d3d9', type : 'boolean', value : true, description: 'Build D3D9')
|
||||
option('enable_d3d10', type : 'boolean', value : true, description: 'Build D3D10')
|
||||
option('enable_d3d11', type : 'boolean', value : true, description: 'Build D3D11')
|
||||
|
|
|
@ -172,6 +172,7 @@ if [ $with_dxgi -ne 0 ] || [ "$action" == "uninstall" ]; then
|
|||
$action dxgi
|
||||
fi
|
||||
|
||||
$action d3d9
|
||||
$action d3d10
|
||||
$action d3d10_1
|
||||
$action d3d10core
|
||||
|
|
22
src/d3d9/d3d9.def
Normal file
22
src/d3d9/d3d9.def
Normal file
|
@ -0,0 +1,22 @@
|
|||
LIBRARY D3D9.DLL
|
||||
EXPORTS
|
||||
Direct3DShaderValidatorCreate9 @ 24
|
||||
|
||||
PSGPError @ 25
|
||||
PSGPSampleTexture @ 26
|
||||
|
||||
D3DPERF_BeginEvent @ 27
|
||||
D3DPERF_EndEvent @ 28
|
||||
D3DPERF_GetStatus @ 29
|
||||
D3DPERF_QueryRepeatFrame @ 30
|
||||
D3DPERF_SetMarker @ 31
|
||||
D3DPERF_SetOptions @ 32
|
||||
D3DPERF_SetRegion @ 33
|
||||
|
||||
DebugSetLevel @ 34
|
||||
DebugSetMute @ 35
|
||||
|
||||
Direct3D9EnableMaximizedWindowedModeShim @ 36
|
||||
|
||||
Direct3DCreate9 @ 37
|
||||
Direct3DCreate9Ex @ 38
|
20
src/d3d9/d3d9.spec
Normal file
20
src/d3d9/d3d9.spec
Normal file
|
@ -0,0 +1,20 @@
|
|||
@ stdcall Direct3DShaderValidatorCreate9()
|
||||
|
||||
@ stdcall PSGPError(ptr long long)
|
||||
@ stdcall PSGPSampleTexture(ptr long ptr long ptr)
|
||||
|
||||
@ stdcall D3DPERF_BeginEvent(long wstr)
|
||||
@ stdcall D3DPERF_EndEvent()
|
||||
@ stdcall D3DPERF_GetStatus()
|
||||
@ stdcall D3DPERF_QueryRepeatFrame()
|
||||
@ stdcall D3DPERF_SetMarker(long wstr)
|
||||
@ stdcall D3DPERF_SetOptions(long)
|
||||
@ stdcall D3DPERF_SetRegion(long wstr)
|
||||
|
||||
@ stdcall DebugSetLevel()
|
||||
@ stdcall DebugSetMute()
|
||||
|
||||
@ stdcall Direct3D9EnableMaximizedWindowedModeShim(long)
|
||||
|
||||
@ stdcall Direct3DCreate9(long)
|
||||
@ stdcall Direct3DCreate9Ex(long ptr)
|
804
src/d3d9/d3d9_adapter.cpp
Normal file
804
src/d3d9/d3d9_adapter.cpp
Normal file
|
@ -0,0 +1,804 @@
|
|||
#include "d3d9_adapter.h"
|
||||
|
||||
#include "d3d9_interface.h"
|
||||
#include "d3d9_monitor.h"
|
||||
#include "d3d9_caps.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
#include "../util/util_bit.h"
|
||||
#include "../util/util_luid.h"
|
||||
#include "../util/util_ratio.h"
|
||||
|
||||
#include <cfloat>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
const char* GetDriverDLL(DxvkGpuVendor vendor) {
|
||||
switch (vendor) {
|
||||
default:
|
||||
case DxvkGpuVendor::Nvidia: return "nvd3dum.dll";
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64)
|
||||
case DxvkGpuVendor::Amd: return "aticfx64.dll";
|
||||
case DxvkGpuVendor::Intel: return "igdumd64.dll";
|
||||
#else
|
||||
case DxvkGpuVendor::Amd: return "aticfx32.dll";
|
||||
case DxvkGpuVendor::Intel: return "igdumd32.dll";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
D3D9Adapter::D3D9Adapter(
|
||||
D3D9InterfaceEx* pParent,
|
||||
Rc<DxvkAdapter> Adapter,
|
||||
UINT Ordinal)
|
||||
: m_parent (pParent)
|
||||
, m_adapter (Adapter)
|
||||
, m_ordinal (Ordinal)
|
||||
, m_modeCacheFormat (D3D9Format::Unknown)
|
||||
, m_d3d9Formats (Adapter, m_parent->GetOptions()) {
|
||||
m_adapter->logAdapterInfo();
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::GetAdapterIdentifier(
|
||||
DWORD Flags,
|
||||
D3DADAPTER_IDENTIFIER9* pIdentifier) {
|
||||
if (unlikely(pIdentifier == nullptr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto& options = m_parent->GetOptions();
|
||||
|
||||
const auto& props = m_adapter->deviceProperties();
|
||||
|
||||
::MONITORINFOEXA monInfo;
|
||||
monInfo.cbSize = sizeof(monInfo);
|
||||
|
||||
if (!::GetMonitorInfoA(GetDefaultMonitor(), reinterpret_cast<MONITORINFO*>(&monInfo))) {
|
||||
Logger::err("D3D9Adapter::GetAdapterIdentifier: Failed to query monitor info");
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
GUID guid = bit::cast<GUID>(m_adapter->devicePropertiesExt().coreDeviceId.deviceUUID);
|
||||
|
||||
uint32_t vendorId = options.customVendorId == -1 ? props.vendorID : uint32_t(options.customVendorId);
|
||||
uint32_t deviceId = options.customDeviceId == -1 ? props.deviceID : uint32_t(options.customDeviceId);
|
||||
const char* desc = options.customDeviceDesc.empty() ? props.deviceName : options.customDeviceDesc.c_str();
|
||||
const char* driver = GetDriverDLL(DxvkGpuVendor(vendorId));
|
||||
|
||||
std::strncpy(pIdentifier->Description, desc, countof(pIdentifier->Description));
|
||||
std::strncpy(pIdentifier->DeviceName, monInfo.szDevice, countof(pIdentifier->DeviceName)); // The GDI device name. Not the actual device name.
|
||||
std::strncpy(pIdentifier->Driver, driver, countof(pIdentifier->Driver)); // This is the driver's dll.
|
||||
|
||||
pIdentifier->DeviceIdentifier = guid;
|
||||
pIdentifier->DeviceId = deviceId;
|
||||
pIdentifier->VendorId = vendorId;
|
||||
pIdentifier->Revision = 0;
|
||||
pIdentifier->SubSysId = 0;
|
||||
pIdentifier->WHQLLevel = m_parent->IsExtended() ? 1 : 0; // This doesn't check with the driver on Direct3D9Ex and is always 1.
|
||||
pIdentifier->DriverVersion.QuadPart = INT64_MAX;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::CheckDeviceType(
|
||||
D3DDEVTYPE DevType,
|
||||
D3D9Format AdapterFormat,
|
||||
D3D9Format BackBufferFormat,
|
||||
BOOL bWindowed) {
|
||||
if (!IsSupportedBackBufferFormat(
|
||||
AdapterFormat, BackBufferFormat, bWindowed))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::CheckDeviceFormat(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format AdapterFormat,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType,
|
||||
D3D9Format CheckFormat) {
|
||||
if (!IsSupportedAdapterFormat(AdapterFormat))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (!IsSupportedDisplayFormat(AdapterFormat, false))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
const bool dmap = Usage & D3DUSAGE_DMAP;
|
||||
const bool rt = Usage & D3DUSAGE_RENDERTARGET;
|
||||
const bool ds = Usage & D3DUSAGE_DEPTHSTENCIL;
|
||||
|
||||
const bool surface = RType == D3DRTYPE_SURFACE;
|
||||
const bool texture = RType == D3DRTYPE_TEXTURE;
|
||||
|
||||
const bool twoDimensional = surface || texture;
|
||||
|
||||
const bool srgb = (Usage & (D3DUSAGE_QUERY_SRGBREAD | D3DUSAGE_QUERY_SRGBWRITE)) != 0;
|
||||
|
||||
if (CheckFormat == D3D9Format::INST)
|
||||
return D3D_OK;
|
||||
|
||||
if (rt && CheckFormat == D3D9Format::A8 && m_parent->GetOptions().disableA8RT)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (ds && !IsDepthFormat(CheckFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (rt && CheckFormat == D3D9Format::NULL_FORMAT && twoDimensional)
|
||||
return D3D_OK;
|
||||
|
||||
if (rt && CheckFormat == D3D9Format::RESZ && surface)
|
||||
return D3D_OK;
|
||||
|
||||
if (CheckFormat == D3D9Format::ATOC && surface)
|
||||
return D3D_OK;
|
||||
|
||||
if (CheckFormat == D3D9Format::NVDB && surface)
|
||||
return D3D_OK;
|
||||
|
||||
// I really don't want to support this...
|
||||
if (dmap)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
auto mapping = m_d3d9Formats.GetFormatMapping(CheckFormat);
|
||||
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (mapping.FormatSrgb == VK_FORMAT_UNDEFINED && srgb)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (RType == D3DRTYPE_VERTEXBUFFER || RType == D3DRTYPE_INDEXBUFFER)
|
||||
return D3D_OK;
|
||||
|
||||
// Let's actually ask Vulkan now that we got some quirks out the way!
|
||||
|
||||
return CheckDeviceVkFormat(mapping.FormatColor, Usage, RType);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::CheckDeviceMultiSampleType(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format SurfaceFormat,
|
||||
BOOL Windowed,
|
||||
D3DMULTISAMPLE_TYPE MultiSampleType,
|
||||
DWORD* pQualityLevels) {
|
||||
if (pQualityLevels != nullptr)
|
||||
*pQualityLevels = 1;
|
||||
|
||||
auto dst = ConvertFormatUnfixed(SurfaceFormat);
|
||||
if (dst.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (MultiSampleType != D3DMULTISAMPLE_NONE
|
||||
&& (SurfaceFormat == D3D9Format::D32_LOCKABLE
|
||||
|| SurfaceFormat == D3D9Format::D32F_LOCKABLE
|
||||
|| SurfaceFormat == D3D9Format::D16_LOCKABLE))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
uint32_t sampleCount = std::max<uint32_t>(MultiSampleType, 1u);
|
||||
|
||||
// Check if this is a power of two...
|
||||
if (sampleCount & (sampleCount - 1))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
// Therefore...
|
||||
VkSampleCountFlags sampleFlags = VkSampleCountFlags(sampleCount);
|
||||
|
||||
auto availableFlags = !IsDepthFormat(SurfaceFormat)
|
||||
? m_adapter->deviceProperties().limits.framebufferColorSampleCounts
|
||||
: m_adapter->deviceProperties().limits.framebufferDepthSampleCounts;
|
||||
|
||||
if (!(availableFlags & sampleFlags))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (pQualityLevels != nullptr) {
|
||||
if (MultiSampleType == D3DMULTISAMPLE_NONMASKABLE)
|
||||
*pQualityLevels = (32 - bit::lzcnt(availableFlags));
|
||||
else
|
||||
*pQualityLevels = 1;
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::CheckDepthStencilMatch(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format AdapterFormat,
|
||||
D3D9Format RenderTargetFormat,
|
||||
D3D9Format DepthStencilFormat) {
|
||||
if (!IsSupportedAdapterFormat(AdapterFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
if (!IsDepthFormat(DepthStencilFormat))
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
auto mapping = ConvertFormatUnfixed(RenderTargetFormat);
|
||||
if (mapping.FormatColor == VK_FORMAT_UNDEFINED)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::CheckDeviceFormatConversion(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format SourceFormat,
|
||||
D3D9Format TargetFormat) {
|
||||
bool sourceSupported = IsSupportedBackBufferFormat(SourceFormat, FALSE);
|
||||
bool targetSupported = TargetFormat == D3D9Format::X1R5G5B5
|
||||
|| TargetFormat == D3D9Format::A1R5G5B5
|
||||
|| TargetFormat == D3D9Format::R5G6B5
|
||||
// || TargetFormat == D3D9Format::R8G8B8 <-- We don't support R8G8B8
|
||||
|| TargetFormat == D3D9Format::X8R8G8B8
|
||||
|| TargetFormat == D3D9Format::A8R8G8B8
|
||||
|| TargetFormat == D3D9Format::A2R10G10B10
|
||||
|| TargetFormat == D3D9Format::A16B16G16R16
|
||||
|| TargetFormat == D3D9Format::A2B10G10R10
|
||||
|| TargetFormat == D3D9Format::A8B8G8R8
|
||||
|| TargetFormat == D3D9Format::X8B8G8R8
|
||||
|| TargetFormat == D3D9Format::A16B16G16R16F
|
||||
|| TargetFormat == D3D9Format::A32B32G32R32F;
|
||||
|
||||
return (sourceSupported && targetSupported)
|
||||
? D3D_OK
|
||||
: D3DERR_NOTAVAILABLE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::GetDeviceCaps(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DCAPS9* pCaps) {
|
||||
using namespace dxvk::caps;
|
||||
|
||||
if (pCaps == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto& options = m_parent->GetOptions();
|
||||
|
||||
// TODO: Actually care about what the adapter supports here.
|
||||
// ^ For Intel and older cards most likely here.
|
||||
|
||||
// Device Type
|
||||
pCaps->DeviceType = DeviceType;
|
||||
// Adapter Id
|
||||
pCaps->AdapterOrdinal = m_ordinal;
|
||||
// Caps 1
|
||||
pCaps->Caps = D3DCAPS_READ_SCANLINE;
|
||||
// Caps 2
|
||||
pCaps->Caps2 = D3DCAPS2_FULLSCREENGAMMA
|
||||
/* | D3DCAPS2_CANCALIBRATEGAMMA */
|
||||
/* | D3DCAPS2_RESERVED */
|
||||
/* | D3DCAPS2_CANMANAGERESOURCE */
|
||||
| D3DCAPS2_DYNAMICTEXTURES
|
||||
| D3DCAPS2_CANAUTOGENMIPMAP
|
||||
/* | D3DCAPS2_CANSHARERESOURCE */;
|
||||
// Caps 3
|
||||
pCaps->Caps3 = D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD
|
||||
| D3DCAPS3_LINEAR_TO_SRGB_PRESENTATION
|
||||
| D3DCAPS3_COPY_TO_VIDMEM
|
||||
| D3DCAPS3_COPY_TO_SYSTEMMEM
|
||||
/* | D3DCAPS3_DXVAHD */
|
||||
/* | D3DCAPS3_DXVAHD_LIMITED */;
|
||||
// Presentation Intervals
|
||||
pCaps->PresentationIntervals = D3DPRESENT_INTERVAL_DEFAULT
|
||||
| D3DPRESENT_INTERVAL_ONE
|
||||
| D3DPRESENT_INTERVAL_TWO
|
||||
| D3DPRESENT_INTERVAL_THREE
|
||||
| D3DPRESENT_INTERVAL_FOUR
|
||||
| D3DPRESENT_INTERVAL_IMMEDIATE;
|
||||
// Cursor
|
||||
pCaps->CursorCaps = D3DCURSORCAPS_COLOR; // I do not support Cursor yet, but I don't want to say I don't support it for compatibility reasons.
|
||||
// Dev Caps
|
||||
pCaps->DevCaps = D3DDEVCAPS_EXECUTESYSTEMMEMORY
|
||||
| D3DDEVCAPS_EXECUTEVIDEOMEMORY
|
||||
| D3DDEVCAPS_TLVERTEXSYSTEMMEMORY
|
||||
| D3DDEVCAPS_TLVERTEXVIDEOMEMORY
|
||||
/* | D3DDEVCAPS_TEXTURESYSTEMMEMORY */
|
||||
| D3DDEVCAPS_TEXTUREVIDEOMEMORY
|
||||
| D3DDEVCAPS_DRAWPRIMTLVERTEX
|
||||
| D3DDEVCAPS_CANRENDERAFTERFLIP
|
||||
| D3DDEVCAPS_TEXTURENONLOCALVIDMEM
|
||||
| D3DDEVCAPS_DRAWPRIMITIVES2
|
||||
/* | D3DDEVCAPS_SEPARATETEXTUREMEMORIES */
|
||||
| D3DDEVCAPS_DRAWPRIMITIVES2EX
|
||||
| D3DDEVCAPS_HWTRANSFORMANDLIGHT
|
||||
| D3DDEVCAPS_CANBLTSYSTONONLOCAL
|
||||
| D3DDEVCAPS_HWRASTERIZATION
|
||||
| D3DDEVCAPS_PUREDEVICE
|
||||
/* | D3DDEVCAPS_QUINTICRTPATCHES */
|
||||
/* | D3DDEVCAPS_RTPATCHES */
|
||||
/* | D3DDEVCAPS_RTPATCHHANDLEZERO */
|
||||
/* | D3DDEVCAPS_NPATCHES */;
|
||||
// Primitive Misc. Caps
|
||||
pCaps->PrimitiveMiscCaps = D3DPMISCCAPS_MASKZ
|
||||
| D3DPMISCCAPS_CULLNONE
|
||||
| D3DPMISCCAPS_CULLCW
|
||||
| D3DPMISCCAPS_CULLCCW
|
||||
| D3DPMISCCAPS_COLORWRITEENABLE
|
||||
| D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
|
||||
/* | D3DPMISCCAPS_CLIPTLVERTS */
|
||||
| D3DPMISCCAPS_TSSARGTEMP
|
||||
| D3DPMISCCAPS_BLENDOP
|
||||
/* | D3DPMISCCAPS_NULLREFERENCE */
|
||||
| D3DPMISCCAPS_INDEPENDENTWRITEMASKS
|
||||
| D3DPMISCCAPS_PERSTAGECONSTANT
|
||||
| D3DPMISCCAPS_FOGANDSPECULARALPHA
|
||||
| D3DPMISCCAPS_SEPARATEALPHABLEND
|
||||
| D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS
|
||||
| D3DPMISCCAPS_MRTPOSTPIXELSHADERBLENDING
|
||||
| D3DPMISCCAPS_FOGVERTEXCLAMPED
|
||||
| D3DPMISCCAPS_POSTBLENDSRGBCONVERT;
|
||||
// Raster Caps
|
||||
pCaps->RasterCaps = D3DPRASTERCAPS_DITHER
|
||||
| D3DPRASTERCAPS_ZTEST
|
||||
| D3DPRASTERCAPS_FOGVERTEX
|
||||
| D3DPRASTERCAPS_FOGTABLE
|
||||
| D3DPRASTERCAPS_MIPMAPLODBIAS
|
||||
/* | D3DPRASTERCAPS_ZBUFFERLESSHSR */
|
||||
| D3DPRASTERCAPS_FOGRANGE
|
||||
| D3DPRASTERCAPS_ANISOTROPY
|
||||
/* | D3DPRASTERCAPS_WBUFFER */
|
||||
| D3DPRASTERCAPS_WFOG
|
||||
| D3DPRASTERCAPS_ZFOG
|
||||
| D3DPRASTERCAPS_COLORPERSPECTIVE
|
||||
| D3DPRASTERCAPS_SCISSORTEST
|
||||
| D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS
|
||||
| D3DPRASTERCAPS_DEPTHBIAS
|
||||
| D3DPRASTERCAPS_MULTISAMPLE_TOGGLE; // <-- TODO! (but difficult in Vk)
|
||||
// Z Comparison Caps
|
||||
pCaps->ZCmpCaps = D3DPCMPCAPS_NEVER
|
||||
| D3DPCMPCAPS_LESS
|
||||
| D3DPCMPCAPS_EQUAL
|
||||
| D3DPCMPCAPS_LESSEQUAL
|
||||
| D3DPCMPCAPS_GREATER
|
||||
| D3DPCMPCAPS_NOTEQUAL
|
||||
| D3DPCMPCAPS_GREATEREQUAL
|
||||
| D3DPCMPCAPS_ALWAYS;
|
||||
// Source Blend Caps
|
||||
pCaps->SrcBlendCaps = D3DPBLENDCAPS_ZERO
|
||||
| D3DPBLENDCAPS_ONE
|
||||
| D3DPBLENDCAPS_SRCCOLOR
|
||||
| D3DPBLENDCAPS_INVSRCCOLOR
|
||||
| D3DPBLENDCAPS_SRCALPHA
|
||||
| D3DPBLENDCAPS_INVSRCALPHA
|
||||
| D3DPBLENDCAPS_DESTALPHA
|
||||
| D3DPBLENDCAPS_INVDESTALPHA
|
||||
| D3DPBLENDCAPS_DESTCOLOR
|
||||
| D3DPBLENDCAPS_INVDESTCOLOR
|
||||
| D3DPBLENDCAPS_SRCALPHASAT
|
||||
| D3DPBLENDCAPS_BOTHSRCALPHA
|
||||
| D3DPBLENDCAPS_BOTHINVSRCALPHA
|
||||
| D3DPBLENDCAPS_BLENDFACTOR
|
||||
| D3DPBLENDCAPS_INVSRCCOLOR2
|
||||
| D3DPBLENDCAPS_SRCCOLOR2;
|
||||
// Destination Blend Caps
|
||||
pCaps->DestBlendCaps = pCaps->SrcBlendCaps;
|
||||
// Alpha Comparison Caps
|
||||
pCaps->AlphaCmpCaps = pCaps->ZCmpCaps;
|
||||
// Shade Caps
|
||||
pCaps->ShadeCaps = D3DPSHADECAPS_COLORGOURAUDRGB
|
||||
| D3DPSHADECAPS_SPECULARGOURAUDRGB
|
||||
| D3DPSHADECAPS_ALPHAGOURAUDBLEND
|
||||
| D3DPSHADECAPS_FOGGOURAUD;
|
||||
// Texture Caps
|
||||
pCaps->TextureCaps = D3DPTEXTURECAPS_PERSPECTIVE
|
||||
/* | D3DPTEXTURECAPS_POW2 */
|
||||
| D3DPTEXTURECAPS_ALPHA
|
||||
/* | D3DPTEXTURECAPS_SQUAREONLY */
|
||||
| D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE
|
||||
| D3DPTEXTURECAPS_ALPHAPALETTE
|
||||
/* | D3DPTEXTURECAPS_NONPOW2CONDITIONAL */
|
||||
| D3DPTEXTURECAPS_PROJECTED
|
||||
| D3DPTEXTURECAPS_CUBEMAP
|
||||
| D3DPTEXTURECAPS_VOLUMEMAP
|
||||
| D3DPTEXTURECAPS_MIPMAP
|
||||
| D3DPTEXTURECAPS_MIPVOLUMEMAP
|
||||
| D3DPTEXTURECAPS_MIPCUBEMAP
|
||||
/* | D3DPTEXTURECAPS_CUBEMAP_POW2 */
|
||||
/* | D3DPTEXTURECAPS_VOLUMEMAP_POW2 */
|
||||
/* | D3DPTEXTURECAPS_NOPROJECTEDBUMPENV */;
|
||||
// Texture Filter Caps
|
||||
pCaps->TextureFilterCaps = D3DPTFILTERCAPS_MINFPOINT
|
||||
| D3DPTFILTERCAPS_MINFLINEAR
|
||||
| D3DPTFILTERCAPS_MINFANISOTROPIC
|
||||
/* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
|
||||
| D3DPTFILTERCAPS_MIPFPOINT
|
||||
| D3DPTFILTERCAPS_MIPFLINEAR
|
||||
/* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
|
||||
| D3DPTFILTERCAPS_MAGFPOINT
|
||||
| D3DPTFILTERCAPS_MAGFLINEAR
|
||||
| D3DPTFILTERCAPS_MAGFANISOTROPIC
|
||||
/* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
|
||||
// Cube Texture Filter Caps
|
||||
pCaps->CubeTextureFilterCaps = pCaps->TextureFilterCaps;
|
||||
// Volume Texture Filter Caps
|
||||
pCaps->VolumeTextureFilterCaps = pCaps->TextureFilterCaps;
|
||||
// Texture Address Caps
|
||||
pCaps->TextureAddressCaps = D3DPTADDRESSCAPS_WRAP
|
||||
| D3DPTADDRESSCAPS_MIRROR
|
||||
| D3DPTADDRESSCAPS_CLAMP
|
||||
| D3DPTADDRESSCAPS_BORDER
|
||||
| D3DPTADDRESSCAPS_INDEPENDENTUV
|
||||
| D3DPTADDRESSCAPS_MIRRORONCE;
|
||||
// Volume Texture Address Caps
|
||||
pCaps->VolumeTextureAddressCaps = pCaps->TextureAddressCaps;
|
||||
// Line Caps
|
||||
pCaps->LineCaps = D3DLINECAPS_TEXTURE
|
||||
| D3DLINECAPS_ZTEST
|
||||
| D3DLINECAPS_BLEND
|
||||
| D3DLINECAPS_ALPHACMP
|
||||
| D3DLINECAPS_FOG
|
||||
| D3DLINECAPS_ANTIALIAS; //<-- Lying about doing AA lines here, we don't *fully* support that.
|
||||
// Max Texture Width
|
||||
pCaps->MaxTextureWidth = MaxTextureDimension;
|
||||
// Max Texture Height
|
||||
pCaps->MaxTextureHeight = MaxTextureDimension;
|
||||
// Max Volume Extent
|
||||
pCaps->MaxVolumeExtent = 8192;
|
||||
// Max Texture Repeat
|
||||
pCaps->MaxTextureRepeat = 8192;
|
||||
// Max Texture Aspect Ratio
|
||||
pCaps->MaxTextureAspectRatio = 8192;
|
||||
// Max Anisotropy
|
||||
pCaps->MaxAnisotropy = 16;
|
||||
// Max Vertex W
|
||||
pCaps->MaxVertexW = 1e10f;
|
||||
// Guard Bands
|
||||
pCaps->GuardBandLeft = -32768.0f;
|
||||
pCaps->GuardBandTop = -32768.0f;
|
||||
pCaps->GuardBandRight = 32768.0f;
|
||||
pCaps->GuardBandBottom = 32768.0f;
|
||||
// Extents Adjust
|
||||
pCaps->ExtentsAdjust = 0.0f;
|
||||
// Stencil Caps
|
||||
pCaps->StencilCaps = D3DSTENCILCAPS_KEEP
|
||||
| D3DSTENCILCAPS_ZERO
|
||||
| D3DSTENCILCAPS_REPLACE
|
||||
| D3DSTENCILCAPS_INCRSAT
|
||||
| D3DSTENCILCAPS_DECRSAT
|
||||
| D3DSTENCILCAPS_INVERT
|
||||
| D3DSTENCILCAPS_INCR
|
||||
| D3DSTENCILCAPS_DECR
|
||||
| D3DSTENCILCAPS_TWOSIDED;
|
||||
// FVF Caps
|
||||
pCaps->FVFCaps = (MaxSimultaneousTextures & D3DFVFCAPS_TEXCOORDCOUNTMASK)
|
||||
/* | D3DFVFCAPS_DONOTSTRIPELEMENTS */
|
||||
| D3DFVFCAPS_PSIZE;
|
||||
// Texture Op Caps
|
||||
pCaps->TextureOpCaps = D3DTEXOPCAPS_DISABLE
|
||||
| D3DTEXOPCAPS_SELECTARG1
|
||||
| D3DTEXOPCAPS_SELECTARG2
|
||||
| D3DTEXOPCAPS_MODULATE
|
||||
| D3DTEXOPCAPS_MODULATE2X
|
||||
| D3DTEXOPCAPS_MODULATE4X
|
||||
| D3DTEXOPCAPS_ADD
|
||||
| D3DTEXOPCAPS_ADDSIGNED
|
||||
| D3DTEXOPCAPS_ADDSIGNED2X
|
||||
| D3DTEXOPCAPS_SUBTRACT
|
||||
| D3DTEXOPCAPS_ADDSMOOTH
|
||||
| D3DTEXOPCAPS_BLENDDIFFUSEALPHA
|
||||
| D3DTEXOPCAPS_BLENDTEXTUREALPHA
|
||||
| D3DTEXOPCAPS_BLENDFACTORALPHA
|
||||
| D3DTEXOPCAPS_BLENDTEXTUREALPHAPM
|
||||
| D3DTEXOPCAPS_BLENDCURRENTALPHA
|
||||
| D3DTEXOPCAPS_PREMODULATE
|
||||
| D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR
|
||||
| D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA
|
||||
| D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR
|
||||
| D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA
|
||||
| D3DTEXOPCAPS_BUMPENVMAP
|
||||
| D3DTEXOPCAPS_BUMPENVMAPLUMINANCE
|
||||
| D3DTEXOPCAPS_DOTPRODUCT3
|
||||
| D3DTEXOPCAPS_MULTIPLYADD
|
||||
| D3DTEXOPCAPS_LERP;
|
||||
// Max Texture Blend Stages
|
||||
pCaps->MaxTextureBlendStages = MaxTextureBlendStages;
|
||||
// Max Simultaneous Textures
|
||||
pCaps->MaxSimultaneousTextures = MaxSimultaneousTextures;
|
||||
// Vertex Processing Caps
|
||||
pCaps->VertexProcessingCaps = D3DVTXPCAPS_TEXGEN
|
||||
| D3DVTXPCAPS_MATERIALSOURCE7
|
||||
| D3DVTXPCAPS_DIRECTIONALLIGHTS
|
||||
| D3DVTXPCAPS_POSITIONALLIGHTS
|
||||
| D3DVTXPCAPS_LOCALVIEWER
|
||||
| D3DVTXPCAPS_TWEENING
|
||||
| D3DVTXPCAPS_TEXGEN_SPHEREMAP
|
||||
/* | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER*/;
|
||||
// Max Active Lights
|
||||
pCaps->MaxActiveLights = caps::MaxEnabledLights;
|
||||
// Max User Clip Planes
|
||||
pCaps->MaxUserClipPlanes = MaxClipPlanes;
|
||||
// Max Vertex Blend Matrices
|
||||
pCaps->MaxVertexBlendMatrices = 4;
|
||||
// Max Vertex Blend Matrix Index
|
||||
pCaps->MaxVertexBlendMatrixIndex = 8;
|
||||
// Max Point Size
|
||||
pCaps->MaxPointSize = 256.0f;
|
||||
// Max Primitive Count
|
||||
pCaps->MaxPrimitiveCount = 0x00555555;
|
||||
// Max Vertex Index
|
||||
pCaps->MaxVertexIndex = 0x00ffffff;
|
||||
// Max Streams
|
||||
pCaps->MaxStreams = MaxStreams;
|
||||
// Max Stream Stride
|
||||
pCaps->MaxStreamStride = 508; // bytes
|
||||
|
||||
const uint32_t majorVersion = options.shaderModel;
|
||||
const uint32_t minorVersion = options.shaderModel != 1 ? 0 : 4;
|
||||
|
||||
// Shader Versions
|
||||
pCaps->VertexShaderVersion = D3DVS_VERSION(majorVersion, minorVersion);
|
||||
pCaps->PixelShaderVersion = D3DPS_VERSION(majorVersion, minorVersion);
|
||||
|
||||
// Max Vertex Shader Const
|
||||
pCaps->MaxVertexShaderConst = MaxFloatConstantsVS;
|
||||
// Max PS1 Value
|
||||
pCaps->PixelShader1xMaxValue = FLT_MAX;
|
||||
// Dev Caps 2
|
||||
pCaps->DevCaps2 = D3DDEVCAPS2_STREAMOFFSET
|
||||
/* | D3DDEVCAPS2_DMAPNPATCH */
|
||||
/* | D3DDEVCAPS2_ADAPTIVETESSRTPATCH */
|
||||
/* | D3DDEVCAPS2_ADAPTIVETESSNPATCH */
|
||||
| D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES
|
||||
/* | D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH */
|
||||
| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
|
||||
// Max N Patch Tesselation Level
|
||||
pCaps->MaxNpatchTessellationLevel = 0.0f;
|
||||
// Reserved for... something
|
||||
pCaps->Reserved5 = 0;
|
||||
// Master adapter for us is adapter 0, atm...
|
||||
pCaps->MasterAdapterOrdinal = 0;
|
||||
// The group of adapters this one is in
|
||||
pCaps->AdapterOrdinalInGroup = 0;
|
||||
// Number of adapters in current group
|
||||
pCaps->NumberOfAdaptersInGroup = 1;
|
||||
// Decl Type Caps
|
||||
pCaps->DeclTypes = D3DDTCAPS_UBYTE4
|
||||
| D3DDTCAPS_UBYTE4N
|
||||
| D3DDTCAPS_SHORT2N
|
||||
| D3DDTCAPS_SHORT4N
|
||||
| D3DDTCAPS_USHORT2N
|
||||
| D3DDTCAPS_USHORT4N
|
||||
| D3DDTCAPS_UDEC3
|
||||
| D3DDTCAPS_DEC3N
|
||||
| D3DDTCAPS_FLOAT16_2
|
||||
| D3DDTCAPS_FLOAT16_4;
|
||||
// Number of simultaneous RTs
|
||||
pCaps->NumSimultaneousRTs = MaxSimultaneousRenderTargets;
|
||||
// Possible StretchRect filters
|
||||
pCaps->StretchRectFilterCaps = D3DPTFILTERCAPS_MINFPOINT
|
||||
| D3DPTFILTERCAPS_MINFLINEAR
|
||||
/* | D3DPTFILTERCAPS_MINFANISOTROPIC */
|
||||
/* | D3DPTFILTERCAPS_MINFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MINFGAUSSIANQUAD */
|
||||
/* | D3DPTFILTERCAPS_MIPFPOINT */
|
||||
/* | D3DPTFILTERCAPS_MIPFLINEAR */
|
||||
/* | D3DPTFILTERCAPS_CONVOLUTIONMONO */
|
||||
| D3DPTFILTERCAPS_MAGFPOINT
|
||||
| D3DPTFILTERCAPS_MAGFLINEAR
|
||||
/* | D3DPTFILTERCAPS_MAGFANISOTROPIC */
|
||||
/* | D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD */
|
||||
/* | D3DPTFILTERCAPS_MAGFGAUSSIANQUAD */;
|
||||
|
||||
// Not too bothered about doing these longhand
|
||||
// We should match whatever my AMD hardware reports here
|
||||
// methinks for the best chance of stuff working.
|
||||
pCaps->VS20Caps.Caps = 1;
|
||||
pCaps->VS20Caps.DynamicFlowControlDepth = 24;
|
||||
pCaps->VS20Caps.NumTemps = 32;
|
||||
pCaps->VS20Caps.StaticFlowControlDepth = 4;
|
||||
|
||||
pCaps->PS20Caps.Caps = 31;
|
||||
pCaps->PS20Caps.DynamicFlowControlDepth = 24;
|
||||
pCaps->PS20Caps.NumTemps = 32;
|
||||
pCaps->PS20Caps.StaticFlowControlDepth = 4;
|
||||
|
||||
pCaps->PS20Caps.NumInstructionSlots = options.shaderModel >= 2 ? 512 : 256;
|
||||
|
||||
pCaps->VertexTextureFilterCaps = 50332416;
|
||||
pCaps->MaxVShaderInstructionsExecuted = 4294967295;
|
||||
pCaps->MaxPShaderInstructionsExecuted = 4294967295;
|
||||
|
||||
pCaps->MaxVertexShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
|
||||
pCaps->MaxPixelShader30InstructionSlots = options.shaderModel == 3 ? 32768 : 0;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HMONITOR D3D9Adapter::GetMonitor() {
|
||||
return GetDefaultMonitor();
|
||||
}
|
||||
|
||||
|
||||
UINT D3D9Adapter::GetAdapterModeCountEx(CONST D3DDISPLAYMODEFILTER* pFilter) {
|
||||
if (pFilter == nullptr)
|
||||
return 0;
|
||||
|
||||
// We don't offer any interlaced formats here so early out and avoid destroying mode cache.
|
||||
if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
|
||||
return 0;
|
||||
|
||||
CacheModes(EnumerateFormat(pFilter->Format));
|
||||
return m_modes.size();
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::EnumAdapterModesEx(
|
||||
const D3DDISPLAYMODEFILTER* pFilter,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODEEX* pMode) {
|
||||
if (pMode == nullptr || pFilter == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
const D3D9Format format =
|
||||
EnumerateFormat(pFilter->Format);
|
||||
|
||||
if (FAILED(CheckDeviceFormat(
|
||||
D3DDEVTYPE_HAL, EnumerateFormat(pFilter->Format),
|
||||
D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE,
|
||||
EnumerateFormat(pFilter->Format))))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
CacheModes(format);
|
||||
|
||||
// We don't return any scanline orderings that aren't progressive,
|
||||
// The format filtering is already handled for us by cache modes
|
||||
// So we can early out here and then just index.
|
||||
if (pFilter->ScanLineOrdering == D3DSCANLINEORDERING_INTERLACED)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (Mode >= m_modes.size())
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*pMode = m_modes[Mode];
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::GetAdapterDisplayModeEx(
|
||||
D3DDISPLAYMODEEX* pMode,
|
||||
D3DDISPLAYROTATION* pRotation) {
|
||||
if (pRotation != nullptr)
|
||||
*pRotation = D3DDISPLAYROTATION_IDENTITY;
|
||||
|
||||
D3DDISPLAYMODEFILTER filter;
|
||||
filter.Size = sizeof(filter);
|
||||
filter.Format = D3DFMT_X8R8G8B8;
|
||||
filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
|
||||
|
||||
return this->EnumAdapterModesEx(&filter, 0, pMode);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::GetAdapterLUID(LUID* pLUID) {
|
||||
if (pLUID == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto& deviceId = m_adapter->devicePropertiesExt().coreDeviceId;
|
||||
|
||||
if (deviceId.deviceLUIDValid)
|
||||
*pLUID = bit::cast<LUID>(deviceId.deviceLUID);
|
||||
else
|
||||
*pLUID = dxvk::GetAdapterLUID(m_ordinal);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Adapter::CheckDeviceVkFormat(
|
||||
VkFormat Format,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType) {
|
||||
VkFormatFeatureFlags checkFlags = 0;
|
||||
|
||||
if (RType != D3DRTYPE_SURFACE)
|
||||
checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
|
||||
if (Usage & D3DUSAGE_RENDERTARGET) {
|
||||
checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
if (Usage & D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING)
|
||||
checkFlags |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
|
||||
}
|
||||
|
||||
if (Usage & D3DUSAGE_DEPTHSTENCIL)
|
||||
checkFlags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
else
|
||||
checkFlags |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
|
||||
VkFormatFeatureFlags checkFlagsMipGen = checkFlags;
|
||||
|
||||
if (Usage & D3DUSAGE_AUTOGENMIPMAP) {
|
||||
checkFlagsMipGen |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
checkFlagsMipGen |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
VkFormatProperties fmtSupport = m_adapter->formatProperties(Format);
|
||||
VkFormatFeatureFlags imgFeatures = fmtSupport.optimalTilingFeatures | fmtSupport.linearTilingFeatures;
|
||||
|
||||
if ((imgFeatures & checkFlags) != checkFlags)
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
|
||||
return ((imgFeatures & checkFlagsMipGen) != checkFlagsMipGen)
|
||||
? D3DOK_NOAUTOGEN
|
||||
: D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D9Adapter::CacheModes(D3D9Format Format) {
|
||||
if (!m_modes.empty() && m_modeCacheFormat == Format)
|
||||
return; // We already cached the modes for this format. No need to do it again.
|
||||
|
||||
::MONITORINFOEXW monInfo;
|
||||
monInfo.cbSize = sizeof(monInfo);
|
||||
|
||||
if (!::GetMonitorInfoW(GetDefaultMonitor(), reinterpret_cast<MONITORINFO*>(&monInfo))) {
|
||||
Logger::err("D3D9Adapter::CacheModes: failed to query monitor info");
|
||||
return;
|
||||
}
|
||||
|
||||
m_modes.clear();
|
||||
m_modeCacheFormat = Format;
|
||||
|
||||
// Skip unsupported formats
|
||||
if (!IsSupportedAdapterFormat(Format) || !IsSupportedDisplayFormat(Format, false))
|
||||
return;
|
||||
|
||||
auto& options = m_parent->GetOptions();
|
||||
|
||||
// Walk over all modes that the display supports and
|
||||
// return those that match the requested format etc.
|
||||
DEVMODEW devMode = { };
|
||||
devMode.dmSize = sizeof(DEVMODEW);
|
||||
|
||||
uint32_t modeIndex = 0;
|
||||
|
||||
const auto forcedRatio = Ratio<DWORD>(options.forceAspectRatio);
|
||||
|
||||
while (::EnumDisplaySettingsW(monInfo.szDevice, modeIndex++, &devMode)) {
|
||||
// Skip interlaced modes altogether
|
||||
if (devMode.dmDisplayFlags & DM_INTERLACED)
|
||||
continue;
|
||||
|
||||
// Skip modes with incompatible formats
|
||||
if (devMode.dmBitsPerPel != GetMonitorFormatBpp(Format))
|
||||
continue;
|
||||
|
||||
if (!forcedRatio.undefined() && Ratio<DWORD>(devMode.dmPelsWidth, devMode.dmPelsHeight) != forcedRatio)
|
||||
continue;
|
||||
|
||||
D3DDISPLAYMODEEX mode;
|
||||
mode.Size = sizeof(D3DDISPLAYMODEEX);
|
||||
mode.Width = devMode.dmPelsWidth;
|
||||
mode.Height = devMode.dmPelsHeight;
|
||||
mode.RefreshRate = devMode.dmDisplayFrequency;
|
||||
mode.Format = static_cast<D3DFORMAT>(Format);
|
||||
mode.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
|
||||
|
||||
m_modes.push_back(mode);
|
||||
}
|
||||
|
||||
// Sort display modes by width, height and refresh rate,
|
||||
// in that order. Some games rely on correct ordering.
|
||||
std::sort(m_modes.begin(), m_modes.end(),
|
||||
[](const D3DDISPLAYMODEEX & a, const D3DDISPLAYMODEEX & b) {
|
||||
if (a.Width < b.Width) return true;
|
||||
if (a.Width > b.Width) return false;
|
||||
|
||||
if (a.Height < b.Height) return true;
|
||||
if (a.Height > b.Height) return false;
|
||||
|
||||
return a.RefreshRate < b.RefreshRate;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
112
src/d3d9/d3d9_adapter.h
Normal file
112
src/d3d9/d3d9_adapter.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
#include "d3d9_options.h"
|
||||
#include "d3d9_format.h"
|
||||
|
||||
#include "../dxvk/dxvk_adapter.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9InterfaceEx;
|
||||
|
||||
class D3D9Adapter {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Adapter(
|
||||
D3D9InterfaceEx* pParent,
|
||||
Rc<DxvkAdapter> Adapter,
|
||||
UINT Ordinal);
|
||||
|
||||
HRESULT GetAdapterIdentifier(
|
||||
DWORD Flags,
|
||||
D3DADAPTER_IDENTIFIER9* pIdentifier);
|
||||
|
||||
HRESULT CheckDeviceType(
|
||||
D3DDEVTYPE DevType,
|
||||
D3D9Format AdapterFormat,
|
||||
D3D9Format BackBufferFormat,
|
||||
BOOL bWindowed);
|
||||
|
||||
HRESULT CheckDeviceFormat(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format AdapterFormat,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType,
|
||||
D3D9Format CheckFormat);
|
||||
|
||||
HRESULT CheckDeviceMultiSampleType(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format SurfaceFormat,
|
||||
BOOL Windowed,
|
||||
D3DMULTISAMPLE_TYPE MultiSampleType,
|
||||
DWORD* pQualityLevels);
|
||||
|
||||
HRESULT CheckDepthStencilMatch(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format AdapterFormat,
|
||||
D3D9Format RenderTargetFormat,
|
||||
D3D9Format DepthStencilFormat);
|
||||
|
||||
HRESULT CheckDeviceFormatConversion(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3D9Format SourceFormat,
|
||||
D3D9Format TargetFormat);
|
||||
|
||||
HRESULT GetDeviceCaps(
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DCAPS9* pCaps);
|
||||
|
||||
HMONITOR GetMonitor();
|
||||
|
||||
UINT GetAdapterModeCountEx(CONST D3DDISPLAYMODEFILTER* pFilter);
|
||||
|
||||
HRESULT EnumAdapterModesEx(
|
||||
const D3DDISPLAYMODEFILTER* pFilter,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODEEX* pMode);
|
||||
|
||||
HRESULT GetAdapterDisplayModeEx(
|
||||
D3DDISPLAYMODEEX* pMode,
|
||||
D3DDISPLAYROTATION* pRotation);
|
||||
|
||||
HRESULT GetAdapterLUID(LUID* pLUID);
|
||||
|
||||
UINT GetOrdinal() { return m_ordinal; }
|
||||
|
||||
Rc<DxvkAdapter> GetDXVKAdapter() { return m_adapter; }
|
||||
|
||||
D3D9_VK_FORMAT_MAPPING GetFormatMapping(
|
||||
D3D9Format Format) const {
|
||||
return m_d3d9Formats.GetFormatMapping(Format);
|
||||
}
|
||||
|
||||
DxvkFormatInfo GetUnsupportedFormatInfo(
|
||||
D3D9Format Format) const {
|
||||
return m_d3d9Formats.GetUnsupportedFormatInfo(Format);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
HRESULT CheckDeviceVkFormat(
|
||||
VkFormat Format,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType);
|
||||
|
||||
void CacheModes(D3D9Format Format);
|
||||
|
||||
D3D9InterfaceEx* m_parent;
|
||||
|
||||
Rc<DxvkAdapter> m_adapter;
|
||||
UINT m_ordinal;
|
||||
|
||||
std::vector<D3DDISPLAYMODEEX> m_modes;
|
||||
D3D9Format m_modeCacheFormat;
|
||||
|
||||
const D3D9VkFormatTable m_d3d9Formats;
|
||||
|
||||
};
|
||||
|
||||
}
|
114
src/d3d9/d3d9_buffer.cpp
Normal file
114
src/d3d9/d3d9_buffer.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
#include "d3d9_buffer.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
////////////////////////
|
||||
// D3D9VertexBuffer
|
||||
////////////////////////
|
||||
|
||||
D3D9VertexBuffer::D3D9VertexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: D3D9VertexBufferBase( pDevice, pDesc ) { }
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VertexBuffer::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DVertexBuffer9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9VertexBuffer::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9VertexBuffer::GetType() {
|
||||
return D3DRTYPE_VERTEXBUFFER;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VertexBuffer::GetDesc(
|
||||
D3DVERTEXBUFFER_DESC* pDesc) {
|
||||
if (pDesc == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3D9_BUFFER_DESC desc;
|
||||
m_buffer.GetDesc(&desc);
|
||||
|
||||
pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
|
||||
pDesc->Type = desc.Type;
|
||||
pDesc->Usage = desc.Usage;
|
||||
pDesc->Pool = desc.Pool;
|
||||
pDesc->Size = desc.Size;
|
||||
pDesc->FVF = desc.FVF;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////
|
||||
// D3D9IndexBuffer
|
||||
//////////////////////
|
||||
|
||||
|
||||
D3D9IndexBuffer::D3D9IndexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: D3D9IndexBufferBase( pDevice, pDesc ) { }
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9IndexBuffer::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DIndexBuffer9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9IndexBuffer::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9IndexBuffer::GetType() {
|
||||
return D3DRTYPE_INDEXBUFFER;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9IndexBuffer::GetDesc(
|
||||
D3DINDEXBUFFER_DESC* pDesc) {
|
||||
if (pDesc == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3D9_BUFFER_DESC desc;
|
||||
m_buffer.GetDesc(&desc);
|
||||
|
||||
pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
|
||||
pDesc->Type = desc.Type;
|
||||
pDesc->Usage = desc.Usage;
|
||||
pDesc->Pool = desc.Pool;
|
||||
pDesc->Size = desc.Size;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
92
src/d3d9/d3d9_buffer.h
Normal file
92
src/d3d9/d3d9_buffer.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_resource.h"
|
||||
|
||||
#include "d3d9_common_buffer.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename... Type>
|
||||
class D3D9Buffer : public D3D9Resource<Type...> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Buffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: D3D9Resource<Type...> ( pDevice )
|
||||
, m_buffer ( pDevice, pDesc ) { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Lock(
|
||||
UINT OffsetToLock,
|
||||
UINT SizeToLock,
|
||||
void** ppbData,
|
||||
DWORD Flags) final {
|
||||
return m_buffer.Lock(
|
||||
OffsetToLock,
|
||||
SizeToLock,
|
||||
ppbData,
|
||||
Flags);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Unlock() final {
|
||||
return m_buffer.Unlock();
|
||||
}
|
||||
|
||||
D3D9CommonBuffer* GetCommonBuffer() {
|
||||
return &m_buffer;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
D3D9CommonBuffer m_buffer;
|
||||
|
||||
};
|
||||
|
||||
|
||||
using D3D9VertexBufferBase = D3D9Buffer<IDirect3DVertexBuffer9>;
|
||||
class D3D9VertexBuffer final : public D3D9VertexBufferBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9VertexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) final;
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(
|
||||
D3DVERTEXBUFFER_DESC* pDesc) final;
|
||||
|
||||
};
|
||||
|
||||
using D3D9IndexBufferBase = D3D9Buffer<IDirect3DIndexBuffer9>;
|
||||
class D3D9IndexBuffer final : public D3D9IndexBufferBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9IndexBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) final;
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(
|
||||
D3DINDEXBUFFER_DESC* pDesc) final;
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline D3D9CommonBuffer* GetCommonBuffer(const T& pResource) {
|
||||
return pResource != nullptr ? pResource->GetCommonBuffer() : nullptr;
|
||||
}
|
||||
|
||||
}
|
32
src/d3d9/d3d9_caps.h
Normal file
32
src/d3d9/d3d9_caps.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk::caps {
|
||||
|
||||
constexpr uint32_t MaxClipPlanes = 6;
|
||||
constexpr uint32_t MaxSamplers = 16;
|
||||
constexpr uint32_t MaxStreams = 16;
|
||||
constexpr uint32_t MaxSimultaneousTextures = 8;
|
||||
constexpr uint32_t MaxTextureBlendStages = MaxSimultaneousTextures;
|
||||
constexpr uint32_t MaxSimultaneousRenderTargets = D3D_MAX_SIMULTANEOUS_RENDERTARGETS;
|
||||
|
||||
constexpr uint32_t MaxFloatConstantsVS = 256;
|
||||
constexpr uint32_t MaxFloatConstantsPS = 224;
|
||||
constexpr uint32_t MaxOtherConstants = 16;
|
||||
constexpr uint32_t MaxFloatConstantsSoftware = 8192;
|
||||
constexpr uint32_t MaxOtherConstantsSoftware = 2048;
|
||||
|
||||
constexpr uint32_t InputRegisterCount = 16;
|
||||
|
||||
constexpr uint32_t MaxTextureDimension = 16384;
|
||||
constexpr uint32_t MaxMipLevels = 15;
|
||||
constexpr uint32_t MaxSubresources = 15 * 6;
|
||||
|
||||
constexpr uint32_t MaxTransforms = 10 + 256;
|
||||
|
||||
constexpr uint32_t TextureStageCount = MaxSimultaneousTextures;
|
||||
|
||||
constexpr uint32_t MaxEnabledLights = 8;
|
||||
|
||||
}
|
124
src/d3d9/d3d9_common_buffer.cpp
Normal file
124
src/d3d9/d3d9_common_buffer.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
#include "d3d9_common_buffer.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9CommonBuffer::D3D9CommonBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc)
|
||||
: m_parent ( pDevice ), m_desc ( *pDesc ) {
|
||||
m_buffer = CreateBuffer();
|
||||
if (GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
|
||||
m_stagingBuffer = CreateStagingBuffer();
|
||||
|
||||
m_sliceHandle = GetMapBuffer()->getSliceHandle();
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9CommonBuffer::Lock(
|
||||
UINT OffsetToLock,
|
||||
UINT SizeToLock,
|
||||
void** ppbData,
|
||||
DWORD Flags) {
|
||||
return m_parent->LockBuffer(
|
||||
this,
|
||||
OffsetToLock,
|
||||
SizeToLock,
|
||||
ppbData,
|
||||
Flags);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9CommonBuffer::Unlock() {
|
||||
return m_parent->UnlockBuffer(this);
|
||||
}
|
||||
|
||||
|
||||
void D3D9CommonBuffer::GetDesc(
|
||||
D3D9_BUFFER_DESC* pDesc) {
|
||||
*pDesc = m_desc;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9CommonBuffer::ValidateBufferProperties(const D3D9_BUFFER_DESC* pDesc) {
|
||||
if (pDesc->Size == 0)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkBuffer> D3D9CommonBuffer::CreateBuffer() const {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = m_desc.Size;
|
||||
info.usage = 0;
|
||||
info.stages = 0;
|
||||
info.access = 0;
|
||||
|
||||
VkMemoryPropertyFlags memoryFlags = 0;
|
||||
|
||||
if (m_desc.Type == D3DRTYPE_VERTEXBUFFER) {
|
||||
info.usage |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
info.access |= VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT;
|
||||
|
||||
if (m_parent->SupportsSWVP()) {
|
||||
info.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
info.stages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
|
||||
info.access |= VK_ACCESS_SHADER_WRITE_BIT;
|
||||
}
|
||||
}
|
||||
else if (m_desc.Type == D3DRTYPE_INDEXBUFFER) {
|
||||
info.usage |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||
info.stages |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
info.access |= VK_ACCESS_INDEX_READ_BIT;
|
||||
}
|
||||
|
||||
if (GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_DIRECT) {
|
||||
info.stages |= VK_PIPELINE_STAGE_HOST_BIT;
|
||||
info.access |= VK_ACCESS_HOST_WRITE_BIT;
|
||||
|
||||
if (!(m_desc.Usage & D3DUSAGE_WRITEONLY))
|
||||
info.access |= VK_ACCESS_HOST_READ_BIT;
|
||||
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
}
|
||||
else {
|
||||
info.stages |= VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
info.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
||||
info.access |= VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
memoryFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
||||
}
|
||||
|
||||
return m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkBuffer> D3D9CommonBuffer::CreateStagingBuffer() const {
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = m_desc.Size;
|
||||
info.stages = VK_PIPELINE_STAGE_HOST_BIT
|
||||
| VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
|
||||
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
||||
|
||||
info.access = VK_ACCESS_HOST_WRITE_BIT
|
||||
| VK_ACCESS_TRANSFER_READ_BIT;
|
||||
|
||||
if (!(m_desc.Usage & D3DUSAGE_WRITEONLY))
|
||||
info.access |= VK_ACCESS_HOST_READ_BIT;
|
||||
|
||||
VkMemoryPropertyFlags memoryFlags =
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
|
||||
return m_parent->GetDXVKDevice()->createBuffer(info, memoryFlags);
|
||||
}
|
||||
|
||||
}
|
202
src/d3d9/d3d9_common_buffer.h
Normal file
202
src/d3d9/d3d9_common_buffer.h
Normal file
|
@ -0,0 +1,202 @@
|
|||
#pragma once
|
||||
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
|
||||
#include "d3d9_device_child.h"
|
||||
#include "d3d9_format.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Buffer map mode
|
||||
*/
|
||||
enum D3D9_COMMON_BUFFER_MAP_MODE {
|
||||
D3D9_COMMON_BUFFER_MAP_MODE_BUFFER,
|
||||
D3D9_COMMON_BUFFER_MAP_MODE_DIRECT
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Common buffer descriptor
|
||||
*/
|
||||
struct D3D9_BUFFER_DESC {
|
||||
D3DRESOURCETYPE Type;
|
||||
UINT Size;
|
||||
DWORD Usage;
|
||||
D3D9Format Format;
|
||||
D3DPOOL Pool;
|
||||
DWORD FVF;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief The type of buffer you want to use
|
||||
*/
|
||||
enum D3D9_COMMON_BUFFER_TYPE {
|
||||
D3D9_COMMON_BUFFER_TYPE_MAPPING,
|
||||
D3D9_COMMON_BUFFER_TYPE_STAGING,
|
||||
D3D9_COMMON_BUFFER_TYPE_REAL
|
||||
};
|
||||
|
||||
struct D3D9Range {
|
||||
D3D9Range() { Clear(); }
|
||||
|
||||
D3D9Range(uint32_t min, uint32_t max)
|
||||
: min(min), max(max) { }
|
||||
|
||||
bool IsDegenerate() { return min == max; }
|
||||
|
||||
void Conjoin(D3D9Range range) {
|
||||
if (IsDegenerate())
|
||||
*this = range;
|
||||
else {
|
||||
min = std::min(range.min, min);
|
||||
max = std::max(range.max, max);
|
||||
}
|
||||
}
|
||||
|
||||
bool Overlaps(D3D9Range range) {
|
||||
if (IsDegenerate())
|
||||
return false;
|
||||
|
||||
return range.max > min && range.min < max;
|
||||
}
|
||||
|
||||
void Clear() { min = 0; max = 0; }
|
||||
|
||||
uint32_t min = 0;
|
||||
uint32_t max = 0;
|
||||
};
|
||||
|
||||
class D3D9CommonBuffer {
|
||||
static constexpr VkDeviceSize BufferSliceAlignment = 64;
|
||||
public:
|
||||
|
||||
D3D9CommonBuffer(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_BUFFER_DESC* pDesc);
|
||||
|
||||
HRESULT Lock(
|
||||
UINT OffsetToLock,
|
||||
UINT SizeToLock,
|
||||
void** ppbData,
|
||||
DWORD Flags);
|
||||
|
||||
HRESULT Unlock();
|
||||
|
||||
void GetDesc(
|
||||
D3D9_BUFFER_DESC* pDesc);
|
||||
|
||||
D3D9_COMMON_BUFFER_MAP_MODE GetMapMode() const {
|
||||
return (m_desc.Pool == D3DPOOL_DEFAULT && (m_desc.Usage & (D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)))
|
||||
? D3D9_COMMON_BUFFER_MAP_MODE_DIRECT
|
||||
: D3D9_COMMON_BUFFER_MAP_MODE_BUFFER;
|
||||
}
|
||||
|
||||
template <D3D9_COMMON_BUFFER_TYPE Type>
|
||||
Rc<DxvkBuffer> GetBuffer() const {
|
||||
if constexpr (Type == D3D9_COMMON_BUFFER_TYPE_MAPPING)
|
||||
return GetMapBuffer();
|
||||
else if constexpr (Type == D3D9_COMMON_BUFFER_TYPE_STAGING)
|
||||
return GetStagingBuffer();
|
||||
else //if constexpr (Type == D3D9_COMMON_BUFFER_TYPE_REAL)
|
||||
return GetRealBuffer();
|
||||
}
|
||||
|
||||
template <D3D9_COMMON_BUFFER_TYPE Type>
|
||||
DxvkBufferSlice GetBufferSlice() const {
|
||||
return GetBufferSlice<Type>(0, m_desc.Size);
|
||||
}
|
||||
|
||||
template <D3D9_COMMON_BUFFER_TYPE Type>
|
||||
DxvkBufferSlice GetBufferSlice(VkDeviceSize offset) const {
|
||||
return GetBufferSlice<Type>(offset, m_desc.Size - offset);
|
||||
}
|
||||
|
||||
template <D3D9_COMMON_BUFFER_TYPE Type>
|
||||
DxvkBufferSlice GetBufferSlice(VkDeviceSize offset, VkDeviceSize length) const {
|
||||
return DxvkBufferSlice(GetBuffer<Type>(), offset, length);
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle AllocMapSlice() {
|
||||
return GetMapBuffer()->allocSlice();
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle DiscardMapSlice() {
|
||||
m_sliceHandle = GetMapBuffer()->allocSlice();
|
||||
return m_sliceHandle;
|
||||
}
|
||||
|
||||
DxvkBufferSliceHandle GetMappedSlice() const {
|
||||
return m_sliceHandle;
|
||||
}
|
||||
|
||||
DWORD GetMapFlags() const { return m_mapFlags; }
|
||||
|
||||
void SetMapFlags(DWORD Flags) { m_mapFlags = Flags; }
|
||||
|
||||
const D3D9_BUFFER_DESC* Desc() const {
|
||||
return &m_desc;
|
||||
}
|
||||
|
||||
static HRESULT ValidateBufferProperties(const D3D9_BUFFER_DESC* pDesc);
|
||||
|
||||
D3D9Range& LockRange() { return m_lockRange; }
|
||||
D3D9Range& DirtyRange() { return m_dirtyRange; }
|
||||
|
||||
bool GetReadLocked() const { return m_readLocked; }
|
||||
void SetReadLocked(bool state) { m_readLocked = state; }
|
||||
|
||||
uint32_t IncrementLockCount() { return ++m_lockCount; }
|
||||
uint32_t DecrementLockCount() {
|
||||
if (m_lockCount == 0)
|
||||
return 0;
|
||||
|
||||
return --m_lockCount;
|
||||
}
|
||||
|
||||
void MarkUploaded() { m_needsUpload = false; }
|
||||
void MarkNeedsUpload() { m_needsUpload = true; }
|
||||
bool NeedsUpload() const { return m_needsUpload; }
|
||||
|
||||
bool MarkLocked() {
|
||||
bool locked = m_readLocked;
|
||||
m_readLocked = true;
|
||||
return locked;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkBuffer> CreateBuffer() const;
|
||||
Rc<DxvkBuffer> CreateStagingBuffer() const;
|
||||
|
||||
Rc<DxvkBuffer> GetMapBuffer() const {
|
||||
return m_stagingBuffer != nullptr ? m_stagingBuffer : m_buffer;
|
||||
}
|
||||
|
||||
Rc<DxvkBuffer> GetStagingBuffer() const {
|
||||
return m_stagingBuffer;
|
||||
}
|
||||
|
||||
Rc<DxvkBuffer> GetRealBuffer() const {
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
D3D9DeviceEx* m_parent;
|
||||
const D3D9_BUFFER_DESC m_desc;
|
||||
DWORD m_mapFlags;
|
||||
bool m_readLocked = false;
|
||||
|
||||
Rc<DxvkBuffer> m_buffer;
|
||||
Rc<DxvkBuffer> m_stagingBuffer;
|
||||
|
||||
DxvkBufferSliceHandle m_sliceHandle;
|
||||
|
||||
D3D9Range m_lockRange;
|
||||
D3D9Range m_dirtyRange;
|
||||
|
||||
uint32_t m_lockCount = 0;
|
||||
|
||||
bool m_needsUpload = false;
|
||||
|
||||
};
|
||||
|
||||
}
|
508
src/d3d9/d3d9_common_texture.cpp
Normal file
508
src/d3d9/d3d9_common_texture.cpp
Normal file
|
@ -0,0 +1,508 @@
|
|||
#include "d3d9_common_texture.h"
|
||||
|
||||
#include "d3d9_util.h"
|
||||
#include "d3d9_device.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9CommonTexture::D3D9CommonTexture(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: m_device(pDevice), m_desc(*pDesc), m_type(ResourceType), m_mapping(Mapping) {
|
||||
if (m_desc.Format == D3D9Format::Unknown)
|
||||
m_desc.Format = (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL)
|
||||
? D3D9Format::D32
|
||||
: D3D9Format::X8R8G8B8;
|
||||
|
||||
auto pxSize = m_mapping.VideoFormatInfo.MacroPixelSize;
|
||||
m_adjustedExtent = VkExtent3D{ m_desc.Width / pxSize.width, m_desc.Height / pxSize.height, m_desc.Depth };
|
||||
|
||||
m_mapMode = DetermineMapMode();
|
||||
m_shadow = DetermineShadowState();
|
||||
|
||||
if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED) {
|
||||
try {
|
||||
m_image = CreatePrimaryImage(ResourceType);
|
||||
}
|
||||
catch (const DxvkError& e) {
|
||||
if (m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP) {
|
||||
m_desc.Usage &= ~D3DUSAGE_AUTOGENMIPMAP;
|
||||
m_desc.MipLevels = 1;
|
||||
m_image = CreatePrimaryImage(ResourceType);
|
||||
}
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
|
||||
CreateInitialViews();
|
||||
|
||||
if (!IsManaged()) {
|
||||
m_size = m_image->memSize();
|
||||
if (!m_device->ChangeReportedMemory(-m_size))
|
||||
throw DxvkError("D3D9: Reporting out of memory from tracking.");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM)
|
||||
CreateBuffers();
|
||||
}
|
||||
|
||||
|
||||
D3D9CommonTexture::~D3D9CommonTexture() {
|
||||
if (m_size != 0)
|
||||
m_device->ChangeReportedMemory(m_size);
|
||||
}
|
||||
|
||||
|
||||
VkImageSubresource D3D9CommonTexture::GetSubresourceFromIndex(
|
||||
VkImageAspectFlags Aspect,
|
||||
UINT Subresource) const {
|
||||
VkImageSubresource result;
|
||||
result.aspectMask = Aspect;
|
||||
result.mipLevel = Subresource % m_desc.MipLevels;
|
||||
result.arrayLayer = Subresource / m_desc.MipLevels;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9CommonTexture::NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING* pMapping) {
|
||||
auto* options = pDevice->GetOptions();
|
||||
|
||||
//////////////////////
|
||||
// Mapping Validation
|
||||
|
||||
*pMapping = pDevice->LookupFormat(pDesc->Format);
|
||||
|
||||
// Handle DisableA8RT hack for The Sims 2
|
||||
if (pDesc->Format == D3D9Format::A8 &&
|
||||
(pDesc->Usage & D3DUSAGE_RENDERTARGET) &&
|
||||
options->disableA8RT)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// If the mapping is invalid then lets return invalid
|
||||
// Some edge cases:
|
||||
// NULL format does not map to anything, but should succeed
|
||||
// SCRATCH textures can still be made if the device does not support
|
||||
// the format at all.
|
||||
|
||||
if (!pMapping->IsValid() && pDesc->Format != D3D9Format::NULL_FORMAT) {
|
||||
auto info = pDevice->UnsupportedFormatInfo(pDesc->Format);
|
||||
|
||||
if (pDesc->Pool != D3DPOOL_SCRATCH || info.elementSize == 0)
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// Desc Validation
|
||||
|
||||
if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (FAILED(DecodeMultiSampleType(pDesc->MultiSample, pDesc->MultisampleQuality, nullptr)))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Using MANAGED pool with DYNAMIC usage is illegal
|
||||
if (IsPoolManaged(pDesc->Pool) && (pDesc->Usage & D3DUSAGE_DYNAMIC))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// D3DUSAGE_WRITEONLY doesn't apply to textures.
|
||||
if (pDesc->Usage & D3DUSAGE_WRITEONLY)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// RENDERTARGET and DEPTHSTENCIL must be default pool
|
||||
constexpr DWORD incompatibleUsages = D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL;
|
||||
if (pDesc->Pool != D3DPOOL_DEFAULT && (pDesc->Usage & incompatibleUsages))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// Use the maximum possible mip level count if the supplied
|
||||
// mip level count is either unspecified (0) or invalid
|
||||
const uint32_t maxMipLevelCount =
|
||||
(pDesc->MultiSample <= D3DMULTISAMPLE_NONMASKABLE && !(pDesc->Usage & D3DUSAGE_AUTOGENMIPMAP))
|
||||
? util::computeMipLevelCount({ pDesc->Width, pDesc->Height, pDesc->Depth })
|
||||
: 1u;
|
||||
|
||||
if (pDesc->MipLevels == 0 || pDesc->MipLevels > maxMipLevelCount)
|
||||
pDesc->MipLevels = maxMipLevelCount;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
bool D3D9CommonTexture::CreateBufferSubresource(UINT Subresource) {
|
||||
if (m_buffers[Subresource] != nullptr)
|
||||
return false;
|
||||
|
||||
DxvkBufferCreateInfo info;
|
||||
info.size = GetMipSize(Subresource);
|
||||
info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||
info.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
info.access = VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
if (m_mapping.VideoFormatInfo.FormatType != D3D9VideoFormat_None) {
|
||||
info.usage |= VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
|
||||
info.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
}
|
||||
|
||||
VkMemoryPropertyFlags memType = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
|
||||
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
|
||||
if (m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM || IsManaged())
|
||||
memType |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||
|
||||
m_buffers[Subresource] = m_device->GetDXVKDevice()->createBuffer(info, memType);
|
||||
m_mappedSlices[Subresource] = m_buffers[Subresource]->getSliceHandle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
VkDeviceSize D3D9CommonTexture::GetMipSize(UINT Subresource) const {
|
||||
const UINT MipLevel = Subresource % m_desc.MipLevels;
|
||||
|
||||
const DxvkFormatInfo formatInfo = m_mapping.FormatColor != VK_FORMAT_UNDEFINED
|
||||
? *imageFormatInfo(m_mapping.FormatColor)
|
||||
: m_device->UnsupportedFormatInfo(m_desc.Format);
|
||||
|
||||
const VkExtent3D mipExtent = util::computeMipLevelExtent(
|
||||
m_adjustedExtent, MipLevel);
|
||||
|
||||
const VkExtent3D blockCount = util::computeBlockCount(
|
||||
mipExtent, formatInfo.blockSize);
|
||||
|
||||
return formatInfo.elementSize
|
||||
* blockCount.width
|
||||
* blockCount.height
|
||||
* blockCount.depth;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImage> D3D9CommonTexture::CreatePrimaryImage(D3DRESOURCETYPE ResourceType) const {
|
||||
DxvkImageCreateInfo imageInfo;
|
||||
imageInfo.type = GetImageTypeFromResourceType(ResourceType);
|
||||
imageInfo.format = m_mapping.FormatColor;
|
||||
imageInfo.flags = 0;
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.extent.width = m_desc.Width;
|
||||
imageInfo.extent.height = m_desc.Height;
|
||||
imageInfo.extent.depth = m_desc.Depth;
|
||||
imageInfo.numLayers = m_desc.ArraySize;
|
||||
imageInfo.mipLevels = m_desc.MipLevels;
|
||||
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| m_device->GetEnabledShaderStages();
|
||||
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT
|
||||
| VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
imageInfo.layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
|
||||
if (m_mapping.VideoFormatInfo.FormatType != D3D9VideoFormat_None) {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
}
|
||||
|
||||
DecodeMultiSampleType(m_desc.MultiSample, m_desc.MultisampleQuality, &imageInfo.sampleCount);
|
||||
|
||||
// The image must be marked as mutable if it can be reinterpreted
|
||||
// by a view with a different format. Depth-stencil formats cannot
|
||||
// be reinterpreted in Vulkan, so we'll ignore those.
|
||||
auto formatProperties = imageFormatInfo(m_mapping.FormatColor);
|
||||
|
||||
bool isMutable = m_mapping.FormatSrgb != VK_FORMAT_UNDEFINED;
|
||||
bool isColorFormat = (formatProperties->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
|
||||
|
||||
if (isMutable && isColorFormat) {
|
||||
imageInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
|
||||
|
||||
imageInfo.viewFormatCount = 2;
|
||||
imageInfo.viewFormats = m_mapping.Formats;
|
||||
}
|
||||
|
||||
if (m_desc.Usage & D3DUSAGE_RENDERTARGET || m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP) {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
|
||||
if (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) {
|
||||
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
|
||||
if (ResourceType == D3DRTYPE_CUBETEXTURE)
|
||||
imageInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||
|
||||
// Some image formats (i.e. the R32G32B32 ones) are
|
||||
// only supported with linear tiling on most GPUs
|
||||
if (!CheckImageSupport(&imageInfo, VK_IMAGE_TILING_OPTIMAL))
|
||||
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
|
||||
|
||||
// We must keep LINEAR images in GENERAL layout, but we
|
||||
// can choose a better layout for the image based on how
|
||||
// it is going to be used by the game.
|
||||
if (imageInfo.tiling == VK_IMAGE_TILING_OPTIMAL)
|
||||
imageInfo.layout = OptimizeLayout(imageInfo.usage);
|
||||
|
||||
// For some formats, we need to enable render target
|
||||
// capabilities if available, but these should
|
||||
// in no way affect the default image layout
|
||||
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
|
||||
|
||||
// Check if we can actually create the image
|
||||
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
|
||||
throw DxvkError(str::format(
|
||||
"D3D9: Cannot create texture:",
|
||||
"\n Type: ", std::hex, ResourceType,
|
||||
"\n Format: ", m_desc.Format,
|
||||
"\n Extent: ", m_desc.Width,
|
||||
"x", m_desc.Height,
|
||||
"x", m_desc.Depth,
|
||||
"\n Samples: ", m_desc.MultiSample,
|
||||
"\n Layers: ", m_desc.ArraySize,
|
||||
"\n Levels: ", m_desc.MipLevels,
|
||||
"\n Usage: ", std::hex, m_desc.Usage,
|
||||
"\n Pool: ", std::hex, m_desc.Pool));
|
||||
}
|
||||
|
||||
return m_device->GetDXVKDevice()->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImage> D3D9CommonTexture::CreateResolveImage() const {
|
||||
DxvkImageCreateInfo imageInfo = m_image->info();
|
||||
imageInfo.sampleCount = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
return m_device->GetDXVKDevice()->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
}
|
||||
|
||||
|
||||
void D3D9CommonTexture::RecreateSampledView(UINT Lod) {
|
||||
// This will be a no-op for SYSTEMMEM types given we
|
||||
// don't expose the cap to allow texturing with them.
|
||||
if (unlikely(m_mapMode == D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM))
|
||||
return;
|
||||
|
||||
const D3D9_VK_FORMAT_MAPPING formatInfo = m_device->LookupFormat(m_desc.Format);
|
||||
|
||||
m_views.Sample = CreateColorViewPair(formatInfo, AllLayers, VK_IMAGE_USAGE_SAMPLED_BIT, Lod);
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D9CommonTexture::DetermineShadowState() const {
|
||||
static std::array<D3D9Format, 3> blacklist = {
|
||||
D3D9Format::INTZ, D3D9Format::DF16, D3D9Format::DF24
|
||||
};
|
||||
|
||||
return IsDepthFormat(m_desc.Format)
|
||||
&& std::find(blacklist.begin(), blacklist.end(), m_desc.Format) == blacklist.end();
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D9CommonTexture::CheckImageSupport(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
VkImageTiling Tiling) const {
|
||||
const Rc<DxvkAdapter> adapter = m_device->GetDXVKDevice()->adapter();
|
||||
|
||||
VkImageFormatProperties formatProps = { };
|
||||
|
||||
VkResult status = adapter->imageFormatProperties(
|
||||
pImageInfo->format, pImageInfo->type, Tiling,
|
||||
pImageInfo->usage, pImageInfo->flags, formatProps);
|
||||
|
||||
if (status != VK_SUCCESS)
|
||||
return FALSE;
|
||||
|
||||
return (pImageInfo->extent.width <= formatProps.maxExtent.width)
|
||||
&& (pImageInfo->extent.height <= formatProps.maxExtent.height)
|
||||
&& (pImageInfo->extent.depth <= formatProps.maxExtent.depth)
|
||||
&& (pImageInfo->numLayers <= formatProps.maxArrayLayers)
|
||||
&& (pImageInfo->mipLevels <= formatProps.maxMipLevels)
|
||||
&& (pImageInfo->sampleCount & formatProps.sampleCounts);
|
||||
}
|
||||
|
||||
|
||||
VkImageUsageFlags D3D9CommonTexture::EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling) const {
|
||||
VkFormatFeatureFlags requestedFeatures = 0;
|
||||
|
||||
if (Format == VK_FORMAT_D16_UNORM || Format == VK_FORMAT_D32_SFLOAT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (Format == VK_FORMAT_R16_UNORM || Format == VK_FORMAT_R32_SFLOAT)
|
||||
requestedFeatures |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
if (requestedFeatures == 0)
|
||||
return 0;
|
||||
|
||||
// Enable usage flags for all supported and requested features
|
||||
VkFormatProperties properties = m_device->GetDXVKDevice()->adapter()->formatProperties(Format);
|
||||
|
||||
requestedFeatures &= Tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? properties.optimalTilingFeatures
|
||||
: properties.linearTilingFeatures;
|
||||
|
||||
VkImageUsageFlags requestedUsage = 0;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (requestedFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)
|
||||
requestedUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return requestedUsage;
|
||||
}
|
||||
|
||||
|
||||
VkImageType D3D9CommonTexture::GetImageTypeFromResourceType(D3DRESOURCETYPE Type) {
|
||||
switch (Type) {
|
||||
case D3DRTYPE_TEXTURE: return VK_IMAGE_TYPE_2D;
|
||||
case D3DRTYPE_VOLUMETEXTURE: return VK_IMAGE_TYPE_3D;
|
||||
case D3DRTYPE_CUBETEXTURE: return VK_IMAGE_TYPE_2D;
|
||||
default: throw DxvkError("D3D9CommonTexture: Unhandled resource type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkImageViewType D3D9CommonTexture::GetImageViewTypeFromResourceType(
|
||||
D3DRESOURCETYPE Dimension,
|
||||
UINT Layer) {
|
||||
switch (Dimension) {
|
||||
case D3DRTYPE_TEXTURE: return VK_IMAGE_VIEW_TYPE_2D;
|
||||
case D3DRTYPE_VOLUMETEXTURE: return VK_IMAGE_VIEW_TYPE_3D;
|
||||
case D3DRTYPE_CUBETEXTURE: return Layer == AllLayers
|
||||
? VK_IMAGE_VIEW_TYPE_CUBE
|
||||
: VK_IMAGE_VIEW_TYPE_2D;
|
||||
default: throw DxvkError("D3D9CommonTexture: Unhandled resource type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkImageLayout D3D9CommonTexture::OptimizeLayout(VkImageUsageFlags Usage) {
|
||||
const VkImageUsageFlags usageFlags = Usage;
|
||||
|
||||
// Filter out unnecessary flags. Transfer operations
|
||||
// are handled by the backend in a transparent manner.
|
||||
Usage &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||
|
||||
// If the image is used only as an attachment, we never
|
||||
// have to transform the image back to a different layout
|
||||
if (Usage == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
|
||||
return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
if (Usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
Usage &= ~(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
|
||||
| VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
|
||||
// If the image is used for reading but not as a storage
|
||||
// image, we can optimize the image for texture access
|
||||
if (Usage == VK_IMAGE_USAGE_SAMPLED_BIT) {
|
||||
return usageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
||||
// Otherwise, we have to stick with the default layout
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkImageView> D3D9CommonTexture::CreateView(
|
||||
D3D9_VK_FORMAT_MAPPING FormatInfo,
|
||||
UINT Layer,
|
||||
VkImageUsageFlags UsageFlags,
|
||||
UINT Lod,
|
||||
BOOL Srgb) {
|
||||
DxvkImageViewCreateInfo viewInfo;
|
||||
viewInfo.format = PickSRGB(FormatInfo.FormatColor, FormatInfo.FormatSrgb, Srgb);
|
||||
viewInfo.aspect = imageFormatInfo(viewInfo.format)->aspectMask;
|
||||
viewInfo.swizzle = FormatInfo.Swizzle;
|
||||
viewInfo.usage = UsageFlags;
|
||||
viewInfo.type = GetImageViewTypeFromResourceType(m_type, Layer);
|
||||
viewInfo.minLevel = Lod;
|
||||
viewInfo.numLevels = m_desc.MipLevels - Lod;
|
||||
viewInfo.minLayer = Layer == AllLayers ? 0 : Layer;
|
||||
viewInfo.numLayers = Layer == AllLayers ? m_desc.ArraySize : 1;
|
||||
|
||||
// Remove the stencil aspect if we are trying to create a regular image
|
||||
// view of a depth stencil format
|
||||
if (UsageFlags != VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
viewInfo.aspect &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
|
||||
if (UsageFlags == VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ||
|
||||
UsageFlags == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
viewInfo.numLevels = 1;
|
||||
|
||||
// Remove swizzle on depth views.
|
||||
if (UsageFlags == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
|
||||
viewInfo.swizzle = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
|
||||
|
||||
// Create the underlying image view object
|
||||
return m_device->GetDXVKDevice()->createImageView(GetImage(), viewInfo);
|
||||
}
|
||||
|
||||
|
||||
D3D9ColorView D3D9CommonTexture::CreateColorViewPair(
|
||||
D3D9_VK_FORMAT_MAPPING FormatInfo,
|
||||
UINT Layer,
|
||||
VkImageUsageFlags UsageFlags,
|
||||
UINT Lod) {
|
||||
D3D9ColorView pair;
|
||||
pair.Color = CreateView(FormatInfo, Layer, UsageFlags, Lod, FALSE);
|
||||
|
||||
if (FormatInfo.FormatSrgb != VK_FORMAT_UNDEFINED)
|
||||
pair.Srgb = CreateView(FormatInfo, Layer, UsageFlags, Lod, TRUE);
|
||||
else
|
||||
pair.Srgb = pair.Color;
|
||||
|
||||
return pair;
|
||||
}
|
||||
|
||||
|
||||
void D3D9CommonTexture::CreateInitialViews() {
|
||||
const D3D9_VK_FORMAT_MAPPING formatInfo = m_device->LookupFormat(m_desc.Format);
|
||||
|
||||
m_views.Sample = CreateColorViewPair(formatInfo, AllLayers, VK_IMAGE_USAGE_SAMPLED_BIT, 0);
|
||||
|
||||
for (uint32_t i = 0; i < m_desc.ArraySize; i++) {
|
||||
for (uint32_t j = 0; j < m_desc.MipLevels; j++)
|
||||
m_views.SubresourceSample[i][j] = CreateColorViewPair(formatInfo, i, VK_IMAGE_USAGE_SAMPLED_BIT, j);
|
||||
}
|
||||
|
||||
if (m_desc.Usage & D3DUSAGE_RENDERTARGET) {
|
||||
for (uint32_t i = 0; i < m_desc.ArraySize; i++) {
|
||||
for (uint32_t j = 0; j < m_desc.MipLevels; j++)
|
||||
m_views.SubresourceRenderTarget[i][j] = CreateColorViewPair(formatInfo, i, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, j);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) {
|
||||
for (uint32_t i = 0; i < m_desc.ArraySize; i++) {
|
||||
for (uint32_t j = 0; j < m_desc.MipLevels; j++)
|
||||
m_views.SubresourceDepth[i][j] = CreateView(formatInfo, i, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, j, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
431
src/d3d9/d3d9_common_texture.h
Normal file
431
src/d3d9/d3d9_common_texture.h
Normal file
|
@ -0,0 +1,431 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_format.h"
|
||||
#include "d3d9_util.h"
|
||||
#include "d3d9_caps.h"
|
||||
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
|
||||
/**
|
||||
* \brief Image memory mapping mode
|
||||
*
|
||||
* Determines how exactly \c LockBox will
|
||||
* behave when mapping an image.
|
||||
*/
|
||||
enum D3D9_COMMON_TEXTURE_MAP_MODE {
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE_NONE, ///< No mapping available
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE_BACKED, ///< Mapped image through buffer
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM, ///< Only a buffer - no image
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Common texture description
|
||||
*
|
||||
* Contains all members that can be
|
||||
* defined for 2D, Cube and 3D textures.
|
||||
*/
|
||||
struct D3D9_COMMON_TEXTURE_DESC {
|
||||
UINT Width;
|
||||
UINT Height;
|
||||
UINT Depth;
|
||||
UINT ArraySize;
|
||||
UINT MipLevels;
|
||||
DWORD Usage;
|
||||
D3D9Format Format;
|
||||
D3DPOOL Pool;
|
||||
BOOL Discard;
|
||||
D3DMULTISAMPLE_TYPE MultiSample;
|
||||
DWORD MultisampleQuality;
|
||||
};
|
||||
|
||||
struct D3D9ColorView {
|
||||
inline Rc<DxvkImageView> Pick(bool Srgb) const {
|
||||
return Srgb ? this->Srgb : this->Color;
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> Color;
|
||||
Rc<DxvkImageView> Srgb;
|
||||
};
|
||||
|
||||
struct D3D9ViewSet {
|
||||
D3D9ColorView Sample;
|
||||
|
||||
std::array<
|
||||
std::array<D3D9ColorView, 15>, 6> SubresourceSample;
|
||||
std::array<
|
||||
std::array<D3D9ColorView, 15>, 6> SubresourceRenderTarget;
|
||||
std::array<
|
||||
std::array<Rc<DxvkImageView>, 15>, 6> SubresourceDepth;
|
||||
|
||||
bool Hazardous = false;
|
||||
|
||||
VkImageLayout GetRTLayout() const {
|
||||
return SubresourceRenderTarget[0][0].Color != nullptr
|
||||
&& SubresourceRenderTarget[0][0].Color->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
&& !Hazardous
|
||||
? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
|
||||
VkImageLayout GetDepthLayout() const {
|
||||
return SubresourceDepth[0][0] != nullptr
|
||||
&& SubresourceDepth[0][0]->imageInfo().tiling == VK_IMAGE_TILING_OPTIMAL
|
||||
? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
|
||||
: VK_IMAGE_LAYOUT_GENERAL;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using D3D9SubresourceArray = std::array<T, caps::MaxSubresources>;
|
||||
|
||||
class D3D9CommonTexture {
|
||||
|
||||
public:
|
||||
|
||||
D3D9CommonTexture(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping);
|
||||
|
||||
~D3D9CommonTexture();
|
||||
|
||||
/**
|
||||
* \brief Device
|
||||
* \returns The parent device
|
||||
*/
|
||||
D3D9DeviceEx* Device() const {
|
||||
return m_device;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Texture properties
|
||||
*
|
||||
* The returned data can be used to fill in
|
||||
* \c D3D11_TEXTURE2D_DESC and similar structs.
|
||||
* \returns Pointer to texture description
|
||||
*/
|
||||
const D3D9_COMMON_TEXTURE_DESC* Desc() const {
|
||||
return &m_desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Vulkan Format
|
||||
* \returns The Vulkan format of the resource
|
||||
*/
|
||||
const D3D9_VK_FORMAT_MAPPING GetFormatMapping() const {
|
||||
return m_mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Counts number of subresources
|
||||
* \returns Number of subresources
|
||||
*/
|
||||
UINT CountSubresources() const {
|
||||
return m_desc.ArraySize * m_desc.MipLevels;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Map mode
|
||||
* \returns Map mode
|
||||
*/
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE GetMapMode() const {
|
||||
return m_mapMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief The DXVK image
|
||||
* Note, this will be nullptr if the map mode is D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM
|
||||
* \returns The DXVK image
|
||||
*/
|
||||
Rc<DxvkImage> GetImage() const {
|
||||
return m_image;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get a copy of the main image, but with a single sample
|
||||
* This function will allocate/reuse an image with the same info
|
||||
* as the main image
|
||||
* \returns An image with identical info, but 1 sample
|
||||
*/
|
||||
Rc<DxvkImage> GetResolveImage() {
|
||||
if (unlikely(m_resolveImage == nullptr))
|
||||
m_resolveImage = CreateResolveImage();
|
||||
|
||||
return m_resolveImage;
|
||||
}
|
||||
|
||||
Rc<DxvkBuffer> GetBuffer(UINT Subresource) {
|
||||
return m_buffers[Subresource];
|
||||
}
|
||||
|
||||
|
||||
DxvkBufferSliceHandle GetMappedSlice(UINT Subresource) {
|
||||
return m_mappedSlices[Subresource];
|
||||
}
|
||||
|
||||
|
||||
DxvkBufferSliceHandle DiscardMapSlice(UINT Subresource) {
|
||||
DxvkBufferSliceHandle handle = m_buffers[Subresource]->allocSlice();
|
||||
m_mappedSlices[Subresource] = handle;
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Computes subresource from the subresource index
|
||||
*
|
||||
* Used by some functions that operate on only
|
||||
* one subresource, such as \c UpdateSurface.
|
||||
* \param [in] Aspect The image aspect
|
||||
* \param [in] Subresource Subresource index
|
||||
* \returns The Vulkan image subresource
|
||||
*/
|
||||
VkImageSubresource GetSubresourceFromIndex(
|
||||
VkImageAspectFlags Aspect,
|
||||
UINT Subresource) const;
|
||||
|
||||
/**
|
||||
* \brief Normalizes and validates texture description
|
||||
*
|
||||
* Fills in undefined values and validates the texture
|
||||
* parameters. Any error returned by this method should
|
||||
* be forwarded to the application.
|
||||
* \param [in,out] pDesc Texture description
|
||||
* \returns \c S_OK if the parameters are valid
|
||||
*/
|
||||
static HRESULT NormalizeTextureProperties(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING* pMapping);
|
||||
|
||||
/**
|
||||
* \brief Lock Flags
|
||||
* Set the lock flags for a given subresource
|
||||
*/
|
||||
void SetLockFlags(UINT Subresource, DWORD Flags) {
|
||||
m_lockFlags[Subresource] = Flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Lock Flags
|
||||
* \returns The log flags for a given subresource
|
||||
*/
|
||||
DWORD GetLockFlags(UINT Subresource) const {
|
||||
return m_lockFlags[Subresource];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Shadow
|
||||
* \returns Whether the texture is to be depth compared
|
||||
*/
|
||||
bool IsShadow() const {
|
||||
return m_shadow;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Subresource
|
||||
* \returns The subresource idx of a given face and mip level
|
||||
*/
|
||||
UINT CalcSubresource(UINT Face, UINT MipLevel) const {
|
||||
return Face * m_desc.MipLevels + MipLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates buffers
|
||||
* Creates mapping and staging buffers for all subresources
|
||||
* allocates new buffers if necessary
|
||||
*/
|
||||
void CreateBuffers() {
|
||||
const uint32_t count = CountSubresources();
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
CreateBufferSubresource(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates a buffer
|
||||
* Creates mapping and staging buffers for a given subresource
|
||||
* allocates new buffers if necessary
|
||||
* \returns Whether an allocation happened
|
||||
*/
|
||||
bool CreateBufferSubresource(UINT Subresource);
|
||||
|
||||
/**
|
||||
* \brief Destroys a buffer
|
||||
* Destroys mapping and staging buffers for a given subresource
|
||||
*/
|
||||
void DestroyBufferSubresource(UINT Subresource) {
|
||||
m_buffers[Subresource] = nullptr;
|
||||
SetDirty(Subresource, true);
|
||||
}
|
||||
|
||||
bool IsDynamic() const {
|
||||
return m_desc.Usage & D3DUSAGE_DYNAMIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Managed
|
||||
* \returns Whether a resource is managed (pool) or not
|
||||
*/
|
||||
bool IsManaged() const {
|
||||
return IsPoolManaged(m_desc.Pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Render Target
|
||||
* \returns Whether a resource is a render target or not
|
||||
*/
|
||||
bool IsRenderTarget() const {
|
||||
return m_desc.Usage & D3DUSAGE_RENDERTARGET;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Autogen Mipmap
|
||||
* \returns Whether the texture is to have automatic mip generation
|
||||
*/
|
||||
bool IsAutomaticMip() const {
|
||||
return m_desc.Usage & D3DUSAGE_AUTOGENMIPMAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Autogen Mipmap
|
||||
* \returns Whether the texture is to have automatic mip generation
|
||||
*/
|
||||
const D3D9ViewSet& GetViews() const {
|
||||
return m_views;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Recreate main image view
|
||||
* Recreates the main view of the sampler w/ a specific LOD.
|
||||
* SetLOD only works on MANAGED textures so this is A-okay.
|
||||
*/
|
||||
void RecreateSampledView(UINT Lod);
|
||||
|
||||
/**
|
||||
* \brief Extent
|
||||
* \returns The extent of the top-level mip
|
||||
*/
|
||||
VkExtent3D GetExtent() const {
|
||||
return m_adjustedExtent;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mip Extent
|
||||
* \returns The extent of a mip or subresource
|
||||
*/
|
||||
VkExtent3D GetExtentMip(UINT Subresource) const {
|
||||
UINT MipLevel = Subresource % m_desc.MipLevels;
|
||||
return util::computeMipLevelExtent(GetExtent(), MipLevel);
|
||||
}
|
||||
|
||||
bool MarkHazardous() {
|
||||
return std::exchange(m_views.Hazardous, true);
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE GetType() {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
const D3D9_VK_FORMAT_MAPPING& GetMapping() { return m_mapping; }
|
||||
|
||||
bool MarkLocked(UINT Subresource, bool value) { return std::exchange(m_locked[Subresource], value); }
|
||||
|
||||
bool SetDirty(UINT Subresource, bool value) { return std::exchange(m_dirty[Subresource], value); }
|
||||
void MarkAllDirty() { for (uint32_t i = 0; i < m_dirty.size(); i++) m_dirty[i] = true; }
|
||||
|
||||
private:
|
||||
|
||||
D3D9DeviceEx* m_device;
|
||||
D3D9_COMMON_TEXTURE_DESC m_desc;
|
||||
D3DRESOURCETYPE m_type;
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE m_mapMode;
|
||||
|
||||
Rc<DxvkImage> m_image;
|
||||
Rc<DxvkImage> m_resolveImage;
|
||||
D3D9SubresourceArray<
|
||||
Rc<DxvkBuffer>> m_buffers;
|
||||
D3D9SubresourceArray<
|
||||
DxvkBufferSliceHandle> m_mappedSlices;
|
||||
D3D9SubresourceArray<DWORD> m_lockFlags;
|
||||
|
||||
D3D9ViewSet m_views;
|
||||
|
||||
D3D9_VK_FORMAT_MAPPING m_mapping;
|
||||
|
||||
VkExtent3D m_adjustedExtent;
|
||||
|
||||
bool m_shadow; //< Depth Compare-ness
|
||||
|
||||
int64_t m_size = 0;
|
||||
|
||||
bool m_systemmemModified = false;
|
||||
|
||||
D3D9SubresourceArray<
|
||||
bool> m_locked = { };
|
||||
|
||||
D3D9SubresourceArray<
|
||||
bool> m_dirty = { };
|
||||
|
||||
/**
|
||||
* \brief Mip level
|
||||
* \returns Size of packed mip level in bytes
|
||||
*/
|
||||
VkDeviceSize GetMipSize(UINT Subresource) const;
|
||||
|
||||
Rc<DxvkImage> CreatePrimaryImage(D3DRESOURCETYPE ResourceType) const;
|
||||
|
||||
Rc<DxvkImage> CreateResolveImage() const;
|
||||
|
||||
BOOL DetermineShadowState() const;
|
||||
|
||||
BOOL CheckImageSupport(
|
||||
const DxvkImageCreateInfo* pImageInfo,
|
||||
VkImageTiling Tiling) const;
|
||||
|
||||
VkImageUsageFlags EnableMetaCopyUsage(
|
||||
VkFormat Format,
|
||||
VkImageTiling Tiling) const;
|
||||
|
||||
D3D9_COMMON_TEXTURE_MAP_MODE DetermineMapMode() const {
|
||||
if (m_desc.Format == D3D9Format::NULL_FORMAT)
|
||||
return D3D9_COMMON_TEXTURE_MAP_MODE_NONE;
|
||||
|
||||
if (m_desc.Pool == D3DPOOL_SYSTEMMEM || m_desc.Pool == D3DPOOL_SCRATCH)
|
||||
return D3D9_COMMON_TEXTURE_MAP_MODE_SYSTEMMEM;
|
||||
|
||||
return D3D9_COMMON_TEXTURE_MAP_MODE_BACKED;
|
||||
}
|
||||
|
||||
static VkImageType GetImageTypeFromResourceType(
|
||||
D3DRESOURCETYPE Dimension);
|
||||
|
||||
static VkImageViewType GetImageViewTypeFromResourceType(
|
||||
D3DRESOURCETYPE Dimension,
|
||||
UINT Layer);
|
||||
|
||||
static VkImageLayout OptimizeLayout(
|
||||
VkImageUsageFlags Usage);
|
||||
|
||||
static constexpr UINT AllLayers = UINT32_MAX;
|
||||
|
||||
Rc<DxvkImageView> CreateView(
|
||||
D3D9_VK_FORMAT_MAPPING FormatInfo,
|
||||
UINT Layer,
|
||||
VkImageUsageFlags UsageFlags,
|
||||
UINT Lod,
|
||||
BOOL Srgb);
|
||||
|
||||
D3D9ColorView CreateColorViewPair(
|
||||
D3D9_VK_FORMAT_MAPPING FormatInfo,
|
||||
UINT Layer,
|
||||
VkImageUsageFlags UsageFlags,
|
||||
UINT Lod);
|
||||
|
||||
void CreateInitialViews();
|
||||
};
|
||||
|
||||
}
|
26
src/d3d9/d3d9_constant_layout.h
Normal file
26
src/d3d9/d3d9_constant_layout.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "d3d9_caps.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D9ConstantLayout {
|
||||
uint32_t floatCount;
|
||||
uint32_t intCount;
|
||||
uint32_t boolCount;
|
||||
uint32_t bitmaskCount;
|
||||
|
||||
uint32_t floatSize() const { return floatCount * 4 * sizeof(float); }
|
||||
uint32_t intSize() const { return intCount * 4 * sizeof(int); }
|
||||
uint32_t bitmaskSize() const { return bitmaskCount * 1 * sizeof(uint32_t); }
|
||||
|
||||
uint32_t floatOffset() const { return 0; }
|
||||
uint32_t intOffset() const { return floatOffset() + floatSize(); }
|
||||
uint32_t bitmaskOffset() const { return intOffset() + intSize(); }
|
||||
|
||||
uint32_t totalSize() const { return floatSize() + intSize() + bitmaskSize(); }
|
||||
};
|
||||
|
||||
}
|
47
src/d3d9/d3d9_constant_set.h
Normal file
47
src/d3d9/d3d9_constant_set.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_caps.h"
|
||||
|
||||
#include "../dxvk/dxvk_buffer.h"
|
||||
|
||||
#include "../dxso/dxso_isgn.h"
|
||||
|
||||
#include "../util/util_math.h"
|
||||
#include "../util/util_vector.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum class D3D9ConstantType {
|
||||
Float,
|
||||
Int,
|
||||
Bool
|
||||
};
|
||||
|
||||
// We make an assumption later based on the packing of this struct for copying.
|
||||
struct D3D9ShaderConstantsVSSoftware {
|
||||
Vector4 fConsts[caps::MaxFloatConstantsSoftware];
|
||||
Vector4i iConsts[caps::MaxOtherConstantsSoftware];
|
||||
uint32_t bConsts[caps::MaxOtherConstantsSoftware / 32];
|
||||
};
|
||||
|
||||
struct D3D9ShaderConstantsVSHardware {
|
||||
Vector4 fConsts[caps::MaxFloatConstantsVS];
|
||||
Vector4i iConsts[caps::MaxOtherConstants];
|
||||
uint32_t bConsts[1];
|
||||
};
|
||||
|
||||
struct D3D9ShaderConstantsPS {
|
||||
Vector4 fConsts[caps::MaxFloatConstantsPS];
|
||||
Vector4i iConsts[caps::MaxOtherConstants];
|
||||
uint32_t bConsts[1];
|
||||
};
|
||||
|
||||
struct D3D9ConstantSets {
|
||||
Rc<DxvkBuffer> buffer;
|
||||
const DxsoShaderMetaInfo* meta = nullptr;
|
||||
bool dirty = true;
|
||||
};
|
||||
|
||||
}
|
42
src/d3d9/d3d9_cursor.cpp
Normal file
42
src/d3d9/d3d9_cursor.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "d3d9_cursor.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
void D3D9Cursor::UpdateCursor(int X, int Y) {
|
||||
::SetCursorPos(X, Y);
|
||||
}
|
||||
|
||||
|
||||
BOOL D3D9Cursor::ShowCursor(BOOL bShow) {
|
||||
::SetCursor(bShow ? m_hCursor : nullptr);
|
||||
return std::exchange(m_visible, bShow);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Cursor::SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap) {
|
||||
DWORD mask[32];
|
||||
std::memset(mask, ~0, sizeof(mask));
|
||||
|
||||
ICONINFO info;
|
||||
info.fIcon = FALSE;
|
||||
info.xHotspot = XHotSpot;
|
||||
info.yHotspot = YHotSpot;
|
||||
info.hbmMask = ::CreateBitmap(HardwareCursorWidth, HardwareCursorHeight, 1, 1, mask);
|
||||
info.hbmColor = ::CreateBitmap(HardwareCursorWidth, HardwareCursorHeight, 1, 32, &bitmap[0]);
|
||||
|
||||
if (m_hCursor != nullptr)
|
||||
::DestroyCursor(m_hCursor);
|
||||
|
||||
m_hCursor = ::CreateIconIndirect(&info);
|
||||
|
||||
::DeleteObject(info.hbmMask);
|
||||
::DeleteObject(info.hbmColor);
|
||||
|
||||
ShowCursor(m_visible);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
33
src/d3d9/d3d9_cursor.h
Normal file
33
src/d3d9/d3d9_cursor.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr uint32_t HardwareCursorWidth = 32u;
|
||||
constexpr uint32_t HardwareCursorHeight = 32u;
|
||||
constexpr uint32_t HardwareCursorFormatSize = 4u;
|
||||
constexpr uint32_t HardwareCursorPitch = HardwareCursorWidth * HardwareCursorFormatSize;
|
||||
|
||||
// Format Size of 4 bytes (ARGB)
|
||||
using CursorBitmap = uint8_t[HardwareCursorHeight * HardwareCursorPitch];
|
||||
|
||||
class D3D9Cursor {
|
||||
|
||||
public:
|
||||
|
||||
void UpdateCursor(int X, int Y);
|
||||
|
||||
BOOL ShowCursor(BOOL bShow);
|
||||
|
||||
HRESULT SetHardwareCursor(UINT XHotSpot, UINT YHotSpot, const CursorBitmap& bitmap);
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_visible = FALSE;
|
||||
|
||||
HCURSOR m_hCursor = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
6530
src/d3d9/d3d9_device.cpp
Normal file
6530
src/d3d9/d3d9_device.cpp
Normal file
File diff suppressed because it is too large
Load diff
1154
src/d3d9/d3d9_device.h
Normal file
1154
src/d3d9/d3d9_device.h
Normal file
File diff suppressed because it is too large
Load diff
61
src/d3d9/d3d9_device_child.h
Normal file
61
src/d3d9/d3d9_device_child.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
|
||||
template <typename Base>
|
||||
class D3D9DeviceChild : public ComObjectClamp<Base> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9DeviceChild(D3D9DeviceEx* pDevice)
|
||||
: m_parent( pDevice ) { }
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() {
|
||||
uint32_t refCount = this->m_refCount++;
|
||||
if (unlikely(!refCount)) {
|
||||
this->AddRefPrivate();
|
||||
GetDevice()->AddRef();
|
||||
}
|
||||
|
||||
return refCount + 1;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release() {
|
||||
uint32_t refCount = --this->m_refCount;
|
||||
if (unlikely(!refCount)) {
|
||||
auto* pDevice = GetDevice();
|
||||
this->ReleasePrivate();
|
||||
pDevice->Release();
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDevice(IDirect3DDevice9** ppDevice) {
|
||||
InitReturnPtr(ppDevice);
|
||||
|
||||
if (ppDevice == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppDevice = ref(GetDevice());
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
IDirect3DDevice9Ex* GetDevice() {
|
||||
return reinterpret_cast<IDirect3DDevice9Ex*>(m_parent);
|
||||
}
|
||||
|
||||
D3D9DeviceEx* GetParent() {
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
D3D9DeviceEx* m_parent;
|
||||
|
||||
};
|
||||
|
||||
}
|
2311
src/d3d9/d3d9_fixed_function.cpp
Normal file
2311
src/d3d9/d3d9_fixed_function.cpp
Normal file
File diff suppressed because it is too large
Load diff
247
src/d3d9/d3d9_fixed_function.h
Normal file
247
src/d3d9/d3d9_fixed_function.h
Normal file
|
@ -0,0 +1,247 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
#include "d3d9_caps.h"
|
||||
|
||||
#include "../dxvk/dxvk_shader.h"
|
||||
|
||||
#include "../dxso/dxso_isgn.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <bitset>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9DeviceEx;
|
||||
class SpirvModule;
|
||||
|
||||
struct D3D9Options;
|
||||
|
||||
struct D3D9FogContext {
|
||||
// General inputs...
|
||||
bool IsPixel;
|
||||
bool RangeFog;
|
||||
uint32_t RenderState;
|
||||
uint32_t vPos;
|
||||
uint32_t vFog;
|
||||
|
||||
uint32_t oColor;
|
||||
|
||||
bool HasFogInput;
|
||||
};
|
||||
|
||||
struct D3D9FixedFunctionOptions {
|
||||
D3D9FixedFunctionOptions(const D3D9Options* options);
|
||||
|
||||
bool invariantPosition;
|
||||
};
|
||||
|
||||
// Returns new oFog if VS
|
||||
// Returns new oColor if PS
|
||||
uint32_t DoFixedFunctionFog(SpirvModule& spvModule, const D3D9FogContext& fogCtx);
|
||||
|
||||
// Returns a render state block
|
||||
uint32_t SetupRenderStateBlock(SpirvModule& spvModule);
|
||||
|
||||
struct D3D9PointSizeInfoVS {
|
||||
uint32_t defaultValue;
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
};
|
||||
|
||||
// Default point size and point scale magic!
|
||||
D3D9PointSizeInfoVS GetPointSizeInfoVS(SpirvModule& spvModule, uint32_t vPos, uint32_t vtx, uint32_t perVertPointSize, uint32_t rsBlock);
|
||||
|
||||
struct D3D9PointSizeInfoPS {
|
||||
uint32_t isSprite;
|
||||
};
|
||||
|
||||
D3D9PointSizeInfoPS GetPointSizeInfoPS(SpirvModule& spvModule, uint32_t rsBlock);
|
||||
|
||||
uint32_t GetPointCoord(SpirvModule& spvModule, std::vector<uint32_t>& entryPointInterfaces);
|
||||
|
||||
uint32_t GetSharedConstants(SpirvModule& spvModule);
|
||||
|
||||
constexpr uint32_t TCIOffset = 16;
|
||||
constexpr uint32_t TCIMask = 0b111 << TCIOffset;
|
||||
|
||||
enum D3D9FF_VertexBlendMode {
|
||||
D3D9FF_VertexBlendMode_Disabled,
|
||||
D3D9FF_VertexBlendMode_Normal,
|
||||
D3D9FF_VertexBlendMode_Tween,
|
||||
};
|
||||
|
||||
struct D3D9FFShaderKeyVSData {
|
||||
union {
|
||||
struct {
|
||||
uint32_t TexcoordIndices : 24;
|
||||
|
||||
uint32_t HasPositionT : 1;
|
||||
|
||||
uint32_t HasColor0 : 1; // Diffuse
|
||||
uint32_t HasColor1 : 1; // Specular
|
||||
|
||||
uint32_t HasPointSize : 1;
|
||||
|
||||
uint32_t UseLighting : 1;
|
||||
|
||||
uint32_t NormalizeNormals : 1;
|
||||
uint32_t LocalViewer : 1;
|
||||
uint32_t RangeFog : 1;
|
||||
|
||||
uint32_t TexcoordFlags : 24;
|
||||
|
||||
uint32_t DiffuseSource : 2;
|
||||
uint32_t AmbientSource : 2;
|
||||
uint32_t SpecularSource : 2;
|
||||
uint32_t EmissiveSource : 2;
|
||||
|
||||
uint32_t TransformFlags : 24;
|
||||
|
||||
uint32_t LightCount : 4;
|
||||
|
||||
uint32_t TexcoordDeclMask : 24;
|
||||
uint32_t HasFog : 1;
|
||||
|
||||
uint32_t VertexBlendMode : 2;
|
||||
uint32_t VertexBlendIndexed : 1;
|
||||
uint32_t VertexBlendCount : 3;
|
||||
} Contents;
|
||||
|
||||
uint32_t Primitive[4];
|
||||
};
|
||||
};
|
||||
|
||||
struct D3D9FFShaderKeyVS {
|
||||
D3D9FFShaderKeyVS() {
|
||||
// memcmp safety
|
||||
std::memset(&Data, 0, sizeof(Data));
|
||||
}
|
||||
|
||||
D3D9FFShaderKeyVSData Data;
|
||||
};
|
||||
|
||||
constexpr uint32_t TextureArgCount = 3;
|
||||
|
||||
struct D3D9FFShaderStage {
|
||||
union {
|
||||
struct {
|
||||
uint32_t ColorOp : 5;
|
||||
uint32_t ColorArg0 : 6;
|
||||
uint32_t ColorArg1 : 6;
|
||||
uint32_t ColorArg2 : 6;
|
||||
|
||||
uint32_t AlphaOp : 5;
|
||||
uint32_t AlphaArg0 : 6;
|
||||
uint32_t AlphaArg1 : 6;
|
||||
uint32_t AlphaArg2 : 6;
|
||||
|
||||
uint32_t Type : 2;
|
||||
uint32_t ResultIsTemp : 1;
|
||||
uint32_t Projected : 1;
|
||||
|
||||
uint32_t ProjectedCount : 3;
|
||||
|
||||
// Included in here, read from Stage 0 for packing reasons
|
||||
// Affects all stages.
|
||||
uint32_t GlobalSpecularEnable : 1;
|
||||
uint32_t GlobalFlatShade : 1;
|
||||
} Contents;
|
||||
|
||||
uint32_t Primitive[2];
|
||||
};
|
||||
};
|
||||
|
||||
struct D3D9FFShaderKeyFS {
|
||||
D3D9FFShaderKeyFS() {
|
||||
// memcmp safety
|
||||
std::memset(Stages, 0, sizeof(Stages));
|
||||
|
||||
// Normalize this. DISABLE != 0.
|
||||
for (uint32_t i = 0; i < caps::TextureStageCount; i++) {
|
||||
Stages[i].Contents.ColorOp = D3DTOP_DISABLE;
|
||||
Stages[i].Contents.AlphaOp = D3DTOP_DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
D3D9FFShaderStage Stages[caps::TextureStageCount];
|
||||
};
|
||||
|
||||
struct D3D9FFShaderKeyHash {
|
||||
size_t operator () (const D3D9FFShaderKeyVS& key) const;
|
||||
size_t operator () (const D3D9FFShaderKeyFS& key) const;
|
||||
};
|
||||
|
||||
bool operator == (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b);
|
||||
bool operator != (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b);
|
||||
bool operator == (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b);
|
||||
bool operator != (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b);
|
||||
|
||||
struct D3D9FFShaderKeyEq {
|
||||
bool operator () (const D3D9FFShaderKeyVS& a, const D3D9FFShaderKeyVS& b) const;
|
||||
bool operator () (const D3D9FFShaderKeyFS& a, const D3D9FFShaderKeyFS& b) const;
|
||||
};
|
||||
|
||||
class D3D9FFShader {
|
||||
|
||||
public:
|
||||
|
||||
D3D9FFShader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9FFShaderKeyVS& Key);
|
||||
|
||||
D3D9FFShader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9FFShaderKeyFS& Key);
|
||||
|
||||
template <typename T>
|
||||
void Dump(const T& Key, const std::string& Name);
|
||||
|
||||
Rc<DxvkShader> GetShader() const {
|
||||
return m_shader;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Rc<DxvkShader> m_shader;
|
||||
|
||||
DxsoIsgn m_isgn;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class D3D9FFShaderModuleSet : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
D3D9FFShader GetShaderModule(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9FFShaderKeyVS& ShaderKey);
|
||||
|
||||
D3D9FFShader GetShaderModule(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9FFShaderKeyFS& ShaderKey);
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_map<
|
||||
D3D9FFShaderKeyVS,
|
||||
D3D9FFShader,
|
||||
D3D9FFShaderKeyHash, D3D9FFShaderKeyEq> m_vsModules;
|
||||
|
||||
std::unordered_map<
|
||||
D3D9FFShaderKeyFS,
|
||||
D3D9FFShader,
|
||||
D3D9FFShaderKeyHash, D3D9FFShaderKeyEq> m_fsModules;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline const DxsoIsgn& GetFixedFunctionIsgn() {
|
||||
extern DxsoIsgn g_ffIsgn;
|
||||
|
||||
return g_ffIsgn;
|
||||
}
|
||||
|
||||
}
|
500
src/d3d9/d3d9_format.cpp
Normal file
500
src/d3d9/d3d9_format.cpp
Normal file
|
@ -0,0 +1,500 @@
|
|||
#include "d3d9_format.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// It is also worth noting that the msb/lsb-ness is flipped between VK and D3D9.
|
||||
D3D9_VK_FORMAT_MAPPING ConvertFormatUnfixed(D3D9Format Format) {
|
||||
switch (Format) {
|
||||
case D3D9Format::Unknown: return {};
|
||||
|
||||
case D3D9Format::R8G8B8: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::A8R8G8B8: return {
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_FORMAT_B8G8R8A8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::X8R8G8B8: return {
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_FORMAT_B8G8R8A8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::R5G6B5: return {
|
||||
VK_FORMAT_R5G6B5_UNORM_PACK16,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT};
|
||||
|
||||
case D3D9Format::X1R5G5B5: return {
|
||||
VK_FORMAT_A1R5G5B5_UNORM_PACK16,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A1R5G5B5: return {
|
||||
VK_FORMAT_A1R5G5B5_UNORM_PACK16,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A4R4G4B4: return {
|
||||
VK_FORMAT_R4G4B4A4_UNORM_PACK16,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
||||
VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R }};
|
||||
|
||||
case D3D9Format::R3G3B2: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::A8: return {
|
||||
VK_FORMAT_R8_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_R }};
|
||||
|
||||
case D3D9Format::A8R3G3B2: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::X4R4G4B4: return {
|
||||
VK_FORMAT_R4G4B4A4_UNORM_PACK16,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
|
||||
VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A2B10G10R10: return {
|
||||
VK_FORMAT_A2B10G10R10_UNORM_PACK32, // The A2 is out of place here. This should be investigated.
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A8B8G8R8: return {
|
||||
VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::X8B8G8R8: return {
|
||||
VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::G16R16: return {
|
||||
VK_FORMAT_R16G16_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A2R10G10B10: return {
|
||||
VK_FORMAT_A2R10G10B10_UNORM_PACK32,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A16B16G16R16: return {
|
||||
VK_FORMAT_R16G16B16A16_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A8P8: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::P8: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::L8: return {
|
||||
VK_FORMAT_R8_UNORM,
|
||||
VK_FORMAT_R8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A8L8: return {
|
||||
VK_FORMAT_R8G8_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G }};
|
||||
|
||||
case D3D9Format::A4L4: return {
|
||||
VK_FORMAT_R4G4_UNORM_PACK8,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R }};
|
||||
|
||||
case D3D9Format::V8U8: return {
|
||||
VK_FORMAT_R8G8_SNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::L6V5U5: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::X8L8V8U8: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::Q8W8V8U8: return {
|
||||
VK_FORMAT_R8G8B8A8_SNORM,
|
||||
VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::V16U16: return {
|
||||
VK_FORMAT_R16G16_SNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A2W10V10U10: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::UYVY: return {
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
|
||||
{ D3D9VideoFormat_UYVY, { 2u, 1u } }
|
||||
};
|
||||
|
||||
case D3D9Format::R8G8_B8G8: return {
|
||||
VK_FORMAT_G8B8G8R8_422_UNORM, // This format may have been _SCALED in DX9.
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::YUY2: return {
|
||||
VK_FORMAT_B8G8R8A8_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
|
||||
{ D3D9VideoFormat_YUY2, { 2u, 1u } }
|
||||
};
|
||||
|
||||
case D3D9Format::G8R8_G8B8: return {
|
||||
VK_FORMAT_B8G8R8G8_422_UNORM, // This format may have been _SCALED in DX9.
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::DXT1: return {
|
||||
VK_FORMAT_BC1_RGBA_UNORM_BLOCK,
|
||||
VK_FORMAT_BC1_RGBA_SRGB_BLOCK,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::DXT2: return {
|
||||
VK_FORMAT_BC2_UNORM_BLOCK,
|
||||
VK_FORMAT_BC2_SRGB_BLOCK,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::DXT3: return {
|
||||
VK_FORMAT_BC2_UNORM_BLOCK,
|
||||
VK_FORMAT_BC2_SRGB_BLOCK,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::DXT4: return {
|
||||
VK_FORMAT_BC3_UNORM_BLOCK,
|
||||
VK_FORMAT_BC3_SRGB_BLOCK,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::DXT5: return {
|
||||
VK_FORMAT_BC3_UNORM_BLOCK,
|
||||
VK_FORMAT_BC3_SRGB_BLOCK,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::D16_LOCKABLE: return {
|
||||
VK_FORMAT_D16_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT };
|
||||
|
||||
case D3D9Format::D32: return {
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT };
|
||||
|
||||
case D3D9Format::D15S1: return {}; // Unsupported (everywhere)
|
||||
|
||||
case D3D9Format::D24S8: return {
|
||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT };
|
||||
|
||||
case D3D9Format::D24X8: return {
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT };
|
||||
|
||||
case D3D9Format::D24X4S4: return {}; // Unsupported (everywhere)
|
||||
|
||||
case D3D9Format::D16: return {
|
||||
VK_FORMAT_D16_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT };
|
||||
|
||||
case D3D9Format::D32F_LOCKABLE: return {
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT };
|
||||
|
||||
case D3D9Format::D24FS8: return {
|
||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT };
|
||||
|
||||
case D3D9Format::D32_LOCKABLE: return {
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT };
|
||||
|
||||
case D3D9Format::S8_LOCKABLE: return {
|
||||
VK_FORMAT_S8_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_STENCIL_BIT };
|
||||
|
||||
case D3D9Format::L16: return {
|
||||
VK_FORMAT_R16_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::VERTEXDATA: return {
|
||||
VK_FORMAT_R8_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
0 };
|
||||
|
||||
case D3D9Format::INDEX16: return {
|
||||
VK_FORMAT_R16_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
0 };
|
||||
|
||||
case D3D9Format::INDEX32: return {
|
||||
VK_FORMAT_R32_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
0 };
|
||||
|
||||
case D3D9Format::Q16W16V16U16: return {
|
||||
VK_FORMAT_R16G16B16A16_SNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::MULTI2_ARGB8: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::R16F: return {
|
||||
VK_FORMAT_R16_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::G16R16F: return {
|
||||
VK_FORMAT_R16G16_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A16B16G16R16F: return {
|
||||
VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::R32F: return {
|
||||
VK_FORMAT_R32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::G32R32F: return {
|
||||
VK_FORMAT_R32G32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::A32B32G32R32F: return {
|
||||
VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::CxV8U8: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::A1: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::A2B10G10R10_XR_BIAS: return {
|
||||
VK_FORMAT_A2B10G10R10_SNORM_PACK32,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::BINARYBUFFER: return {
|
||||
VK_FORMAT_R8_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
0 };
|
||||
|
||||
case D3D9Format::ATI1: return {
|
||||
VK_FORMAT_BC4_UNORM_BLOCK,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::ATI2: return {
|
||||
VK_FORMAT_BC5_UNORM_BLOCK,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::INST: return {}; // Driver hack, handled elsewhere
|
||||
|
||||
case D3D9Format::DF24: return {
|
||||
VK_FORMAT_D32_SFLOAT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::DF16: return {
|
||||
VK_FORMAT_D16_UNORM,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_ONE }};
|
||||
|
||||
case D3D9Format::NULL_FORMAT: return {}; // Driver hack, handled elsewhere
|
||||
|
||||
case D3D9Format::GET4: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::GET1: return {}; // Unsupported
|
||||
|
||||
case D3D9Format::NVDB: return {}; // Driver hack, handled elsewhere
|
||||
|
||||
case D3D9Format::A2M1: return {}; // Driver hack, handled elsewhere
|
||||
|
||||
case D3D9Format::A2M0: return {}; // Driver hack, handled elsewhere
|
||||
|
||||
case D3D9Format::ATOC: return {}; // Driver hack, handled elsewhere
|
||||
|
||||
case D3D9Format::INTZ: return {
|
||||
VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_UNDEFINED,
|
||||
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||
{ VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R }};
|
||||
|
||||
case D3D9Format::RAWZ: return {}; // Unsupported
|
||||
|
||||
default:
|
||||
Logger::warn(str::format("ConvertFormat: Unknown format encountered: ", Format));
|
||||
return {}; // Unsupported
|
||||
}
|
||||
}
|
||||
|
||||
D3D9VkFormatTable::D3D9VkFormatTable(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const D3D9Options& options) {
|
||||
m_dfSupport = options.supportDFFormats;
|
||||
m_x4r4g4b4Support = options.supportX4R4G4B4;
|
||||
m_d32supportFinal = options.supportD32;
|
||||
|
||||
// AMD do not support 24-bit depth buffers on Vulkan,
|
||||
// so we have to fall back to a 32-bit depth format.
|
||||
m_d24s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
|
||||
|
||||
// NVIDIA do not support 16-bit depth buffers with stencil on Vulkan,
|
||||
// so we have to fall back to a 32-bit depth format.
|
||||
m_d16s8Support = CheckImageFormatSupport(adapter, VK_FORMAT_D16_UNORM_S8_UINT,
|
||||
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
|
||||
|
||||
if (!m_d24s8Support)
|
||||
Logger::warn("D3D9: VK_FORMAT_D24_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
|
||||
|
||||
if (!m_d16s8Support) {
|
||||
if (m_d24s8Support)
|
||||
Logger::warn("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D24_UNORM_S8_UINT");
|
||||
else
|
||||
Logger::warn("D3D9: VK_FORMAT_D16_UNORM_S8_UINT -> VK_FORMAT_D32_SFLOAT_S8_UINT");
|
||||
}
|
||||
}
|
||||
|
||||
D3D9_VK_FORMAT_MAPPING D3D9VkFormatTable::GetFormatMapping(
|
||||
D3D9Format Format) const {
|
||||
D3D9_VK_FORMAT_MAPPING mapping = ConvertFormatUnfixed(Format);
|
||||
|
||||
if (Format == D3D9Format::X4R4G4B4 && !m_x4r4g4b4Support)
|
||||
return D3D9_VK_FORMAT_MAPPING();
|
||||
|
||||
if (Format == D3D9Format::DF16 && !m_dfSupport)
|
||||
return D3D9_VK_FORMAT_MAPPING();
|
||||
|
||||
if (Format == D3D9Format::DF24 && !m_dfSupport)
|
||||
return D3D9_VK_FORMAT_MAPPING();
|
||||
|
||||
if (Format == D3D9Format::D32 && !m_d32supportFinal)
|
||||
return D3D9_VK_FORMAT_MAPPING();
|
||||
|
||||
if (!m_d24s8Support && mapping.FormatColor == VK_FORMAT_D24_UNORM_S8_UINT)
|
||||
mapping.FormatColor = VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
|
||||
if (!m_d16s8Support && mapping.FormatColor == VK_FORMAT_D16_UNORM_S8_UINT)
|
||||
mapping.FormatColor = m_d24s8Support ? VK_FORMAT_D24_UNORM_S8_UINT : VK_FORMAT_D32_SFLOAT_S8_UINT;
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
|
||||
DxvkFormatInfo D3D9VkFormatTable::GetUnsupportedFormatInfo(
|
||||
D3D9Format Format) const {
|
||||
switch (Format) {
|
||||
case D3D9Format::R8G8B8:
|
||||
return { 3, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::R3G3B2:
|
||||
return { 1, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A8R3G3B2:
|
||||
return { 2, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A8P8:
|
||||
return { 2, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::P8:
|
||||
return { 1, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::L6V5U5:
|
||||
return { 2, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::X8L8V8U8:
|
||||
return { 4, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
case D3D9Format::A2W10V10U10:
|
||||
return { 4, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
// MULTI2_ARGB8 -> Don't have a clue what this is.
|
||||
|
||||
case D3D9Format::CxV8U8:
|
||||
return { 2, VK_IMAGE_ASPECT_COLOR_BIT };
|
||||
|
||||
// A1 -> Doesn't map nicely here cause it's not byte aligned.
|
||||
// Gonna just pretend that doesn't exist until something
|
||||
// depends on that.
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool D3D9VkFormatTable::CheckImageFormatSupport(
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
VkFormat Format,
|
||||
VkFormatFeatureFlags Features) const {
|
||||
VkFormatProperties supported = Adapter->formatProperties(Format);
|
||||
|
||||
return (supported.linearTilingFeatures & Features) == Features
|
||||
|| (supported.optimalTilingFeatures & Features) == Features;
|
||||
}
|
||||
|
||||
}
|
215
src/d3d9/d3d9_format.h
Normal file
215
src/d3d9/d3d9_format.h
Normal file
|
@ -0,0 +1,215 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
#include "d3d9_options.h"
|
||||
|
||||
#include "../dxvk/dxvk_adapter.h"
|
||||
#include "../dxvk/dxvk_format.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum class D3D9Format : uint32_t {
|
||||
Unknown = 0,
|
||||
|
||||
R8G8B8 = 20,
|
||||
A8R8G8B8 = 21,
|
||||
X8R8G8B8 = 22,
|
||||
R5G6B5 = 23,
|
||||
X1R5G5B5 = 24,
|
||||
A1R5G5B5 = 25,
|
||||
A4R4G4B4 = 26,
|
||||
R3G3B2 = 27,
|
||||
A8 = 28,
|
||||
A8R3G3B2 = 29,
|
||||
X4R4G4B4 = 30,
|
||||
A2B10G10R10 = 31,
|
||||
A8B8G8R8 = 32,
|
||||
X8B8G8R8 = 33,
|
||||
G16R16 = 34,
|
||||
A2R10G10B10 = 35,
|
||||
A16B16G16R16 = 36,
|
||||
A8P8 = 40,
|
||||
P8 = 41,
|
||||
L8 = 50,
|
||||
A8L8 = 51,
|
||||
A4L4 = 52,
|
||||
V8U8 = 60,
|
||||
L6V5U5 = 61,
|
||||
X8L8V8U8 = 62,
|
||||
Q8W8V8U8 = 63,
|
||||
V16U16 = 64,
|
||||
A2W10V10U10 = 67,
|
||||
UYVY = MAKEFOURCC('U', 'Y', 'V', 'Y'),
|
||||
R8G8_B8G8 = MAKEFOURCC('R', 'G', 'B', 'G'),
|
||||
YUY2 = MAKEFOURCC('Y', 'U', 'Y', '2'),
|
||||
G8R8_G8B8 = MAKEFOURCC('G', 'R', 'G', 'B'),
|
||||
DXT1 = MAKEFOURCC('D', 'X', 'T', '1'),
|
||||
DXT2 = MAKEFOURCC('D', 'X', 'T', '2'),
|
||||
DXT3 = MAKEFOURCC('D', 'X', 'T', '3'),
|
||||
DXT4 = MAKEFOURCC('D', 'X', 'T', '4'),
|
||||
DXT5 = MAKEFOURCC('D', 'X', 'T', '5'),
|
||||
D16_LOCKABLE = 70,
|
||||
D32 = 71,
|
||||
D15S1 = 73,
|
||||
D24S8 = 75,
|
||||
D24X8 = 77,
|
||||
D24X4S4 = 79,
|
||||
D16 = 80,
|
||||
D32F_LOCKABLE = 82,
|
||||
D24FS8 = 83,
|
||||
D32_LOCKABLE = 84,
|
||||
S8_LOCKABLE = 85,
|
||||
L16 = 81,
|
||||
VERTEXDATA = 100,
|
||||
INDEX16 = 101,
|
||||
INDEX32 = 102,
|
||||
Q16W16V16U16 = 110,
|
||||
MULTI2_ARGB8 = MAKEFOURCC('M', 'E', 'T', '1'),
|
||||
R16F = 111,
|
||||
G16R16F = 112,
|
||||
A16B16G16R16F = 113,
|
||||
R32F = 114,
|
||||
G32R32F = 115,
|
||||
A32B32G32R32F = 116,
|
||||
CxV8U8 = 117,
|
||||
A1 = 118,
|
||||
A2B10G10R10_XR_BIAS = 119,
|
||||
BINARYBUFFER = 199,
|
||||
|
||||
// Driver Hacks / Unofficial Formats
|
||||
ATI1 = MAKEFOURCC('A', 'T', 'I', '1'),
|
||||
ATI2 = MAKEFOURCC('A', 'T', 'I', '2'),
|
||||
INST = MAKEFOURCC('I', 'N', 'S', 'T'),
|
||||
DF24 = MAKEFOURCC('D', 'F', '2', '4'),
|
||||
DF16 = MAKEFOURCC('D', 'F', '1', '6'),
|
||||
NULL_FORMAT = MAKEFOURCC('N', 'U', 'L', 'L'),
|
||||
GET4 = MAKEFOURCC('G', 'E', 'T', '4'),
|
||||
GET1 = MAKEFOURCC('G', 'E', 'T', '1'),
|
||||
NVDB = MAKEFOURCC('N', 'V', 'D', 'B'),
|
||||
A2M1 = MAKEFOURCC('A', '2', 'M', '1'),
|
||||
A2M0 = MAKEFOURCC('A', '2', 'M', '0'),
|
||||
ATOC = MAKEFOURCC('A', 'T', 'O', 'C'),
|
||||
INTZ = MAKEFOURCC('I', 'N', 'T', 'Z'),
|
||||
RAWZ = MAKEFOURCC('R', 'A', 'W', 'Z'),
|
||||
RESZ = MAKEFOURCC('R', 'E', 'S', 'Z'),
|
||||
|
||||
NV11 = MAKEFOURCC('N', 'V', '1', '1'),
|
||||
NV12 = MAKEFOURCC('N', 'V', '1', '2'),
|
||||
P010 = MAKEFOURCC('P', '0', '1', '0'), // Same as NV12 but 10 bit
|
||||
P016 = MAKEFOURCC('P', '0', '1', '6'), // Same as NV12 but 16 bit
|
||||
Y210 = MAKEFOURCC('Y', '2', '1', '0'),
|
||||
Y216 = MAKEFOURCC('Y', '2', '1', '6'),
|
||||
Y410 = MAKEFOURCC('Y', '4', '1', '0'),
|
||||
AYUV = MAKEFOURCC('A', 'Y', 'U', 'V'),
|
||||
YV12 = MAKEFOURCC('Y', 'V', '1', '2'),
|
||||
OPAQUE_420 = MAKEFOURCC('4', '2', '0', 'O'),
|
||||
|
||||
// Not supported but exist
|
||||
AI44 = MAKEFOURCC('A', 'I', '4', '4'),
|
||||
IA44 = MAKEFOURCC('I', 'A', '4', '4'),
|
||||
R2VB = MAKEFOURCC('R', '2', 'V', 'B'),
|
||||
COPM = MAKEFOURCC('C', 'O', 'P', 'M'),
|
||||
SSAA = MAKEFOURCC('S', 'S', 'A', 'A'),
|
||||
AL16 = MAKEFOURCC('A', 'L', '1', '6'),
|
||||
R16 = MAKEFOURCC(' ', 'R', '1', '6'),
|
||||
|
||||
EXT1 = MAKEFOURCC('E', 'X', 'T', '1'),
|
||||
FXT1 = MAKEFOURCC('F', 'X', 'T', '1'),
|
||||
GXT1 = MAKEFOURCC('G', 'X', 'T', '1'),
|
||||
HXT1 = MAKEFOURCC('H', 'X', 'T', '1'),
|
||||
};
|
||||
|
||||
inline D3D9Format EnumerateFormat(D3DFORMAT format) {
|
||||
return static_cast<D3D9Format>(format);
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, D3D9Format format);
|
||||
|
||||
enum D3D9VideoFormat : uint32_t {
|
||||
D3D9VideoFormat_None = 0,
|
||||
D3D9VideoFormat_YUY2 = 1,
|
||||
D3D9VideoFormat_UYVY,
|
||||
D3D9VideoFormat_Count
|
||||
};
|
||||
|
||||
struct D3D9_VIDEO_FORMAT_INFO {
|
||||
D3D9VideoFormat FormatType = D3D9VideoFormat_None;
|
||||
VkExtent2D MacroPixelSize = { 1u, 1u };
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Format mapping
|
||||
*
|
||||
* Maps a D3D9 format to a set of Vulkan formats.
|
||||
*/
|
||||
struct D3D9_VK_FORMAT_MAPPING {
|
||||
union {
|
||||
struct {
|
||||
VkFormat FormatColor; ///< Corresponding color format
|
||||
VkFormat FormatSrgb; ///< Corresponding color format
|
||||
};
|
||||
VkFormat Formats[2];
|
||||
};
|
||||
VkImageAspectFlags Aspect = 0; ///< Defined aspects for the color format
|
||||
VkComponentMapping Swizzle = { ///< Color component swizzle
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
|
||||
D3D9_VIDEO_FORMAT_INFO VideoFormatInfo = { };
|
||||
|
||||
bool IsValid() { return FormatColor != VK_FORMAT_UNDEFINED; }
|
||||
};
|
||||
|
||||
D3D9_VK_FORMAT_MAPPING ConvertFormatUnfixed(D3D9Format Format);
|
||||
|
||||
/**
|
||||
* \brief Format table
|
||||
*
|
||||
* Initializes a format table for a specific
|
||||
* device and provides methods to look up
|
||||
* formats.
|
||||
*/
|
||||
class D3D9VkFormatTable {
|
||||
|
||||
public:
|
||||
|
||||
D3D9VkFormatTable(
|
||||
const Rc<DxvkAdapter>& adapter,
|
||||
const D3D9Options& options);
|
||||
|
||||
/**
|
||||
* \brief Retrieves info for a given D3D9 format
|
||||
*
|
||||
* \param [in] Format The D3D9 format to look up
|
||||
* \param [in] Mode the format lookup mode
|
||||
* \returns Format info
|
||||
*/
|
||||
D3D9_VK_FORMAT_MAPPING GetFormatMapping(
|
||||
D3D9Format Format) const;
|
||||
|
||||
/**
|
||||
* \brief Retrieves format info for unsupported
|
||||
* formats.
|
||||
*
|
||||
* \param [in] Format The D3D9 format to look up
|
||||
*/
|
||||
DxvkFormatInfo GetUnsupportedFormatInfo(
|
||||
D3D9Format Format) const;
|
||||
|
||||
private:
|
||||
|
||||
bool CheckImageFormatSupport(
|
||||
const Rc<DxvkAdapter>& Adapter,
|
||||
VkFormat Format,
|
||||
VkFormatFeatureFlags Features) const;
|
||||
|
||||
bool m_d24s8Support;
|
||||
bool m_d16s8Support;
|
||||
|
||||
bool m_dfSupport;
|
||||
bool m_x4r4g4b4Support;
|
||||
bool m_d32supportFinal;
|
||||
};
|
||||
|
||||
}
|
82
src/d3d9/d3d9_format_helpers.cpp
Normal file
82
src/d3d9/d3d9_format_helpers.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#include "d3d9_format_helpers.h"
|
||||
|
||||
#include <d3d9_convert_yuy2_uyvy.h>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9FormatHelper::D3D9FormatHelper(const Rc<DxvkDevice>& device)
|
||||
: m_device(device), m_context(m_device->createContext()) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
InitShaders();
|
||||
}
|
||||
|
||||
|
||||
void D3D9FormatHelper::ConvertVideoFormat(
|
||||
D3D9_VIDEO_FORMAT_INFO videoFormat,
|
||||
const Rc<DxvkImage>& dstImage,
|
||||
VkImageSubresourceLayers dstSubresource,
|
||||
const Rc<DxvkBuffer>& srcBuffer) {
|
||||
DxvkImageViewCreateInfo imageViewInfo;
|
||||
imageViewInfo.type = VK_IMAGE_VIEW_TYPE_2D;
|
||||
imageViewInfo.format = dstImage->info().format;
|
||||
imageViewInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
imageViewInfo.aspect = dstSubresource.aspectMask;
|
||||
imageViewInfo.minLevel = dstSubresource.mipLevel;
|
||||
imageViewInfo.numLevels = 1;
|
||||
imageViewInfo.minLayer = dstSubresource.baseArrayLayer;
|
||||
imageViewInfo.numLayers = dstSubresource.layerCount;
|
||||
auto tmpImageView = m_device->createImageView(dstImage, imageViewInfo);
|
||||
|
||||
VkExtent3D imageExtent = dstImage->mipLevelExtent(dstSubresource.mipLevel);
|
||||
imageExtent = VkExtent3D{ imageExtent.width / videoFormat.MacroPixelSize.width,
|
||||
imageExtent.height / videoFormat.MacroPixelSize.height,
|
||||
1 };
|
||||
|
||||
DxvkBufferViewCreateInfo bufferViewInfo;
|
||||
bufferViewInfo.format = VK_FORMAT_R32_UINT;
|
||||
bufferViewInfo.rangeOffset = 0;
|
||||
bufferViewInfo.rangeLength = srcBuffer->info().size;
|
||||
auto tmpBufferView = m_device->createBufferView(srcBuffer, bufferViewInfo);
|
||||
|
||||
if (videoFormat.FormatType == D3D9VideoFormat_UYVY
|
||||
|| videoFormat.FormatType == D3D9VideoFormat_YUY2) {
|
||||
m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, videoFormat.FormatType == D3D9VideoFormat_UYVY);
|
||||
}
|
||||
|
||||
m_context->bindResourceView(BindingIds::Image, tmpImageView, nullptr);
|
||||
m_context->bindResourceView(BindingIds::Buffer, nullptr, tmpBufferView);
|
||||
m_context->bindShader(VK_SHADER_STAGE_COMPUTE_BIT, m_shaders[videoFormat.FormatType]);
|
||||
m_context->pushConstants(0, sizeof(VkExtent2D), &imageExtent);
|
||||
m_context->dispatch(
|
||||
(imageExtent.width / 8) + (imageExtent.width % 8),
|
||||
(imageExtent.height / 8) + (imageExtent.height % 8),
|
||||
1);
|
||||
|
||||
// Reset the spec constants used...
|
||||
m_context->setSpecConstant(VK_PIPELINE_BIND_POINT_COMPUTE, 0, 0);
|
||||
|
||||
m_context->flushCommandList();
|
||||
}
|
||||
|
||||
|
||||
void D3D9FormatHelper::InitShaders() {
|
||||
m_shaders[D3D9VideoFormat_YUY2] = InitShader(d3d9_convert_yuy2_uyvy);
|
||||
m_shaders[D3D9VideoFormat_UYVY] = m_shaders[D3D9VideoFormat_YUY2];
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkShader> D3D9FormatHelper::InitShader(SpirvCodeBuffer code) {
|
||||
const std::array<DxvkResourceSlot, 2> resourceSlots = { {
|
||||
{ BindingIds::Image, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
|
||||
{ BindingIds::Buffer, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_IMAGE_VIEW_TYPE_1D },
|
||||
} };
|
||||
|
||||
return m_device->createShader(
|
||||
VK_SHADER_STAGE_COMPUTE_BIT,
|
||||
resourceSlots.size(), resourceSlots.data(),
|
||||
{ 0u, 0u, 0u, sizeof(VkExtent2D) }, code);
|
||||
}
|
||||
|
||||
}
|
40
src/d3d9/d3d9_format_helpers.h
Normal file
40
src/d3d9/d3d9_format_helpers.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
#include "d3d9_format.h"
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
#include "../dxvk/dxvk_context.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9FormatHelper {
|
||||
|
||||
public:
|
||||
|
||||
D3D9FormatHelper(const Rc<DxvkDevice>& device);
|
||||
|
||||
void ConvertVideoFormat(
|
||||
D3D9_VIDEO_FORMAT_INFO videoFormat,
|
||||
const Rc<DxvkImage>& dstImage,
|
||||
VkImageSubresourceLayers dstSubresource,
|
||||
const Rc<DxvkBuffer>& srcBuffer);
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
Image = 0,
|
||||
Buffer = 1,
|
||||
};
|
||||
|
||||
void InitShaders();
|
||||
|
||||
Rc<DxvkShader> InitShader(SpirvCodeBuffer code);
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
std::array<Rc<DxvkShader>, D3D9VideoFormat_Count> m_shaders;
|
||||
|
||||
};
|
||||
|
||||
}
|
36
src/d3d9/d3d9_hud.cpp
Normal file
36
src/d3d9/d3d9_hud.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "d3d9_hud.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
HudSamplerCount::HudSamplerCount(D3D9DeviceEx* device)
|
||||
: m_device (device)
|
||||
, m_samplerCount ("0"){
|
||||
|
||||
}
|
||||
|
||||
|
||||
void HudSamplerCount::update(dxvk::high_resolution_clock::time_point time) {
|
||||
m_samplerCount = str::format(m_device->GetSamplerCount());
|
||||
}
|
||||
|
||||
|
||||
HudPos HudSamplerCount::render(
|
||||
HudRenderer& renderer,
|
||||
HudPos position) {
|
||||
position.y += 16.0f;
|
||||
|
||||
renderer.drawText(16.0f,
|
||||
{ position.x, position.y },
|
||||
{ 0.0f, 1.0f, 0.75f, 1.0f },
|
||||
"Samplers:");
|
||||
|
||||
renderer.drawText(16.0f,
|
||||
{ position.x + 120.0f, position.y },
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
m_samplerCount);
|
||||
|
||||
position.y += 8.0f;
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
31
src/d3d9/d3d9_hud.h
Normal file
31
src/d3d9/d3d9_hud.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "../dxvk/hud/dxvk_hud_item.h"
|
||||
|
||||
namespace dxvk::hud {
|
||||
|
||||
/**
|
||||
* \brief HUD item to display DXVK version
|
||||
*/
|
||||
class HudSamplerCount : public HudItem {
|
||||
|
||||
public:
|
||||
|
||||
HudSamplerCount(D3D9DeviceEx* device);
|
||||
|
||||
void update(dxvk::high_resolution_clock::time_point time);
|
||||
|
||||
HudPos render(
|
||||
HudRenderer& renderer,
|
||||
HudPos position);
|
||||
|
||||
private:
|
||||
|
||||
D3D9DeviceEx* m_device;
|
||||
|
||||
std::string m_samplerCount;
|
||||
|
||||
};
|
||||
|
||||
}
|
95
src/d3d9/d3d9_include.h
Normal file
95
src/d3d9/d3d9_include.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <d3d9.h>
|
||||
|
||||
//for some reason we need to specify __declspec(dllexport) for MinGW
|
||||
#if defined(__WINE__)
|
||||
#define DLLEXPORT __attribute__((visibility("default")))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DLLEXPORT
|
||||
#else
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
|
||||
#include "../util/com/com_guid.h"
|
||||
#include "../util/com/com_object.h"
|
||||
#include "../util/com/com_pointer.h"
|
||||
|
||||
#include "../util/log/log.h"
|
||||
#include "../util/log/log_debug.h"
|
||||
|
||||
#include "../util/rc/util_rc.h"
|
||||
#include "../util/rc/util_rc_ptr.h"
|
||||
|
||||
#include "../util/util_env.h"
|
||||
#include "../util/util_enum.h"
|
||||
#include "../util/util_error.h"
|
||||
#include "../util/util_flags.h"
|
||||
#include "../util/util_likely.h"
|
||||
#include "../util/util_math.h"
|
||||
#include "../util/util_string.h"
|
||||
#include "../util/util_misc.h"
|
||||
|
||||
// Missed definitions in Wine/MinGW.
|
||||
|
||||
#ifndef D3DPRESENT_BACK_BUFFERS_MAX_EX
|
||||
#define D3DPRESENT_BACK_BUFFERS_MAX_EX 30
|
||||
#endif
|
||||
|
||||
#ifndef D3DSI_OPCODE_MASK
|
||||
#define D3DSI_OPCODE_MASK 0x0000FFFF
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_TEXTURETYPE_MASK
|
||||
#define D3DSP_TEXTURETYPE_MASK 0x78000000
|
||||
#endif
|
||||
|
||||
#ifndef D3DUSAGE_AUTOGENMIPMAP
|
||||
#define D3DUSAGE_AUTOGENMIPMAP 0x00000400L
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_DCL_USAGE_MASK
|
||||
#define D3DSP_DCL_USAGE_MASK 0x0000000f
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_OPCODESPECIFICCONTROL_MASK
|
||||
#define D3DSP_OPCODESPECIFICCONTROL_MASK 0x00ff0000
|
||||
#endif
|
||||
|
||||
#ifndef D3DSP_OPCODESPECIFICCONTROL_SHIFT
|
||||
#define D3DSP_OPCODESPECIFICCONTROL_SHIFT 16
|
||||
#endif
|
||||
|
||||
#ifndef D3DCURSOR_IMMEDIATE_UPDATE
|
||||
#define D3DCURSOR_IMMEDIATE_UPDATE 0x00000001L
|
||||
#endif
|
||||
|
||||
#ifndef D3DPRESENT_FORCEIMMEDIATE
|
||||
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
|
||||
#endif
|
||||
|
||||
// MinGW headers are broken. Who'dve guessed?
|
||||
#ifndef _MSC_VER
|
||||
typedef struct _D3DDEVINFO_RESOURCEMANAGER
|
||||
{
|
||||
char dummy;
|
||||
} D3DDEVINFO_RESOURCEMANAGER, * LPD3DDEVINFO_RESOURCEMANAGER;
|
||||
|
||||
#ifndef __WINE__
|
||||
extern "C" WINUSERAPI WINBOOL WINAPI SetProcessDPIAware(VOID);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// This is the managed pool on D3D9Ex, it's just hidden!
|
||||
#define D3DPOOL_MANAGED_EX D3DPOOL(6)
|
||||
|
||||
using D3D9VertexElements = std::vector<D3DVERTEXELEMENT9>;
|
165
src/d3d9/d3d9_initializer.cpp
Normal file
165
src/d3d9/d3d9_initializer.cpp
Normal file
|
@ -0,0 +1,165 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "d3d9_initializer.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9Initializer::D3D9Initializer(
|
||||
const Rc<DxvkDevice>& Device)
|
||||
: m_device(Device), m_context(m_device->createContext()) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
}
|
||||
|
||||
|
||||
D3D9Initializer::~D3D9Initializer() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::Flush() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_transferCommands != 0)
|
||||
FlushInternal();
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::InitBuffer(
|
||||
D3D9CommonBuffer* pBuffer) {
|
||||
VkMemoryPropertyFlags memFlags = pBuffer->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>()->memFlags();
|
||||
|
||||
(memFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
? InitHostVisibleBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>())
|
||||
: InitDeviceLocalBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>());
|
||||
|
||||
if (pBuffer->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER)
|
||||
InitHostVisibleBuffer(pBuffer->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_STAGING>());
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::InitTexture(
|
||||
D3D9CommonTexture* pTexture,
|
||||
void* pInitialData) {
|
||||
if (pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_NONE)
|
||||
return;
|
||||
|
||||
(pTexture->GetMapMode() == D3D9_COMMON_TEXTURE_MAP_MODE_BACKED)
|
||||
? InitDeviceLocalTexture(pTexture)
|
||||
: InitHostVisibleTexture(pTexture, pInitialData);
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::InitDeviceLocalBuffer(
|
||||
DxvkBufferSlice Slice) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
m_transferCommands += 1;
|
||||
|
||||
m_context->clearBuffer(
|
||||
Slice.buffer(),
|
||||
Slice.offset(),
|
||||
Slice.length(),
|
||||
0u);
|
||||
|
||||
FlushImplicit();
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::InitHostVisibleBuffer(
|
||||
DxvkBufferSlice Slice) {
|
||||
// If the buffer is mapped, we can write data directly
|
||||
// to the mapped memory region instead of doing it on
|
||||
// the GPU. Same goes for zero-initialization.
|
||||
std::memset(
|
||||
Slice.mapPtr(0), 0,
|
||||
Slice.length());
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::InitDeviceLocalTexture(
|
||||
D3D9CommonTexture* pTexture) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
auto InitImage = [&](Rc<DxvkImage> image) {
|
||||
if (image == nullptr)
|
||||
return;
|
||||
|
||||
auto formatInfo = imageFormatInfo(image->info().format);
|
||||
|
||||
m_transferCommands += 1;
|
||||
|
||||
// While the Microsoft docs state that resource contents are
|
||||
// undefined if no initial data is provided, some applications
|
||||
// expect a resource to be pre-cleared. We can only do that
|
||||
// for non-compressed images, but that should be fine.
|
||||
VkImageSubresourceRange subresources;
|
||||
subresources.aspectMask = formatInfo->aspectMask;
|
||||
subresources.baseMipLevel = 0;
|
||||
subresources.levelCount = image->info().mipLevels;
|
||||
subresources.baseArrayLayer = 0;
|
||||
subresources.layerCount = image->info().numLayers;
|
||||
|
||||
if (formatInfo->flags.test(DxvkFormatFlag::BlockCompressed)) {
|
||||
m_context->clearCompressedColorImage(image, subresources);
|
||||
} else {
|
||||
if (subresources.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
|
||||
VkClearColorValue value = { };
|
||||
|
||||
m_context->clearColorImage(
|
||||
image, value, subresources);
|
||||
} else {
|
||||
VkClearDepthStencilValue value;
|
||||
value.depth = 0.0f;
|
||||
value.stencil = 0;
|
||||
|
||||
m_context->clearDepthStencilImage(
|
||||
image, value, subresources);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
InitImage(pTexture->GetImage());
|
||||
|
||||
FlushImplicit();
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::InitHostVisibleTexture(
|
||||
D3D9CommonTexture* pTexture,
|
||||
void* pInitialData) {
|
||||
// If the buffer is mapped, we can write data directly
|
||||
// to the mapped memory region instead of doing it on
|
||||
// the GPU. Same goes for zero-initialization.
|
||||
for (uint32_t i = 0; i < pTexture->CountSubresources(); i++) {
|
||||
DxvkBufferSliceHandle mapSlice = pTexture->GetBuffer(i)->getSliceHandle();
|
||||
|
||||
if (pInitialData != nullptr) {
|
||||
std::memcpy(
|
||||
mapSlice.mapPtr,
|
||||
pInitialData,
|
||||
mapSlice.length);
|
||||
} else {
|
||||
std::memset(
|
||||
mapSlice.mapPtr, 0,
|
||||
mapSlice.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::FlushImplicit() {
|
||||
if (m_transferCommands > MaxTransferCommands
|
||||
|| m_transferMemory > MaxTransferMemory)
|
||||
FlushInternal();
|
||||
}
|
||||
|
||||
|
||||
void D3D9Initializer::FlushInternal() {
|
||||
m_context->flushCommandList();
|
||||
|
||||
m_transferCommands = 0;
|
||||
m_transferMemory = 0;
|
||||
}
|
||||
|
||||
}
|
62
src/d3d9/d3d9_initializer.h
Normal file
62
src/d3d9/d3d9_initializer.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_common_buffer.h"
|
||||
#include "d3d9_common_texture.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Resource initialization context
|
||||
*
|
||||
* Manages a context which is used for resource
|
||||
* initialization. This includes
|
||||
* zero-initialization for buffers and images.
|
||||
*/
|
||||
class D3D9Initializer {
|
||||
constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024;
|
||||
constexpr static size_t MaxTransferCommands = 512;
|
||||
public:
|
||||
|
||||
D3D9Initializer(
|
||||
const Rc<DxvkDevice>& Device);
|
||||
|
||||
~D3D9Initializer();
|
||||
|
||||
void Flush();
|
||||
|
||||
void InitBuffer(
|
||||
D3D9CommonBuffer* pBuffer);
|
||||
|
||||
void InitTexture(
|
||||
D3D9CommonTexture* pTexture,
|
||||
void* pInitialData = nullptr);
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
size_t m_transferCommands = 0;
|
||||
size_t m_transferMemory = 0;
|
||||
|
||||
void InitDeviceLocalBuffer(
|
||||
DxvkBufferSlice Slice);
|
||||
|
||||
void InitHostVisibleBuffer(
|
||||
DxvkBufferSlice Slice);
|
||||
|
||||
void InitDeviceLocalTexture(
|
||||
D3D9CommonTexture* pTexture);
|
||||
|
||||
void InitHostVisibleTexture(
|
||||
D3D9CommonTexture* pTexture,
|
||||
void* pInitialData);
|
||||
|
||||
void FlushImplicit();
|
||||
void FlushInternal();
|
||||
|
||||
};
|
||||
|
||||
}
|
316
src/d3d9/d3d9_interface.cpp
Normal file
316
src/d3d9/d3d9_interface.cpp
Normal file
|
@ -0,0 +1,316 @@
|
|||
#include "d3d9_interface.h"
|
||||
|
||||
#include "d3d9_monitor.h"
|
||||
#include "d3d9_caps.h"
|
||||
#include "d3d9_device.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9InterfaceEx::D3D9InterfaceEx(bool bExtended)
|
||||
: m_instance ( new DxvkInstance() )
|
||||
, m_extended ( bExtended )
|
||||
, m_d3d9Options ( nullptr, m_instance->config() ) {
|
||||
m_adapters.reserve(m_instance->adapterCount());
|
||||
for (uint32_t i = 0; i < m_instance->adapterCount(); i++)
|
||||
m_adapters.emplace_back(this, m_instance->enumAdapters(i), i);
|
||||
|
||||
if (m_d3d9Options.dpiAware) {
|
||||
Logger::info("Process set as DPI aware");
|
||||
SetProcessDPIAware();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3D9)
|
||||
|| (m_extended && riid == __uuidof(IDirect3D9Ex))) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9InterfaceEx::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::RegisterSoftwareDevice(void* pInitializeFunction) {
|
||||
Logger::warn("D3D9InterfaceEx::RegisterSoftwareDevice: Stub");
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterCount() {
|
||||
return UINT(m_adapters.size());
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterIdentifier(
|
||||
UINT Adapter,
|
||||
DWORD Flags,
|
||||
D3DADAPTER_IDENTIFIER9* pIdentifier) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->GetAdapterIdentifier(Flags, pIdentifier);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterModeCount(UINT Adapter, D3DFORMAT Format) {
|
||||
D3DDISPLAYMODEFILTER filter;
|
||||
filter.Size = sizeof(D3DDISPLAYMODEFILTER);
|
||||
filter.Format = Format;
|
||||
filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
|
||||
|
||||
return this->GetAdapterModeCountEx(Adapter, &filter);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode) {
|
||||
constexpr D3DFORMAT format = D3DFMT_X8R8G8B8;
|
||||
const UINT mode = GetAdapterModeCount(Adapter, format) - 1;
|
||||
|
||||
return this->EnumAdapterModes(Adapter, format, mode, pMode);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceType(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DevType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
D3DFORMAT BackBufferFormat,
|
||||
BOOL bWindowed) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->CheckDeviceType(
|
||||
DevType, EnumerateFormat(AdapterFormat),
|
||||
EnumerateFormat(BackBufferFormat), bWindowed);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceFormat(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType,
|
||||
D3DFORMAT CheckFormat) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->CheckDeviceFormat(
|
||||
DeviceType, EnumerateFormat(AdapterFormat),
|
||||
Usage, RType,
|
||||
EnumerateFormat(CheckFormat));
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceMultiSampleType(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT SurfaceFormat,
|
||||
BOOL Windowed,
|
||||
D3DMULTISAMPLE_TYPE MultiSampleType,
|
||||
DWORD* pQualityLevels) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->CheckDeviceMultiSampleType(
|
||||
DeviceType, EnumerateFormat(SurfaceFormat),
|
||||
Windowed, MultiSampleType,
|
||||
pQualityLevels);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDepthStencilMatch(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
D3DFORMAT RenderTargetFormat,
|
||||
D3DFORMAT DepthStencilFormat) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->CheckDepthStencilMatch(
|
||||
DeviceType, EnumerateFormat(AdapterFormat),
|
||||
EnumerateFormat(RenderTargetFormat),
|
||||
EnumerateFormat(DepthStencilFormat));
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CheckDeviceFormatConversion(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT SourceFormat,
|
||||
D3DFORMAT TargetFormat) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->CheckDeviceFormatConversion(
|
||||
DeviceType, EnumerateFormat(SourceFormat),
|
||||
EnumerateFormat(TargetFormat));
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetDeviceCaps(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DCAPS9* pCaps) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->GetDeviceCaps(
|
||||
DeviceType, pCaps);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HMONITOR STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterMonitor(UINT Adapter) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->GetMonitor();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CreateDevice(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
IDirect3DDevice9** ppReturnedDeviceInterface) {
|
||||
return this->CreateDeviceEx(
|
||||
Adapter,
|
||||
DeviceType,
|
||||
hFocusWindow,
|
||||
BehaviorFlags,
|
||||
pPresentationParameters,
|
||||
nullptr, // <-- pFullscreenDisplayMode
|
||||
reinterpret_cast<IDirect3DDevice9Ex**>(ppReturnedDeviceInterface));
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::EnumAdapterModes(
|
||||
UINT Adapter,
|
||||
D3DFORMAT Format,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODE* pMode) {
|
||||
if (pMode == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3DDISPLAYMODEFILTER filter;
|
||||
filter.Format = Format;
|
||||
filter.ScanLineOrdering = D3DSCANLINEORDERING_PROGRESSIVE;
|
||||
filter.Size = sizeof(D3DDISPLAYMODEFILTER);
|
||||
|
||||
D3DDISPLAYMODEEX modeEx;
|
||||
HRESULT hr = this->EnumAdapterModesEx(Adapter, &filter, Mode, &modeEx);
|
||||
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
pMode->Width = modeEx.Width;
|
||||
pMode->Height = modeEx.Height;
|
||||
pMode->RefreshRate = modeEx.RefreshRate;
|
||||
pMode->Format = modeEx.Format;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
// Ex Methods
|
||||
|
||||
|
||||
UINT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterModeCountEx(UINT Adapter, CONST D3DDISPLAYMODEFILTER* pFilter) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->GetAdapterModeCountEx(pFilter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::EnumAdapterModesEx(
|
||||
UINT Adapter,
|
||||
const D3DDISPLAYMODEFILTER* pFilter,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODEEX* pMode) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->EnumAdapterModesEx(pFilter, Mode, pMode);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterDisplayModeEx(
|
||||
UINT Adapter,
|
||||
D3DDISPLAYMODEEX* pMode,
|
||||
D3DDISPLAYROTATION* pRotation) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->GetAdapterDisplayModeEx(pMode, pRotation);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::CreateDeviceEx(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
|
||||
IDirect3DDevice9Ex** ppReturnedDeviceInterface) {
|
||||
InitReturnPtr(ppReturnedDeviceInterface);
|
||||
|
||||
if (ppReturnedDeviceInterface == nullptr
|
||||
|| pPresentationParameters == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto* adapter = GetAdapter(Adapter);
|
||||
|
||||
if (adapter == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto dxvkAdapter = adapter->GetDXVKAdapter();
|
||||
|
||||
std::string clientApi = str::format("D3D9", m_extended ? "Ex" : "");
|
||||
|
||||
try {
|
||||
auto dxvkDevice = dxvkAdapter->createDevice(m_instance, clientApi, D3D9DeviceEx::GetDeviceFeatures(dxvkAdapter));
|
||||
|
||||
*ppReturnedDeviceInterface = ref(new D3D9DeviceEx(
|
||||
this,
|
||||
adapter,
|
||||
DeviceType,
|
||||
hFocusWindow,
|
||||
BehaviorFlags,
|
||||
pPresentationParameters,
|
||||
pFullscreenDisplayMode,
|
||||
dxvkDevice));
|
||||
}
|
||||
catch (const DxvkError& e) {
|
||||
Logger::err(e.message());
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9InterfaceEx::GetAdapterLUID(UINT Adapter, LUID* pLUID) {
|
||||
if (auto* adapter = GetAdapter(Adapter))
|
||||
return adapter->GetAdapterLUID(pLUID);
|
||||
|
||||
return D3DERR_INVALIDCALL;
|
||||
}
|
||||
|
||||
}
|
148
src/d3d9/d3d9_interface.h
Normal file
148
src/d3d9/d3d9_interface.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_adapter.h"
|
||||
|
||||
#include "../dxvk/dxvk_instance.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief D3D9 interface implementation
|
||||
*
|
||||
* Implements the IDirect3DDevice9Ex interfaces
|
||||
* which provides the way to get adapters and create other objects such as \ref IDirect3DDevice9Ex.
|
||||
* similar to \ref DxgiFactory but for D3D9.
|
||||
*/
|
||||
class D3D9InterfaceEx final : public ComObjectClamp<IDirect3D9Ex> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9InterfaceEx(bool bExtended);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE RegisterSoftwareDevice(void* pInitializeFunction);
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAdapterCount();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAdapterIdentifier(
|
||||
UINT Adapter,
|
||||
DWORD Flags,
|
||||
D3DADAPTER_IDENTIFIER9* pIdentifier);
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAdapterModeCount(UINT Adapter, D3DFORMAT Format);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceType(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DevType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
D3DFORMAT BackBufferFormat,
|
||||
BOOL bWindowed);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceFormat(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
DWORD Usage,
|
||||
D3DRESOURCETYPE RType,
|
||||
D3DFORMAT CheckFormat);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceMultiSampleType(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT SurfaceFormat,
|
||||
BOOL Windowed,
|
||||
D3DMULTISAMPLE_TYPE MultiSampleType,
|
||||
DWORD* pQualityLevels);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDepthStencilMatch(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT AdapterFormat,
|
||||
D3DFORMAT RenderTargetFormat,
|
||||
D3DFORMAT DepthStencilFormat);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CheckDeviceFormatConversion(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DFORMAT SourceFormat,
|
||||
D3DFORMAT TargetFormat);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDeviceCaps(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
D3DCAPS9* pCaps);
|
||||
|
||||
HMONITOR STDMETHODCALLTYPE GetAdapterMonitor(UINT Adapter);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateDevice(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
IDirect3DDevice9** ppReturnedDeviceInterface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnumAdapterModes(
|
||||
UINT Adapter,
|
||||
D3DFORMAT Format,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODE* pMode);
|
||||
|
||||
// Ex Methods
|
||||
|
||||
UINT STDMETHODCALLTYPE GetAdapterModeCountEx(UINT Adapter, CONST D3DDISPLAYMODEFILTER* pFilter);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE EnumAdapterModesEx(
|
||||
UINT Adapter,
|
||||
const D3DDISPLAYMODEFILTER* pFilter,
|
||||
UINT Mode,
|
||||
D3DDISPLAYMODEEX* pMode);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAdapterDisplayModeEx(
|
||||
UINT Adapter,
|
||||
D3DDISPLAYMODEEX* pMode,
|
||||
D3DDISPLAYROTATION* pRotation);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE CreateDeviceEx(
|
||||
UINT Adapter,
|
||||
D3DDEVTYPE DeviceType,
|
||||
HWND hFocusWindow,
|
||||
DWORD BehaviorFlags,
|
||||
D3DPRESENT_PARAMETERS* pPresentationParameters,
|
||||
D3DDISPLAYMODEEX* pFullscreenDisplayMode,
|
||||
IDirect3DDevice9Ex** ppReturnedDeviceInterface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetAdapterLUID(UINT Adapter, LUID* pLUID);
|
||||
|
||||
const D3D9Options& GetOptions() { return m_d3d9Options; }
|
||||
|
||||
D3D9Adapter* GetAdapter(UINT Ordinal) {
|
||||
return Ordinal < m_adapters.size()
|
||||
? &m_adapters[Ordinal]
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
bool IsExtended() { return m_extended; }
|
||||
|
||||
Rc<DxvkInstance> GetInstance() { return m_instance; }
|
||||
|
||||
private:
|
||||
|
||||
void CacheModes(D3D9Format Format);
|
||||
|
||||
static const char* GetDriverDllName(DxvkGpuVendor vendor);
|
||||
|
||||
Rc<DxvkInstance> m_instance;
|
||||
|
||||
bool m_extended;
|
||||
|
||||
D3D9Options m_d3d9Options;
|
||||
|
||||
std::vector<D3D9Adapter> m_adapters;
|
||||
|
||||
};
|
||||
|
||||
}
|
86
src/d3d9/d3d9_main.cpp
Normal file
86
src/d3d9/d3d9_main.cpp
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include "../dxvk/dxvk_instance.h"
|
||||
|
||||
#include "d3d9_interface.h"
|
||||
#include "d3d9_shader_validator.h"
|
||||
|
||||
class D3DFE_PROCESSVERTICES;
|
||||
using PSGPERRORID = UINT;
|
||||
|
||||
namespace dxvk {
|
||||
Logger Logger::s_instance("d3d9.log");
|
||||
|
||||
HRESULT CreateD3D9(
|
||||
bool Extended,
|
||||
IDirect3D9Ex** ppDirect3D9Ex) {
|
||||
if (!ppDirect3D9Ex)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppDirect3D9Ex = ref(new D3D9InterfaceEx( Extended ));
|
||||
return D3D_OK;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
DLLEXPORT IDirect3D9* __stdcall Direct3DCreate9(UINT nSDKVersion) {
|
||||
IDirect3D9Ex* pDirect3D = nullptr;
|
||||
dxvk::CreateD3D9(false, &pDirect3D);
|
||||
|
||||
return pDirect3D;
|
||||
}
|
||||
|
||||
DLLEXPORT HRESULT __stdcall Direct3DCreate9Ex(UINT nSDKVersion, IDirect3D9Ex** ppDirect3D9Ex) {
|
||||
return dxvk::CreateD3D9(true, ppDirect3D9Ex);
|
||||
}
|
||||
|
||||
DLLEXPORT int __stdcall D3DPERF_BeginEvent(D3DCOLOR col, LPCWSTR wszName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DLLEXPORT int __stdcall D3DPERF_EndEvent(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall D3DPERF_SetMarker(D3DCOLOR col, LPCWSTR wszName) {
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall D3DPERF_SetRegion(D3DCOLOR col, LPCWSTR wszName) {
|
||||
}
|
||||
|
||||
DLLEXPORT BOOL __stdcall D3DPERF_QueryRepeatFrame(void) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall D3DPERF_SetOptions(DWORD dwOptions) {
|
||||
}
|
||||
|
||||
DLLEXPORT DWORD __stdcall D3DPERF_GetStatus(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
DLLEXPORT void __stdcall DebugSetMute(void) {
|
||||
}
|
||||
|
||||
DLLEXPORT int __stdcall DebugSetLevel(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Processor Specific Geometry Pipeline
|
||||
// for P3 SIMD/AMD 3DNow.
|
||||
|
||||
DLLEXPORT void __stdcall PSGPError(D3DFE_PROCESSVERTICES* a, PSGPERRORID b, UINT c) {
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall PSGPSampleTexture(D3DFE_PROCESSVERTICES* a, UINT b, float(*const c)[4], UINT d, float(*const e)[4]) {
|
||||
}
|
||||
|
||||
DLLEXPORT dxvk::D3D9ShaderValidator* __stdcall Direct3DShaderValidatorCreate9(void) {
|
||||
return ref(new dxvk::D3D9ShaderValidator());
|
||||
}
|
||||
|
||||
DLLEXPORT int __stdcall Direct3D9EnableMaximizedWindowedModeShim(UINT a) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
175
src/d3d9/d3d9_monitor.cpp
Normal file
175
src/d3d9/d3d9_monitor.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include "d3d9_monitor.h"
|
||||
|
||||
#include "d3d9_format.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
uint32_t GetMonitorFormatBpp(D3D9Format Format) {
|
||||
switch (Format) {
|
||||
case D3D9Format::A8R8G8B8:
|
||||
case D3D9Format::X8R8G8B8: // This is still 32 bit even though the alpha is unspecified.
|
||||
case D3D9Format::A2R10G10B10:
|
||||
return 32;
|
||||
|
||||
case D3D9Format::A1R5G5B5:
|
||||
case D3D9Format::X1R5G5B5:
|
||||
case D3D9Format::R5G6B5:
|
||||
return 16;
|
||||
|
||||
default:
|
||||
Logger::warn(str::format(
|
||||
"GetMonitorFormatBpp: Unknown format: ",
|
||||
Format));
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool IsSupportedAdapterFormat(
|
||||
D3D9Format Format) {
|
||||
return Format == D3D9Format::A2R10G10B10
|
||||
|| Format == D3D9Format::X8R8G8B8
|
||||
|| Format == D3D9Format::A8R8G8B8
|
||||
|| Format == D3D9Format::X1R5G5B5
|
||||
|| Format == D3D9Format::A1R5G5B5
|
||||
|| Format == D3D9Format::R5G6B5;
|
||||
}
|
||||
|
||||
|
||||
bool IsSupportedDisplayFormat(
|
||||
D3D9Format Format,
|
||||
BOOL Windowed) {
|
||||
return (Format == D3D9Format::A2R10G10B10 && !Windowed)
|
||||
|| Format == D3D9Format::X8R8G8B8
|
||||
|| Format == D3D9Format::X1R5G5B5
|
||||
|| Format == D3D9Format::R5G6B5;
|
||||
}
|
||||
|
||||
|
||||
bool IsSupportedBackBufferFormat(
|
||||
D3D9Format AdapterFormat,
|
||||
D3D9Format BackBufferFormat,
|
||||
BOOL Windowed) {
|
||||
if (!IsSupportedAdapterFormat(AdapterFormat))
|
||||
return false;
|
||||
|
||||
if (AdapterFormat == D3D9Format::A2R10G10B10 && Windowed)
|
||||
return false;
|
||||
|
||||
return AdapterFormat == BackBufferFormat
|
||||
|| (AdapterFormat == D3D9Format::X8R8G8B8 && BackBufferFormat == D3D9Format::A8R8G8B8)
|
||||
|| (AdapterFormat == D3D9Format::X1R5G5B5 && BackBufferFormat == D3D9Format::A1R5G5B5);
|
||||
}
|
||||
|
||||
|
||||
bool IsSupportedBackBufferFormat(
|
||||
D3D9Format BackBufferFormat,
|
||||
BOOL Windowed) {
|
||||
return (BackBufferFormat == D3D9Format::A2R10G10B10 && !Windowed)
|
||||
|| BackBufferFormat == D3D9Format::A8R8G8B8
|
||||
|| BackBufferFormat == D3D9Format::X8R8G8B8
|
||||
|| BackBufferFormat == D3D9Format::A1R5G5B5
|
||||
|| BackBufferFormat == D3D9Format::X1R5G5B5
|
||||
|| BackBufferFormat == D3D9Format::R5G6B5;
|
||||
}
|
||||
|
||||
|
||||
HMONITOR GetDefaultMonitor() {
|
||||
return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
|
||||
}
|
||||
|
||||
|
||||
HRESULT SetMonitorDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
const D3DDISPLAYMODEEX* pMode) {
|
||||
::MONITORINFOEXW monInfo;
|
||||
monInfo.cbSize = sizeof(monInfo);
|
||||
|
||||
if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
|
||||
Logger::err("D3D9: Failed to query monitor info");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
DEVMODEW devMode = { };
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
|
||||
devMode.dmPelsWidth = pMode->Width;
|
||||
devMode.dmPelsHeight = pMode->Height;
|
||||
devMode.dmBitsPerPel = GetMonitorFormatBpp(EnumerateFormat(pMode->Format));
|
||||
|
||||
if (pMode->RefreshRate != 0) {
|
||||
devMode.dmFields |= DM_DISPLAYFREQUENCY;
|
||||
devMode.dmDisplayFrequency = pMode->RefreshRate;
|
||||
}
|
||||
|
||||
Logger::info(str::format("D3D9: Setting display mode: ",
|
||||
devMode.dmPelsWidth, "x", devMode.dmPelsHeight, "@",
|
||||
devMode.dmDisplayFrequency));
|
||||
|
||||
LONG status = ::ChangeDisplaySettingsExW(
|
||||
monInfo.szDevice, &devMode, nullptr, CDS_FULLSCREEN, nullptr);
|
||||
|
||||
if (status != DISP_CHANGE_SUCCESSFUL) {
|
||||
// Try again but without setting the frequency.
|
||||
devMode.dmFields &= ~DM_DISPLAYFREQUENCY;
|
||||
devMode.dmDisplayFrequency = 0;
|
||||
status = ::ChangeDisplaySettingsExW(
|
||||
monInfo.szDevice, &devMode, nullptr, CDS_FULLSCREEN, nullptr);
|
||||
}
|
||||
|
||||
return status == DISP_CHANGE_SUCCESSFUL ? D3D_OK : D3DERR_NOTAVAILABLE;
|
||||
}
|
||||
|
||||
|
||||
void GetWindowClientSize(
|
||||
HWND hWnd,
|
||||
UINT* pWidth,
|
||||
UINT* pHeight) {
|
||||
RECT rect = { };
|
||||
::GetClientRect(hWnd, &rect);
|
||||
|
||||
if (pWidth)
|
||||
*pWidth = rect.right - rect.left;
|
||||
|
||||
if (pHeight)
|
||||
*pHeight = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
|
||||
void GetMonitorClientSize(
|
||||
HMONITOR hMonitor,
|
||||
UINT* pWidth,
|
||||
UINT* pHeight) {
|
||||
::MONITORINFOEXW monInfo;
|
||||
monInfo.cbSize = sizeof(monInfo);
|
||||
|
||||
if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
|
||||
Logger::err("D3D9: Failed to query monitor info");
|
||||
return;
|
||||
}
|
||||
|
||||
auto rect = monInfo.rcMonitor;
|
||||
|
||||
if (pWidth)
|
||||
*pWidth = rect.right - rect.left;
|
||||
|
||||
if (pHeight)
|
||||
*pHeight = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
|
||||
void GetMonitorRect(
|
||||
HMONITOR hMonitor,
|
||||
RECT* pRect) {
|
||||
::MONITORINFOEXW monInfo;
|
||||
monInfo.cbSize = sizeof(monInfo);
|
||||
|
||||
if (!::GetMonitorInfoW(hMonitor, reinterpret_cast<MONITORINFO*>(&monInfo))) {
|
||||
Logger::err("D3D9: Failed to query monitor info");
|
||||
return;
|
||||
}
|
||||
|
||||
*pRect = monInfo.rcMonitor;
|
||||
}
|
||||
|
||||
}
|
88
src/d3d9/d3d9_monitor.h
Normal file
88
src/d3d9/d3d9_monitor.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
#include "d3d9_format.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Queries bits per pixel for a format
|
||||
*
|
||||
* The format must be a valid swap chain format.
|
||||
* \param [in] Format The D3D9 format to query
|
||||
* \returns Bits per pixel for this format
|
||||
*/
|
||||
uint32_t GetMonitorFormatBpp(
|
||||
D3D9Format Format);
|
||||
|
||||
/**
|
||||
* \brief Returns if a format is supported for a backbuffer/swapchain.
|
||||
*
|
||||
* \param [in] Format The D3D9 format to query
|
||||
* \returns If it is supported as a swapchain/backbuffer format.
|
||||
*/
|
||||
bool IsSupportedAdapterFormat(
|
||||
D3D9Format Format);
|
||||
|
||||
bool IsSupportedDisplayFormat(
|
||||
D3D9Format Format,
|
||||
BOOL Windowed);
|
||||
|
||||
bool IsSupportedBackBufferFormat(
|
||||
D3D9Format AdapterFormat,
|
||||
D3D9Format BackBufferFormat,
|
||||
BOOL Windowed);
|
||||
|
||||
bool IsSupportedBackBufferFormat(
|
||||
D3D9Format BackBufferFormat,
|
||||
BOOL Windowed);
|
||||
|
||||
HMONITOR GetDefaultMonitor();
|
||||
|
||||
/**
|
||||
* \brief Sets monitor display mode
|
||||
*
|
||||
* \param [in] hMonitor Monitor handle
|
||||
* \param [in] pMode Display mode properties
|
||||
* \returns S_OK on success
|
||||
*/
|
||||
HRESULT SetMonitorDisplayMode(
|
||||
HMONITOR hMonitor,
|
||||
const D3DDISPLAYMODEEX* pMode);
|
||||
|
||||
/**
|
||||
* \brief Queries window client size
|
||||
*
|
||||
* \param [in] hWnd Window to query
|
||||
* \param [out] pWidth Client width
|
||||
* \param [out] pHeight Client height
|
||||
*/
|
||||
void GetWindowClientSize(
|
||||
HWND hWnd,
|
||||
UINT* pWidth,
|
||||
UINT* pHeight);
|
||||
|
||||
/**
|
||||
* \brief Queries monitor size
|
||||
*
|
||||
* \param [in] hMonitor Monitor to query
|
||||
* \param [out] pWidth Client width
|
||||
* \param [out] pHeight Client height
|
||||
*/
|
||||
void GetMonitorClientSize(
|
||||
HMONITOR hMonitor,
|
||||
UINT* pWidth,
|
||||
UINT* pHeight);
|
||||
|
||||
/**
|
||||
* \brief Queries monitor rect
|
||||
*
|
||||
* \param [in] hMonitor Monitor to query
|
||||
* \param [out] pRect The rect to return
|
||||
*/
|
||||
void GetMonitorRect(
|
||||
HMONITOR hMonitor,
|
||||
RECT* pRect);
|
||||
|
||||
}
|
41
src/d3d9/d3d9_multithread.cpp
Normal file
41
src/d3d9/d3d9_multithread.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "d3d9_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
void D3D9DeviceMutex::lock() {
|
||||
while (!try_lock())
|
||||
dxvk::this_thread::yield();
|
||||
}
|
||||
|
||||
|
||||
void D3D9DeviceMutex::unlock() {
|
||||
if (likely(m_counter == 0))
|
||||
m_owner.store(0, std::memory_order_release);
|
||||
else
|
||||
m_counter -= 1;
|
||||
}
|
||||
|
||||
|
||||
bool D3D9DeviceMutex::try_lock() {
|
||||
uint32_t threadId = GetCurrentThreadId();
|
||||
uint32_t expected = 0;
|
||||
|
||||
bool status = m_owner.compare_exchange_weak(
|
||||
expected, threadId, std::memory_order_acquire);
|
||||
|
||||
if (status)
|
||||
return true;
|
||||
|
||||
if (expected != threadId)
|
||||
return false;
|
||||
|
||||
m_counter += 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
D3D9Multithread::D3D9Multithread(
|
||||
BOOL Protected)
|
||||
: m_protected( Protected ) { }
|
||||
|
||||
}
|
101
src/d3d9/d3d9_multithread.h
Normal file
101
src/d3d9/d3d9_multithread.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Device mutex
|
||||
*
|
||||
* Effectively implements a recursive spinlock
|
||||
* which is used to lock the D3D9 device.
|
||||
*/
|
||||
class D3D9DeviceMutex {
|
||||
|
||||
public:
|
||||
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
bool try_lock();
|
||||
|
||||
private:
|
||||
|
||||
std::atomic<uint32_t> m_owner = { 0u };
|
||||
uint32_t m_counter = { 0u };
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Device lock
|
||||
*
|
||||
* Lightweight RAII wrapper that implements
|
||||
* a subset of the functionality provided by
|
||||
* \c std::unique_lock, with the goal of being
|
||||
* cheaper to construct and destroy.
|
||||
*/
|
||||
class D3D9DeviceLock {
|
||||
|
||||
public:
|
||||
|
||||
D3D9DeviceLock()
|
||||
: m_mutex(nullptr) { }
|
||||
|
||||
D3D9DeviceLock(D3D9DeviceMutex& mutex)
|
||||
: m_mutex(&mutex) {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
D3D9DeviceLock(D3D9DeviceLock&& other)
|
||||
: m_mutex(other.m_mutex) {
|
||||
other.m_mutex = nullptr;
|
||||
}
|
||||
|
||||
D3D9DeviceLock& operator = (D3D9DeviceLock&& other) {
|
||||
if (m_mutex)
|
||||
m_mutex->unlock();
|
||||
|
||||
m_mutex = other.m_mutex;
|
||||
other.m_mutex = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~D3D9DeviceLock() {
|
||||
if (m_mutex != nullptr)
|
||||
m_mutex->unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D9DeviceMutex* m_mutex;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief D3D9 context lock
|
||||
*/
|
||||
class D3D9Multithread {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Multithread(
|
||||
BOOL Protected);
|
||||
|
||||
D3D9DeviceLock AcquireLock() {
|
||||
return m_protected
|
||||
? D3D9DeviceLock(m_mutex)
|
||||
: D3D9DeviceLock();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_protected;
|
||||
|
||||
D3D9DeviceMutex m_mutex;
|
||||
|
||||
};
|
||||
|
||||
}
|
230
src/d3d9/d3d9_names.cpp
Normal file
230
src/d3d9/d3d9_names.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
#include "d3d9_format.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
std::ostream& operator << (std::ostream& os, D3D9Format e) {
|
||||
switch (e) {
|
||||
ENUM_NAME(D3D9Format::Unknown);
|
||||
|
||||
ENUM_NAME(D3D9Format::R8G8B8);
|
||||
ENUM_NAME(D3D9Format::A8R8G8B8);
|
||||
ENUM_NAME(D3D9Format::X8R8G8B8);
|
||||
ENUM_NAME(D3D9Format::R5G6B5);
|
||||
ENUM_NAME(D3D9Format::X1R5G5B5);
|
||||
ENUM_NAME(D3D9Format::A1R5G5B5);
|
||||
ENUM_NAME(D3D9Format::A4R4G4B4);
|
||||
ENUM_NAME(D3D9Format::R3G3B2);
|
||||
ENUM_NAME(D3D9Format::A8);
|
||||
ENUM_NAME(D3D9Format::A8R3G3B2);
|
||||
ENUM_NAME(D3D9Format::X4R4G4B4);
|
||||
ENUM_NAME(D3D9Format::A2B10G10R10);
|
||||
ENUM_NAME(D3D9Format::A8B8G8R8);
|
||||
ENUM_NAME(D3D9Format::X8B8G8R8);
|
||||
ENUM_NAME(D3D9Format::G16R16);
|
||||
ENUM_NAME(D3D9Format::A2R10G10B10);
|
||||
ENUM_NAME(D3D9Format::A16B16G16R16);
|
||||
ENUM_NAME(D3D9Format::A8P8);
|
||||
ENUM_NAME(D3D9Format::P8);
|
||||
ENUM_NAME(D3D9Format::L8);
|
||||
ENUM_NAME(D3D9Format::A8L8);
|
||||
ENUM_NAME(D3D9Format::A4L4);
|
||||
ENUM_NAME(D3D9Format::V8U8);
|
||||
ENUM_NAME(D3D9Format::L6V5U5);
|
||||
ENUM_NAME(D3D9Format::X8L8V8U8);
|
||||
ENUM_NAME(D3D9Format::Q8W8V8U8);
|
||||
ENUM_NAME(D3D9Format::V16U16);
|
||||
ENUM_NAME(D3D9Format::A2W10V10U10);
|
||||
ENUM_NAME(D3D9Format::UYVY);
|
||||
ENUM_NAME(D3D9Format::R8G8_B8G8);
|
||||
ENUM_NAME(D3D9Format::YUY2);
|
||||
ENUM_NAME(D3D9Format::G8R8_G8B8);
|
||||
ENUM_NAME(D3D9Format::DXT1);
|
||||
ENUM_NAME(D3D9Format::DXT2);
|
||||
ENUM_NAME(D3D9Format::DXT3);
|
||||
ENUM_NAME(D3D9Format::DXT4);
|
||||
ENUM_NAME(D3D9Format::DXT5);
|
||||
ENUM_NAME(D3D9Format::D16_LOCKABLE);
|
||||
ENUM_NAME(D3D9Format::D32);
|
||||
ENUM_NAME(D3D9Format::D15S1);
|
||||
ENUM_NAME(D3D9Format::D24S8);
|
||||
ENUM_NAME(D3D9Format::D24X8);
|
||||
ENUM_NAME(D3D9Format::D24X4S4);
|
||||
ENUM_NAME(D3D9Format::D16);
|
||||
ENUM_NAME(D3D9Format::D32F_LOCKABLE);
|
||||
ENUM_NAME(D3D9Format::D24FS8);
|
||||
ENUM_NAME(D3D9Format::D32_LOCKABLE);
|
||||
ENUM_NAME(D3D9Format::S8_LOCKABLE);
|
||||
ENUM_NAME(D3D9Format::L16);
|
||||
ENUM_NAME(D3D9Format::VERTEXDATA);
|
||||
ENUM_NAME(D3D9Format::INDEX16);
|
||||
ENUM_NAME(D3D9Format::INDEX32);
|
||||
ENUM_NAME(D3D9Format::Q16W16V16U16);
|
||||
ENUM_NAME(D3D9Format::MULTI2_ARGB8);
|
||||
ENUM_NAME(D3D9Format::R16F);
|
||||
ENUM_NAME(D3D9Format::G16R16F);
|
||||
ENUM_NAME(D3D9Format::A16B16G16R16F);
|
||||
ENUM_NAME(D3D9Format::R32F);
|
||||
ENUM_NAME(D3D9Format::G32R32F);
|
||||
ENUM_NAME(D3D9Format::A32B32G32R32F);
|
||||
ENUM_NAME(D3D9Format::CxV8U8);
|
||||
ENUM_NAME(D3D9Format::A1);
|
||||
ENUM_NAME(D3D9Format::A2B10G10R10_XR_BIAS);
|
||||
ENUM_NAME(D3D9Format::BINARYBUFFER);
|
||||
|
||||
// Driver Hacks / Unofficial Formats
|
||||
ENUM_NAME(D3D9Format::ATI1);
|
||||
ENUM_NAME(D3D9Format::ATI2);
|
||||
ENUM_NAME(D3D9Format::INST);
|
||||
ENUM_NAME(D3D9Format::DF24);
|
||||
ENUM_NAME(D3D9Format::DF16);
|
||||
ENUM_NAME(D3D9Format::NULL_FORMAT);
|
||||
ENUM_NAME(D3D9Format::GET4);
|
||||
ENUM_NAME(D3D9Format::GET1);
|
||||
ENUM_NAME(D3D9Format::NVDB);
|
||||
ENUM_NAME(D3D9Format::A2M1);
|
||||
ENUM_NAME(D3D9Format::A2M0);
|
||||
ENUM_NAME(D3D9Format::ATOC);
|
||||
ENUM_NAME(D3D9Format::INTZ);
|
||||
ENUM_NAME(D3D9Format::RAWZ);
|
||||
ENUM_NAME(D3D9Format::RESZ);
|
||||
|
||||
ENUM_NAME(D3D9Format::NV11);
|
||||
ENUM_NAME(D3D9Format::NV12);
|
||||
ENUM_NAME(D3D9Format::P010);
|
||||
ENUM_NAME(D3D9Format::P016);
|
||||
ENUM_NAME(D3D9Format::Y210);
|
||||
ENUM_NAME(D3D9Format::Y216);
|
||||
ENUM_NAME(D3D9Format::Y410);
|
||||
ENUM_NAME(D3D9Format::AYUV);
|
||||
ENUM_NAME(D3D9Format::YV12);
|
||||
ENUM_NAME(D3D9Format::OPAQUE_420);
|
||||
|
||||
ENUM_NAME(D3D9Format::AI44);
|
||||
ENUM_NAME(D3D9Format::IA44);
|
||||
ENUM_NAME(D3D9Format::R2VB);
|
||||
ENUM_NAME(D3D9Format::COPM);
|
||||
ENUM_NAME(D3D9Format::SSAA);
|
||||
ENUM_NAME(D3D9Format::AL16);
|
||||
ENUM_NAME(D3D9Format::R16);
|
||||
|
||||
ENUM_NAME(D3D9Format::EXT1);
|
||||
ENUM_NAME(D3D9Format::FXT1);
|
||||
ENUM_NAME(D3D9Format::GXT1);
|
||||
ENUM_NAME(D3D9Format::HXT1);
|
||||
|
||||
ENUM_DEFAULT(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator << (std::ostream& os, D3DRENDERSTATETYPE e) {
|
||||
switch (e) {
|
||||
ENUM_NAME(D3DRS_ZENABLE);
|
||||
ENUM_NAME(D3DRS_FILLMODE);
|
||||
ENUM_NAME(D3DRS_SHADEMODE);
|
||||
ENUM_NAME(D3DRS_ZWRITEENABLE);
|
||||
ENUM_NAME(D3DRS_ALPHATESTENABLE);
|
||||
ENUM_NAME(D3DRS_LASTPIXEL);
|
||||
ENUM_NAME(D3DRS_SRCBLEND);
|
||||
ENUM_NAME(D3DRS_DESTBLEND);
|
||||
ENUM_NAME(D3DRS_CULLMODE);
|
||||
ENUM_NAME(D3DRS_ZFUNC);
|
||||
ENUM_NAME(D3DRS_ALPHAREF);
|
||||
ENUM_NAME(D3DRS_ALPHAFUNC);
|
||||
ENUM_NAME(D3DRS_DITHERENABLE);
|
||||
ENUM_NAME(D3DRS_ALPHABLENDENABLE);
|
||||
ENUM_NAME(D3DRS_FOGENABLE);
|
||||
ENUM_NAME(D3DRS_SPECULARENABLE);
|
||||
ENUM_NAME(D3DRS_FOGCOLOR);
|
||||
ENUM_NAME(D3DRS_FOGTABLEMODE);
|
||||
ENUM_NAME(D3DRS_FOGSTART);
|
||||
ENUM_NAME(D3DRS_FOGEND);
|
||||
ENUM_NAME(D3DRS_FOGDENSITY);
|
||||
ENUM_NAME(D3DRS_RANGEFOGENABLE);
|
||||
ENUM_NAME(D3DRS_STENCILENABLE);
|
||||
ENUM_NAME(D3DRS_STENCILFAIL);
|
||||
ENUM_NAME(D3DRS_STENCILZFAIL);
|
||||
ENUM_NAME(D3DRS_STENCILPASS);
|
||||
ENUM_NAME(D3DRS_STENCILFUNC);
|
||||
ENUM_NAME(D3DRS_STENCILREF);
|
||||
ENUM_NAME(D3DRS_STENCILMASK);
|
||||
ENUM_NAME(D3DRS_STENCILWRITEMASK);
|
||||
ENUM_NAME(D3DRS_TEXTUREFACTOR);
|
||||
ENUM_NAME(D3DRS_WRAP0);
|
||||
ENUM_NAME(D3DRS_WRAP1);
|
||||
ENUM_NAME(D3DRS_WRAP2);
|
||||
ENUM_NAME(D3DRS_WRAP3);
|
||||
ENUM_NAME(D3DRS_WRAP4);
|
||||
ENUM_NAME(D3DRS_WRAP5);
|
||||
ENUM_NAME(D3DRS_WRAP6);
|
||||
ENUM_NAME(D3DRS_WRAP7);
|
||||
ENUM_NAME(D3DRS_CLIPPING);
|
||||
ENUM_NAME(D3DRS_LIGHTING);
|
||||
ENUM_NAME(D3DRS_AMBIENT);
|
||||
ENUM_NAME(D3DRS_FOGVERTEXMODE);
|
||||
ENUM_NAME(D3DRS_COLORVERTEX);
|
||||
ENUM_NAME(D3DRS_LOCALVIEWER);
|
||||
ENUM_NAME(D3DRS_NORMALIZENORMALS);
|
||||
ENUM_NAME(D3DRS_DIFFUSEMATERIALSOURCE);
|
||||
ENUM_NAME(D3DRS_SPECULARMATERIALSOURCE);
|
||||
ENUM_NAME(D3DRS_AMBIENTMATERIALSOURCE);
|
||||
ENUM_NAME(D3DRS_EMISSIVEMATERIALSOURCE);
|
||||
ENUM_NAME(D3DRS_VERTEXBLEND);
|
||||
ENUM_NAME(D3DRS_CLIPPLANEENABLE);
|
||||
ENUM_NAME(D3DRS_POINTSIZE);
|
||||
ENUM_NAME(D3DRS_POINTSIZE_MIN);
|
||||
ENUM_NAME(D3DRS_POINTSPRITEENABLE);
|
||||
ENUM_NAME(D3DRS_POINTSCALEENABLE);
|
||||
ENUM_NAME(D3DRS_POINTSCALE_A);
|
||||
ENUM_NAME(D3DRS_POINTSCALE_B);
|
||||
ENUM_NAME(D3DRS_POINTSCALE_C);
|
||||
ENUM_NAME(D3DRS_MULTISAMPLEANTIALIAS);
|
||||
ENUM_NAME(D3DRS_MULTISAMPLEMASK);
|
||||
ENUM_NAME(D3DRS_PATCHEDGESTYLE);
|
||||
ENUM_NAME(D3DRS_DEBUGMONITORTOKEN);
|
||||
ENUM_NAME(D3DRS_POINTSIZE_MAX);
|
||||
ENUM_NAME(D3DRS_INDEXEDVERTEXBLENDENABLE);
|
||||
ENUM_NAME(D3DRS_COLORWRITEENABLE);
|
||||
ENUM_NAME(D3DRS_TWEENFACTOR);
|
||||
ENUM_NAME(D3DRS_BLENDOP);
|
||||
ENUM_NAME(D3DRS_POSITIONDEGREE);
|
||||
ENUM_NAME(D3DRS_NORMALDEGREE);
|
||||
ENUM_NAME(D3DRS_SCISSORTESTENABLE);
|
||||
ENUM_NAME(D3DRS_SLOPESCALEDEPTHBIAS);
|
||||
ENUM_NAME(D3DRS_ANTIALIASEDLINEENABLE);
|
||||
ENUM_NAME(D3DRS_MINTESSELLATIONLEVEL);
|
||||
ENUM_NAME(D3DRS_MAXTESSELLATIONLEVEL);
|
||||
ENUM_NAME(D3DRS_ADAPTIVETESS_X);
|
||||
ENUM_NAME(D3DRS_ADAPTIVETESS_Y);
|
||||
ENUM_NAME(D3DRS_ADAPTIVETESS_Z);
|
||||
ENUM_NAME(D3DRS_ADAPTIVETESS_W);
|
||||
ENUM_NAME(D3DRS_ENABLEADAPTIVETESSELLATION);
|
||||
ENUM_NAME(D3DRS_TWOSIDEDSTENCILMODE);
|
||||
ENUM_NAME(D3DRS_CCW_STENCILFAIL);
|
||||
ENUM_NAME(D3DRS_CCW_STENCILZFAIL);
|
||||
ENUM_NAME(D3DRS_CCW_STENCILPASS);
|
||||
ENUM_NAME(D3DRS_CCW_STENCILFUNC);
|
||||
ENUM_NAME(D3DRS_COLORWRITEENABLE1);
|
||||
ENUM_NAME(D3DRS_COLORWRITEENABLE2);
|
||||
ENUM_NAME(D3DRS_COLORWRITEENABLE3);
|
||||
ENUM_NAME(D3DRS_BLENDFACTOR);
|
||||
ENUM_NAME(D3DRS_SRGBWRITEENABLE);
|
||||
ENUM_NAME(D3DRS_DEPTHBIAS);
|
||||
ENUM_NAME(D3DRS_WRAP8);
|
||||
ENUM_NAME(D3DRS_WRAP9);
|
||||
ENUM_NAME(D3DRS_WRAP10);
|
||||
ENUM_NAME(D3DRS_WRAP11);
|
||||
ENUM_NAME(D3DRS_WRAP12);
|
||||
ENUM_NAME(D3DRS_WRAP13);
|
||||
ENUM_NAME(D3DRS_WRAP14);
|
||||
ENUM_NAME(D3DRS_WRAP15);
|
||||
ENUM_NAME(D3DRS_SEPARATEALPHABLENDENABLE);
|
||||
ENUM_NAME(D3DRS_SRCBLENDALPHA);
|
||||
ENUM_NAME(D3DRS_DESTBLENDALPHA);
|
||||
ENUM_NAME(D3DRS_BLENDOPALPHA);
|
||||
|
||||
ENUM_DEFAULT(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
7
src/d3d9/d3d9_names.h
Normal file
7
src/d3d9/d3d9_names.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
std::ostream& operator << (std::ostream& os, D3DRENDERSTATETYPE e);
|
||||
|
||||
}
|
76
src/d3d9/d3d9_options.cpp
Normal file
76
src/d3d9/d3d9_options.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
#include "d3d9_options.h"
|
||||
|
||||
#include "d3d9_caps.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
static int32_t parsePciId(const std::string& str) {
|
||||
if (str.size() != 4)
|
||||
return -1;
|
||||
|
||||
int32_t id = 0;
|
||||
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
id *= 16;
|
||||
|
||||
if (str[i] >= '0' && str[i] <= '9')
|
||||
id += str[i] - '0';
|
||||
else if (str[i] >= 'A' && str[i] <= 'F')
|
||||
id += str[i] - 'A' + 10;
|
||||
else if (str[i] >= 'a' && str[i] <= 'f')
|
||||
id += str[i] - 'a' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
D3D9Options::D3D9Options(const Rc<DxvkDevice>& device, const Config& config) {
|
||||
const Rc<DxvkAdapter> adapter = device != nullptr ? device->adapter() : nullptr;
|
||||
|
||||
// Fetch these as a string representing a hexadecimal number and parse it.
|
||||
this->customVendorId = parsePciId(config.getOption<std::string>("d3d9.customVendorId"));
|
||||
this->customDeviceId = parsePciId(config.getOption<std::string>("d3d9.customDeviceId"));
|
||||
this->customDeviceDesc = config.getOption<std::string>("d3d9.customDeviceDesc");
|
||||
|
||||
const int32_t vendorId = this->customDeviceId != -1 ? this->customDeviceId : (adapter != nullptr ? adapter->deviceProperties().vendorID : 0);
|
||||
|
||||
this->maxFrameLatency = config.getOption<int32_t> ("d3d9.maxFrameLatency", 0);
|
||||
this->presentInterval = config.getOption<int32_t> ("d3d9.presentInterval", -1);
|
||||
this->shaderModel = config.getOption<int32_t> ("d3d9.shaderModel", 3);
|
||||
this->evictManagedOnUnlock = config.getOption<bool> ("d3d9.evictManagedOnUnlock", false);
|
||||
this->dpiAware = config.getOption<bool> ("d3d9.dpiAware", true);
|
||||
this->allowLockFlagReadonly = config.getOption<bool> ("d3d9.allowLockFlagReadonly", true);
|
||||
this->strictConstantCopies = config.getOption<bool> ("d3d9.strictConstantCopies", false);
|
||||
this->strictPow = config.getOption<bool> ("d3d9.strictPow", true);
|
||||
this->lenientClear = config.getOption<bool> ("d3d9.lenientClear", false);
|
||||
this->numBackBuffers = config.getOption<int32_t> ("d3d9.numBackBuffers", 0);
|
||||
this->deferSurfaceCreation = config.getOption<bool> ("d3d9.deferSurfaceCreation", false);
|
||||
this->samplerAnisotropy = config.getOption<int32_t> ("d3d9.samplerAnisotropy", -1);
|
||||
this->maxAvailableMemory = config.getOption<int32_t> ("d3d9.maxAvailableMemory", 4096);
|
||||
this->supportDFFormats = config.getOption<bool> ("d3d9.supportDFFormats", true);
|
||||
this->supportX4R4G4B4 = config.getOption<bool> ("d3d9.supportX4R4G4B4", true);
|
||||
this->supportD32 = config.getOption<bool> ("d3d9.supportD32", true);
|
||||
this->swvpFloatCount = config.getOption<int32_t> ("d3d9.swvpFloatCount", caps::MaxFloatConstantsSoftware);
|
||||
this->swvpIntCount = config.getOption<int32_t> ("d3d9.swvpIntCount", caps::MaxOtherConstantsSoftware);
|
||||
this->swvpBoolCount = config.getOption<int32_t> ("d3d9.swvpBoolCount", caps::MaxOtherConstantsSoftware);
|
||||
this->disableA8RT = config.getOption<bool> ("d3d9.disableA8RT", false);
|
||||
this->invariantPosition = config.getOption<bool> ("d3d9.invariantPosition", false);
|
||||
this->memoryTrackTest = config.getOption<bool> ("d3d9.memoryTrackTest", false);
|
||||
this->supportVCache = config.getOption<bool> ("d3d9.supportVCache", vendorId == 0x10de);
|
||||
this->enableDialogMode = config.getOption<bool> ("d3d9.enableDialogMode", false);
|
||||
|
||||
this->forceAspectRatio = config.getOption<std::string>("d3d9.forceAspectRatio", "");
|
||||
|
||||
// If we are not Nvidia, enable general hazards.
|
||||
this->generalHazards = adapter == nullptr || !adapter->matchesDriver(DxvkGpuVendor::Nvidia, VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR, 0, 0);
|
||||
applyTristate(this->generalHazards, config.getOption<Tristate>("d3d9.generalHazards", Tristate::Auto));
|
||||
|
||||
this->d3d9FloatEmulation = true; // <-- Future Extension?
|
||||
|
||||
applyTristate(this->d3d9FloatEmulation, config.getOption<Tristate>("d3d9.floatEmulation", Tristate::Auto));
|
||||
}
|
||||
|
||||
}
|
117
src/d3d9/d3d9_options.h
Normal file
117
src/d3d9/d3d9_options.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
#pragma once
|
||||
|
||||
#include "../util/config/config.h"
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D9Options {
|
||||
|
||||
D3D9Options(const Rc<DxvkDevice>& device, const Config& config);
|
||||
|
||||
/// Override PCI vendor and device IDs reported to the
|
||||
/// application. This may make apps think they are running
|
||||
/// on a different GPU than they do and behave differently.
|
||||
int32_t customVendorId;
|
||||
int32_t customDeviceId;
|
||||
std::string customDeviceDesc;
|
||||
|
||||
/// Present interval. Overrides the value
|
||||
/// in D3DPRESENT_PARAMS used in swapchain present.
|
||||
int32_t presentInterval;
|
||||
|
||||
/// Override maximum frame latency if the app specifies
|
||||
/// a higher value. May help with frame timing issues.
|
||||
int32_t maxFrameLatency;
|
||||
|
||||
/// Set the max shader model the device can support in the caps.
|
||||
int32_t shaderModel;
|
||||
|
||||
/// Whether or not managed resources should stay in memory until unlock, or until manually evicted.
|
||||
bool evictManagedOnUnlock;
|
||||
|
||||
/// Whether or not to set the process as DPI aware in Windows when the API interface is created.
|
||||
bool dpiAware;
|
||||
|
||||
/// Handle D3DLOCK_READONLY properly.
|
||||
///
|
||||
/// Risen 1 writes to buffers mapped with readonly.
|
||||
bool allowLockFlagReadonly;
|
||||
|
||||
/// True: Copy our constant set into UBO if we are relative indexing ever.
|
||||
/// False: Copy our constant set into UBO if we are relative indexing at the start of a defined constant
|
||||
/// Why?: In theory, FXC should never generate code where this would be an issue.
|
||||
bool strictConstantCopies;
|
||||
|
||||
/// Whether or not we should care about pow(0, 0) = 1
|
||||
bool strictPow;
|
||||
|
||||
/// Whether or not to do a fast path clear if we're close enough to the whole render target.
|
||||
bool lenientClear;
|
||||
|
||||
/// Back buffer count for the Vulkan swap chain.
|
||||
/// Overrides buffer count in present parameters.
|
||||
int32_t numBackBuffers;
|
||||
|
||||
/// Defer surface creation
|
||||
bool deferSurfaceCreation;
|
||||
|
||||
/// Whether to transition to general
|
||||
/// for rendering hazards
|
||||
bool generalHazards;
|
||||
|
||||
/// Anisotropic filter override
|
||||
///
|
||||
/// Enforces anisotropic filtering with the
|
||||
/// given anisotropy value for all samplers.
|
||||
int32_t samplerAnisotropy;
|
||||
|
||||
/// Max available memory override
|
||||
///
|
||||
/// Changes the max initial value used in
|
||||
/// tracking and GetAvailableTextureMem
|
||||
uint32_t maxAvailableMemory;
|
||||
|
||||
/// D3D9 Floating Point Emulation (anything * 0 = 0)
|
||||
bool d3d9FloatEmulation;
|
||||
|
||||
/// Support the DF16 & DF24 texture format
|
||||
bool supportDFFormats;
|
||||
|
||||
/// Support X4R4G4B4
|
||||
bool supportX4R4G4B4;
|
||||
|
||||
/// Support D32
|
||||
bool supportD32;
|
||||
|
||||
/// SWVP Constant Limits
|
||||
int32_t swvpFloatCount;
|
||||
int32_t swvpIntCount;
|
||||
int32_t swvpBoolCount;
|
||||
|
||||
/// Disable D3DFMT_A8 for render targets.
|
||||
/// Specifically to work around a game
|
||||
/// bug in The Sims 2 that happens on native too!
|
||||
bool disableA8RT;
|
||||
|
||||
/// Work around a NV driver quirk
|
||||
/// Fixes flickering/z-fighting in some games.
|
||||
bool invariantPosition;
|
||||
|
||||
/// Whether or not to respect memory tracking for
|
||||
/// failing resource allocation.
|
||||
bool memoryTrackTest;
|
||||
|
||||
/// Support VCACHE query
|
||||
bool supportVCache;
|
||||
|
||||
/// Forced aspect ratio, disable other modes
|
||||
std::string forceAspectRatio;
|
||||
|
||||
/// Enable dialog mode (ie. no exclusive fullscreen)
|
||||
bool enableDialogMode;
|
||||
};
|
||||
|
||||
}
|
312
src/d3d9/d3d9_query.cpp
Normal file
312
src/d3d9/d3d9_query.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
#include "d3d9_query.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9Query::D3D9Query(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DQUERYTYPE QueryType)
|
||||
: D3D9DeviceChild<IDirect3DQuery9>(pDevice)
|
||||
, m_queryType (QueryType)
|
||||
, m_state (D3D9_VK_QUERY_INITIAL) {
|
||||
Rc<DxvkDevice> dxvkDevice = m_parent->GetDXVKDevice();
|
||||
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_VCACHE:
|
||||
if (!pDevice->GetOptions()->supportVCache)
|
||||
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType, " (from d3d9.supportVCache)"));
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_EVENT:
|
||||
m_event[0] = dxvkDevice->createGpuEvent();
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
m_query[0] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_OCCLUSION,
|
||||
VK_QUERY_CONTROL_PRECISE_BIT, 0);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
m_query[0] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TIMESTAMP, 0, 0);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
m_query[i] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_TIMESTAMP, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
m_query[0] = dxvkDevice->createGpuQuery(
|
||||
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Query::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DQuery9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9Query::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
D3DQUERYTYPE STDMETHODCALLTYPE D3D9Query::GetType() {
|
||||
return m_queryType;
|
||||
}
|
||||
|
||||
|
||||
DWORD STDMETHODCALLTYPE D3D9Query::GetDataSize() {
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_VCACHE: return sizeof(D3DDEVINFO_VCACHE);
|
||||
case D3DQUERYTYPE_RESOURCEMANAGER: return sizeof(D3DDEVINFO_RESOURCEMANAGER);
|
||||
case D3DQUERYTYPE_VERTEXSTATS: return sizeof(D3DDEVINFO_D3DVERTEXSTATS);
|
||||
case D3DQUERYTYPE_EVENT: return sizeof(BOOL);
|
||||
case D3DQUERYTYPE_OCCLUSION: return sizeof(DWORD);
|
||||
case D3DQUERYTYPE_TIMESTAMP: return sizeof(UINT64);
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT: return sizeof(BOOL);
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ: return sizeof(UINT64);
|
||||
case D3DQUERYTYPE_PIPELINETIMINGS: return sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS);
|
||||
case D3DQUERYTYPE_INTERFACETIMINGS: return sizeof(D3DDEVINFO_D3D9INTERFACETIMINGS);
|
||||
case D3DQUERYTYPE_VERTEXTIMINGS: return sizeof(D3DDEVINFO_D3D9STAGETIMINGS);
|
||||
case D3DQUERYTYPE_PIXELTIMINGS: return sizeof(D3DDEVINFO_D3D9PIPELINETIMINGS);
|
||||
case D3DQUERYTYPE_BANDWIDTHTIMINGS: return sizeof(D3DDEVINFO_D3D9BANDWIDTHTIMINGS);
|
||||
case D3DQUERYTYPE_CACHEUTILIZATION: return sizeof(D3DDEVINFO_D3D9CACHEUTILIZATION);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Query::Issue(DWORD dwIssueFlags) {
|
||||
// Note: No need to submit to CS if we don't do anything!
|
||||
|
||||
if (dwIssueFlags == D3DISSUE_BEGIN) {
|
||||
if (QueryBeginnable(m_queryType)) {
|
||||
if (m_state == D3D9_VK_QUERY_BEGUN && QueryEndable(m_queryType))
|
||||
m_parent->End(this);
|
||||
|
||||
m_parent->Begin(this);
|
||||
|
||||
m_state = D3D9_VK_QUERY_BEGUN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (QueryEndable(m_queryType)) {
|
||||
if (m_state != D3D9_VK_QUERY_BEGUN && QueryBeginnable(m_queryType))
|
||||
m_parent->Begin(this);
|
||||
|
||||
m_resetCtr.fetch_add(1, std::memory_order_acquire);
|
||||
|
||||
m_parent->End(this);
|
||||
|
||||
}
|
||||
m_state = D3D9_VK_QUERY_ENDED;
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Query::GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
|
||||
HRESULT hr = this->GetQueryData(pData, dwSize);
|
||||
|
||||
bool flush = dwGetDataFlags & D3DGETDATA_FLUSH;
|
||||
|
||||
// If we get S_FALSE and it's not from the fact
|
||||
// they didn't call end, do some flushy stuff...
|
||||
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
|
||||
this->NotifyStall();
|
||||
m_parent->FlushImplicit(FALSE);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Query::GetQueryData(void* pData, DWORD dwSize) {
|
||||
// Let the game know that calling end might be a good idea...
|
||||
if (m_state == D3D9_VK_QUERY_BEGUN)
|
||||
return S_FALSE;
|
||||
|
||||
if (unlikely(!pData && dwSize))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
// The game forgot to even issue the query!
|
||||
// Let's do it for them...
|
||||
// This will issue both the begin, and the end.
|
||||
if (m_state == D3D9_VK_QUERY_INITIAL)
|
||||
this->Issue(D3DISSUE_END);
|
||||
|
||||
if (m_resetCtr != 0u)
|
||||
return S_FALSE;
|
||||
|
||||
if (m_queryType == D3DQUERYTYPE_EVENT) {
|
||||
DxvkGpuEventStatus status = m_event[0]->test();
|
||||
|
||||
if (status == DxvkGpuEventStatus::Invalid)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
bool signaled = status == DxvkGpuEventStatus::Signaled;
|
||||
|
||||
if (pData != nullptr)
|
||||
*static_cast<BOOL*>(pData) = signaled;
|
||||
|
||||
return signaled ? D3D_OK : S_FALSE;
|
||||
}
|
||||
else {
|
||||
std::array<DxvkQueryData, MaxGpuQueries> queryData = { };
|
||||
|
||||
for (uint32_t i = 0; i < MaxGpuQueries && m_query[i] != nullptr; i++) {
|
||||
DxvkGpuQueryStatus status = m_query[i]->getData(queryData[i]);
|
||||
|
||||
if (status == DxvkGpuQueryStatus::Invalid
|
||||
|| status == DxvkGpuQueryStatus::Failed)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (status == DxvkGpuQueryStatus::Pending)
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
if (pData == nullptr)
|
||||
return D3D_OK;
|
||||
|
||||
auto* data = static_cast<D3D9_QUERY_DATA*>(pData);
|
||||
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_VCACHE:
|
||||
// Don't know what the hell any of this means.
|
||||
// Nor do I care. This just makes games work.
|
||||
data->VCache.Pattern = MAKEFOURCC('H', 'C', 'A', 'C');
|
||||
data->VCache.OptMethod = 1;
|
||||
data->VCache.CacheSize = 24;
|
||||
data->VCache.MagicNumber = 20;
|
||||
return D3D_OK;
|
||||
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
data->Occlusion = DWORD(queryData[0].occlusion.samplesPassed);
|
||||
return D3D_OK;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
data->Timestamp = queryData[0].timestamp.time;
|
||||
return D3D_OK;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
data->TimestampDisjoint = queryData[0].timestamp.time < queryData[1].timestamp.time;
|
||||
return D3D_OK;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
data->TimestampFreq = GetTimestampQueryFrequency();
|
||||
return D3D_OK;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
data->VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
|
||||
data->VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
|
||||
return D3D_OK;
|
||||
|
||||
default:
|
||||
return D3D_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UINT64 D3D9Query::GetTimestampQueryFrequency() const {
|
||||
Rc<DxvkDevice> device = m_parent->GetDXVKDevice();
|
||||
Rc<DxvkAdapter> adapter = device->adapter();
|
||||
|
||||
VkPhysicalDeviceLimits limits = adapter->deviceProperties().limits;
|
||||
return uint64_t(1'000'000'000.0f / limits.timestampPeriod);
|
||||
}
|
||||
|
||||
|
||||
void D3D9Query::Begin(DxvkContext* ctx) {
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
ctx->beginQuery(m_query[0]);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
ctx->writeTimestamp(m_query[1]);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D9Query::End(DxvkContext* ctx) {
|
||||
switch (m_queryType) {
|
||||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
ctx->writeTimestamp(m_query[0]);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
ctx->endQuery(m_query[0]);
|
||||
break;
|
||||
|
||||
case D3DQUERYTYPE_EVENT:
|
||||
ctx->signalGpuEvent(m_event[0]);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
m_resetCtr.fetch_sub(1, std::memory_order_release);
|
||||
}
|
||||
|
||||
|
||||
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
|
||||
return QueryType == D3DQUERYTYPE_OCCLUSION
|
||||
|| QueryType == D3DQUERYTYPE_VERTEXSTATS
|
||||
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
|
||||
}
|
||||
|
||||
|
||||
bool D3D9Query::QueryEndable(D3DQUERYTYPE QueryType) {
|
||||
return QueryBeginnable(QueryType)
|
||||
|| QueryType == D3DQUERYTYPE_TIMESTAMP
|
||||
|| QueryType == D3DQUERYTYPE_EVENT;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9Query::QuerySupported(D3DQUERYTYPE QueryType) {
|
||||
switch (QueryType) {
|
||||
case D3DQUERYTYPE_VCACHE:
|
||||
case D3DQUERYTYPE_EVENT:
|
||||
case D3DQUERYTYPE_OCCLUSION:
|
||||
case D3DQUERYTYPE_TIMESTAMP:
|
||||
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
|
||||
case D3DQUERYTYPE_TIMESTAMPFREQ:
|
||||
case D3DQUERYTYPE_VERTEXSTATS:
|
||||
return D3D_OK;
|
||||
|
||||
default:
|
||||
return D3DERR_NOTAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
88
src/d3d9/d3d9_query.h
Normal file
88
src/d3d9/d3d9_query.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device_child.h"
|
||||
|
||||
#include "../dxvk/dxvk_context.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum D3D9_VK_QUERY_STATE : uint32_t {
|
||||
D3D9_VK_QUERY_INITIAL,
|
||||
D3D9_VK_QUERY_BEGUN,
|
||||
D3D9_VK_QUERY_ENDED,
|
||||
};
|
||||
|
||||
union D3D9_QUERY_DATA {
|
||||
D3DDEVINFO_VCACHE VCache;
|
||||
DWORD Occlusion;
|
||||
UINT64 Timestamp;
|
||||
BOOL TimestampDisjoint;
|
||||
UINT64 TimestampFreq;
|
||||
D3DDEVINFO_D3DVERTEXSTATS VertexStats;
|
||||
};
|
||||
|
||||
class D3D9Query : public D3D9DeviceChild<IDirect3DQuery9> {
|
||||
constexpr static uint32_t MaxGpuQueries = 2;
|
||||
constexpr static uint32_t MaxGpuEvents = 1;
|
||||
public:
|
||||
|
||||
D3D9Query(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DQUERYTYPE QueryType);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
D3DQUERYTYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetDataSize() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Issue(DWORD dwIssueFlags) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) final;
|
||||
|
||||
HRESULT GetQueryData(void* pData, DWORD dwSize);
|
||||
|
||||
void Begin(DxvkContext* ctx);
|
||||
void End(DxvkContext* ctx);
|
||||
|
||||
static bool QueryBeginnable(D3DQUERYTYPE QueryType);
|
||||
static bool QueryEndable(D3DQUERYTYPE QueryType);
|
||||
|
||||
static HRESULT QuerySupported(D3DQUERYTYPE QueryType);
|
||||
|
||||
bool IsEvent() const {
|
||||
return m_queryType == D3DQUERYTYPE_EVENT;
|
||||
}
|
||||
|
||||
bool IsStalling() const {
|
||||
return m_stallFlag;
|
||||
}
|
||||
|
||||
void NotifyEnd() {
|
||||
m_stallMask <<= 1;
|
||||
}
|
||||
|
||||
void NotifyStall() {
|
||||
m_stallMask |= 1;
|
||||
m_stallFlag |= bit::popcnt(m_stallMask) >= 16;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3DQUERYTYPE m_queryType;
|
||||
|
||||
D3D9_VK_QUERY_STATE m_state;
|
||||
|
||||
std::array<Rc<DxvkGpuQuery>, MaxGpuQueries> m_query;
|
||||
std::array<Rc<DxvkGpuEvent>, MaxGpuEvents> m_event;
|
||||
|
||||
uint32_t m_stallMask = 0;
|
||||
bool m_stallFlag = false;
|
||||
|
||||
std::atomic<uint32_t> m_resetCtr = { 0u };
|
||||
|
||||
UINT64 GetTimestampQueryFrequency() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
87
src/d3d9/d3d9_resource.h
Normal file
87
src/d3d9/d3d9_resource.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device_child.h"
|
||||
|
||||
#include "../util/com/com_private_data.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename... Type>
|
||||
class D3D9Resource : public D3D9DeviceChild<Type...> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Resource(D3D9DeviceEx* pDevice)
|
||||
: D3D9DeviceChild<Type...>(pDevice)
|
||||
, m_priority ( 0 ) { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(
|
||||
REFGUID refguid,
|
||||
const void* pData,
|
||||
DWORD SizeOfData,
|
||||
DWORD Flags) final {
|
||||
HRESULT hr;
|
||||
if (Flags & D3DSPD_IUNKNOWN) {
|
||||
IUnknown* unknown =
|
||||
const_cast<IUnknown*>(
|
||||
reinterpret_cast<const IUnknown*>(pData));
|
||||
hr = m_privateData.setInterface(
|
||||
refguid, unknown);
|
||||
}
|
||||
else
|
||||
hr = m_privateData.setData(
|
||||
refguid, SizeOfData, pData);
|
||||
|
||||
if (FAILED(hr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(
|
||||
REFGUID refguid,
|
||||
void* pData,
|
||||
DWORD* pSizeOfData) final {
|
||||
HRESULT hr = m_privateData.getData(
|
||||
refguid, reinterpret_cast<UINT*>(pSizeOfData), pData);
|
||||
|
||||
if (FAILED(hr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE FreePrivateData(REFGUID refguid) final {
|
||||
HRESULT hr = m_privateData.setData(refguid, 0, nullptr);
|
||||
|
||||
if (FAILED(hr))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetPriority(DWORD PriorityNew) {
|
||||
DWORD oldPriority = m_priority;
|
||||
m_priority = PriorityNew;
|
||||
return oldPriority;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetPriority() {
|
||||
return m_priority;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE PreLoad() {
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
DWORD m_priority;
|
||||
|
||||
private:
|
||||
|
||||
ComPrivateData m_privateData;
|
||||
|
||||
};
|
||||
|
||||
}
|
47
src/d3d9/d3d9_sampler.cpp
Normal file
47
src/d3d9/d3d9_sampler.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "d3d9_sampler.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
size_t D3D9SamplerKeyHash::operator () (const D3D9SamplerKey& key) const {
|
||||
DxvkHashState state;
|
||||
|
||||
std::hash<DWORD> dhash;
|
||||
std::hash<D3DTEXTUREADDRESS> tahash;
|
||||
std::hash<D3DTEXTUREFILTERTYPE> tfhash;
|
||||
std::hash<float> fhash;
|
||||
|
||||
state.add(tahash(key.AddressU));
|
||||
state.add(tahash(key.AddressV));
|
||||
state.add(tahash(key.AddressW));
|
||||
state.add(tfhash(key.MagFilter));
|
||||
state.add(tfhash(key.MinFilter));
|
||||
state.add(tfhash(key.MipFilter));
|
||||
state.add(dhash (key.MaxAnisotropy));
|
||||
state.add(fhash (key.MipmapLodBias));
|
||||
state.add(dhash (key.MaxMipLevel));
|
||||
state.add(fhash (key.BorderColor[0]));
|
||||
state.add(fhash (key.BorderColor[1]));
|
||||
state.add(fhash (key.BorderColor[2]));
|
||||
state.add(fhash (key.BorderColor[3]));
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
bool D3D9SamplerKeyEq::operator () (const D3D9SamplerKey& a, const D3D9SamplerKey& b) const {
|
||||
return a.AddressU == b.AddressU
|
||||
&& a.AddressV == b.AddressV
|
||||
&& a.AddressW == b.AddressW
|
||||
&& a.MagFilter == b.MagFilter
|
||||
&& a.MinFilter == b.MinFilter
|
||||
&& a.MipFilter == b.MipFilter
|
||||
&& a.MaxAnisotropy == b.MaxAnisotropy
|
||||
&& a.MipmapLodBias == b.MipmapLodBias
|
||||
&& a.MaxMipLevel == b.MaxMipLevel
|
||||
&& a.BorderColor[0] == b.BorderColor[0]
|
||||
&& a.BorderColor[1] == b.BorderColor[1]
|
||||
&& a.BorderColor[2] == b.BorderColor[2]
|
||||
&& a.BorderColor[3] == b.BorderColor[3];
|
||||
}
|
||||
|
||||
}
|
75
src/d3d9/d3d9_sampler.h
Normal file
75
src/d3d9/d3d9_sampler.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
#include "d3d9_util.h"
|
||||
|
||||
#include "../dxvk/dxvk_hash.h"
|
||||
|
||||
#include "../util/util_math.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D9SamplerKey {
|
||||
D3DTEXTUREADDRESS AddressU;
|
||||
D3DTEXTUREADDRESS AddressV;
|
||||
D3DTEXTUREADDRESS AddressW;
|
||||
D3DTEXTUREFILTERTYPE MagFilter;
|
||||
D3DTEXTUREFILTERTYPE MinFilter;
|
||||
D3DTEXTUREFILTERTYPE MipFilter;
|
||||
DWORD MaxAnisotropy;
|
||||
float MipmapLodBias;
|
||||
DWORD MaxMipLevel;
|
||||
float BorderColor[4];
|
||||
};
|
||||
|
||||
struct D3D9SamplerKeyHash {
|
||||
size_t operator () (const D3D9SamplerKey& key) const;
|
||||
};
|
||||
|
||||
struct D3D9SamplerKeyEq {
|
||||
bool operator () (const D3D9SamplerKey& a, const D3D9SamplerKey& b) const;
|
||||
};
|
||||
|
||||
inline void NormalizeSamplerKey(D3D9SamplerKey& key) {
|
||||
key.AddressU = std::clamp(key.AddressU, D3DTADDRESS_WRAP, D3DTADDRESS_MIRRORONCE);
|
||||
key.AddressV = std::clamp(key.AddressV, D3DTADDRESS_WRAP, D3DTADDRESS_MIRRORONCE);
|
||||
key.AddressW = std::clamp(key.AddressW, D3DTADDRESS_WRAP, D3DTADDRESS_MIRRORONCE);
|
||||
|
||||
key.MagFilter = std::clamp(key.MagFilter, D3DTEXF_NONE, D3DTEXF_ANISOTROPIC);
|
||||
key.MinFilter = std::clamp(key.MinFilter, D3DTEXF_NONE, D3DTEXF_ANISOTROPIC);
|
||||
key.MipFilter = std::clamp(key.MipFilter, D3DTEXF_NONE, D3DTEXF_ANISOTROPIC);
|
||||
|
||||
key.MaxAnisotropy = std::clamp<DWORD>(key.MaxAnisotropy, 0, 16);
|
||||
|
||||
if (key.MipFilter == D3DTEXF_NONE) {
|
||||
// May as well try and keep slots down.
|
||||
key.MipmapLodBias = 0;
|
||||
}
|
||||
else {
|
||||
// Games also pass NAN/INF here, this accounts for that.
|
||||
if (unlikely(std::isnan(key.MipmapLodBias)))
|
||||
key.MipmapLodBias = 0.0f;
|
||||
|
||||
// Clamp between -15.0f and 15.0f, matching mip limits of d3d9.
|
||||
key.MipmapLodBias = std::clamp(key.MipmapLodBias, -15.0f, 15.0f);
|
||||
|
||||
// Round to the nearest .5
|
||||
// Fixes sampler leaks in UE3 games w/ mip streaming
|
||||
// eg. Borderlands 2
|
||||
key.MipmapLodBias = std::round(key.MipmapLodBias * 2.0f) / 2.0f;
|
||||
}
|
||||
|
||||
if (key.AddressU != D3DTADDRESS_BORDER
|
||||
&& key.AddressV != D3DTADDRESS_BORDER
|
||||
&& key.AddressW != D3DTADDRESS_BORDER) {
|
||||
for (auto& val : key.BorderColor)
|
||||
val = 0.0f;
|
||||
}
|
||||
else {
|
||||
for (auto& val : key.BorderColor)
|
||||
val = val >= 0.5f ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
143
src/d3d9/d3d9_shader.cpp
Normal file
143
src/d3d9/d3d9_shader.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include "d3d9_shader.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9CommonShader::D3D9CommonShader() {}
|
||||
|
||||
D3D9CommonShader::D3D9CommonShader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
VkShaderStageFlagBits ShaderStage,
|
||||
const Sha1Hash* pHash,
|
||||
const DxsoModuleInfo* pDxsoModuleInfo,
|
||||
const void* pShaderBytecode,
|
||||
const DxsoAnalysisInfo& AnalysisInfo,
|
||||
DxsoModule* pModule) {
|
||||
const uint32_t bytecodeLength = AnalysisInfo.bytecodeByteLength;
|
||||
m_bytecode.resize(bytecodeLength);
|
||||
std::memcpy(m_bytecode.data(), pShaderBytecode, bytecodeLength);
|
||||
|
||||
DxvkShaderKey shaderKey = { ShaderStage, *pHash };
|
||||
|
||||
const std::string name = shaderKey.toString();
|
||||
Logger::debug(str::format("Compiling shader ", name));
|
||||
|
||||
// If requested by the user, dump both the raw DXBC
|
||||
// shader and the compiled SPIR-V module to a file.
|
||||
const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
|
||||
|
||||
if (dumpPath.size() != 0) {
|
||||
DxsoReader reader(
|
||||
reinterpret_cast<const char*>(pShaderBytecode));
|
||||
|
||||
reader.store(std::ofstream(str::format(dumpPath, "/", name, ".dxso"),
|
||||
std::ios_base::binary | std::ios_base::trunc), bytecodeLength);
|
||||
|
||||
char comment[2048];
|
||||
Com<ID3DBlob> blob;
|
||||
HRESULT hr = DisassembleShader(
|
||||
pShaderBytecode,
|
||||
TRUE,
|
||||
comment,
|
||||
&blob);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
std::ofstream disassembledOut(str::format(dumpPath, "/", name, ".dxso.dis"), std::ios_base::binary | std::ios_base::trunc);
|
||||
disassembledOut.write(
|
||||
reinterpret_cast<const char*>(blob->GetBufferPointer()),
|
||||
blob->GetBufferSize());
|
||||
}
|
||||
}
|
||||
|
||||
// Decide whether we need to create a pass-through
|
||||
// geometry shader for vertex shader stream output
|
||||
|
||||
const D3D9ConstantLayout& constantLayout = ShaderStage == VK_SHADER_STAGE_VERTEX_BIT
|
||||
? pDevice->GetVertexConstantLayout()
|
||||
: pDevice->GetPixelConstantLayout();
|
||||
|
||||
m_shaders = pModule->compile(*pDxsoModuleInfo, name, AnalysisInfo, constantLayout);
|
||||
m_isgn = pModule->isgn();
|
||||
m_usedSamplers = pModule->usedSamplers();
|
||||
m_usedRTs = pModule->usedRTs();
|
||||
|
||||
m_info = pModule->info();
|
||||
m_meta = pModule->meta();
|
||||
m_constants = pModule->constants();
|
||||
|
||||
m_shaders[0]->setShaderKey(shaderKey);
|
||||
|
||||
if (m_shaders[1] != nullptr) {
|
||||
// Lets lie about the shader key type for the state cache.
|
||||
m_shaders[1]->setShaderKey({ VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, *pHash });
|
||||
}
|
||||
|
||||
if (dumpPath.size() != 0) {
|
||||
std::ofstream dumpStream(
|
||||
str::format(dumpPath, "/", name, ".spv"),
|
||||
std::ios_base::binary | std::ios_base::trunc);
|
||||
|
||||
m_shaders[0]->dump(dumpStream);
|
||||
}
|
||||
|
||||
pDevice->GetDXVKDevice()->registerShader(m_shaders[0]);
|
||||
|
||||
if (m_shaders[1] != nullptr)
|
||||
pDevice->GetDXVKDevice()->registerShader(m_shaders[1]);
|
||||
}
|
||||
|
||||
|
||||
D3D9CommonShader D3D9ShaderModuleSet::GetShaderModule(
|
||||
D3D9DeviceEx* pDevice,
|
||||
VkShaderStageFlagBits ShaderStage,
|
||||
const DxsoModuleInfo* pDxbcModuleInfo,
|
||||
const void* pShaderBytecode) {
|
||||
DxsoReader reader(
|
||||
reinterpret_cast<const char*>(pShaderBytecode));
|
||||
|
||||
DxsoModule module(reader);
|
||||
|
||||
if (module.info().majorVersion() > pDxbcModuleInfo->options.shaderModel)
|
||||
throw DxvkError("GetShaderModule: Out of range of supported shader model");
|
||||
|
||||
if (module.info().shaderStage() != ShaderStage)
|
||||
throw DxvkError("GetShaderModule: Bytecode does not match shader stage");
|
||||
|
||||
DxsoAnalysisInfo info = module.analyze();
|
||||
|
||||
Sha1Hash hash = Sha1Hash::compute(
|
||||
pShaderBytecode, info.bytecodeByteLength);
|
||||
|
||||
DxvkShaderKey lookupKey = DxvkShaderKey(ShaderStage, hash);
|
||||
|
||||
// Use the shader's unique key for the lookup
|
||||
{ std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto entry = m_modules.find(lookupKey);
|
||||
if (entry != m_modules.end())
|
||||
return entry->second;
|
||||
}
|
||||
|
||||
// This shader has not been compiled yet, so we have to create a
|
||||
// new module. This takes a while, so we won't lock the structure.
|
||||
D3D9CommonShader commonShader(
|
||||
pDevice, ShaderStage, &hash,
|
||||
pDxbcModuleInfo, pShaderBytecode,
|
||||
info, &module);
|
||||
|
||||
// Insert the new module into the lookup table. If another thread
|
||||
// has compiled the same shader in the meantime, we should return
|
||||
// that object instead and discard the newly created module.
|
||||
{ std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto status = m_modules.insert({ lookupKey, commonShader });
|
||||
if (!status.second)
|
||||
return status.first->second;
|
||||
}
|
||||
|
||||
return commonShader;
|
||||
}
|
||||
|
||||
}
|
195
src/d3d9/d3d9_shader.h
Normal file
195
src/d3d9/d3d9_shader.h
Normal file
|
@ -0,0 +1,195 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_resource.h"
|
||||
#include "../dxso/dxso_module.h"
|
||||
#include "d3d9_shader_permutations.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
|
||||
/**
|
||||
* \brief Common shader object
|
||||
*
|
||||
* Stores the compiled SPIR-V shader and the SHA-1
|
||||
* hash of the original DXBC shader, which can be
|
||||
* used to identify the shader.
|
||||
*/
|
||||
class D3D9CommonShader {
|
||||
|
||||
public:
|
||||
|
||||
D3D9CommonShader();
|
||||
|
||||
D3D9CommonShader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
VkShaderStageFlagBits ShaderStage,
|
||||
const Sha1Hash* pHash,
|
||||
const DxsoModuleInfo* pDxbcModuleInfo,
|
||||
const void* pShaderBytecode,
|
||||
const DxsoAnalysisInfo& AnalysisInfo,
|
||||
DxsoModule* pModule);
|
||||
|
||||
|
||||
Rc<DxvkShader> GetShader(D3D9ShaderPermutation Permutation) const {
|
||||
return m_shaders[Permutation];
|
||||
}
|
||||
|
||||
std::string GetName() const {
|
||||
return m_shaders[D3D9ShaderPermutations::None]->debugName();
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& GetBytecode() const {
|
||||
return m_bytecode;
|
||||
}
|
||||
|
||||
const DxsoIsgn& GetIsgn() const {
|
||||
return m_isgn;
|
||||
}
|
||||
|
||||
const DxsoShaderMetaInfo& GetMeta() const { return m_meta; }
|
||||
const DxsoDefinedConstants& GetConstants() const { return m_constants; }
|
||||
|
||||
D3D9ShaderMasks GetShaderMask() const { return D3D9ShaderMasks{ m_usedSamplers, m_usedRTs }; }
|
||||
|
||||
const DxsoProgramInfo& GetInfo() const { return m_info; }
|
||||
|
||||
private:
|
||||
|
||||
DxsoIsgn m_isgn;
|
||||
uint32_t m_usedSamplers;
|
||||
uint32_t m_usedRTs;
|
||||
|
||||
DxsoProgramInfo m_info;
|
||||
DxsoShaderMetaInfo m_meta;
|
||||
DxsoDefinedConstants m_constants;
|
||||
|
||||
DxsoPermutations m_shaders;
|
||||
|
||||
std::vector<uint8_t> m_bytecode;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Common shader interface
|
||||
*
|
||||
* Implements methods for all D3D11*Shader
|
||||
* interfaces and stores the actual shader
|
||||
* module object.
|
||||
*/
|
||||
template <typename Base>
|
||||
class D3D9Shader : public D3D9DeviceChild<Base> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Shader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9CommonShader& CommonShader)
|
||||
: D3D9DeviceChild<Base>( pDevice )
|
||||
, m_shader ( CommonShader ) { }
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(Base)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9Shader::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetFunction(void* pOut, UINT* pSizeOfData) {
|
||||
if (pSizeOfData == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
const auto& bytecode = m_shader.GetBytecode();
|
||||
|
||||
if (pOut == nullptr) {
|
||||
*pSizeOfData = bytecode.size();
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
size_t copyAmount = std::min(size_t(*pSizeOfData), bytecode.size());
|
||||
std::memcpy(pOut, bytecode.data(), copyAmount);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
const D3D9CommonShader* GetCommonShader() const {
|
||||
return &m_shader;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
D3D9CommonShader m_shader;
|
||||
|
||||
};
|
||||
|
||||
// Needs their own classes and not usings for forward decl.
|
||||
|
||||
class D3D9VertexShader final : public D3D9Shader<IDirect3DVertexShader9> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9VertexShader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9CommonShader& CommonShader)
|
||||
: D3D9Shader<IDirect3DVertexShader9>( pDevice, CommonShader ) { }
|
||||
|
||||
};
|
||||
|
||||
class D3D9PixelShader final : public D3D9Shader<IDirect3DPixelShader9> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9PixelShader(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9CommonShader& CommonShader)
|
||||
: D3D9Shader<IDirect3DPixelShader9>( pDevice, CommonShader ) { }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Shader module set
|
||||
*
|
||||
* Some applications may compile the same shader multiple
|
||||
* times, so we should cache the resulting shader modules
|
||||
* and reuse them rather than creating new ones. This
|
||||
* class is thread-safe.
|
||||
*/
|
||||
class D3D9ShaderModuleSet : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
D3D9CommonShader GetShaderModule(
|
||||
D3D9DeviceEx* pDevice,
|
||||
VkShaderStageFlagBits ShaderStage,
|
||||
const DxsoModuleInfo* pDxbcModuleInfo,
|
||||
const void* pShaderBytecode);
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
std::unordered_map<
|
||||
DxvkShaderKey,
|
||||
D3D9CommonShader,
|
||||
DxvkHash, DxvkEq> m_modules;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
const D3D9CommonShader* GetCommonShader(const T& pShader) {
|
||||
return pShader != nullptr ? pShader->GetCommonShader() : nullptr;
|
||||
}
|
||||
|
||||
}
|
20
src/d3d9/d3d9_shader_permutations.h
Normal file
20
src/d3d9/d3d9_shader_permutations.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class DxvkShader;
|
||||
|
||||
namespace D3D9ShaderPermutations {
|
||||
enum D3D9ShaderPermutation {
|
||||
None,
|
||||
FlatShade,
|
||||
Count
|
||||
};
|
||||
}
|
||||
using D3D9ShaderPermutation = D3D9ShaderPermutations::D3D9ShaderPermutation;
|
||||
|
||||
using DxsoPermutations = std::array<Rc<DxvkShader>, D3D9ShaderPermutations::Count>;
|
||||
|
||||
}
|
68
src/d3d9/d3d9_shader_validator.h
Normal file
68
src/d3d9/d3d9_shader_validator.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class IDirect3DShaderValidator9 : public IUnknown {
|
||||
|
||||
public:
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Begin(
|
||||
void* pCallback,
|
||||
void* pUserParam,
|
||||
DWORD Unknown) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Instruction(
|
||||
const char* pUnknown1,
|
||||
UINT Unknown2,
|
||||
const DWORD* pInstruction,
|
||||
DWORD InstructionLength) = 0;
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE End() = 0;
|
||||
|
||||
};
|
||||
|
||||
class D3D9ShaderValidator final : public ComObjectClamp<IDirect3DShaderValidator9> {
|
||||
|
||||
public:
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Begin(
|
||||
void* pCallback,
|
||||
void* pUserParam,
|
||||
DWORD Unknown) {
|
||||
Logger::debug("D3D9ShaderValidator::Begin: Stub");
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Instruction(
|
||||
const char* pUnknown1,
|
||||
UINT Unknown2,
|
||||
const DWORD* pInstruction,
|
||||
DWORD InstructionLength) {
|
||||
Logger::debug("D3D9ShaderValidator::Instruction: Stub");
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE End() {
|
||||
Logger::debug("D3D9ShaderValidator::End: Stub");
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
19
src/d3d9/d3d9_spec_constants.h
Normal file
19
src/d3d9/d3d9_spec_constants.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum D3D9SpecConstantId : uint32_t {
|
||||
AlphaTestEnable = 0,
|
||||
AlphaCompareOp = 1,
|
||||
SamplerType = 2,
|
||||
FogEnabled = 3,
|
||||
VertexFogMode = 4,
|
||||
PixelFogMode = 5,
|
||||
|
||||
PointMode = 6,
|
||||
ProjectionType = 7,
|
||||
};
|
||||
|
||||
}
|
26
src/d3d9/d3d9_state.cpp
Normal file
26
src/d3d9/d3d9_state.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "d3d9_state.h"
|
||||
|
||||
#include "d3d9_texture.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9CapturableState::D3D9CapturableState() {
|
||||
for (uint32_t i = 0; i < textures.size(); i++)
|
||||
textures[i] = nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < clipPlanes.size(); i++)
|
||||
clipPlanes[i] = D3D9ClipPlane();
|
||||
|
||||
for (uint32_t i = 0; i < streamFreq.size(); i++)
|
||||
streamFreq[i] = 1;
|
||||
|
||||
for (uint32_t i = 0; i < enabledLightIndices.size(); i++)
|
||||
enabledLightIndices[i] = UINT32_MAX;
|
||||
}
|
||||
|
||||
D3D9CapturableState::~D3D9CapturableState() {
|
||||
for (uint32_t i = 0; i < textures.size(); i++)
|
||||
TextureChangePrivate(textures[i], nullptr);
|
||||
}
|
||||
|
||||
}
|
352
src/d3d9/d3d9_state.h
Normal file
352
src/d3d9/d3d9_state.h
Normal file
|
@ -0,0 +1,352 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_caps.h"
|
||||
#include "d3d9_constant_set.h"
|
||||
#include "../dxso/dxso_common.h"
|
||||
#include "../util/util_matrix.h"
|
||||
|
||||
#include "d3d9_surface.h"
|
||||
#include "d3d9_shader.h"
|
||||
#include "d3d9_vertex_declaration.h"
|
||||
#include "d3d9_buffer.h"
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <optional>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
static constexpr uint32_t RenderStateCount = 256;
|
||||
static constexpr uint32_t SamplerStateCount = D3DSAMP_DMAPOFFSET + 1;
|
||||
static constexpr uint32_t SamplerCount = 21;
|
||||
static constexpr uint32_t TextureStageStateCount = D3DTSS_CONSTANT + 1;
|
||||
|
||||
namespace hacks::PointSize {
|
||||
static constexpr DWORD AlphaToCoverageDisabled = MAKEFOURCC('A', '2', 'M', '0');
|
||||
static constexpr DWORD AlphaToCoverageEnabled = MAKEFOURCC('A', '2', 'M', '1');
|
||||
}
|
||||
|
||||
struct D3D9ClipPlane {
|
||||
float coeff[4];
|
||||
};
|
||||
|
||||
struct D3D9RenderStateInfo {
|
||||
std::array<float, 3> fogColor = { };
|
||||
float fogScale = 0.0f;
|
||||
float fogEnd = 1.0f;
|
||||
float fogDensity = 1.0f;
|
||||
|
||||
float alphaRef = 0.0f;
|
||||
|
||||
float pointSize = 1.0f;
|
||||
float pointSizeMin = 1.0f;
|
||||
float pointSizeMax = 64.0f;
|
||||
float pointScaleA = 1.0f;
|
||||
float pointScaleB = 0.0f;
|
||||
float pointScaleC = 0.0f;
|
||||
};
|
||||
|
||||
enum class D3D9RenderStateItem {
|
||||
FogColor = 0,
|
||||
FogScale = 1,
|
||||
FogEnd,
|
||||
FogDensity,
|
||||
AlphaRef,
|
||||
|
||||
PointSize,
|
||||
PointSizeMin,
|
||||
PointSizeMax,
|
||||
PointScaleA,
|
||||
PointScaleB,
|
||||
PointScaleC,
|
||||
|
||||
Count
|
||||
};
|
||||
|
||||
|
||||
// This is needed in fixed function for POSITION_T support.
|
||||
// These are constants we need to * and add to move
|
||||
// Window Coords -> Real Coords w/ respect to the viewport.
|
||||
struct D3D9ViewportInfo {
|
||||
Vector4 inverseOffset;
|
||||
Vector4 inverseExtent;
|
||||
};
|
||||
|
||||
struct D3D9Light {
|
||||
D3D9Light(const D3DLIGHT9& light, Matrix4 viewMtx) {
|
||||
Diffuse = Vector4(light.Diffuse.r, light.Diffuse.g, light.Diffuse.b, light.Diffuse.a);
|
||||
Specular = Vector4(light.Specular.r, light.Specular.g, light.Specular.b, light.Specular.a);
|
||||
Ambient = Vector4(light.Ambient.r, light.Ambient.g, light.Ambient.b, light.Ambient.a);
|
||||
|
||||
Position = viewMtx * Vector4(light.Position.x, light.Position.y, light.Position.z, 1.0f);
|
||||
Direction = Vector4(light.Direction.x, light.Direction.y, light.Direction.z, 0.0f);
|
||||
Direction = normalize(viewMtx * Direction);
|
||||
|
||||
Type = light.Type;
|
||||
Range = light.Range;
|
||||
Falloff = light.Falloff;
|
||||
Attenuation0 = light.Attenuation0;
|
||||
Attenuation1 = light.Attenuation1;
|
||||
Attenuation2 = light.Attenuation2;
|
||||
Theta = cosf(light.Theta / 2.0f);
|
||||
Phi = cosf(light.Phi / 2.0f);
|
||||
}
|
||||
|
||||
Vector4 Diffuse;
|
||||
Vector4 Specular;
|
||||
Vector4 Ambient;
|
||||
|
||||
Vector4 Position;
|
||||
Vector4 Direction;
|
||||
|
||||
D3DLIGHTTYPE Type;
|
||||
float Range;
|
||||
float Falloff;
|
||||
float Attenuation0;
|
||||
float Attenuation1;
|
||||
float Attenuation2;
|
||||
float Theta;
|
||||
float Phi;
|
||||
};
|
||||
|
||||
|
||||
struct D3D9FixedFunctionVS {
|
||||
Matrix4 WorldView;
|
||||
Matrix4 NormalMatrix;
|
||||
Matrix4 Projection;
|
||||
|
||||
std::array<Matrix4, 8> TexcoordMatrices;
|
||||
|
||||
D3D9ViewportInfo ViewportInfo;
|
||||
|
||||
Vector4 GlobalAmbient;
|
||||
std::array<D3D9Light, caps::MaxEnabledLights> Lights;
|
||||
D3DMATERIAL9 Material;
|
||||
float TweenFactor;
|
||||
};
|
||||
|
||||
|
||||
struct D3D9FixedFunctionVertexBlendDataHW {
|
||||
Matrix4 WorldView[8];
|
||||
};
|
||||
|
||||
|
||||
struct D3D9FixedFunctionVertexBlendDataSW {
|
||||
Matrix4 WorldView[256];
|
||||
};
|
||||
|
||||
|
||||
struct D3D9FixedFunctionPS {
|
||||
Vector4 textureFactor;
|
||||
};
|
||||
|
||||
enum D3D9SharedPSStages {
|
||||
D3D9SharedPSStages_Constant,
|
||||
D3D9SharedPSStages_BumpEnvMat0,
|
||||
D3D9SharedPSStages_BumpEnvMat1,
|
||||
D3D9SharedPSStages_BumpEnvLScale,
|
||||
D3D9SharedPSStages_BumpEnvLOffset,
|
||||
D3D9SharedPSStages_Count,
|
||||
};
|
||||
|
||||
struct D3D9SharedPS {
|
||||
struct Stage {
|
||||
float Constant[4];
|
||||
float BumpEnvMat[2][2];
|
||||
float BumpEnvLScale;
|
||||
float BumpEnvLOffset;
|
||||
float Padding[2];
|
||||
} Stages[8];
|
||||
};
|
||||
|
||||
struct D3D9VBO {
|
||||
Com<D3D9VertexBuffer, false> vertexBuffer;
|
||||
|
||||
UINT offset = 0;
|
||||
UINT stride = 0;
|
||||
};
|
||||
|
||||
constexpr D3DLIGHT9 DefaultLight = {
|
||||
D3DLIGHT_DIRECTIONAL, // Type
|
||||
{1.0f, 1.0f, 1.0f, 1.0f}, // Diffuse
|
||||
{0.0f, 0.0f, 0.0f, 0.0f}, // Specular
|
||||
{0.0f, 0.0f, 0.0f, 0.0f}, // Ambient
|
||||
{0.0f, 0.0f, 0.0f}, // Position
|
||||
{0.0f, 0.0f, 0.0f}, // Direction
|
||||
0.0f, // Range
|
||||
0.0f, // Falloff
|
||||
0.0f, 0.0f, 0.0f, // Attenuations [constant, linear, quadratic]
|
||||
0.0f, // Theta
|
||||
0.0f // Phi
|
||||
};
|
||||
|
||||
struct D3D9CapturableState {
|
||||
D3D9CapturableState();
|
||||
|
||||
~D3D9CapturableState();
|
||||
|
||||
Com<D3D9VertexDecl, false> vertexDecl;
|
||||
Com<D3D9IndexBuffer, false> indices;
|
||||
|
||||
std::array<DWORD, RenderStateCount> renderStates = { 0 };
|
||||
|
||||
std::array<
|
||||
std::array<DWORD, SamplerStateCount>,
|
||||
SamplerCount> samplerStates;
|
||||
|
||||
std::array<D3D9VBO, caps::MaxStreams> vertexBuffers;
|
||||
|
||||
std::array<
|
||||
IDirect3DBaseTexture9*,
|
||||
SamplerCount> textures;
|
||||
|
||||
Com<D3D9VertexShader, false> vertexShader;
|
||||
Com<D3D9PixelShader, false> pixelShader;
|
||||
|
||||
D3DVIEWPORT9 viewport;
|
||||
RECT scissorRect;
|
||||
|
||||
std::array<
|
||||
D3D9ClipPlane,
|
||||
caps::MaxClipPlanes> clipPlanes;
|
||||
|
||||
std::array<
|
||||
std::array<DWORD, TextureStageStateCount>,
|
||||
caps::TextureStageCount> textureStages;
|
||||
|
||||
D3D9ShaderConstantsVSSoftware vsConsts;
|
||||
D3D9ShaderConstantsPS psConsts;
|
||||
|
||||
std::array<UINT, caps::MaxStreams> streamFreq;
|
||||
|
||||
std::array<Matrix4, caps::MaxTransforms> transforms;
|
||||
|
||||
D3DMATERIAL9 material = D3DMATERIAL9();
|
||||
|
||||
std::vector<std::optional<D3DLIGHT9>> lights;
|
||||
std::array<DWORD, caps::MaxEnabledLights> enabledLightIndices;
|
||||
|
||||
bool IsLightEnabled(DWORD Index) {
|
||||
const auto& indices = enabledLightIndices;
|
||||
return std::find(indices.begin(), indices.end(), Index) != indices.end();
|
||||
}
|
||||
};
|
||||
|
||||
template <
|
||||
DxsoProgramType ProgramType,
|
||||
D3D9ConstantType ConstantType,
|
||||
typename T>
|
||||
HRESULT UpdateStateConstants(
|
||||
D3D9CapturableState* pState,
|
||||
UINT StartRegister,
|
||||
const T* pConstantData,
|
||||
UINT Count,
|
||||
bool FloatEmu) {
|
||||
auto UpdateHelper = [&] (auto& set) {
|
||||
if constexpr (ConstantType == D3D9ConstantType::Float) {
|
||||
auto begin = reinterpret_cast<const Vector4*>(pConstantData);
|
||||
auto end = begin + Count;
|
||||
|
||||
if (!FloatEmu)
|
||||
std::copy(begin, end, &set.fConsts[StartRegister]);
|
||||
else
|
||||
std::transform(begin, end, &set.fConsts[StartRegister], replaceNaN);
|
||||
}
|
||||
else if constexpr (ConstantType == D3D9ConstantType::Int) {
|
||||
auto begin = reinterpret_cast<const Vector4i*>(pConstantData);
|
||||
auto end = begin + Count;
|
||||
|
||||
std::copy(begin, end, &set.iConsts[StartRegister]);
|
||||
}
|
||||
else {
|
||||
for (uint32_t i = 0; i < Count; i++) {
|
||||
const uint32_t constantIdx = StartRegister + i;
|
||||
const uint32_t arrayIdx = constantIdx / 32;
|
||||
const uint32_t bitIdx = constantIdx % 32;
|
||||
|
||||
const uint32_t bit = 1u << bitIdx;
|
||||
|
||||
set.bConsts[arrayIdx] &= ~bit;
|
||||
if (pConstantData[i])
|
||||
set.bConsts[arrayIdx] |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
return D3D_OK;
|
||||
};
|
||||
|
||||
return ProgramType == DxsoProgramTypes::VertexShader
|
||||
? UpdateHelper(pState->vsConsts)
|
||||
: UpdateHelper(pState->psConsts);
|
||||
}
|
||||
|
||||
enum class D3D9CapturedStateFlag : uint32_t {
|
||||
VertexDecl,
|
||||
Indices,
|
||||
RenderStates,
|
||||
SamplerStates,
|
||||
VertexBuffers,
|
||||
Textures,
|
||||
VertexShader,
|
||||
PixelShader,
|
||||
Viewport,
|
||||
ScissorRect,
|
||||
ClipPlanes,
|
||||
VsConstants,
|
||||
PsConstants,
|
||||
StreamFreq,
|
||||
Transforms,
|
||||
TextureStages,
|
||||
Material
|
||||
};
|
||||
|
||||
using D3D9CapturedStateFlags = Flags<D3D9CapturedStateFlag>;
|
||||
|
||||
struct D3D9StateCaptures {
|
||||
D3D9CapturedStateFlags flags;
|
||||
|
||||
std::bitset<RenderStateCount> renderStates;
|
||||
|
||||
std::bitset<SamplerCount> samplers;
|
||||
std::array<
|
||||
std::bitset<SamplerStateCount>,
|
||||
SamplerCount> samplerStates;
|
||||
|
||||
std::bitset<caps::MaxStreams> vertexBuffers;
|
||||
std::bitset<SamplerCount> textures;
|
||||
std::bitset<caps::MaxClipPlanes> clipPlanes;
|
||||
std::bitset<caps::MaxStreams> streamFreq;
|
||||
std::bitset<caps::MaxTransforms> transforms;
|
||||
std::bitset<caps::TextureStageCount> textureStages;
|
||||
std::array<
|
||||
std::bitset<D3DTSS_CONSTANT>,
|
||||
caps::TextureStageCount> textureStageStates;
|
||||
|
||||
struct {
|
||||
std::bitset<caps::MaxFloatConstantsSoftware> fConsts;
|
||||
std::bitset<caps::MaxOtherConstantsSoftware> iConsts;
|
||||
std::bitset<caps::MaxOtherConstantsSoftware> bConsts;
|
||||
} vsConsts;
|
||||
|
||||
struct {
|
||||
std::bitset<caps::MaxFloatConstantsPS> fConsts;
|
||||
std::bitset<caps::MaxOtherConstants> iConsts;
|
||||
std::bitset<caps::MaxOtherConstants> bConsts;
|
||||
} psConsts;
|
||||
};
|
||||
|
||||
struct Direct3DState9 : public D3D9CapturableState {
|
||||
|
||||
std::array<Com<D3D9Surface, false>, caps::MaxSimultaneousRenderTargets> renderTargets;
|
||||
Com<D3D9Surface, false> depthStencil;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct D3D9InputAssemblyState {
|
||||
D3DPRIMITIVETYPE primitiveType = D3DPRIMITIVETYPE(0);
|
||||
uint32_t streamsInstanced = 0;
|
||||
uint32_t streamsUsed = 0;
|
||||
};
|
||||
|
||||
}
|
519
src/d3d9/d3d9_stateblock.cpp
Normal file
519
src/d3d9/d3d9_stateblock.cpp
Normal file
|
@ -0,0 +1,519 @@
|
|||
#include "d3d9_stateblock.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_vertex_declaration.h"
|
||||
#include "d3d9_buffer.h"
|
||||
#include "d3d9_shader.h"
|
||||
#include "d3d9_texture.h"
|
||||
|
||||
#include "d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9StateBlock::D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type)
|
||||
: D3D9StateBlockBase(pDevice)
|
||||
, m_deviceState (pDevice->GetRawState()) {
|
||||
CaptureType(Type);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9StateBlock::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DStateBlock9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9StateBlock::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9StateBlock::Capture() {
|
||||
ApplyOrCapture<D3D9StateFunction::Capture>();
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9StateBlock::Apply() {
|
||||
m_applying = true;
|
||||
ApplyOrCapture<D3D9StateFunction::Apply>();
|
||||
m_applying = false;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetVertexDeclaration(D3D9VertexDecl* pDecl) {
|
||||
m_state.vertexDecl = pDecl;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VertexDecl);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetIndices(D3D9IndexBuffer* pIndexData) {
|
||||
m_state.indices = pIndexData;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Indices);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetRenderState(D3DRENDERSTATETYPE State, DWORD Value) {
|
||||
m_state.renderStates[State] = Value;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::RenderStates);
|
||||
m_captures.renderStates[State] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetStateSamplerState(
|
||||
DWORD StateSampler,
|
||||
D3DSAMPLERSTATETYPE Type,
|
||||
DWORD Value) {
|
||||
m_state.samplerStates[StateSampler][Type] = Value;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::SamplerStates);
|
||||
m_captures.samplers[StateSampler] = true;
|
||||
m_captures.samplerStates[StateSampler][Type] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetStreamSource(
|
||||
UINT StreamNumber,
|
||||
D3D9VertexBuffer* pStreamData,
|
||||
UINT OffsetInBytes,
|
||||
UINT Stride) {
|
||||
m_state.vertexBuffers[StreamNumber].vertexBuffer = pStreamData;
|
||||
|
||||
m_state.vertexBuffers[StreamNumber].offset = OffsetInBytes;
|
||||
m_state.vertexBuffers[StreamNumber].stride = Stride;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VertexBuffers);
|
||||
m_captures.vertexBuffers[StreamNumber] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetStreamSourceFreq(UINT StreamNumber, UINT Setting) {
|
||||
m_state.streamFreq[StreamNumber] = Setting;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::StreamFreq);
|
||||
m_captures.streamFreq[StreamNumber] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetStateTexture(DWORD StateSampler, IDirect3DBaseTexture9* pTexture) {
|
||||
TextureChangePrivate(m_state.textures[StateSampler], pTexture);
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Textures);
|
||||
m_captures.textures[StateSampler] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetVertexShader(D3D9VertexShader* pShader) {
|
||||
m_state.vertexShader = pShader;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VertexShader);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetPixelShader(D3D9PixelShader* pShader) {
|
||||
m_state.pixelShader = pShader;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::PixelShader);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetMaterial(const D3DMATERIAL9* pMaterial) {
|
||||
m_state.material = *pMaterial;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Material);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix) {
|
||||
m_state.transforms[idx] = ConvertMatrix(pMatrix);
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Transforms);
|
||||
m_captures.transforms.set(idx);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetTextureStageState(
|
||||
DWORD Stage,
|
||||
D3DTEXTURESTAGESTATETYPE Type,
|
||||
DWORD Value) {
|
||||
m_state.textureStages[Stage][Type] = Value;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::TextureStages);
|
||||
m_captures.textureStages[Stage] = true;
|
||||
m_captures.textureStageStates[Stage][Type] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::MultiplyStateTransform(uint32_t idx, const D3DMATRIX* pMatrix) {
|
||||
m_state.transforms[idx] = ConvertMatrix(pMatrix) * m_state.transforms[idx];
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Transforms);
|
||||
m_captures.transforms.set(idx);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetViewport(const D3DVIEWPORT9* pViewport) {
|
||||
m_state.viewport = *pViewport;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Viewport);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetScissorRect(const RECT* pRect) {
|
||||
m_state.scissorRect = *pRect;
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::ScissorRect);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetClipPlane(DWORD Index, const float* pPlane) {
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
m_state.clipPlanes[Index].coeff[i] = pPlane[i];
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::ClipPlanes);
|
||||
m_captures.clipPlanes[Index] = true;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetVertexShaderConstantF(
|
||||
UINT StartRegister,
|
||||
const float* pConstantData,
|
||||
UINT Vector4fCount) {
|
||||
return SetShaderConstants<
|
||||
DxsoProgramTypes::VertexShader,
|
||||
D3D9ConstantType::Float>(
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
Vector4fCount);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetVertexShaderConstantI(
|
||||
UINT StartRegister,
|
||||
const int* pConstantData,
|
||||
UINT Vector4iCount) {
|
||||
return SetShaderConstants<
|
||||
DxsoProgramTypes::VertexShader,
|
||||
D3D9ConstantType::Int>(
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
Vector4iCount);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetVertexShaderConstantB(
|
||||
UINT StartRegister,
|
||||
const BOOL* pConstantData,
|
||||
UINT BoolCount) {
|
||||
return SetShaderConstants<
|
||||
DxsoProgramTypes::VertexShader,
|
||||
D3D9ConstantType::Bool>(
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
BoolCount);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetPixelShaderConstantF(
|
||||
UINT StartRegister,
|
||||
const float* pConstantData,
|
||||
UINT Vector4fCount) {
|
||||
return SetShaderConstants<
|
||||
DxsoProgramTypes::PixelShader,
|
||||
D3D9ConstantType::Float>(
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
Vector4fCount);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetPixelShaderConstantI(
|
||||
UINT StartRegister,
|
||||
const int* pConstantData,
|
||||
UINT Vector4iCount) {
|
||||
return SetShaderConstants<
|
||||
DxsoProgramTypes::PixelShader,
|
||||
D3D9ConstantType::Int>(
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
Vector4iCount);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetPixelShaderConstantB(
|
||||
UINT StartRegister,
|
||||
const BOOL* pConstantData,
|
||||
UINT BoolCount) {
|
||||
return SetShaderConstants<
|
||||
DxsoProgramTypes::PixelShader,
|
||||
D3D9ConstantType::Bool>(
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
BoolCount);
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits) {
|
||||
m_state.vsConsts.bConsts[idx] &= ~mask;
|
||||
m_state.vsConsts.bConsts[idx] |= bits & mask;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT D3D9StateBlock::SetPixelBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits) {
|
||||
m_state.psConsts.bConsts[idx] &= ~mask;
|
||||
m_state.psConsts.bConsts[idx] |= bits & mask;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CapturePixelRenderStates() {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::RenderStates);
|
||||
|
||||
m_captures.renderStates[D3DRS_ZENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_FILLMODE] = true;
|
||||
m_captures.renderStates[D3DRS_SHADEMODE] = true;
|
||||
m_captures.renderStates[D3DRS_ZWRITEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_ALPHATESTENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_LASTPIXEL] = true;
|
||||
m_captures.renderStates[D3DRS_SRCBLEND] = true;
|
||||
m_captures.renderStates[D3DRS_DESTBLEND] = true;
|
||||
m_captures.renderStates[D3DRS_ZFUNC] = true;
|
||||
m_captures.renderStates[D3DRS_ALPHAREF] = true;
|
||||
m_captures.renderStates[D3DRS_ALPHAFUNC] = true;
|
||||
m_captures.renderStates[D3DRS_DITHERENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_FOGSTART] = true;
|
||||
m_captures.renderStates[D3DRS_FOGEND] = true;
|
||||
m_captures.renderStates[D3DRS_FOGDENSITY] = true;
|
||||
m_captures.renderStates[D3DRS_ALPHABLENDENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_DEPTHBIAS] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILFAIL] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILZFAIL] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILPASS] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILFUNC] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILREF] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILMASK] = true;
|
||||
m_captures.renderStates[D3DRS_STENCILWRITEMASK] = true;
|
||||
m_captures.renderStates[D3DRS_TEXTUREFACTOR] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP0] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP1] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP2] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP3] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP4] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP5] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP6] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP7] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP8] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP9] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP10] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP11] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP12] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP13] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP14] = true;
|
||||
m_captures.renderStates[D3DRS_WRAP15] = true;
|
||||
m_captures.renderStates[D3DRS_COLORWRITEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_BLENDOP] = true;
|
||||
m_captures.renderStates[D3DRS_SCISSORTESTENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_SLOPESCALEDEPTHBIAS] = true;
|
||||
m_captures.renderStates[D3DRS_ANTIALIASEDLINEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_TWOSIDEDSTENCILMODE] = true;
|
||||
m_captures.renderStates[D3DRS_CCW_STENCILFAIL] = true;
|
||||
m_captures.renderStates[D3DRS_CCW_STENCILZFAIL] = true;
|
||||
m_captures.renderStates[D3DRS_CCW_STENCILPASS] = true;
|
||||
m_captures.renderStates[D3DRS_CCW_STENCILFUNC] = true;
|
||||
m_captures.renderStates[D3DRS_COLORWRITEENABLE1] = true;
|
||||
m_captures.renderStates[D3DRS_COLORWRITEENABLE2] = true;
|
||||
m_captures.renderStates[D3DRS_COLORWRITEENABLE3] = true;
|
||||
m_captures.renderStates[D3DRS_BLENDFACTOR] = true;
|
||||
m_captures.renderStates[D3DRS_SRGBWRITEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_SEPARATEALPHABLENDENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_SRCBLENDALPHA] = true;
|
||||
m_captures.renderStates[D3DRS_DESTBLENDALPHA] = true;
|
||||
m_captures.renderStates[D3DRS_BLENDOPALPHA] = true;
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CapturePixelSamplerStates() {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::SamplerStates);
|
||||
|
||||
for (uint32_t i = 0; i < 17; i++) {
|
||||
m_captures.samplers[i] = true;
|
||||
|
||||
m_captures.samplerStates[i][D3DSAMP_ADDRESSU] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_ADDRESSV] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_ADDRESSW] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_BORDERCOLOR] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_MAGFILTER] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_MINFILTER] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_MIPFILTER] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_MIPMAPLODBIAS] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_MAXMIPLEVEL] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_MAXANISOTROPY] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_SRGBTEXTURE] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_ELEMENTINDEX] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CapturePixelShaderStates() {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::PixelShader);
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::PsConstants);
|
||||
|
||||
m_captures.psConsts.fConsts.flip();
|
||||
m_captures.psConsts.iConsts.flip();
|
||||
m_captures.psConsts.bConsts.flip();
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CaptureVertexRenderStates() {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::RenderStates);
|
||||
|
||||
m_captures.renderStates[D3DRS_CULLMODE] = true;
|
||||
m_captures.renderStates[D3DRS_FOGENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_FOGCOLOR] = true;
|
||||
m_captures.renderStates[D3DRS_FOGTABLEMODE] = true;
|
||||
m_captures.renderStates[D3DRS_FOGSTART] = true;
|
||||
m_captures.renderStates[D3DRS_FOGEND] = true;
|
||||
m_captures.renderStates[D3DRS_FOGDENSITY] = true;
|
||||
m_captures.renderStates[D3DRS_RANGEFOGENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_AMBIENT] = true;
|
||||
m_captures.renderStates[D3DRS_COLORVERTEX] = true;
|
||||
m_captures.renderStates[D3DRS_FOGVERTEXMODE] = true;
|
||||
m_captures.renderStates[D3DRS_CLIPPING] = true;
|
||||
m_captures.renderStates[D3DRS_LIGHTING] = true;
|
||||
m_captures.renderStates[D3DRS_LOCALVIEWER] = true;
|
||||
m_captures.renderStates[D3DRS_EMISSIVEMATERIALSOURCE] = true;
|
||||
m_captures.renderStates[D3DRS_AMBIENTMATERIALSOURCE] = true;
|
||||
m_captures.renderStates[D3DRS_DIFFUSEMATERIALSOURCE] = true;
|
||||
m_captures.renderStates[D3DRS_SPECULARMATERIALSOURCE] = true;
|
||||
m_captures.renderStates[D3DRS_VERTEXBLEND] = true;
|
||||
m_captures.renderStates[D3DRS_CLIPPLANEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSIZE] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSIZE_MIN] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSPRITEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSCALEENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSCALE_A] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSCALE_B] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSCALE_C] = true;
|
||||
m_captures.renderStates[D3DRS_MULTISAMPLEANTIALIAS] = true;
|
||||
m_captures.renderStates[D3DRS_MULTISAMPLEMASK] = true;
|
||||
m_captures.renderStates[D3DRS_PATCHEDGESTYLE] = true;
|
||||
m_captures.renderStates[D3DRS_POINTSIZE_MAX] = true;
|
||||
m_captures.renderStates[D3DRS_INDEXEDVERTEXBLENDENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_TWEENFACTOR] = true;
|
||||
m_captures.renderStates[D3DRS_POSITIONDEGREE] = true;
|
||||
m_captures.renderStates[D3DRS_NORMALDEGREE] = true;
|
||||
m_captures.renderStates[D3DRS_MINTESSELLATIONLEVEL] = true;
|
||||
m_captures.renderStates[D3DRS_MAXTESSELLATIONLEVEL] = true;
|
||||
m_captures.renderStates[D3DRS_ADAPTIVETESS_X] = true;
|
||||
m_captures.renderStates[D3DRS_ADAPTIVETESS_Y] = true;
|
||||
m_captures.renderStates[D3DRS_ADAPTIVETESS_Z] = true;
|
||||
m_captures.renderStates[D3DRS_ADAPTIVETESS_W] = true;
|
||||
m_captures.renderStates[D3DRS_ENABLEADAPTIVETESSELLATION] = true;
|
||||
m_captures.renderStates[D3DRS_NORMALIZENORMALS] = true;
|
||||
m_captures.renderStates[D3DRS_SPECULARENABLE] = true;
|
||||
m_captures.renderStates[D3DRS_SHADEMODE] = true;
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CaptureVertexSamplerStates() {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::SamplerStates);
|
||||
|
||||
for (uint32_t i = 17; i < SamplerCount; i++) {
|
||||
m_captures.samplers[i] = true;
|
||||
m_captures.samplerStates[i][D3DSAMP_DMAPOFFSET] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CaptureVertexShaderStates() {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VertexShader);
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VsConstants);
|
||||
|
||||
m_captures.vsConsts.fConsts.flip();
|
||||
m_captures.vsConsts.iConsts.flip();
|
||||
m_captures.vsConsts.bConsts.flip();
|
||||
}
|
||||
|
||||
|
||||
void D3D9StateBlock::CaptureType(D3D9StateBlockType Type) {
|
||||
if (Type == D3D9StateBlockType::PixelState || Type == D3D9StateBlockType::All) {
|
||||
CapturePixelRenderStates();
|
||||
CapturePixelSamplerStates();
|
||||
CapturePixelShaderStates();
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::TextureStages);
|
||||
m_captures.textureStages.flip();
|
||||
for (auto& stage : m_captures.textureStageStates)
|
||||
stage.flip();
|
||||
}
|
||||
|
||||
if (Type == D3D9StateBlockType::VertexState || Type == D3D9StateBlockType::All) {
|
||||
CaptureVertexRenderStates();
|
||||
CaptureVertexSamplerStates();
|
||||
CaptureVertexShaderStates();
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VertexDecl);
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::StreamFreq);
|
||||
|
||||
for (uint32_t i = 0; i < caps::MaxStreams; i++)
|
||||
m_captures.streamFreq[i] = true;
|
||||
}
|
||||
|
||||
if (Type == D3D9StateBlockType::All) {
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Textures);
|
||||
m_captures.textures.flip();
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VertexBuffers);
|
||||
m_captures.vertexBuffers.flip();
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Indices);
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Viewport);
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::ScissorRect);
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::ClipPlanes);
|
||||
m_captures.clipPlanes.flip();
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Transforms);
|
||||
m_captures.transforms.flip();
|
||||
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::Material);
|
||||
}
|
||||
|
||||
if (Type != D3D9StateBlockType::None)
|
||||
this->Capture();
|
||||
}
|
||||
|
||||
}
|
333
src/d3d9/d3d9_stateblock.h
Normal file
333
src/d3d9/d3d9_stateblock.h
Normal file
|
@ -0,0 +1,333 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device_child.h"
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_state.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum class D3D9StateBlockType :uint32_t {
|
||||
None,
|
||||
VertexState,
|
||||
PixelState,
|
||||
All
|
||||
};
|
||||
|
||||
inline D3D9StateBlockType ConvertStateBlockType(D3DSTATEBLOCKTYPE type) {
|
||||
switch (type) {
|
||||
case D3DSBT_PIXELSTATE: return D3D9StateBlockType::PixelState;
|
||||
case D3DSBT_VERTEXSTATE: return D3D9StateBlockType::VertexState;
|
||||
default:
|
||||
case D3DSBT_ALL: return D3D9StateBlockType::All;
|
||||
}
|
||||
}
|
||||
|
||||
using D3D9StateBlockBase = D3D9DeviceChild<IDirect3DStateBlock9>;
|
||||
class D3D9StateBlock : public D3D9StateBlockBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9StateBlock(D3D9DeviceEx* pDevice, D3D9StateBlockType Type);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Capture() final;
|
||||
HRESULT STDMETHODCALLTYPE Apply() final;
|
||||
|
||||
HRESULT SetVertexDeclaration(D3D9VertexDecl* pDecl);
|
||||
|
||||
HRESULT SetIndices(D3D9IndexBuffer* pIndexData);
|
||||
|
||||
HRESULT SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
|
||||
|
||||
HRESULT SetStateSamplerState(
|
||||
DWORD StateSampler,
|
||||
D3DSAMPLERSTATETYPE Type,
|
||||
DWORD Value);
|
||||
|
||||
HRESULT SetStreamSource(
|
||||
UINT StreamNumber,
|
||||
D3D9VertexBuffer* pStreamData,
|
||||
UINT OffsetInBytes,
|
||||
UINT Stride);
|
||||
|
||||
HRESULT SetStreamSourceFreq(UINT StreamNumber, UINT Setting);
|
||||
|
||||
HRESULT SetStateTexture(DWORD StateSampler, IDirect3DBaseTexture9* pTexture);
|
||||
|
||||
HRESULT SetVertexShader(D3D9VertexShader* pShader);
|
||||
|
||||
HRESULT SetPixelShader(D3D9PixelShader* pShader);
|
||||
|
||||
HRESULT SetMaterial(const D3DMATERIAL9* pMaterial);
|
||||
|
||||
HRESULT SetStateTransform(uint32_t idx, const D3DMATRIX* pMatrix);
|
||||
|
||||
HRESULT SetTextureStageState(
|
||||
DWORD Stage,
|
||||
D3DTEXTURESTAGESTATETYPE Type,
|
||||
DWORD Value);
|
||||
|
||||
HRESULT MultiplyStateTransform(uint32_t idx, const D3DMATRIX* pMatrix);
|
||||
|
||||
HRESULT SetViewport(const D3DVIEWPORT9* pViewport);
|
||||
|
||||
HRESULT SetScissorRect(const RECT* pRect);
|
||||
|
||||
HRESULT SetClipPlane(DWORD Index, const float* pPlane);
|
||||
|
||||
|
||||
HRESULT SetVertexShaderConstantF(
|
||||
UINT StartRegister,
|
||||
const float* pConstantData,
|
||||
UINT Vector4fCount);
|
||||
|
||||
HRESULT SetVertexShaderConstantI(
|
||||
UINT StartRegister,
|
||||
const int* pConstantData,
|
||||
UINT Vector4iCount);
|
||||
|
||||
HRESULT SetVertexShaderConstantB(
|
||||
UINT StartRegister,
|
||||
const BOOL* pConstantData,
|
||||
UINT BoolCount);
|
||||
|
||||
|
||||
HRESULT SetPixelShaderConstantF(
|
||||
UINT StartRegister,
|
||||
const float* pConstantData,
|
||||
UINT Vector4fCount);
|
||||
|
||||
HRESULT SetPixelShaderConstantI(
|
||||
UINT StartRegister,
|
||||
const int* pConstantData,
|
||||
UINT Vector4iCount);
|
||||
|
||||
HRESULT SetPixelShaderConstantB(
|
||||
UINT StartRegister,
|
||||
const BOOL* pConstantData,
|
||||
UINT BoolCount);
|
||||
|
||||
enum class D3D9StateFunction {
|
||||
Apply,
|
||||
Capture
|
||||
};
|
||||
|
||||
template <typename Dst, typename Src>
|
||||
void ApplyOrCapture(Dst* dst, const Src* src) {
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::VertexDecl))
|
||||
dst->SetVertexDeclaration(src->vertexDecl.ptr());
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::StreamFreq)) {
|
||||
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
|
||||
if (m_captures.streamFreq[i])
|
||||
dst->SetStreamSourceFreq(i, src->streamFreq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::Indices))
|
||||
dst->SetIndices(src->indices.ptr());
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::RenderStates)) {
|
||||
for (uint32_t i = 0; i < m_captures.renderStates.size(); i++) {
|
||||
if (m_captures.renderStates[i])
|
||||
dst->SetRenderState(D3DRENDERSTATETYPE(i), src->renderStates[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::SamplerStates)) {
|
||||
for (uint32_t i = 0; i < m_captures.samplerStates.size(); i++) {
|
||||
if (m_captures.samplers[i]) {
|
||||
for (uint32_t j = 0; j < m_captures.samplerStates[i].size(); j++) {
|
||||
if (m_captures.samplerStates[i][j])
|
||||
dst->SetStateSamplerState(i, D3DSAMPLERSTATETYPE(j), src->samplerStates[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::VertexBuffers)) {
|
||||
for (uint32_t i = 0; i < m_captures.vertexBuffers.size(); i++) {
|
||||
if (m_captures.vertexBuffers[i]) {
|
||||
const auto& vbo = src->vertexBuffers[i];
|
||||
dst->SetStreamSource(
|
||||
i,
|
||||
vbo.vertexBuffer.ptr(),
|
||||
vbo.offset,
|
||||
vbo.stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::Material))
|
||||
dst->SetMaterial(&src->material);
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::Textures)) {
|
||||
for (uint32_t i = 0; i < m_captures.textures.size(); i++) {
|
||||
if (m_captures.textures[i])
|
||||
dst->SetStateTexture(i, src->textures[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::VertexShader))
|
||||
dst->SetVertexShader(src->vertexShader.ptr());
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::PixelShader))
|
||||
dst->SetPixelShader(src->pixelShader.ptr());
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::Transforms)) {
|
||||
for (uint32_t i = 0; i < m_captures.transforms.size(); i++) {
|
||||
if (m_captures.transforms[i])
|
||||
dst->SetStateTransform(i, reinterpret_cast<const D3DMATRIX*>(&src->transforms[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::TextureStages)) {
|
||||
for (uint32_t i = 0; i < m_captures.textureStages.size(); i++) {
|
||||
if (m_captures.textureStages[i]) {
|
||||
for (uint32_t j = 0; j < m_captures.textureStageStates[i].size(); j++) {
|
||||
if (m_captures.textureStageStates[i][j])
|
||||
dst->SetTextureStageState(i, (D3DTEXTURESTAGESTATETYPE)j, src->textureStages[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::Viewport))
|
||||
dst->SetViewport(&src->viewport);
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::ScissorRect))
|
||||
dst->SetScissorRect(&src->scissorRect);
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::ClipPlanes)) {
|
||||
for (uint32_t i = 0; i < m_captures.clipPlanes.size(); i++) {
|
||||
if (m_captures.clipPlanes[i])
|
||||
dst->SetClipPlane(i, src->clipPlanes[i].coeff);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::VsConstants)) {
|
||||
for (uint32_t i = 0; i < m_captures.vsConsts.fConsts.size(); i++) {
|
||||
if (m_captures.vsConsts.fConsts[i])
|
||||
dst->SetVertexShaderConstantF(i, (float*)&src->vsConsts.fConsts[i], 1);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < m_captures.vsConsts.iConsts.size(); i++) {
|
||||
if (m_captures.vsConsts.iConsts[i])
|
||||
dst->SetVertexShaderConstantI(i, (int*)&src->vsConsts.iConsts[i], 1);
|
||||
}
|
||||
|
||||
const uint32_t bitfieldCount = m_parent->GetVertexConstantLayout().bitmaskCount;
|
||||
for (uint32_t i = 0; i < bitfieldCount; i++) {
|
||||
uint32_t boolMask = 0;
|
||||
for (uint32_t j = 0; j < 32; j++) {
|
||||
if (m_captures.vsConsts.bConsts[i * 32 + j])
|
||||
boolMask |= 1u << j;
|
||||
}
|
||||
|
||||
dst->SetVertexBoolBitfield(i, boolMask, src->vsConsts.bConsts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_captures.flags.test(D3D9CapturedStateFlag::PsConstants)) {
|
||||
for (uint32_t i = 0; i < m_captures.psConsts.fConsts.size(); i++) {
|
||||
if (m_captures.psConsts.fConsts[i])
|
||||
dst->SetPixelShaderConstantF(i, (float*)&src->psConsts.fConsts[i], 1);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < m_captures.psConsts.iConsts.size(); i++) {
|
||||
if (m_captures.psConsts.iConsts[i])
|
||||
dst->SetPixelShaderConstantI(i, (int*)&src->psConsts.iConsts[i], 1);
|
||||
}
|
||||
|
||||
uint32_t boolMask = 0;
|
||||
for (uint32_t i = 0; i < m_captures.psConsts.bConsts.size(); i++) {
|
||||
if (m_captures.psConsts.bConsts[i])
|
||||
boolMask |= 1u << i;
|
||||
}
|
||||
|
||||
dst->SetPixelBoolBitfield(0, boolMask, src->psConsts.bConsts[0]);
|
||||
}
|
||||
}
|
||||
|
||||
template <D3D9StateFunction Func>
|
||||
void ApplyOrCapture() {
|
||||
if constexpr (Func == D3D9StateFunction::Apply)
|
||||
ApplyOrCapture(m_parent, &m_state);
|
||||
else if constexpr (Func == D3D9StateFunction::Capture)
|
||||
ApplyOrCapture(this, m_deviceState);
|
||||
}
|
||||
|
||||
template <
|
||||
DxsoProgramType ProgramType,
|
||||
D3D9ConstantType ConstantType,
|
||||
typename T>
|
||||
HRESULT SetShaderConstants(
|
||||
UINT StartRegister,
|
||||
const T* pConstantData,
|
||||
UINT Count) {
|
||||
auto SetHelper = [&](auto& setCaptures) {
|
||||
if constexpr (ProgramType == DxsoProgramTypes::VertexShader)
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::VsConstants);
|
||||
else
|
||||
m_captures.flags.set(D3D9CapturedStateFlag::PsConstants);
|
||||
|
||||
for (uint32_t i = 0; i < Count; i++) {
|
||||
uint32_t reg = StartRegister + i;
|
||||
if constexpr (ConstantType == D3D9ConstantType::Float)
|
||||
setCaptures.fConsts[reg] = true;
|
||||
else if constexpr (ConstantType == D3D9ConstantType::Int)
|
||||
setCaptures.iConsts[reg] = true;
|
||||
else if constexpr (ConstantType == D3D9ConstantType::Bool)
|
||||
setCaptures.bConsts[reg] = true;
|
||||
}
|
||||
|
||||
UpdateStateConstants<
|
||||
ProgramType,
|
||||
ConstantType,
|
||||
T>(
|
||||
&m_state,
|
||||
StartRegister,
|
||||
pConstantData,
|
||||
Count,
|
||||
false);
|
||||
|
||||
return D3D_OK;
|
||||
};
|
||||
|
||||
return ProgramType == DxsoProgramTypes::VertexShader
|
||||
? SetHelper(m_captures.vsConsts)
|
||||
: SetHelper(m_captures.psConsts);
|
||||
}
|
||||
|
||||
HRESULT SetVertexBoolBitfield(uint32_t idx, uint32_t mask, uint32_t bits);
|
||||
HRESULT SetPixelBoolBitfield (uint32_t idx, uint32_t mask, uint32_t bits);
|
||||
|
||||
inline bool IsApplying() {
|
||||
return m_applying;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void CapturePixelRenderStates();
|
||||
void CapturePixelSamplerStates();
|
||||
void CapturePixelShaderStates();
|
||||
|
||||
void CaptureVertexRenderStates();
|
||||
void CaptureVertexSamplerStates();
|
||||
void CaptureVertexShaderStates();
|
||||
|
||||
void CaptureType(D3D9StateBlockType State);
|
||||
|
||||
D3D9CapturableState m_state;
|
||||
D3D9StateCaptures m_captures;
|
||||
|
||||
D3D9CapturableState* m_deviceState;
|
||||
|
||||
bool m_applying = false;
|
||||
|
||||
};
|
||||
|
||||
}
|
106
src/d3d9/d3d9_subresource.h
Normal file
106
src/d3d9/d3d9_subresource.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_resource.h"
|
||||
#include "d3d9_common_texture.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename... Type>
|
||||
class D3D9Subresource : public D3D9Resource<Type...> {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Subresource(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9CommonTexture* pTexture,
|
||||
UINT Face,
|
||||
UINT MipLevel,
|
||||
IDirect3DBaseTexture9* pContainer)
|
||||
: D3D9Resource<Type...> ( pDevice )
|
||||
, m_container ( pContainer )
|
||||
, m_texture ( pTexture )
|
||||
, m_face ( Face )
|
||||
, m_mipLevel ( MipLevel ) { }
|
||||
|
||||
~D3D9Subresource() {
|
||||
// We own the texture!
|
||||
if (m_container == nullptr)
|
||||
delete m_texture;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() final {
|
||||
if (m_container != nullptr)
|
||||
return m_container->AddRef();
|
||||
|
||||
return D3D9Resource<Type...>::AddRef();
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE Release() final {
|
||||
if (m_container != nullptr)
|
||||
return m_container->Release();
|
||||
|
||||
return D3D9Resource<Type...>::Release();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetContainer(REFIID riid, void** ppContainer) final {
|
||||
if (m_container != nullptr)
|
||||
return m_container->QueryInterface(riid, ppContainer);
|
||||
|
||||
return this->GetDevice()->QueryInterface(riid, ppContainer);
|
||||
}
|
||||
|
||||
D3D9CommonTexture* GetCommonTexture() {
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
UINT GetFace() const {
|
||||
return m_face;
|
||||
}
|
||||
|
||||
UINT GetMipLevel() const {
|
||||
return m_mipLevel;
|
||||
}
|
||||
|
||||
UINT GetSubresource() const {
|
||||
return m_texture->CalcSubresource(m_face, m_mipLevel);
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> GetImageView(bool Srgb) {
|
||||
return m_texture->GetViews().SubresourceSample[m_face][m_mipLevel].Pick(Srgb);
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> GetRenderTargetView(bool Srgb) {
|
||||
return m_texture->GetViews().SubresourceRenderTarget[m_face][m_mipLevel].Pick(Srgb);
|
||||
}
|
||||
|
||||
VkImageLayout GetRenderTargetLayout() {
|
||||
return m_texture->GetViews().GetRTLayout();
|
||||
}
|
||||
|
||||
Rc<DxvkImageView> GetDepthStencilView() {
|
||||
return m_texture->GetViews().SubresourceDepth[m_face][m_mipLevel];
|
||||
}
|
||||
|
||||
VkImageLayout GetDepthLayout() {
|
||||
return m_texture->GetViews().GetDepthLayout();
|
||||
}
|
||||
|
||||
bool IsNull() {
|
||||
return m_texture->Desc()->Format == D3D9Format::NULL_FORMAT;
|
||||
}
|
||||
|
||||
IDirect3DBaseTexture9* GetBaseTexture() {
|
||||
return m_container;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
IDirect3DBaseTexture9* m_container;
|
||||
|
||||
D3D9CommonTexture* m_texture;
|
||||
UINT m_face;
|
||||
UINT m_mipLevel;
|
||||
|
||||
};
|
||||
|
||||
}
|
184
src/d3d9/d3d9_surface.cpp
Normal file
184
src/d3d9/d3d9_surface.cpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include "d3d9_surface.h"
|
||||
#include "d3d9_texture.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9Surface::D3D9Surface(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: D3D9SurfaceBase(
|
||||
pDevice,
|
||||
new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_TEXTURE, Mapping ),
|
||||
0, 0,
|
||||
nullptr) { }
|
||||
|
||||
D3D9Surface::D3D9Surface(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9CommonTexture* pTexture,
|
||||
UINT Face,
|
||||
UINT MipLevel,
|
||||
IDirect3DBaseTexture9* pContainer)
|
||||
: D3D9SurfaceBase(
|
||||
pDevice,
|
||||
pTexture,
|
||||
Face, MipLevel,
|
||||
pContainer) { }
|
||||
|
||||
void D3D9Surface::AddRefPrivate() {
|
||||
IDirect3DBaseTexture9* pContainer = this->m_container;
|
||||
|
||||
if (pContainer != nullptr) {
|
||||
D3DRESOURCETYPE type = pContainer->GetType();
|
||||
if (type == D3DRTYPE_TEXTURE)
|
||||
reinterpret_cast<D3D9Texture2D*> (pContainer)->AddRefPrivate();
|
||||
else //if (type == D3DRTYPE_CUBETEXTURE)
|
||||
reinterpret_cast<D3D9TextureCube*>(pContainer)->AddRefPrivate();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
D3D9SurfaceBase::AddRefPrivate();
|
||||
}
|
||||
|
||||
void D3D9Surface::ReleasePrivate() {
|
||||
IDirect3DBaseTexture9* pContainer = this->m_container;
|
||||
|
||||
if (pContainer != nullptr) {
|
||||
D3DRESOURCETYPE type = pContainer->GetType();
|
||||
if (type == D3DRTYPE_TEXTURE)
|
||||
reinterpret_cast<D3D9Texture2D*> (pContainer)->ReleasePrivate();
|
||||
else //if (type == D3DRTYPE_CUBETEXTURE)
|
||||
reinterpret_cast<D3D9TextureCube*>(pContainer)->ReleasePrivate();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
D3D9SurfaceBase::ReleasePrivate();
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Surface::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DSurface9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9Surface::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Surface::GetType() {
|
||||
return D3DRTYPE_SURFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Surface::GetDesc(D3DSURFACE_DESC *pDesc) {
|
||||
if (pDesc == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto& desc = *(m_texture->Desc());
|
||||
|
||||
pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
|
||||
pDesc->Type = D3DRTYPE_SURFACE;
|
||||
pDesc->Usage = desc.Usage;
|
||||
pDesc->Pool = desc.Pool;
|
||||
|
||||
pDesc->MultiSampleType = desc.MultiSample;
|
||||
pDesc->MultiSampleQuality = desc.MultisampleQuality;
|
||||
pDesc->Width = std::max(1u, desc.Width >> m_mipLevel);
|
||||
pDesc->Height = std::max(1u, desc.Height >> m_mipLevel);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Surface::LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
|
||||
D3DBOX box;
|
||||
if (pRect != nullptr) {
|
||||
box.Left = pRect->left;
|
||||
box.Right = pRect->right;
|
||||
box.Top = pRect->top;
|
||||
box.Bottom = pRect->bottom;
|
||||
box.Front = 0;
|
||||
box.Back = 1;
|
||||
}
|
||||
|
||||
D3DLOCKED_BOX lockedBox;
|
||||
|
||||
HRESULT hr = m_parent->LockImage(
|
||||
m_texture,
|
||||
m_face, m_mipLevel,
|
||||
&lockedBox,
|
||||
pRect != nullptr ? &box : nullptr,
|
||||
Flags);
|
||||
|
||||
pLockedRect->pBits = lockedBox.pBits;
|
||||
pLockedRect->Pitch = lockedBox.RowPitch;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Surface::UnlockRect() {
|
||||
return m_parent->UnlockImage(
|
||||
m_texture,
|
||||
m_face, m_mipLevel);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Surface::GetDC(HDC *phDC) {
|
||||
if (phDC == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
const D3D9_COMMON_TEXTURE_DESC& desc = *m_texture->Desc();
|
||||
|
||||
D3DLOCKED_RECT lockedRect;
|
||||
HRESULT hr = LockRect(&lockedRect, nullptr, 0);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
D3DKMT_CREATEDCFROMMEMORY createInfo;
|
||||
// In...
|
||||
createInfo.pMemory = lockedRect.pBits;
|
||||
createInfo.Format = static_cast<D3DFORMAT>(desc.Format);
|
||||
createInfo.Width = desc.Width;
|
||||
createInfo.Height = desc.Height;
|
||||
createInfo.Pitch = lockedRect.Pitch;
|
||||
createInfo.hDeviceDc = CreateCompatibleDC(NULL);
|
||||
createInfo.pColorTable = nullptr;
|
||||
|
||||
// Out...
|
||||
createInfo.hBitmap = nullptr;
|
||||
createInfo.hDc = nullptr;
|
||||
|
||||
D3DKMTCreateDCFromMemory(&createInfo);
|
||||
DeleteDC(createInfo.hDeviceDc);
|
||||
|
||||
// These should now be set...
|
||||
m_dcDesc.hDC = createInfo.hDc;
|
||||
m_dcDesc.hBitmap = createInfo.hBitmap;
|
||||
|
||||
*phDC = m_dcDesc.hDC;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Surface::ReleaseDC(HDC hDC) {
|
||||
if (m_dcDesc.hDC == nullptr || m_dcDesc.hDC != hDC)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
D3DKMTDestroyDCFromMemory(&m_dcDesc);
|
||||
|
||||
HRESULT hr = UnlockRect();
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
53
src/d3d9/d3d9_surface.h
Normal file
53
src/d3d9/d3d9_surface.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_subresource.h"
|
||||
|
||||
#include "d3d9_common_texture.h"
|
||||
|
||||
#include "../util/util_gdi.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
using D3D9GDIDesc = D3DKMT_DESTROYDCFROMMEMORY;
|
||||
|
||||
using D3D9SurfaceBase = D3D9Subresource<IDirect3DSurface9>;
|
||||
class D3D9Surface final : public D3D9SurfaceBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Surface(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping);
|
||||
|
||||
D3D9Surface(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9CommonTexture* pTexture,
|
||||
UINT Face,
|
||||
UINT MipLevel,
|
||||
IDirect3DBaseTexture9* pContainer);
|
||||
|
||||
void AddRefPrivate();
|
||||
|
||||
void ReleasePrivate();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DSURFACE_DESC *pDesc) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect() final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDC(HDC *phDC) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ReleaseDC(HDC hDC) final;
|
||||
|
||||
private:
|
||||
|
||||
D3D9GDIDesc m_dcDesc;
|
||||
|
||||
};
|
||||
}
|
1216
src/d3d9/d3d9_swapchain.cpp
Normal file
1216
src/d3d9/d3d9_swapchain.cpp
Normal file
File diff suppressed because it is too large
Load diff
226
src/d3d9/d3d9_swapchain.h
Normal file
226
src/d3d9/d3d9_swapchain.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device_child.h"
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_format.h"
|
||||
|
||||
#include "../dxvk/hud/dxvk_hud.h"
|
||||
|
||||
#include "../util/sync/sync_signal.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9Surface;
|
||||
|
||||
/**
|
||||
* \brief Gamma control point
|
||||
*
|
||||
* Control points are stored as normalized
|
||||
* 16-bit unsigned integer values that will
|
||||
* be converted back to floats in the shader.
|
||||
*/
|
||||
struct D3D9_VK_GAMMA_CP {
|
||||
uint16_t R, G, B, A;
|
||||
};
|
||||
|
||||
using D3D9SwapChainExBase = D3D9DeviceChild<IDirect3DSwapChain9Ex>;
|
||||
class D3D9SwapChainEx final : public D3D9SwapChainExBase {
|
||||
static constexpr uint32_t NumControlPoints = 256;
|
||||
public:
|
||||
|
||||
D3D9SwapChainEx(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3DPRESENT_PARAMETERS* pPresentParams,
|
||||
const D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||
|
||||
~D3D9SwapChainEx();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE Present(
|
||||
const RECT* pSourceRect,
|
||||
const RECT* pDestRect,
|
||||
HWND hDestWindowOverride,
|
||||
const RGNDATA* pDirtyRegion,
|
||||
DWORD dwFlags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetBackBuffer(
|
||||
UINT iBackBuffer,
|
||||
D3DBACKBUFFER_TYPE Type,
|
||||
IDirect3DSurface9** ppBackBuffer);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetRasterStatus(D3DRASTER_STATUS* pRasterStatus);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDisplayMode(D3DDISPLAYMODE* pMode);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPresentParameters(D3DPRESENT_PARAMETERS* pPresentationParameters);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT* pLastPresentCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetPresentStats(D3DPRESENTSTATS* pPresentationStatistics);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDisplayModeEx(D3DDISPLAYMODEEX* pMode, D3DDISPLAYROTATION* pRotation);
|
||||
|
||||
void Reset(
|
||||
D3DPRESENT_PARAMETERS* pPresentParams,
|
||||
D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||
|
||||
HRESULT WaitForVBlank();
|
||||
|
||||
void SetGammaRamp(
|
||||
DWORD Flags,
|
||||
const D3DGAMMARAMP* pRamp);
|
||||
|
||||
void GetGammaRamp(D3DGAMMARAMP* pRamp);
|
||||
|
||||
void Invalidate(HWND hWindow);
|
||||
|
||||
HRESULT SetDialogBoxMode(bool bEnableDialogs);
|
||||
|
||||
D3D9Surface* GetBackBuffer(UINT iBackBuffer);
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
Image = 0,
|
||||
Gamma = 1,
|
||||
};
|
||||
|
||||
|
||||
struct WindowState {
|
||||
LONG style = 0;
|
||||
LONG exstyle = 0;
|
||||
RECT rect = { 0, 0, 0, 0 };
|
||||
};
|
||||
|
||||
D3DPRESENT_PARAMETERS m_presentParams;
|
||||
D3DGAMMARAMP m_ramp;
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
Rc<DxvkContext> m_context;
|
||||
|
||||
Rc<vk::Presenter> m_presenter;
|
||||
|
||||
Rc<DxvkShader> m_vertShader;
|
||||
Rc<DxvkShader> m_fragShader;
|
||||
|
||||
Rc<DxvkSampler> m_samplerFitting;
|
||||
Rc<DxvkSampler> m_samplerScaling;
|
||||
|
||||
Rc<DxvkSampler> m_gammaSampler;
|
||||
Rc<DxvkImage> m_gammaTexture;
|
||||
Rc<DxvkImageView> m_gammaTextureView;
|
||||
|
||||
Rc<DxvkImage> m_swapImage;
|
||||
Rc<DxvkImage> m_swapImageResolve;
|
||||
Rc<DxvkImageView> m_swapImageView;
|
||||
|
||||
Rc<hud::Hud> m_hud;
|
||||
|
||||
DxvkInputAssemblyState m_iaState;
|
||||
DxvkRasterizerState m_rsState;
|
||||
DxvkMultisampleState m_msState;
|
||||
DxvkDepthStencilState m_dsState;
|
||||
DxvkLogicOpState m_loState;
|
||||
DxvkBlendMode m_blendMode;
|
||||
|
||||
Com<D3D9Surface, false> m_backBuffer = nullptr;
|
||||
|
||||
RECT m_srcRect;
|
||||
RECT m_dstRect;
|
||||
|
||||
DxvkSubmitStatus m_presentStatus;
|
||||
|
||||
std::vector<Rc<DxvkImageView>> m_imageViews;
|
||||
|
||||
|
||||
uint64_t m_frameId = D3D9DeviceEx::MaxFrameLatency;
|
||||
uint32_t m_frameLatencyCap = 0;
|
||||
Rc<sync::Fence> m_frameLatencySignal;
|
||||
|
||||
bool m_dirty = true;
|
||||
bool m_vsync = true;
|
||||
|
||||
bool m_dialog;
|
||||
bool m_dialogChanged = false;
|
||||
|
||||
HWND m_window = nullptr;
|
||||
HMONITOR m_monitor = nullptr;
|
||||
|
||||
MONITORINFOEXW m_monInfo;
|
||||
|
||||
WindowState m_windowState;
|
||||
|
||||
void PresentImage(UINT PresentInterval);
|
||||
|
||||
void SubmitPresent(const vk::PresenterSync& Sync, uint32_t FrameId);
|
||||
|
||||
void SynchronizePresent();
|
||||
|
||||
void RecreateSwapChain(
|
||||
BOOL Vsync);
|
||||
|
||||
void CreatePresenter();
|
||||
|
||||
void CreateRenderTargetViews();
|
||||
|
||||
void CreateBackBuffer();
|
||||
|
||||
void CreateGammaTexture(
|
||||
UINT NumControlPoints,
|
||||
const D3D9_VK_GAMMA_CP* pControlPoints);
|
||||
|
||||
void DestroyGammaTexture();
|
||||
|
||||
void CreateHud();
|
||||
|
||||
void InitRenderState();
|
||||
|
||||
void InitSamplers();
|
||||
|
||||
void InitShaders();
|
||||
|
||||
void InitRamp();
|
||||
|
||||
uint32_t GetActualFrameLatency();
|
||||
|
||||
uint32_t PickFormats(
|
||||
D3D9Format Format,
|
||||
VkSurfaceFormatKHR* pDstFormats);
|
||||
|
||||
uint32_t PickPresentModes(
|
||||
BOOL Vsync,
|
||||
VkPresentModeKHR* pDstModes);
|
||||
|
||||
uint32_t PickImageCount(
|
||||
UINT Preferred);
|
||||
|
||||
void NormalizePresentParameters(D3DPRESENT_PARAMETERS* pPresentParams);
|
||||
|
||||
HRESULT EnterFullscreenMode(
|
||||
D3DPRESENT_PARAMETERS* pPresentParams,
|
||||
const D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||
|
||||
HRESULT LeaveFullscreenMode();
|
||||
|
||||
HRESULT ChangeDisplayMode(
|
||||
D3DPRESENT_PARAMETERS* pPresentParams,
|
||||
const D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||
|
||||
HRESULT RestoreDisplayMode(HMONITOR hMonitor);
|
||||
|
||||
void UpdateMonitorInfo();
|
||||
|
||||
bool UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect);
|
||||
|
||||
VkExtent2D GetPresentExtent();
|
||||
|
||||
VkFullScreenExclusiveEXT PickFullscreenMode();
|
||||
|
||||
};
|
||||
|
||||
}
|
358
src/d3d9/d3d9_swvp_emu.cpp
Normal file
358
src/d3d9/d3d9_swvp_emu.cpp
Normal file
|
@ -0,0 +1,358 @@
|
|||
#include "d3d9_swvp_emu.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_vertex_declaration.h"
|
||||
|
||||
#include "../spirv/spirv_module.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// Doesn't compare everything, only what we use in SWVP.
|
||||
|
||||
size_t D3D9VertexDeclHash::operator () (const D3D9VertexElements& key) const {
|
||||
DxvkHashState hash;
|
||||
|
||||
std::hash<BYTE> bytehash;
|
||||
std::hash<WORD> wordhash;
|
||||
|
||||
for (auto& element : key) {
|
||||
hash.add(wordhash(element.Stream));
|
||||
hash.add(wordhash(element.Offset));
|
||||
hash.add(bytehash(element.Type));
|
||||
hash.add(bytehash(element.Method));
|
||||
hash.add(bytehash(element.Usage));
|
||||
hash.add(bytehash(element.UsageIndex));
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool D3D9VertexDeclEq::operator () (const D3D9VertexElements& a, const D3D9VertexElements& b) const {
|
||||
if (a.size() != b.size())
|
||||
return false;
|
||||
|
||||
bool equal = true;
|
||||
|
||||
for (uint32_t i = 0; i < a.size(); i++)
|
||||
equal &= std::memcmp(&a[i], &b[i], sizeof(a[0])) == 0;
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
enum class DecltypeClass {
|
||||
Float, Byte, Short, Dec, Half
|
||||
};
|
||||
|
||||
enum DecltypeFlags {
|
||||
Signed = 1,
|
||||
Normalize = 2,
|
||||
ReverseRGB = 4
|
||||
};
|
||||
|
||||
struct Decltype {
|
||||
DecltypeClass Class;
|
||||
uint32_t VectorCount;
|
||||
uint32_t Flags;
|
||||
};
|
||||
|
||||
Decltype ClassifyDecltype(D3DDECLTYPE Type) {
|
||||
switch (Type) {
|
||||
case D3DDECLTYPE_FLOAT1: return { DecltypeClass::Float, 1, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_FLOAT2: return { DecltypeClass::Float, 2, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_FLOAT3: return { DecltypeClass::Float, 3, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_FLOAT4: return { DecltypeClass::Float, 4, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_D3DCOLOR: return { DecltypeClass::Byte, 4, DecltypeFlags::Normalize | DecltypeFlags::ReverseRGB };
|
||||
case D3DDECLTYPE_UBYTE4: return { DecltypeClass::Byte, 4, 0 };
|
||||
case D3DDECLTYPE_SHORT2: return { DecltypeClass::Short, 2, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_SHORT4: return { DecltypeClass::Short, 4, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_UBYTE4N: return { DecltypeClass::Byte, 4, DecltypeFlags::Normalize };
|
||||
case D3DDECLTYPE_SHORT2N: return { DecltypeClass::Short, 2, DecltypeFlags::Signed | DecltypeFlags::Normalize };
|
||||
case D3DDECLTYPE_SHORT4N: return { DecltypeClass::Short, 4, DecltypeFlags::Signed | DecltypeFlags::Normalize };
|
||||
case D3DDECLTYPE_USHORT2N: return { DecltypeClass::Short, 2, DecltypeFlags::Normalize };
|
||||
case D3DDECLTYPE_USHORT4N: return { DecltypeClass::Short, 4, DecltypeFlags::Normalize };
|
||||
case D3DDECLTYPE_UDEC3: return { DecltypeClass::Dec, 3, 0 };
|
||||
case D3DDECLTYPE_DEC3N: return { DecltypeClass::Dec, 3, DecltypeFlags::Signed | DecltypeFlags::Normalize };
|
||||
case D3DDECLTYPE_FLOAT16_2: return { DecltypeClass::Half, 2, DecltypeFlags::Signed };
|
||||
case D3DDECLTYPE_FLOAT16_4: return { DecltypeClass::Half, 4, DecltypeFlags::Signed };
|
||||
default: return { DecltypeClass::Float, 4, DecltypeFlags::Signed };
|
||||
}
|
||||
}
|
||||
|
||||
class D3D9SWVPEmulatorGenerator {
|
||||
|
||||
public:
|
||||
|
||||
D3D9SWVPEmulatorGenerator(const std::string& name) {
|
||||
m_entryPointId = m_module.allocateId();
|
||||
|
||||
m_module.setDebugSource(
|
||||
spv::SourceLanguageUnknown, 0,
|
||||
m_module.addDebugString(name.c_str()),
|
||||
nullptr);
|
||||
|
||||
m_module.setMemoryModel(
|
||||
spv::AddressingModelLogical,
|
||||
spv::MemoryModelGLSL450);
|
||||
|
||||
m_module.enableCapability(spv::CapabilityGeometry);
|
||||
|
||||
m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeInputPoints);
|
||||
m_module.setExecutionMode(m_entryPointId, spv::ExecutionModeOutputPoints);
|
||||
// This has to be > 0 for some reason even though
|
||||
// we will never emit a vertex
|
||||
m_module.setOutputVertices(m_entryPointId, 1);
|
||||
m_module.setInvocations(m_entryPointId, 1);
|
||||
|
||||
m_module.functionBegin(m_module.defVoidType(), m_entryPointId, m_module.defFunctionType(
|
||||
m_module.defVoidType(), 0, nullptr), spv::FunctionControlMaskNone);
|
||||
m_module.opLabel(m_module.allocateId());
|
||||
}
|
||||
|
||||
void compile(const D3D9VertexDecl* pDecl) {
|
||||
uint32_t uint_t = m_module.defIntType(32, false);
|
||||
uint32_t float_t = m_module.defFloatType(32);
|
||||
uint32_t vec4_t = m_module.defVectorType(float_t, 4);
|
||||
|
||||
uint32_t vec4_singular_array_t = m_module.defArrayType(vec4_t, m_module.constu32(1));
|
||||
|
||||
// Setup the buffer
|
||||
uint32_t bufferSlot = getSWVPBufferSlot();
|
||||
|
||||
uint32_t arrayType = m_module.defRuntimeArrayTypeUnique(uint_t);
|
||||
m_module.decorateArrayStride(arrayType, sizeof(uint32_t));
|
||||
|
||||
uint32_t buffer_t = m_module.defStructTypeUnique(1, &arrayType);
|
||||
m_module.memberDecorateOffset(buffer_t, 0, 0);
|
||||
m_module.decorate(buffer_t, spv::DecorationBufferBlock);
|
||||
|
||||
uint32_t buffer = m_module.newVar(m_module.defPointerType(buffer_t, spv::StorageClassUniform), spv::StorageClassUniform);
|
||||
m_module.decorateDescriptorSet(buffer, 0);
|
||||
m_module.decorateBinding(buffer, bufferSlot);
|
||||
|
||||
DxvkResourceSlot bufferRes;
|
||||
bufferRes.slot = bufferSlot;
|
||||
bufferRes.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||
bufferRes.view = VK_IMAGE_VIEW_TYPE_MAX_ENUM;
|
||||
bufferRes.access = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
m_resourceSlots.push_back(bufferRes);
|
||||
|
||||
// Load our builtins
|
||||
uint32_t primitiveIdPtr = m_module.newVar(m_module.defPointerType(uint_t, spv::StorageClassInput), spv::StorageClassInput);
|
||||
m_module.decorateBuiltIn(primitiveIdPtr, spv::BuiltInPrimitiveId);
|
||||
m_entryPointInterfaces.push_back(primitiveIdPtr);
|
||||
|
||||
uint32_t primitiveId = m_module.opLoad(uint_t, primitiveIdPtr);
|
||||
|
||||
// The size of any given vertex
|
||||
uint32_t vertexSize = m_module.constu32(pDecl->GetSize() / sizeof(uint32_t));
|
||||
|
||||
//The offset of this vertex from the beginning of the buffer
|
||||
uint32_t thisVertexOffset = m_module.opIMul(uint_t, vertexSize, primitiveId);
|
||||
|
||||
|
||||
for (auto& element : pDecl->GetElements()) {
|
||||
// Load the slot associated with this element
|
||||
DxsoSemantic semantic = { DxsoUsage(element.Usage), element.UsageIndex };
|
||||
|
||||
uint32_t elementPtr;
|
||||
uint32_t elementVar;
|
||||
|
||||
elementPtr = m_module.newVar(m_module.defPointerType(vec4_singular_array_t, spv::StorageClassInput), spv::StorageClassInput);
|
||||
if ((semantic.usage == DxsoUsage::Position || semantic.usage == DxsoUsage::PositionT) && element.UsageIndex == 0) {
|
||||
// Load from builtin
|
||||
m_module.decorateBuiltIn(elementPtr, spv::BuiltInPosition);
|
||||
}
|
||||
else {
|
||||
// Load from slot
|
||||
uint32_t slotIdx = RegisterLinkerSlot(semantic);
|
||||
|
||||
m_module.decorateLocation(elementPtr, slotIdx);
|
||||
m_interfaceSlots.inputSlots |= 1u << slotIdx;
|
||||
}
|
||||
|
||||
uint32_t zero = m_module.constu32(0);
|
||||
elementVar = m_module.opAccessChain(m_module.defPointerType(vec4_t, spv::StorageClassInput), elementPtr, 1, &zero);
|
||||
elementVar = m_module.opLoad(vec4_t, elementVar);
|
||||
|
||||
m_entryPointInterfaces.push_back(elementPtr);
|
||||
|
||||
// The offset of this element from the beginning of any given vertex
|
||||
uint32_t perVertexElementOffset = m_module.constu32(element.Offset / sizeof(uint32_t));
|
||||
|
||||
// The offset of this element from the beginning of the buffer for **THIS** vertex
|
||||
uint32_t elementOffset = m_module.opIAdd(uint_t, thisVertexOffset, perVertexElementOffset);
|
||||
|
||||
// Write to the buffer at the element offset for each part of the vector.
|
||||
Decltype elementInfo = ClassifyDecltype(D3DDECLTYPE(element.Type));
|
||||
|
||||
if (elementInfo.Class == DecltypeClass::Dec) {
|
||||
// TODO!
|
||||
Logger::warn("Encountered DEC3/UDEC3N class, ignoring...");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t vecn_t = m_module.defVectorType(float_t, elementInfo.VectorCount);
|
||||
uint32_t componentSet;
|
||||
|
||||
// Modifiers...
|
||||
if (elementInfo.Flags & DecltypeFlags::ReverseRGB) {
|
||||
std::array<uint32_t, 4> indices = { 2, 1, 0, 3 };
|
||||
componentSet = m_module.opVectorShuffle(vecn_t, elementVar, elementVar, elementInfo.VectorCount, indices.data());
|
||||
}
|
||||
else {
|
||||
std::array<uint32_t, 4> indices = { 0, 1, 2, 3 };
|
||||
componentSet = m_module.opVectorShuffle(vecn_t, elementVar, elementVar, elementInfo.VectorCount, indices.data());
|
||||
}
|
||||
|
||||
if (elementInfo.Flags & DecltypeFlags::Normalize)
|
||||
componentSet = m_module.opVectorTimesScalar(vecn_t, componentSet, m_module.constf32(255.0f));
|
||||
|
||||
|
||||
bool isSigned = elementInfo.Flags & DecltypeFlags::Signed;
|
||||
|
||||
// Convert the component to the correct type/value.
|
||||
switch (elementInfo.Class) {
|
||||
case DecltypeClass::Float: break; // Do nothing!
|
||||
case DecltypeClass::Byte: {
|
||||
m_module.enableCapability(spv::CapabilityInt8);
|
||||
|
||||
uint32_t type = m_module.defIntType(8, isSigned);
|
||||
type = m_module.defVectorType(type, elementInfo.VectorCount);
|
||||
|
||||
componentSet = isSigned
|
||||
? m_module.opConvertFtoS(type, componentSet)
|
||||
: m_module.opConvertFtoU(type, componentSet);
|
||||
|
||||
break;
|
||||
}
|
||||
case DecltypeClass::Short: {
|
||||
m_module.enableCapability(spv::CapabilityInt16);
|
||||
|
||||
uint32_t type = m_module.defIntType(16, isSigned);
|
||||
type = m_module.defVectorType(type, elementInfo.VectorCount);
|
||||
|
||||
componentSet = isSigned
|
||||
? m_module.opConvertFtoS(type, componentSet)
|
||||
: m_module.opConvertFtoU(type, componentSet);
|
||||
|
||||
break;
|
||||
}
|
||||
case DecltypeClass::Half: {
|
||||
m_module.enableCapability(spv::CapabilityFloat16);
|
||||
|
||||
uint32_t type = m_module.defFloatType(16);
|
||||
type = m_module.defVectorType(type, elementInfo.VectorCount);
|
||||
componentSet = m_module.opFConvert(type, componentSet);
|
||||
|
||||
break;
|
||||
}
|
||||
case DecltypeClass::Dec: {
|
||||
// TODO!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Bitcast to dwords before we write.
|
||||
uint32_t dwordCount = GetDecltypeSize(D3DDECLTYPE(element.Type)) / sizeof(uint32_t);
|
||||
uint32_t dwordVector = m_module.opBitcast(
|
||||
m_module.defVectorType(uint_t, dwordCount),
|
||||
componentSet);
|
||||
|
||||
// Finally write each dword to the buffer!
|
||||
for (uint32_t i = 0; i < dwordCount; i++) {
|
||||
std::array<uint32_t, 2> bufferIndices = { m_module.constu32(0), elementOffset };
|
||||
|
||||
uint32_t writeDest = m_module.opAccessChain(m_module.defPointerType(uint_t, spv::StorageClassUniform), buffer, bufferIndices.size(), bufferIndices.data());
|
||||
uint32_t currentDword = m_module.opCompositeExtract(uint_t, dwordVector, 1, &i);
|
||||
|
||||
m_module.opStore(writeDest, currentDword);
|
||||
|
||||
elementOffset = m_module.opIAdd(uint_t, elementOffset, m_module.constu32(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rc<DxvkShader> finalize() {
|
||||
m_module.opReturn();
|
||||
m_module.functionEnd();
|
||||
|
||||
m_module.addEntryPoint(m_entryPointId,
|
||||
spv::ExecutionModelGeometry, "main",
|
||||
m_entryPointInterfaces.size(),
|
||||
m_entryPointInterfaces.data());
|
||||
m_module.setDebugName(m_entryPointId, "main");
|
||||
|
||||
DxvkShaderConstData constData = { };
|
||||
|
||||
return new DxvkShader(
|
||||
VK_SHADER_STAGE_GEOMETRY_BIT,
|
||||
m_resourceSlots.size(),
|
||||
m_resourceSlots.data(),
|
||||
m_interfaceSlots,
|
||||
m_module.compile(),
|
||||
DxvkShaderOptions(),
|
||||
std::move(constData));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
SpirvModule m_module;
|
||||
|
||||
std::vector<uint32_t> m_entryPointInterfaces;
|
||||
uint32_t m_entryPointId = 0;
|
||||
|
||||
std::vector<DxvkResourceSlot> m_resourceSlots;
|
||||
DxvkInterfaceSlots m_interfaceSlots;
|
||||
|
||||
};
|
||||
|
||||
Rc<DxvkShader> D3D9SWVPEmulator::GetShaderModule(D3D9DeviceEx* pDevice, const D3D9VertexDecl* pDecl) {
|
||||
auto& elements = pDecl->GetElements();
|
||||
|
||||
// Use the shader's unique key for the lookup
|
||||
{ std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto entry = m_modules.find(elements);
|
||||
if (entry != m_modules.end())
|
||||
return entry->second;
|
||||
}
|
||||
|
||||
Sha1Hash hash = Sha1Hash::compute(
|
||||
elements.data(), elements.size() * sizeof(elements[0]));
|
||||
|
||||
DxvkShaderKey key = { VK_SHADER_STAGE_GEOMETRY_BIT , hash };
|
||||
std::string name = str::format("SWVP_", key.toString());
|
||||
|
||||
// This shader has not been compiled yet, so we have to create a
|
||||
// new module. This takes a while, so we won't lock the structure.
|
||||
D3D9SWVPEmulatorGenerator generator(name);
|
||||
generator.compile(pDecl);
|
||||
Rc<DxvkShader> shader = generator.finalize();
|
||||
|
||||
shader->setShaderKey(key);
|
||||
pDevice->GetDXVKDevice()->registerShader(shader);
|
||||
|
||||
const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
|
||||
|
||||
if (dumpPath.size() != 0) {
|
||||
std::ofstream dumpStream(
|
||||
str::format(dumpPath, "/", name, ".spv"),
|
||||
std::ios_base::binary | std::ios_base::trunc);
|
||||
|
||||
shader->dump(dumpStream);
|
||||
}
|
||||
|
||||
// Insert the new module into the lookup table. If another thread
|
||||
// has compiled the same shader in the meantime, we should return
|
||||
// that object instead and discard the newly created module.
|
||||
{ std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
auto status = m_modules.insert({ elements, shader });
|
||||
if (!status.second)
|
||||
return status.first->second;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
}
|
36
src/d3d9/d3d9_swvp_emu.h
Normal file
36
src/d3d9/d3d9_swvp_emu.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
#include "../dxvk/dxvk_shader.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
class D3D9VertexDecl;
|
||||
class D3D9DeviceEx;
|
||||
|
||||
struct D3D9VertexDeclHash {
|
||||
size_t operator () (const D3D9VertexElements& key) const;
|
||||
};
|
||||
|
||||
struct D3D9VertexDeclEq {
|
||||
bool operator () (const D3D9VertexElements& a, const D3D9VertexElements& b) const;
|
||||
};
|
||||
|
||||
class D3D9SWVPEmulator {
|
||||
|
||||
public:
|
||||
|
||||
Rc<DxvkShader> GetShaderModule(D3D9DeviceEx* pDevice, const D3D9VertexDecl* pDecl);
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
std::unordered_map<
|
||||
D3D9VertexElements, Rc<DxvkShader>,
|
||||
D3D9VertexDeclHash, D3D9VertexDeclEq> m_modules;
|
||||
|
||||
};
|
||||
|
||||
}
|
252
src/d3d9/d3d9_texture.cpp
Normal file
252
src/d3d9/d3d9_texture.cpp
Normal file
|
@ -0,0 +1,252 @@
|
|||
#include "d3d9_texture.h"
|
||||
|
||||
#include "d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
// Direct3DTexture9
|
||||
|
||||
D3D9Texture2D::D3D9Texture2D(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: D3D9Texture2DBase( pDevice, pDesc, D3DRTYPE_TEXTURE, Mapping ) { }
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture2D::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DBaseTexture9)
|
||||
|| riid == __uuidof(IDirect3DTexture9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9Texture2D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Texture2D::GetType() {
|
||||
return D3DRTYPE_TEXTURE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture2D::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
|
||||
auto* surface = GetSubresource(Level);
|
||||
if (surface == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return surface->GetDesc(pDesc);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture2D::GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel) {
|
||||
InitReturnPtr(ppSurfaceLevel);
|
||||
auto* surface = GetSubresource(Level);
|
||||
|
||||
if (ppSurfaceLevel == nullptr || surface == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppSurfaceLevel = ref(surface);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture2D::LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
|
||||
auto* surface = GetSubresource(Level);
|
||||
if (surface == nullptr || pLockedRect == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return surface->LockRect(pLockedRect, pRect, Flags);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture2D::UnlockRect(UINT Level) {
|
||||
auto* surface = GetSubresource(Level);
|
||||
if (surface == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return surface->UnlockRect();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture2D::AddDirtyRect(CONST RECT* pDirtyRect) {
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
// Direct3DVolumeTexture9
|
||||
|
||||
|
||||
D3D9Texture3D::D3D9Texture3D(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: D3D9Texture3DBase( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE, Mapping ) { }
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture3D::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DBaseTexture9)
|
||||
|| riid == __uuidof(IDirect3DVolumeTexture9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9Texture3D::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9Texture3D::GetType() {
|
||||
return D3DRTYPE_VOLUMETEXTURE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture3D::GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc) {
|
||||
auto* volume = GetSubresource(Level);
|
||||
if (volume == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return volume->GetDesc(pDesc);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture3D::GetVolumeLevel(UINT Level, IDirect3DVolume9** ppVolumeLevel) {
|
||||
InitReturnPtr(ppVolumeLevel);
|
||||
auto* volume = GetSubresource(Level);
|
||||
|
||||
if (ppVolumeLevel == nullptr || volume == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppVolumeLevel = ref(volume);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture3D::LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
|
||||
auto* volume = GetSubresource(Level);
|
||||
if (volume == nullptr || pLockedBox == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return volume->LockBox(pLockedBox, pBox, Flags);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture3D::UnlockBox(UINT Level) {
|
||||
auto* volume = GetSubresource(Level);
|
||||
if (volume == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return volume->UnlockBox();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Texture3D::AddDirtyBox(CONST D3DBOX* pDirtyBox) {
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
// Direct3DCubeTexture9
|
||||
|
||||
|
||||
D3D9TextureCube::D3D9TextureCube(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: D3D9TextureCubeBase( pDevice, pDesc, D3DRTYPE_CUBETEXTURE, Mapping ) { }
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9TextureCube::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DBaseTexture9)
|
||||
|| riid == __uuidof(IDirect3DCubeTexture9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9TextureCube::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE D3D9TextureCube::GetType() {
|
||||
return D3DRTYPE_CUBETEXTURE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9TextureCube::GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc) {
|
||||
auto* surface = GetSubresource(Level);
|
||||
|
||||
if (surface == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return surface->GetDesc(pDesc);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9TextureCube::GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface9** ppSurfaceLevel) {
|
||||
InitReturnPtr(ppSurfaceLevel);
|
||||
|
||||
if (Level >= m_texture.Desc()->MipLevels)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto* surface = GetSubresource(
|
||||
m_texture.CalcSubresource(UINT(Face), Level));
|
||||
|
||||
if (ppSurfaceLevel == nullptr || surface == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*ppSurfaceLevel = ref(surface);
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9TextureCube::LockRect(D3DCUBEMAP_FACES Face, UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
|
||||
auto* surface = GetSubresource(
|
||||
m_texture.CalcSubresource(UINT(Face), Level));
|
||||
|
||||
if (surface == nullptr || pLockedRect == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return surface->LockRect(pLockedRect, pRect, Flags);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9TextureCube::UnlockRect(D3DCUBEMAP_FACES Face, UINT Level) {
|
||||
auto* surface = GetSubresource(
|
||||
m_texture.CalcSubresource(UINT(Face), Level));
|
||||
|
||||
if (surface == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return surface->UnlockRect();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9TextureCube::AddDirtyRect(D3DCUBEMAP_FACES Face, CONST RECT* pDirtyRect) {
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
}
|
236
src/d3d9/d3d9_texture.h
Normal file
236
src/d3d9/d3d9_texture.h
Normal file
|
@ -0,0 +1,236 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_surface.h"
|
||||
#include "d3d9_volume.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <new>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
template <typename SubresourceType, typename... Base>
|
||||
class D3D9BaseTexture : public D3D9Resource<Base...> {
|
||||
|
||||
public:
|
||||
|
||||
struct alignas(16) SubresourceData { uint8_t data[sizeof(SubresourceType)]; };
|
||||
|
||||
D3D9BaseTexture(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3DRESOURCETYPE ResourceType,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: D3D9Resource<Base...> ( pDevice )
|
||||
, m_texture ( pDevice, pDesc, ResourceType, Mapping )
|
||||
, m_lod ( 0 )
|
||||
, m_autogenFilter ( D3DTEXF_LINEAR ) {
|
||||
const uint32_t arraySlices = m_texture.Desc()->ArraySize;
|
||||
const uint32_t mipLevels = m_texture.Desc()->MipLevels;
|
||||
|
||||
m_subresources.resize(arraySlices * mipLevels);
|
||||
|
||||
for (uint32_t i = 0; i < arraySlices; i++) {
|
||||
for (uint32_t j = 0; j < mipLevels; j++) {
|
||||
const uint32_t subresource = m_texture.CalcSubresource(i, j);
|
||||
|
||||
SubresourceType* subObj = this->GetSubresource(subresource);
|
||||
|
||||
new (subObj) SubresourceType(
|
||||
pDevice,
|
||||
&m_texture,
|
||||
i, j,
|
||||
this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~D3D9BaseTexture() {
|
||||
for (uint32_t i = 0; i < m_subresources.size(); i++) {
|
||||
SubresourceType* subObj = this->GetSubresource(i);
|
||||
subObj->~SubresourceType();
|
||||
}
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE SetLOD(DWORD LODNew) final {
|
||||
DWORD oldLod = m_lod;
|
||||
m_lod = LODNew;
|
||||
|
||||
m_texture.RecreateSampledView(LODNew);
|
||||
if (this->GetPrivateRefCount() > 0)
|
||||
this->m_parent->MarkSamplersDirty();
|
||||
|
||||
return oldLod;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetLOD() final {
|
||||
return m_lod;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE GetLevelCount() final {
|
||||
return m_texture.Desc()->MipLevels;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE SetAutoGenFilterType(D3DTEXTUREFILTERTYPE FilterType) final {
|
||||
m_autogenFilter = FilterType;
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
D3DTEXTUREFILTERTYPE STDMETHODCALLTYPE GetAutoGenFilterType() final {
|
||||
return m_autogenFilter;
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE GenerateMipSubLevels() final {
|
||||
if (m_texture.IsAutomaticMip())
|
||||
this->m_parent->GenerateMips(&m_texture);
|
||||
}
|
||||
|
||||
D3D9CommonTexture* GetCommonTexture() {
|
||||
return &m_texture;
|
||||
}
|
||||
|
||||
SubresourceType* GetSubresource(UINT Subresource) {
|
||||
if (unlikely(Subresource >= m_subresources.size()))
|
||||
return nullptr;
|
||||
|
||||
return reinterpret_cast<SubresourceType*>(&m_subresources[Subresource]);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
D3D9CommonTexture m_texture;
|
||||
|
||||
DWORD m_lod;
|
||||
D3DTEXTUREFILTERTYPE m_autogenFilter;
|
||||
|
||||
std::vector<SubresourceData> m_subresources;
|
||||
|
||||
};
|
||||
|
||||
using D3D9Texture2DBase = D3D9BaseTexture<D3D9Surface, IDirect3DTexture9>;
|
||||
class D3D9Texture2D final : public D3D9Texture2DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Texture2D(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetSurfaceLevel(UINT Level, IDirect3DSurface9** ppSurfaceLevel);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect(UINT Level);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyRect(CONST RECT* pDirtyRect);
|
||||
|
||||
};
|
||||
|
||||
using D3D9Texture3DBase = D3D9BaseTexture<D3D9Volume, IDirect3DVolumeTexture9>;
|
||||
class D3D9Texture3D final : public D3D9Texture3DBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Texture3D(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DVOLUME_DESC *pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetVolumeLevel(UINT Level, IDirect3DVolume9** ppSurfaceLevel);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockBox(UINT Level, D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox(UINT Level);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyBox(CONST D3DBOX* pDirtyBox);
|
||||
|
||||
};
|
||||
|
||||
using D3D9TextureCubeBase = D3D9BaseTexture<D3D9Surface, IDirect3DCubeTexture9>;
|
||||
class D3D9TextureCube final : public D3D9TextureCubeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9TextureCube(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
D3DRESOURCETYPE STDMETHODCALLTYPE GetType();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetLevelDesc(UINT Level, D3DSURFACE_DESC *pDesc);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetCubeMapSurface(D3DCUBEMAP_FACES Face, UINT Level, IDirect3DSurface9** ppSurfaceLevel);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockRect(D3DCUBEMAP_FACES Face, UINT Level, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockRect(D3DCUBEMAP_FACES Face, UINT Level);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE AddDirtyRect(D3DCUBEMAP_FACES Face, CONST RECT* pDirtyRect);
|
||||
|
||||
};
|
||||
|
||||
inline D3D9CommonTexture* GetCommonTexture(IDirect3DBaseTexture9* ptr) {
|
||||
if (ptr == nullptr)
|
||||
return nullptr;
|
||||
|
||||
switch (ptr->GetType()) {
|
||||
case D3DRTYPE_TEXTURE: return static_cast<D3D9Texture2D*> (ptr)->GetCommonTexture();
|
||||
case D3DRTYPE_CUBETEXTURE: return static_cast<D3D9TextureCube*>(ptr)->GetCommonTexture();
|
||||
case D3DRTYPE_VOLUMETEXTURE: return static_cast<D3D9Texture3D*> (ptr)->GetCommonTexture();
|
||||
default:
|
||||
Logger::warn("Unknown texture resource type."); break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline D3D9CommonTexture* GetCommonTexture(D3D9Surface* ptr) {
|
||||
if (ptr == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return ptr->GetCommonTexture();
|
||||
}
|
||||
|
||||
inline D3D9CommonTexture* GetCommonTexture(IDirect3DSurface9* ptr) {
|
||||
return GetCommonTexture(static_cast<D3D9Surface*>(ptr));
|
||||
}
|
||||
|
||||
inline void TextureRefPrivate(IDirect3DBaseTexture9* tex, bool AddRef) {
|
||||
if (tex == nullptr)
|
||||
return;
|
||||
|
||||
switch (tex->GetType()) {
|
||||
case D3DRTYPE_TEXTURE: CastRefPrivate<D3D9Texture2D> (tex, AddRef); break;
|
||||
case D3DRTYPE_CUBETEXTURE: CastRefPrivate<D3D9TextureCube>(tex, AddRef); break;
|
||||
case D3DRTYPE_VOLUMETEXTURE: CastRefPrivate<D3D9Texture3D> (tex, AddRef); break;
|
||||
default:
|
||||
Logger::warn("Unknown texture resource type."); break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void TextureChangePrivate(IDirect3DBaseTexture9*& dst, IDirect3DBaseTexture9* src) {
|
||||
TextureRefPrivate(dst, false);
|
||||
TextureRefPrivate(src, true);
|
||||
dst = src;
|
||||
}
|
||||
|
||||
}
|
414
src/d3d9/d3d9_util.cpp
Normal file
414
src/d3d9/d3d9_util.cpp
Normal file
|
@ -0,0 +1,414 @@
|
|||
#include "d3d9_util.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
typedef HRESULT (STDMETHODCALLTYPE *D3DXDisassembleShader) (
|
||||
const void* pShader,
|
||||
BOOL EnableColorCode,
|
||||
char* pComments,
|
||||
ID3DBlob** ppDisassembly); // ppDisassembly is actually a D3DXBUFFER, but it has the exact same vtable as a ID3DBlob at the start.
|
||||
|
||||
D3DXDisassembleShader g_pfnDisassembleShader = nullptr;
|
||||
|
||||
HRESULT DisassembleShader(
|
||||
const void* pShader,
|
||||
BOOL EnableColorCode,
|
||||
char* pComments,
|
||||
ID3DBlob** ppDisassembly) {
|
||||
if (g_pfnDisassembleShader == nullptr) {
|
||||
HMODULE d3d9x = LoadLibraryA("d3dx9.dll");
|
||||
|
||||
if (d3d9x == nullptr)
|
||||
d3d9x = LoadLibraryA("d3dx9_43.dll");
|
||||
|
||||
g_pfnDisassembleShader =
|
||||
reinterpret_cast<D3DXDisassembleShader>(GetProcAddress(d3d9x, "D3DXDisassembleShader"));
|
||||
}
|
||||
|
||||
if (g_pfnDisassembleShader == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
return g_pfnDisassembleShader(
|
||||
pShader,
|
||||
EnableColorCode,
|
||||
pComments,
|
||||
ppDisassembly);
|
||||
}
|
||||
|
||||
|
||||
HRESULT DecodeMultiSampleType(
|
||||
D3DMULTISAMPLE_TYPE MultiSample,
|
||||
DWORD MultisampleQuality,
|
||||
VkSampleCountFlagBits* pCount) {
|
||||
uint32_t sampleCount = std::max<uint32_t>(MultiSample, 1u);
|
||||
|
||||
// Check if this is a power of two...
|
||||
if (sampleCount & (sampleCount - 1))
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
if (MultiSample == D3DMULTISAMPLE_NONMASKABLE)
|
||||
sampleCount = 1u << MultisampleQuality;
|
||||
|
||||
if (pCount != nullptr)
|
||||
*pCount = VkSampleCountFlagBits(sampleCount);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
VkFormat GetPackedDepthStencilFormat(D3D9Format Format) {
|
||||
switch (Format) {
|
||||
case D3D9Format::D15S1:
|
||||
return VK_FORMAT_D16_UNORM_S8_UINT; // This should never happen!
|
||||
|
||||
case D3D9Format::D16:
|
||||
case D3D9Format::D16_LOCKABLE:
|
||||
case D3D9Format::DF16:
|
||||
return VK_FORMAT_D16_UNORM;
|
||||
|
||||
case D3D9Format::D24X8:
|
||||
case D3D9Format::DF24:
|
||||
return VK_FORMAT_X8_D24_UNORM_PACK32;
|
||||
|
||||
case D3D9Format::D24X4S4:
|
||||
case D3D9Format::D24FS8:
|
||||
case D3D9Format::D24S8:
|
||||
case D3D9Format::INTZ:
|
||||
return VK_FORMAT_D24_UNORM_S8_UINT;
|
||||
|
||||
case D3D9Format::D32:
|
||||
case D3D9Format::D32_LOCKABLE:
|
||||
case D3D9Format::D32F_LOCKABLE:
|
||||
return VK_FORMAT_D32_SFLOAT;
|
||||
|
||||
case D3D9Format::S8_LOCKABLE:
|
||||
return VK_FORMAT_S8_UINT;
|
||||
|
||||
default:
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkFormatFeatureFlags GetImageFormatFeatures(DWORD Usage) {
|
||||
VkFormatFeatureFlags features = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
|
||||
|
||||
if (Usage & D3DUSAGE_DEPTHSTENCIL)
|
||||
features |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (Usage & D3DUSAGE_RENDERTARGET)
|
||||
features |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
|
||||
VkImageUsageFlags GetImageUsageFlags(DWORD Usage) {
|
||||
VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
if (Usage & D3DUSAGE_DEPTHSTENCIL)
|
||||
usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
|
||||
if (Usage & D3DUSAGE_RENDERTARGET)
|
||||
usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetVertexCount(D3DPRIMITIVETYPE type, UINT count) {
|
||||
switch (type) {
|
||||
default:
|
||||
case D3DPT_TRIANGLELIST: return count * 3;
|
||||
case D3DPT_POINTLIST: return count;
|
||||
case D3DPT_LINELIST: return count * 2;
|
||||
case D3DPT_LINESTRIP: return count + 1;
|
||||
case D3DPT_TRIANGLESTRIP: return count + 2;
|
||||
case D3DPT_TRIANGLEFAN: return count + 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DxvkInputAssemblyState DecodeInputAssemblyState(D3DPRIMITIVETYPE type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case D3DPT_TRIANGLELIST:
|
||||
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_FALSE, 0 };
|
||||
|
||||
case D3DPT_POINTLIST:
|
||||
return { VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_FALSE, 0 };
|
||||
|
||||
case D3DPT_LINELIST:
|
||||
return { VK_PRIMITIVE_TOPOLOGY_LINE_LIST, VK_FALSE, 0 };
|
||||
|
||||
case D3DPT_LINESTRIP:
|
||||
return { VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_TRUE, 0 };
|
||||
|
||||
case D3DPT_TRIANGLESTRIP:
|
||||
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, VK_TRUE, 0 };
|
||||
|
||||
case D3DPT_TRIANGLEFAN:
|
||||
return { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, VK_TRUE, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkBlendFactor DecodeBlendFactor(D3DBLEND BlendFactor, bool IsAlpha) {
|
||||
switch (BlendFactor) {
|
||||
default:
|
||||
case D3DBLEND_ZERO: return VK_BLEND_FACTOR_ZERO;
|
||||
case D3DBLEND_ONE: return VK_BLEND_FACTOR_ONE;
|
||||
case D3DBLEND_SRCCOLOR: return VK_BLEND_FACTOR_SRC_COLOR;
|
||||
case D3DBLEND_INVSRCCOLOR: return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
||||
case D3DBLEND_SRCALPHA: return VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
case D3DBLEND_INVSRCALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
case D3DBLEND_DESTALPHA: return VK_BLEND_FACTOR_DST_ALPHA;
|
||||
case D3DBLEND_INVDESTALPHA: return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
|
||||
case D3DBLEND_DESTCOLOR: return VK_BLEND_FACTOR_DST_COLOR;
|
||||
case D3DBLEND_INVDESTCOLOR: return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR;
|
||||
case D3DBLEND_SRCALPHASAT: return VK_BLEND_FACTOR_SRC_ALPHA_SATURATE;
|
||||
case D3DBLEND_BOTHSRCALPHA: return VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
case D3DBLEND_BOTHINVSRCALPHA: return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
case D3DBLEND_BLENDFACTOR: return IsAlpha ? VK_BLEND_FACTOR_CONSTANT_ALPHA : VK_BLEND_FACTOR_CONSTANT_COLOR;
|
||||
case D3DBLEND_INVBLENDFACTOR: return IsAlpha ? VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA : VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR;
|
||||
case D3DBLEND_SRCCOLOR2: return VK_BLEND_FACTOR_SRC1_COLOR;
|
||||
case D3DBLEND_INVSRCCOLOR2: return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkBlendOp DecodeBlendOp(D3DBLENDOP BlendOp) {
|
||||
switch (BlendOp) {
|
||||
default:
|
||||
case D3DBLENDOP_ADD: return VK_BLEND_OP_ADD;
|
||||
case D3DBLENDOP_SUBTRACT: return VK_BLEND_OP_SUBTRACT;
|
||||
case D3DBLENDOP_REVSUBTRACT: return VK_BLEND_OP_REVERSE_SUBTRACT;
|
||||
case D3DBLENDOP_MIN: return VK_BLEND_OP_MIN;
|
||||
case D3DBLENDOP_MAX: return VK_BLEND_OP_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkFilter DecodeFilter(D3DTEXTUREFILTERTYPE Filter) {
|
||||
switch (Filter) {
|
||||
case D3DTEXF_NONE:
|
||||
case D3DTEXF_POINT:
|
||||
return VK_FILTER_NEAREST;
|
||||
default:
|
||||
return VK_FILTER_LINEAR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
D3D9MipFilter DecodeMipFilter(D3DTEXTUREFILTERTYPE Filter) {
|
||||
D3D9MipFilter filter;
|
||||
filter.MipsEnabled = Filter != D3DTEXF_NONE;
|
||||
|
||||
switch (Filter) {
|
||||
case D3DTEXF_POINT:
|
||||
case D3DTEXF_NONE:
|
||||
filter.MipFilter = VK_SAMPLER_MIPMAP_MODE_NEAREST; break;
|
||||
default:
|
||||
filter.MipFilter = VK_SAMPLER_MIPMAP_MODE_LINEAR; break;
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
bool IsAnisotropic(D3DTEXTUREFILTERTYPE Filter) {
|
||||
return Filter == D3DTEXF_ANISOTROPIC;
|
||||
}
|
||||
|
||||
|
||||
VkSamplerAddressMode DecodeAddressMode(D3DTEXTUREADDRESS Mode) {
|
||||
switch (Mode) {
|
||||
default:
|
||||
case D3DTADDRESS_WRAP:
|
||||
return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
case D3DTADDRESS_MIRROR:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
||||
case D3DTADDRESS_CLAMP:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
case D3DTADDRESS_BORDER:
|
||||
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
||||
case D3DTADDRESS_MIRRORONCE:
|
||||
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkCompareOp DecodeCompareOp(D3DCMPFUNC Func) {
|
||||
switch (Func) {
|
||||
default:
|
||||
case D3DCMP_NEVER: return VK_COMPARE_OP_NEVER;
|
||||
case D3DCMP_LESS: return VK_COMPARE_OP_LESS;
|
||||
case D3DCMP_EQUAL: return VK_COMPARE_OP_EQUAL;
|
||||
case D3DCMP_LESSEQUAL: return VK_COMPARE_OP_LESS_OR_EQUAL;
|
||||
case D3DCMP_GREATER: return VK_COMPARE_OP_GREATER;
|
||||
case D3DCMP_NOTEQUAL: return VK_COMPARE_OP_NOT_EQUAL;
|
||||
case D3DCMP_GREATEREQUAL: return VK_COMPARE_OP_GREATER_OR_EQUAL;
|
||||
case D3DCMP_ALWAYS: return VK_COMPARE_OP_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkStencilOp DecodeStencilOp(D3DSTENCILOP Op) {
|
||||
switch (Op) {
|
||||
default:
|
||||
case D3DSTENCILOP_KEEP: return VK_STENCIL_OP_KEEP;
|
||||
case D3DSTENCILOP_ZERO: return VK_STENCIL_OP_ZERO;
|
||||
case D3DSTENCILOP_REPLACE: return VK_STENCIL_OP_REPLACE;
|
||||
case D3DSTENCILOP_INCRSAT: return VK_STENCIL_OP_INCREMENT_AND_CLAMP;
|
||||
case D3DSTENCILOP_DECRSAT: return VK_STENCIL_OP_DECREMENT_AND_CLAMP;
|
||||
case D3DSTENCILOP_INVERT: return VK_STENCIL_OP_INVERT;
|
||||
case D3DSTENCILOP_INCR: return VK_STENCIL_OP_INCREMENT_AND_WRAP;
|
||||
case D3DSTENCILOP_DECR: return VK_STENCIL_OP_DECREMENT_AND_WRAP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkCullModeFlags DecodeCullMode(D3DCULL Mode) {
|
||||
switch (Mode) {
|
||||
case D3DCULL_NONE: return VK_CULL_MODE_NONE;
|
||||
case D3DCULL_CW: return VK_CULL_MODE_FRONT_BIT;
|
||||
default:
|
||||
case D3DCULL_CCW: return VK_CULL_MODE_BACK_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkPolygonMode DecodeFillMode(D3DFILLMODE Mode) {
|
||||
switch (Mode) {
|
||||
case D3DFILL_POINT: return VK_POLYGON_MODE_POINT;
|
||||
case D3DFILL_WIREFRAME: return VK_POLYGON_MODE_LINE;
|
||||
default:
|
||||
case D3DFILL_SOLID: return VK_POLYGON_MODE_FILL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VkIndexType DecodeIndexType(D3D9Format Format) {
|
||||
return Format == D3D9Format::INDEX16
|
||||
? VK_INDEX_TYPE_UINT16
|
||||
: VK_INDEX_TYPE_UINT32;
|
||||
}
|
||||
|
||||
|
||||
VkFormat DecodeDecltype(D3DDECLTYPE Type) {
|
||||
switch (Type) {
|
||||
case D3DDECLTYPE_FLOAT1: return VK_FORMAT_R32_SFLOAT;
|
||||
case D3DDECLTYPE_FLOAT2: return VK_FORMAT_R32G32_SFLOAT;
|
||||
case D3DDECLTYPE_FLOAT3: return VK_FORMAT_R32G32B32_SFLOAT;
|
||||
case D3DDECLTYPE_FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||
case D3DDECLTYPE_D3DCOLOR: return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
case D3DDECLTYPE_UBYTE4: return VK_FORMAT_R8G8B8A8_USCALED;
|
||||
case D3DDECLTYPE_SHORT2: return VK_FORMAT_R16G16_SSCALED;
|
||||
case D3DDECLTYPE_SHORT4: return VK_FORMAT_R16G16B16A16_SSCALED;
|
||||
case D3DDECLTYPE_UBYTE4N: return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case D3DDECLTYPE_SHORT2N: return VK_FORMAT_R16G16_SNORM;
|
||||
case D3DDECLTYPE_SHORT4N: return VK_FORMAT_R16G16B16A16_SNORM;
|
||||
case D3DDECLTYPE_USHORT2N: return VK_FORMAT_R16G16_UNORM;
|
||||
case D3DDECLTYPE_USHORT4N: return VK_FORMAT_R16G16B16A16_UNORM;
|
||||
case D3DDECLTYPE_UDEC3: return VK_FORMAT_A2B10G10R10_USCALED_PACK32;
|
||||
case D3DDECLTYPE_FLOAT16_2: return VK_FORMAT_R16G16_SFLOAT;
|
||||
case D3DDECLTYPE_FLOAT16_4: return VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
case D3DDECLTYPE_DEC3N: return VK_FORMAT_A2B10G10R10_SNORM_PACK32;
|
||||
case D3DDECLTYPE_UNUSED:
|
||||
default: return VK_FORMAT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
void ConvertBox(D3DBOX box, VkOffset3D& offset, VkExtent3D& extent) {
|
||||
offset.x = box.Left;
|
||||
offset.y = box.Top;
|
||||
offset.z = box.Front;
|
||||
|
||||
extent.width = box.Right - box.Left;
|
||||
extent.height = box.Bottom - box.Top;
|
||||
extent.depth = box.Back - box.Front;
|
||||
}
|
||||
|
||||
void ConvertRect(RECT rect, VkOffset3D& offset, VkExtent3D& extent) {
|
||||
offset.x = rect.left;
|
||||
offset.y = rect.top;
|
||||
offset.z = 0;
|
||||
|
||||
extent.width = rect.right - rect.left;
|
||||
extent.height = rect.bottom - rect.top;
|
||||
extent.depth = 1;
|
||||
}
|
||||
|
||||
void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent) {
|
||||
offset.x = rect.left;
|
||||
offset.y = rect.top;
|
||||
|
||||
extent.width = rect.right - rect.left;
|
||||
extent.height = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
uint32_t GetDecltypeSize(D3DDECLTYPE Type) {
|
||||
switch (Type) {
|
||||
case D3DDECLTYPE_FLOAT1: return 1 * sizeof(float);
|
||||
case D3DDECLTYPE_FLOAT2: return 2 * sizeof(float);
|
||||
case D3DDECLTYPE_FLOAT3: return 3 * sizeof(float);
|
||||
case D3DDECLTYPE_FLOAT4: return 4 * sizeof(float);
|
||||
case D3DDECLTYPE_D3DCOLOR: return 1 * sizeof(DWORD);
|
||||
case D3DDECLTYPE_UBYTE4: return 4 * sizeof(BYTE);
|
||||
case D3DDECLTYPE_SHORT2: return 2 * sizeof(short);
|
||||
case D3DDECLTYPE_SHORT4: return 4 * sizeof(short);
|
||||
case D3DDECLTYPE_UBYTE4N: return 4 * sizeof(BYTE);
|
||||
case D3DDECLTYPE_SHORT2N: return 2 * sizeof(short);
|
||||
case D3DDECLTYPE_SHORT4N: return 4 * sizeof(short);
|
||||
case D3DDECLTYPE_USHORT2N: return 2 * sizeof(short);
|
||||
case D3DDECLTYPE_USHORT4N: return 4 * sizeof(short);
|
||||
case D3DDECLTYPE_UDEC3: return 4;
|
||||
case D3DDECLTYPE_DEC3N: return 4;
|
||||
case D3DDECLTYPE_FLOAT16_2: return 2 * 2;
|
||||
case D3DDECLTYPE_FLOAT16_4: return 4 * 2;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t GetDecltypeCount(D3DDECLTYPE Type) {
|
||||
switch (Type) {
|
||||
case D3DDECLTYPE_FLOAT1: return 1;
|
||||
case D3DDECLTYPE_FLOAT2: return 2;
|
||||
case D3DDECLTYPE_FLOAT3: return 3;
|
||||
case D3DDECLTYPE_FLOAT4: return 4;
|
||||
case D3DDECLTYPE_D3DCOLOR: return 4;
|
||||
case D3DDECLTYPE_UBYTE4: return 4;
|
||||
case D3DDECLTYPE_SHORT2: return 2;
|
||||
case D3DDECLTYPE_SHORT4: return 4;
|
||||
case D3DDECLTYPE_UBYTE4N: return 4;
|
||||
case D3DDECLTYPE_SHORT2N: return 2;
|
||||
case D3DDECLTYPE_SHORT4N: return 4;
|
||||
case D3DDECLTYPE_USHORT2N: return 2;
|
||||
case D3DDECLTYPE_USHORT4N: return 4;
|
||||
case D3DDECLTYPE_UDEC3: return 3;
|
||||
case D3DDECLTYPE_DEC3N: return 3;
|
||||
case D3DDECLTYPE_FLOAT16_2: return 2;
|
||||
case D3DDECLTYPE_FLOAT16_4: return 4;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool IsDepthFormat(D3D9Format Format) {
|
||||
return Format == D3D9Format::D16_LOCKABLE
|
||||
|| Format == D3D9Format::D32
|
||||
|| Format == D3D9Format::D15S1
|
||||
|| Format == D3D9Format::D24S8
|
||||
|| Format == D3D9Format::D24X8
|
||||
|| Format == D3D9Format::D24X4S4
|
||||
|| Format == D3D9Format::D16
|
||||
|| Format == D3D9Format::D32F_LOCKABLE
|
||||
|| Format == D3D9Format::D24FS8
|
||||
|| Format == D3D9Format::D32_LOCKABLE
|
||||
|| Format == D3D9Format::DF16
|
||||
|| Format == D3D9Format::DF24
|
||||
|| Format == D3D9Format::INTZ;
|
||||
}
|
||||
|
||||
}
|
202
src/d3d9/d3d9_util.h
Normal file
202
src/d3d9/d3d9_util.h
Normal file
|
@ -0,0 +1,202 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_include.h"
|
||||
|
||||
#include "d3d9_format.h"
|
||||
|
||||
#include "../dxso/dxso_common.h"
|
||||
#include "../dxvk/dxvk_device.h"
|
||||
|
||||
#include "../util/util_matrix.h"
|
||||
|
||||
#include <d3dcommon.h>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct D3D9ShaderMasks {
|
||||
uint32_t samplerMask;
|
||||
uint32_t rtMask;
|
||||
};
|
||||
|
||||
struct D3D9MipFilter {
|
||||
bool MipsEnabled;
|
||||
VkSamplerMipmapMode MipFilter;
|
||||
};
|
||||
|
||||
struct D3D9BlendState {
|
||||
D3DBLEND Src;
|
||||
D3DBLEND Dst;
|
||||
D3DBLENDOP Op;
|
||||
};
|
||||
|
||||
inline void FixupBlendState(D3D9BlendState& State) {
|
||||
// Old DirectX 6 HW feature that still exists...
|
||||
// Yuck!
|
||||
if (unlikely(State.Src == D3DBLEND_BOTHSRCALPHA)) {
|
||||
State.Src = D3DBLEND_SRCALPHA;
|
||||
State.Dst = D3DBLEND_INVSRCALPHA;
|
||||
}
|
||||
else if (unlikely(State.Src == D3DBLEND_BOTHINVSRCALPHA)) {
|
||||
State.Src = D3DBLEND_INVSRCALPHA;
|
||||
State.Dst = D3DBLEND_SRCALPHA;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool InvalidSampler(DWORD Sampler) {
|
||||
if (Sampler > 15 && Sampler < D3DDMAPSAMPLER)
|
||||
return true;
|
||||
|
||||
if (Sampler > D3DVERTEXTEXTURESAMPLER3)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline DWORD RemapSamplerState(DWORD Sampler) {
|
||||
if (Sampler >= D3DDMAPSAMPLER)
|
||||
Sampler = 16 + (Sampler - D3DDMAPSAMPLER);
|
||||
|
||||
return Sampler;
|
||||
}
|
||||
|
||||
inline std::pair<DxsoProgramType, DWORD> RemapStateSamplerShader(DWORD Sampler) {
|
||||
if (Sampler >= 17)
|
||||
return std::make_pair(DxsoProgramTypes::VertexShader, Sampler - 17);
|
||||
|
||||
return std::make_pair(DxsoProgramTypes::PixelShader, Sampler);
|
||||
}
|
||||
|
||||
inline std::pair<DxsoProgramType, DWORD> RemapSamplerShader(DWORD Sampler) {
|
||||
Sampler = RemapSamplerState(Sampler);
|
||||
|
||||
return RemapStateSamplerShader(Sampler);
|
||||
}
|
||||
|
||||
template <typename T, typename J>
|
||||
void CastRefPrivate(J* ptr, bool AddRef) {
|
||||
if (ptr == nullptr)
|
||||
return;
|
||||
|
||||
T* castedPtr = reinterpret_cast<T*>(ptr);
|
||||
AddRef ? castedPtr->AddRefPrivate() : castedPtr->ReleasePrivate();
|
||||
}
|
||||
|
||||
HRESULT DisassembleShader(
|
||||
const void* pShader,
|
||||
BOOL EnableColorCode,
|
||||
char* pComments,
|
||||
ID3DBlob** ppDisassembly);
|
||||
|
||||
HRESULT DecodeMultiSampleType(
|
||||
D3DMULTISAMPLE_TYPE MultiSample,
|
||||
DWORD MultisampleQuality,
|
||||
VkSampleCountFlagBits* pCount);
|
||||
|
||||
VkFormat GetPackedDepthStencilFormat(D3D9Format Format);
|
||||
|
||||
VkFormatFeatureFlags GetImageFormatFeatures(DWORD Usage);
|
||||
|
||||
VkImageUsageFlags GetImageUsageFlags(DWORD Usage);
|
||||
|
||||
inline void DecodeD3DCOLOR(D3DCOLOR color, float* rgba) {
|
||||
// Encoded in D3DCOLOR as argb
|
||||
rgba[3] = (float)((color & 0xff000000) >> 24) / 255.0f;
|
||||
rgba[0] = (float)((color & 0x00ff0000) >> 16) / 255.0f;
|
||||
rgba[1] = (float)((color & 0x0000ff00) >> 8) / 255.0f;
|
||||
rgba[2] = (float)((color & 0x000000ff)) / 255.0f;
|
||||
}
|
||||
|
||||
inline VkFormat PickSRGB(VkFormat format, VkFormat srgbFormat, bool srgb) {
|
||||
return srgb ? srgbFormat : format;
|
||||
}
|
||||
|
||||
inline VkShaderStageFlagBits GetShaderStage(DxsoProgramType ProgramType) {
|
||||
switch (ProgramType) {
|
||||
case DxsoProgramTypes::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
case DxsoProgramTypes::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
default: return VkShaderStageFlagBits(0);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t GetTransformIndex(D3DTRANSFORMSTATETYPE Type) {
|
||||
if (Type == D3DTS_VIEW)
|
||||
return 0;
|
||||
|
||||
if (Type == D3DTS_PROJECTION)
|
||||
return 1;
|
||||
|
||||
if (Type >= D3DTS_TEXTURE0 && Type <= D3DTS_TEXTURE7)
|
||||
return 2 + (Type - D3DTS_TEXTURE0);
|
||||
|
||||
return 10 + (Type - D3DTS_WORLD);
|
||||
}
|
||||
|
||||
inline Matrix4 ConvertMatrix(const D3DMATRIX* Matrix) {
|
||||
if (Matrix == nullptr) // Identity.
|
||||
return Matrix4();
|
||||
|
||||
return *(reinterpret_cast<const Matrix4*>(Matrix));
|
||||
}
|
||||
|
||||
uint32_t GetVertexCount(D3DPRIMITIVETYPE type, UINT count);
|
||||
|
||||
DxvkInputAssemblyState DecodeInputAssemblyState(D3DPRIMITIVETYPE type);
|
||||
|
||||
VkBlendFactor DecodeBlendFactor(D3DBLEND BlendFactor, bool IsAlpha);
|
||||
|
||||
VkBlendOp DecodeBlendOp(D3DBLENDOP BlendOp);
|
||||
|
||||
VkFilter DecodeFilter(D3DTEXTUREFILTERTYPE Filter);
|
||||
|
||||
D3D9MipFilter DecodeMipFilter(D3DTEXTUREFILTERTYPE Filter);
|
||||
|
||||
bool IsAnisotropic(D3DTEXTUREFILTERTYPE Filter);
|
||||
|
||||
VkSamplerAddressMode DecodeAddressMode(D3DTEXTUREADDRESS Mode);
|
||||
|
||||
VkCompareOp DecodeCompareOp(D3DCMPFUNC Func);
|
||||
|
||||
VkStencilOp DecodeStencilOp(D3DSTENCILOP Op);
|
||||
|
||||
VkCullModeFlags DecodeCullMode(D3DCULL Mode);
|
||||
|
||||
VkPolygonMode DecodeFillMode(D3DFILLMODE Mode);
|
||||
|
||||
VkIndexType DecodeIndexType(D3D9Format Format);
|
||||
|
||||
VkFormat DecodeDecltype(D3DDECLTYPE Type);
|
||||
|
||||
uint32_t GetDecltypeSize(D3DDECLTYPE Type);
|
||||
|
||||
uint32_t GetDecltypeCount(D3DDECLTYPE Type);
|
||||
|
||||
void ConvertBox(D3DBOX box, VkOffset3D& offset, VkExtent3D& extent);
|
||||
|
||||
void ConvertRect(RECT rect, VkOffset3D& offset, VkExtent3D& extent);
|
||||
|
||||
void ConvertRect(RECT rect, VkOffset2D& offset, VkExtent2D& extent);
|
||||
|
||||
template<typename T>
|
||||
UINT CompactSparseList(T* pData, UINT Mask) {
|
||||
uint32_t count = 0;
|
||||
|
||||
while (Mask != 0) {
|
||||
uint32_t id = bit::tzcnt(Mask);
|
||||
pData[count++] = pData[id];
|
||||
Mask &= Mask - 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
bool IsDepthFormat(D3D9Format Format);
|
||||
|
||||
inline bool IsPoolManaged(D3DPOOL Pool) {
|
||||
return Pool == D3DPOOL_MANAGED || Pool == D3DPOOL_MANAGED_EX;
|
||||
}
|
||||
|
||||
inline D3DRENDERSTATETYPE ColorWriteIndex(uint32_t i) {
|
||||
return D3DRENDERSTATETYPE(i ? D3DRS_COLORWRITEENABLE1 + i - 1 : D3DRS_COLORWRITEENABLE);
|
||||
}
|
||||
|
||||
}
|
231
src/d3d9/d3d9_vertex_declaration.cpp
Normal file
231
src/d3d9/d3d9_vertex_declaration.cpp
Normal file
|
@ -0,0 +1,231 @@
|
|||
#include "d3d9_vertex_declaration.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9VertexDecl::D3D9VertexDecl(
|
||||
D3D9DeviceEx* pDevice,
|
||||
DWORD FVF)
|
||||
: D3D9VertexDeclBase(pDevice) {
|
||||
this->SetFVF(FVF);
|
||||
this->Classify();
|
||||
}
|
||||
|
||||
|
||||
D3D9VertexDecl::D3D9VertexDecl(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3DVERTEXELEMENT9* pVertexElements,
|
||||
uint32_t DeclCount)
|
||||
: D3D9VertexDeclBase( pDevice )
|
||||
, m_elements ( DeclCount )
|
||||
, m_fvf ( 0 ) {
|
||||
std::copy(pVertexElements, pVertexElements + DeclCount, m_elements.begin());
|
||||
this->Classify();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VertexDecl::QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DVertexDeclaration9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9VertexDecl::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9VertexDecl::GetDeclaration(
|
||||
D3DVERTEXELEMENT9* pElement,
|
||||
UINT* pNumElements) {
|
||||
if (pNumElements == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
*pNumElements = UINT(m_elements.size()) + 1u; // Account for D3DDECL_END
|
||||
|
||||
if (pElement == nullptr)
|
||||
return D3D_OK;
|
||||
|
||||
// The native runtime ignores pNumElements here...
|
||||
std::copy(m_elements.begin(), m_elements.end(), pElement);
|
||||
pElement[m_elements.size()] = D3DDECL_END();
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
void D3D9VertexDecl::SetFVF(DWORD FVF) {
|
||||
m_fvf = FVF;
|
||||
|
||||
std::array<D3DVERTEXELEMENT9, 16> elements;
|
||||
uint32_t elemCount = 0;
|
||||
uint32_t texCount = 0;
|
||||
|
||||
uint32_t betas = 0;
|
||||
uint8_t betaIdx = 0xFF;
|
||||
|
||||
switch (FVF & D3DFVF_POSITION_MASK) {
|
||||
case D3DFVF_XYZ:
|
||||
case D3DFVF_XYZB1:
|
||||
case D3DFVF_XYZB2:
|
||||
case D3DFVF_XYZB3:
|
||||
case D3DFVF_XYZB4:
|
||||
case D3DFVF_XYZB5:
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_POSITION;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
|
||||
if ((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZ)
|
||||
break;
|
||||
|
||||
betas = (((FVF & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1) + 1;
|
||||
if (FVF & D3DFVF_LASTBETA_D3DCOLOR)
|
||||
betaIdx = D3DDECLTYPE_D3DCOLOR;
|
||||
else if (FVF & D3DFVF_LASTBETA_UBYTE4)
|
||||
betaIdx = D3DDECLTYPE_UBYTE4;
|
||||
else if ((FVF & D3DFVF_XYZB5) == D3DFVF_XYZB5)
|
||||
betaIdx = D3DDECLTYPE_FLOAT1;
|
||||
|
||||
if (betaIdx != 0xFF)
|
||||
betas--;
|
||||
|
||||
if (betas > 0) {
|
||||
switch (betas) {
|
||||
case 1: elements[elemCount].Type = D3DDECLTYPE_FLOAT1; break;
|
||||
case 2: elements[elemCount].Type = D3DDECLTYPE_FLOAT2; break;
|
||||
case 3: elements[elemCount].Type = D3DDECLTYPE_FLOAT3; break;
|
||||
case 4: elements[elemCount].Type = D3DDECLTYPE_FLOAT4; break;
|
||||
default: break;
|
||||
}
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_BLENDWEIGHT;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
}
|
||||
|
||||
if (betaIdx != 0xFF) {
|
||||
elements[elemCount].Type = betaIdx;
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_BLENDINDICES;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
}
|
||||
break;
|
||||
|
||||
case D3DFVF_XYZW:
|
||||
case D3DFVF_XYZRHW:
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT4;
|
||||
elements[elemCount].Usage =
|
||||
((FVF & D3DFVF_POSITION_MASK) == D3DFVF_XYZW)
|
||||
? D3DDECLUSAGE_POSITION
|
||||
: D3DDECLUSAGE_POSITIONT;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (FVF & D3DFVF_NORMAL) {
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_NORMAL;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
}
|
||||
if (FVF & D3DFVF_PSIZE) {
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT1;
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_PSIZE;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
}
|
||||
if (FVF & D3DFVF_DIFFUSE) {
|
||||
elements[elemCount].Type = D3DDECLTYPE_D3DCOLOR;
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_COLOR;
|
||||
elements[elemCount].UsageIndex = 0;
|
||||
elemCount++;
|
||||
}
|
||||
if (FVF & D3DFVF_SPECULAR) {
|
||||
elements[elemCount].Type = D3DDECLTYPE_D3DCOLOR;
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_COLOR;
|
||||
elements[elemCount].UsageIndex = 1;
|
||||
elemCount++;
|
||||
}
|
||||
|
||||
texCount = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
|
||||
texCount = std::min(texCount, 8u);
|
||||
|
||||
for (uint32_t i = 0; i < texCount; i++) {
|
||||
switch ((FVF >> (16 + i * 2)) & 0x3) {
|
||||
case D3DFVF_TEXTUREFORMAT1:
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT1;
|
||||
break;
|
||||
|
||||
case D3DFVF_TEXTUREFORMAT2:
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT2;
|
||||
break;
|
||||
|
||||
case D3DFVF_TEXTUREFORMAT3:
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT3;
|
||||
break;
|
||||
|
||||
case D3DFVF_TEXTUREFORMAT4:
|
||||
elements[elemCount].Type = D3DDECLTYPE_FLOAT4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
elements[elemCount].Usage = D3DDECLUSAGE_TEXCOORD;
|
||||
elements[elemCount].UsageIndex = i;
|
||||
elemCount++;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < elemCount; i++) {
|
||||
elements[i].Stream = 0;
|
||||
elements[i].Offset = (i == 0)
|
||||
? 0
|
||||
: (elements[i - 1].Offset + GetDecltypeSize(D3DDECLTYPE(elements[i - 1].Type)));
|
||||
|
||||
elements[i].Method = D3DDECLMETHOD_DEFAULT;
|
||||
}
|
||||
|
||||
m_elements.resize(elemCount);
|
||||
std::copy(elements.begin(), elements.begin() + elemCount, m_elements.data());
|
||||
}
|
||||
|
||||
|
||||
void D3D9VertexDecl::Classify() {
|
||||
for (const auto& element : m_elements) {
|
||||
if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 0)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasColor0);
|
||||
else if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 1)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasColor1);
|
||||
else if (element.Usage == D3DDECLUSAGE_POSITIONT)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasPositionT);
|
||||
else if (element.Usage == D3DDECLUSAGE_PSIZE)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasPointSize);
|
||||
else if (element.Usage == D3DDECLUSAGE_FOG)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasFog);
|
||||
else if (element.Usage == D3DDECLUSAGE_BLENDWEIGHT)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasBlendWeight);
|
||||
else if (element.Usage == D3DDECLUSAGE_BLENDINDICES)
|
||||
m_flags.set(D3D9VertexDeclFlag::HasBlendIndices);
|
||||
|
||||
if (element.Usage == D3DDECLUSAGE_TEXCOORD)
|
||||
m_texcoordMask |= GetDecltypeCount(D3DDECLTYPE(element.Type)) << (element.UsageIndex * 3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
83
src/d3d9/d3d9_vertex_declaration.h
Normal file
83
src/d3d9/d3d9_vertex_declaration.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_device_child.h"
|
||||
#include "d3d9_util.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
enum D3D9VertexDeclFlag {
|
||||
HasColor0,
|
||||
HasColor1,
|
||||
HasPositionT,
|
||||
HasPointSize,
|
||||
HasFog,
|
||||
HasBlendWeight,
|
||||
HasBlendIndices
|
||||
};
|
||||
using D3D9VertexDeclFlags = Flags<D3D9VertexDeclFlag>;
|
||||
|
||||
using D3D9VertexDeclBase = D3D9DeviceChild<IDirect3DVertexDeclaration9>;
|
||||
class D3D9VertexDecl final : public D3D9VertexDeclBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9VertexDecl(
|
||||
D3D9DeviceEx* pDevice,
|
||||
DWORD FVF);
|
||||
|
||||
D3D9VertexDecl(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3DVERTEXELEMENT9* pVertexElements,
|
||||
uint32_t DeclCount);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(
|
||||
REFIID riid,
|
||||
void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDeclaration(
|
||||
D3DVERTEXELEMENT9* pElement,
|
||||
UINT* pNumElements);
|
||||
|
||||
inline DWORD GetFVF() {
|
||||
return m_fvf;
|
||||
}
|
||||
|
||||
void SetFVF(DWORD FVF);
|
||||
|
||||
const D3D9VertexElements& GetElements() const {
|
||||
return m_elements;
|
||||
}
|
||||
|
||||
UINT GetSize() const {
|
||||
if (m_elements.size() == 0)
|
||||
return 0;
|
||||
|
||||
auto& end = m_elements.back();
|
||||
return end.Offset + GetDecltypeSize(D3DDECLTYPE(end.Type));
|
||||
}
|
||||
|
||||
bool TestFlag(D3D9VertexDeclFlag flag) const {
|
||||
return m_flags.test(flag);
|
||||
}
|
||||
|
||||
uint32_t GetTexcoordMask() const {
|
||||
return m_texcoordMask;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void Classify();
|
||||
|
||||
D3D9VertexDeclFlags m_flags;
|
||||
|
||||
D3D9VertexElements m_elements;
|
||||
|
||||
DWORD m_fvf;
|
||||
|
||||
uint32_t m_texcoordMask = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
110
src/d3d9/d3d9_volume.cpp
Normal file
110
src/d3d9/d3d9_volume.cpp
Normal file
|
@ -0,0 +1,110 @@
|
|||
#include "d3d9_volume.h"
|
||||
|
||||
#include "d3d9_device.h"
|
||||
#include "d3d9_texture.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
D3D9Volume::D3D9Volume(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping)
|
||||
: D3D9VolumeBase(
|
||||
pDevice,
|
||||
new D3D9CommonTexture( pDevice, pDesc, D3DRTYPE_VOLUMETEXTURE, Mapping ),
|
||||
0, 0,
|
||||
nullptr) { }
|
||||
|
||||
|
||||
D3D9Volume::D3D9Volume(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9CommonTexture* pTexture,
|
||||
UINT Face,
|
||||
UINT MipLevel,
|
||||
IDirect3DBaseTexture9* pContainer)
|
||||
: D3D9VolumeBase(
|
||||
pDevice,
|
||||
pTexture,
|
||||
Face, MipLevel,
|
||||
pContainer) { }
|
||||
|
||||
|
||||
void D3D9Volume::AddRefPrivate() {
|
||||
IDirect3DBaseTexture9* pContainer = this->m_container;
|
||||
|
||||
if (pContainer != nullptr) {
|
||||
reinterpret_cast<D3D9Texture3D*> (pContainer)->AddRefPrivate();
|
||||
return;
|
||||
}
|
||||
|
||||
D3D9VolumeBase::AddRefPrivate();
|
||||
}
|
||||
|
||||
|
||||
void D3D9Volume::ReleasePrivate() {
|
||||
IDirect3DBaseTexture9* pContainer = this->m_container;
|
||||
|
||||
if (pContainer != nullptr) {
|
||||
reinterpret_cast<D3D9Texture3D*> (pContainer)->ReleasePrivate();
|
||||
return;
|
||||
}
|
||||
|
||||
D3D9VolumeBase::ReleasePrivate();
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Volume::QueryInterface(REFIID riid, void** ppvObject) {
|
||||
if (ppvObject == nullptr)
|
||||
return E_POINTER;
|
||||
|
||||
*ppvObject = nullptr;
|
||||
|
||||
if (riid == __uuidof(IUnknown)
|
||||
|| riid == __uuidof(IDirect3DResource9)
|
||||
|| riid == __uuidof(IDirect3DVolume9)) {
|
||||
*ppvObject = ref(this);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Logger::warn("D3D9Volume::QueryInterface: Unknown interface query");
|
||||
Logger::warn(str::format(riid));
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Volume::GetDesc(D3DVOLUME_DESC *pDesc) {
|
||||
if (pDesc == nullptr)
|
||||
return D3DERR_INVALIDCALL;
|
||||
|
||||
auto& desc = *(m_texture->Desc());
|
||||
|
||||
pDesc->Format = static_cast<D3DFORMAT>(desc.Format);
|
||||
pDesc->Type = D3DRTYPE_VOLUME;
|
||||
pDesc->Usage = desc.Usage;
|
||||
pDesc->Pool = desc.Pool;
|
||||
|
||||
pDesc->Width = std::max(1u, desc.Width >> m_mipLevel);
|
||||
pDesc->Height = std::max(1u, desc.Height >> m_mipLevel);
|
||||
pDesc->Depth = std::max(1u, desc.Depth >> m_mipLevel);
|
||||
|
||||
return D3D_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Volume::LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) {
|
||||
return m_parent->LockImage(
|
||||
m_texture,
|
||||
m_face, m_mipLevel,
|
||||
pLockedBox,
|
||||
pBox,
|
||||
Flags);
|
||||
}
|
||||
|
||||
|
||||
HRESULT STDMETHODCALLTYPE D3D9Volume::UnlockBox() {
|
||||
return m_parent->UnlockImage(
|
||||
m_texture,
|
||||
m_face, m_mipLevel);
|
||||
}
|
||||
|
||||
}
|
39
src/d3d9/d3d9_volume.h
Normal file
39
src/d3d9/d3d9_volume.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "d3d9_subresource.h"
|
||||
|
||||
#include "d3d9_common_texture.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
using D3D9VolumeBase = D3D9Subresource<IDirect3DVolume9>;
|
||||
class D3D9Volume final : public D3D9VolumeBase {
|
||||
|
||||
public:
|
||||
|
||||
D3D9Volume(
|
||||
D3D9DeviceEx* pDevice,
|
||||
const D3D9_COMMON_TEXTURE_DESC* pDesc,
|
||||
D3D9_VK_FORMAT_MAPPING Mapping);
|
||||
|
||||
D3D9Volume(
|
||||
D3D9DeviceEx* pDevice,
|
||||
D3D9CommonTexture* pTexture,
|
||||
UINT Face,
|
||||
UINT MipLevel,
|
||||
IDirect3DBaseTexture9* pContainer);
|
||||
|
||||
void AddRefPrivate();
|
||||
|
||||
void ReleasePrivate();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(D3DVOLUME_DESC *pDesc) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE LockBox(D3DLOCKED_BOX* pLockedBox, CONST D3DBOX* pBox, DWORD Flags) final;
|
||||
|
||||
HRESULT STDMETHODCALLTYPE UnlockBox() final;
|
||||
|
||||
};
|
||||
}
|
52
src/d3d9/meson.build
Normal file
52
src/d3d9/meson.build
Normal file
|
@ -0,0 +1,52 @@
|
|||
d3d9_res = wrc_generator.process('version.rc')
|
||||
|
||||
d3d9_shaders = files([
|
||||
'shaders/d3d9_presenter_frag.frag',
|
||||
'shaders/d3d9_presenter_vert.vert',
|
||||
'shaders/d3d9_convert_yuy2_uyvy.comp'
|
||||
])
|
||||
|
||||
d3d9_src = [
|
||||
'd3d9_main.cpp',
|
||||
'd3d9_interface.cpp',
|
||||
'd3d9_adapter.cpp',
|
||||
'd3d9_monitor.cpp',
|
||||
'd3d9_device.cpp',
|
||||
'd3d9_state.cpp',
|
||||
'd3d9_cursor.cpp',
|
||||
'd3d9_swapchain.cpp',
|
||||
'd3d9_format.cpp',
|
||||
'd3d9_common_texture.cpp',
|
||||
'd3d9_texture.cpp',
|
||||
'd3d9_surface.cpp',
|
||||
'd3d9_volume.cpp',
|
||||
'd3d9_common_buffer.cpp',
|
||||
'd3d9_buffer.cpp',
|
||||
'd3d9_shader.cpp',
|
||||
'd3d9_vertex_declaration.cpp',
|
||||
'd3d9_query.cpp',
|
||||
'd3d9_multithread.cpp',
|
||||
'd3d9_options.cpp',
|
||||
'd3d9_stateblock.cpp',
|
||||
'd3d9_sampler.cpp',
|
||||
'd3d9_util.cpp',
|
||||
'd3d9_initializer.cpp',
|
||||
'd3d9_fixed_function.cpp',
|
||||
'd3d9_names.cpp',
|
||||
'd3d9_swvp_emu.cpp',
|
||||
'd3d9_format_helpers.cpp',
|
||||
'd3d9_hud.cpp'
|
||||
]
|
||||
|
||||
d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res,
|
||||
name_prefix : '',
|
||||
dependencies : [ dxso_dep, dxvk_dep ],
|
||||
include_directories : dxvk_include_path,
|
||||
install : true,
|
||||
objects : not dxvk_msvc ? 'd3d9'+def_spec_ext : [],
|
||||
vs_module_defs : 'd3d9'+def_spec_ext,
|
||||
override_options : ['cpp_std='+dxvk_cpp_std])
|
||||
|
||||
d3d9_dep = declare_dependency(
|
||||
link_with : [ d3d9_dll ],
|
||||
include_directories : [ dxvk_include_path ])
|
63
src/d3d9/shaders/d3d9_convert_yuy2_uyvy.comp
Normal file
63
src/d3d9/shaders/d3d9_convert_yuy2_uyvy.comp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#version 450
|
||||
|
||||
layout(constant_id = 1249) const bool s_is_uyvy = false;
|
||||
|
||||
layout(
|
||||
local_size_x = 8,
|
||||
local_size_y = 8,
|
||||
local_size_z = 1) in;
|
||||
|
||||
layout(binding = 0)
|
||||
writeonly uniform image2D dst;
|
||||
|
||||
layout(binding = 1)
|
||||
readonly buffer yuy2_buffer_t {
|
||||
uint data[];
|
||||
} src;
|
||||
|
||||
layout(push_constant)
|
||||
uniform u_info_t {
|
||||
uvec2 extent;
|
||||
} u_info;
|
||||
|
||||
mat3x4 g_yuv_to_rgb = {
|
||||
{ 298 / 256, 0, 409 / 256, 0.5 },
|
||||
{ 298 / 256, -100 / 256, -208 / 256, 0.5 },
|
||||
{ 298 / 256, 516 / 256, 0, 0.5 }
|
||||
};
|
||||
|
||||
vec4 convertYUV(vec3 cde) {
|
||||
vec3 value = vec4(cde, 1 / 255.0) * g_yuv_to_rgb;
|
||||
|
||||
return vec4(clamp(value, 0, 1), 1);
|
||||
}
|
||||
|
||||
void main() {
|
||||
ivec3 thread_id = ivec3(gl_GlobalInvocationID);
|
||||
|
||||
if (all(lessThan(thread_id.xy, u_info.extent))) {
|
||||
uint offset = thread_id.x
|
||||
+ thread_id.y * u_info.extent.x;
|
||||
|
||||
vec4 data = unpackUnorm4x8(src.data[offset]);
|
||||
|
||||
// Flip around stuff for UYVY
|
||||
if (s_is_uyvy)
|
||||
data = data.yxwz;
|
||||
|
||||
float c0 = data.x - (16 / 255.0);
|
||||
float d = data.y - (128 / 255.0);
|
||||
float c1 = data.z - (16 / 255.0);
|
||||
float e = data.w - (128 / 255.0);
|
||||
|
||||
vec4 color0 = convertYUV(vec3(c0, d, e));
|
||||
vec4 color1 = convertYUV(vec3(c1, d, e));
|
||||
|
||||
// YUY2 has a macropixel of [2, 1]
|
||||
// so we write 2 pixels in this run.
|
||||
ivec2 writePos = thread_id.xy * ivec2(2, 1);
|
||||
|
||||
imageStore(dst, ivec2(writePos.x, writePos.y), color0);
|
||||
imageStore(dst, ivec2(writePos.x + 1, writePos.y), color1);
|
||||
}
|
||||
}
|
21
src/d3d9/shaders/d3d9_presenter_frag.frag
Normal file
21
src/d3d9/shaders/d3d9_presenter_frag.frag
Normal file
|
@ -0,0 +1,21 @@
|
|||
#version 450
|
||||
|
||||
layout(constant_id = 1) const bool s_gamma_bound = true;
|
||||
|
||||
layout(binding = 0) uniform sampler2D s_image;
|
||||
layout(binding = 1) uniform sampler1D s_gamma;
|
||||
|
||||
layout(location = 0) in vec2 i_texcoord;
|
||||
layout(location = 0) out vec4 o_color;
|
||||
|
||||
void main() {
|
||||
o_color = texture(s_image, i_texcoord);
|
||||
|
||||
if (s_gamma_bound) {
|
||||
o_color = vec4(
|
||||
texture(s_gamma, o_color.r).r,
|
||||
texture(s_gamma, o_color.g).g,
|
||||
texture(s_gamma, o_color.b).b,
|
||||
o_color.a);
|
||||
}
|
||||
}
|
21
src/d3d9/shaders/d3d9_presenter_vert.vert
Normal file
21
src/d3d9/shaders/d3d9_presenter_vert.vert
Normal file
|
@ -0,0 +1,21 @@
|
|||
#version 450
|
||||
|
||||
layout(location = 0) out vec2 o_texcoord;
|
||||
|
||||
layout(push_constant) uniform present_info_t {
|
||||
vec2 scale;
|
||||
vec2 offset;
|
||||
} u_presentInfo;
|
||||
|
||||
void main() {
|
||||
vec2 coord = vec2(
|
||||
float(gl_VertexIndex & 2),
|
||||
float(gl_VertexIndex & 1) * 2.0f);
|
||||
|
||||
gl_Position = vec4(-1.0f + 2.0f * coord, 0.0f, 1.0f);
|
||||
|
||||
coord *= u_presentInfo.scale;
|
||||
coord += u_presentInfo.offset;
|
||||
|
||||
o_texcoord = coord;
|
||||
}
|
31
src/d3d9/version.rc
Normal file
31
src/d3d9/version.rc
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <windows.h>
|
||||
|
||||
// DLL version information.
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 10,0,17763,1
|
||||
PRODUCTVERSION 10,0,17763,1
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEFLAGS 0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "DXVK"
|
||||
VALUE "FileDescription", "Direct3D 9 Runtime"
|
||||
VALUE "FileVersion", "10.0.17763.1 (WinBuild.160101.0800)"
|
||||
VALUE "InternalName", "D3D9.dll"
|
||||
VALUE "LegalCopyright", "zlib/libpng license"
|
||||
VALUE "OriginalFilename", "D3D9.dll"
|
||||
VALUE "ProductName", "DXVK"
|
||||
VALUE "ProductVersion", "10.0.17763.1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0809, 1200
|
||||
END
|
||||
END
|
47
src/dxso/dxso_analysis.cpp
Normal file
47
src/dxso/dxso_analysis.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "dxso_analysis.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxsoAnalyzer::DxsoAnalyzer(
|
||||
DxsoAnalysisInfo& analysis)
|
||||
: m_analysis(&analysis) { }
|
||||
|
||||
void DxsoAnalyzer::processInstruction(
|
||||
const DxsoInstructionContext& ctx) {
|
||||
DxsoOpcode opcode = ctx.instruction.opcode;
|
||||
|
||||
if (opcode == DxsoOpcode::TexKill)
|
||||
m_analysis->usesKill = true;
|
||||
|
||||
if (opcode == DxsoOpcode::DsX
|
||||
|| opcode == DxsoOpcode::DsY
|
||||
|
||||
|| opcode == DxsoOpcode::Tex
|
||||
|| opcode == DxsoOpcode::TexCoord
|
||||
|| opcode == DxsoOpcode::TexBem
|
||||
|| opcode == DxsoOpcode::TexBemL
|
||||
|| opcode == DxsoOpcode::TexReg2Ar
|
||||
|| opcode == DxsoOpcode::TexReg2Gb
|
||||
|| opcode == DxsoOpcode::TexM3x2Pad
|
||||
|| opcode == DxsoOpcode::TexM3x2Tex
|
||||
|| opcode == DxsoOpcode::TexM3x3Pad
|
||||
|| opcode == DxsoOpcode::TexM3x3Tex
|
||||
|| opcode == DxsoOpcode::TexM3x3Spec
|
||||
|| opcode == DxsoOpcode::TexM3x3VSpec
|
||||
|| opcode == DxsoOpcode::TexReg2Rgb
|
||||
|| opcode == DxsoOpcode::TexDp3Tex
|
||||
|| opcode == DxsoOpcode::TexM3x2Depth
|
||||
|| opcode == DxsoOpcode::TexDp3
|
||||
|| opcode == DxsoOpcode::TexM3x3
|
||||
// Explicit LOD.
|
||||
//|| opcode == DxsoOpcode::TexLdd
|
||||
//|| opcode == DxsoOpcode::TexLdl
|
||||
|| opcode == DxsoOpcode::TexDepth)
|
||||
m_analysis->usesDerivatives = true;
|
||||
}
|
||||
|
||||
void DxsoAnalyzer::finalize(size_t tokenCount) {
|
||||
m_analysis->bytecodeByteLength = tokenCount * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
}
|
37
src/dxso/dxso_analysis.h
Normal file
37
src/dxso/dxso_analysis.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_modinfo.h"
|
||||
#include "dxso_decoder.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct DxsoAnalysisInfo {
|
||||
uint32_t bytecodeByteLength;
|
||||
|
||||
bool usesDerivatives = false;
|
||||
bool usesKill = false;
|
||||
};
|
||||
|
||||
class DxsoAnalyzer {
|
||||
|
||||
public:
|
||||
|
||||
DxsoAnalyzer(
|
||||
DxsoAnalysisInfo& analysis);
|
||||
|
||||
/**
|
||||
* \brief Processes a single instruction
|
||||
* \param [in] ins The instruction
|
||||
*/
|
||||
void processInstruction(
|
||||
const DxsoInstructionContext& ctx);
|
||||
|
||||
void finalize(size_t tokenCount);
|
||||
|
||||
private:
|
||||
|
||||
DxsoAnalysisInfo* m_analysis = nullptr;
|
||||
|
||||
};
|
||||
|
||||
}
|
28
src/dxso/dxso_code.cpp
Normal file
28
src/dxso/dxso_code.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "dxso_code.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxsoCode::DxsoCode(DxsoReader& reader) {
|
||||
m_code =
|
||||
reinterpret_cast<const uint32_t*>(reader.currentPtr());
|
||||
}
|
||||
|
||||
const uint32_t* DxsoCodeIter::ptrAt(uint32_t id) const {
|
||||
return m_ptr + id;
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxsoCodeIter::at(uint32_t id) const {
|
||||
return m_ptr[id];
|
||||
}
|
||||
|
||||
|
||||
uint32_t DxsoCodeIter::read() {
|
||||
return *(m_ptr++);
|
||||
}
|
||||
|
||||
DxsoCodeIter DxsoCodeIter::skip(uint32_t n) const {
|
||||
return DxsoCodeIter(m_ptr + n);
|
||||
}
|
||||
|
||||
}
|
54
src/dxso/dxso_code.h
Normal file
54
src/dxso/dxso_code.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_include.h"
|
||||
#include "dxso_reader.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXBC code iterator
|
||||
*
|
||||
* Convenient pointer wrapper that allows
|
||||
* reading the code token stream.
|
||||
*/
|
||||
class DxsoCodeIter {
|
||||
|
||||
public:
|
||||
|
||||
DxsoCodeIter(
|
||||
const uint32_t* ptr)
|
||||
: m_ptr(ptr) { }
|
||||
|
||||
const uint32_t* ptrAt(uint32_t id) const;
|
||||
|
||||
uint32_t at(uint32_t id) const;
|
||||
uint32_t read();
|
||||
|
||||
DxsoCodeIter skip(uint32_t n) const;
|
||||
|
||||
private:
|
||||
|
||||
const uint32_t* m_ptr = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class DxsoCode {
|
||||
|
||||
public:
|
||||
|
||||
DxsoCode(DxsoReader& reader);
|
||||
|
||||
DxsoCodeIter iter() const {
|
||||
return DxsoCodeIter(m_code);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const uint32_t* m_code;
|
||||
|
||||
};
|
||||
|
||||
}
|
26
src/dxso/dxso_common.cpp
Normal file
26
src/dxso/dxso_common.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "dxso_common.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
VkShaderStageFlagBits DxsoProgramInfo::shaderStage() const {
|
||||
switch (m_type) {
|
||||
case DxsoProgramTypes::PixelShader: return VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
case DxsoProgramTypes::VertexShader: return VK_SHADER_STAGE_VERTEX_BIT;
|
||||
default: break;
|
||||
}
|
||||
|
||||
throw DxvkError("DxsoProgramInfo::shaderStage: Unsupported program type");
|
||||
}
|
||||
|
||||
|
||||
spv::ExecutionModel DxsoProgramInfo::executionModel() const {
|
||||
switch (m_type) {
|
||||
case DxsoProgramTypes::PixelShader: return spv::ExecutionModelFragment;
|
||||
case DxsoProgramTypes::VertexShader: return spv::ExecutionModelVertex;
|
||||
default: break;
|
||||
}
|
||||
|
||||
throw DxvkError("DxsoProgramInfo::executionModel: Unsupported program type");
|
||||
}
|
||||
|
||||
}
|
88
src/dxso/dxso_common.h
Normal file
88
src/dxso/dxso_common.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_include.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXSO Program type
|
||||
*
|
||||
* Defines the shader stage that a DXSO
|
||||
* module has been compiled for.
|
||||
*/
|
||||
namespace DxsoProgramTypes {
|
||||
enum DxsoProgramType : uint16_t {
|
||||
VertexShader = 0,
|
||||
PixelShader = 1,
|
||||
Count = 2,
|
||||
};
|
||||
}
|
||||
using DxsoProgramType = DxsoProgramTypes::DxsoProgramType;
|
||||
|
||||
class DxsoProgramInfo {
|
||||
|
||||
public:
|
||||
|
||||
DxsoProgramInfo() { }
|
||||
DxsoProgramInfo(
|
||||
DxsoProgramType type,
|
||||
uint32_t minorVersion,
|
||||
uint32_t majorVersion)
|
||||
: m_type{ type }
|
||||
, m_minorVersion{ minorVersion }
|
||||
, m_majorVersion{ majorVersion } {}
|
||||
|
||||
/**
|
||||
* \brief Program type
|
||||
* \returns Program type
|
||||
*/
|
||||
DxsoProgramType type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Vulkan shader stage
|
||||
*
|
||||
* The \c VkShaderStageFlagBits constant
|
||||
* that corresponds to the program type.
|
||||
* \returns Vulkan shader stage
|
||||
*/
|
||||
VkShaderStageFlagBits shaderStage() const;
|
||||
|
||||
/**
|
||||
* \brief SPIR-V execution model
|
||||
*
|
||||
* The execution model that corresponds
|
||||
* to the Vulkan shader stage.
|
||||
* \returns SPIR-V execution model
|
||||
*/
|
||||
spv::ExecutionModel executionModel() const;
|
||||
|
||||
/**
|
||||
* \brief Minor version
|
||||
* \returns The minor version of the shader model.
|
||||
*/
|
||||
uint32_t minorVersion() const {
|
||||
return m_minorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Major version
|
||||
* \returns The major version of the shader model.
|
||||
*/
|
||||
uint32_t majorVersion() const {
|
||||
return m_majorVersion;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxsoProgramType m_type;
|
||||
|
||||
uint32_t m_minorVersion;
|
||||
uint32_t m_majorVersion;
|
||||
|
||||
};
|
||||
|
||||
}
|
3579
src/dxso/dxso_compiler.cpp
Normal file
3579
src/dxso/dxso_compiler.cpp
Normal file
File diff suppressed because it is too large
Load diff
674
src/dxso/dxso_compiler.h
Normal file
674
src/dxso/dxso_compiler.h
Normal file
|
@ -0,0 +1,674 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_decoder.h"
|
||||
#include "dxso_header.h"
|
||||
#include "dxso_modinfo.h"
|
||||
#include "dxso_isgn.h"
|
||||
|
||||
#include "../d3d9/d3d9_constant_layout.h"
|
||||
#include "../d3d9/d3d9_shader_permutations.h"
|
||||
#include "../spirv/spirv_module.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Scalar value type
|
||||
*
|
||||
* Enumerates possible register component
|
||||
* types. Scalar types are represented as
|
||||
* a one-component vector type.
|
||||
*/
|
||||
enum class DxsoScalarType : uint32_t {
|
||||
Uint32 = 0,
|
||||
Sint32 = 1,
|
||||
Float32 = 2,
|
||||
Bool = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Vector type
|
||||
*
|
||||
* Convenience struct that stores a scalar
|
||||
* type and a component count. The compiler
|
||||
* can use this to generate SPIR-V types.
|
||||
*/
|
||||
struct DxsoVectorType {
|
||||
DxsoScalarType ctype;
|
||||
uint32_t ccount;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Array type
|
||||
*
|
||||
* Convenience struct that stores a scalar type, a
|
||||
* component count and an array size. An array of
|
||||
* length 0 will be evaluated to a vector type. The
|
||||
* compiler can use this to generate SPIR-V types.
|
||||
*/
|
||||
struct DxsoArrayType {
|
||||
DxsoScalarType ctype;
|
||||
uint32_t ccount;
|
||||
uint32_t alength;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Register info
|
||||
*
|
||||
* Stores the array type of a register and
|
||||
* its storage class. The compiler can use
|
||||
* this to generate SPIR-V pointer types.
|
||||
*/
|
||||
struct DxsoRegisterInfo {
|
||||
DxsoArrayType type;
|
||||
spv::StorageClass sclass;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Register value
|
||||
*
|
||||
* Stores a vector type and a SPIR-V ID that
|
||||
* represents an intermediate value. This is
|
||||
* used to track the type of such values.
|
||||
*/
|
||||
struct DxsoRegisterValue {
|
||||
DxsoVectorType type;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \brief Register pointer
|
||||
*
|
||||
* Stores a vector type and a SPIR-V ID that
|
||||
* represents a pointer to such a vector. This
|
||||
* can be used to load registers conveniently.
|
||||
*/
|
||||
struct DxsoRegisterPointer {
|
||||
DxsoVectorType type;
|
||||
uint32_t id = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sampler info
|
||||
*
|
||||
* Stores a vector type and a SPIR-V ID that
|
||||
* represents a pointer to such a vector. This
|
||||
* can be used to load registers conveniently.
|
||||
*/
|
||||
struct DxsoSamplerInfo {
|
||||
uint32_t dimensions = 0;
|
||||
|
||||
uint32_t varId = 0;
|
||||
uint32_t typeId = 0;
|
||||
};
|
||||
|
||||
enum DxsoSamplerType : uint32_t {
|
||||
SamplerTypeTexture2D = 0,
|
||||
SamplerTypeTexture3D = 1,
|
||||
SamplerTypeTextureCube,
|
||||
|
||||
SamplerTypeCount
|
||||
};
|
||||
|
||||
inline auto SamplerTypeFromTextureType(DxsoTextureType type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case DxsoTextureType::Texture2D: return SamplerTypeTexture2D; break;
|
||||
case DxsoTextureType::Texture3D: return SamplerTypeTexture3D; break;
|
||||
case DxsoTextureType::TextureCube: return SamplerTypeTextureCube; break;
|
||||
}
|
||||
}
|
||||
|
||||
struct DxsoSampler {
|
||||
DxsoSamplerInfo color[SamplerTypeCount];
|
||||
DxsoSamplerInfo depth[SamplerTypeCount];
|
||||
|
||||
uint32_t depthSpecConst;
|
||||
|
||||
DxsoTextureType type;
|
||||
};
|
||||
|
||||
struct DxsoAnalysisInfo;
|
||||
|
||||
/**
|
||||
* \brief Vertex shader-specific structure
|
||||
*/
|
||||
struct DxsoCompilerVsPart {
|
||||
uint32_t functionId = 0;
|
||||
|
||||
////////////////////
|
||||
// Address register
|
||||
DxsoRegisterPointer addr;
|
||||
|
||||
//////////////////////////////
|
||||
// Rasterizer output registers
|
||||
DxsoRegisterPointer oPos;
|
||||
DxsoRegisterPointer oPSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Pixel shader-specific structure
|
||||
*/
|
||||
struct DxsoCompilerPsPart {
|
||||
uint32_t functionId = 0;
|
||||
uint32_t samplerTypeSpec = 0;
|
||||
uint32_t projectionSpec = 0;
|
||||
|
||||
//////////////
|
||||
// Misc Types
|
||||
DxsoRegisterPointer vPos;
|
||||
DxsoRegisterPointer vFace;
|
||||
|
||||
///////////////////
|
||||
// Colour Outputs
|
||||
std::array<DxsoRegisterPointer, 4> oColor;
|
||||
|
||||
////////////////
|
||||
// Depth output
|
||||
DxsoRegisterPointer oDepth;
|
||||
|
||||
////////////////
|
||||
// Shared State
|
||||
uint32_t sharedState = 0;
|
||||
|
||||
uint32_t killState = 0;
|
||||
uint32_t builtinLaneId = 0;
|
||||
|
||||
uint32_t diffuseColorIn = 0;
|
||||
uint32_t specularColorIn = 0;
|
||||
};
|
||||
|
||||
struct DxsoCfgBlockIf {
|
||||
uint32_t ztestId;
|
||||
uint32_t labelIf;
|
||||
uint32_t labelElse;
|
||||
uint32_t labelEnd;
|
||||
size_t headerPtr;
|
||||
};
|
||||
|
||||
struct DxsoCfgBlockLoop {
|
||||
uint32_t labelHeader;
|
||||
uint32_t labelBegin;
|
||||
uint32_t labelContinue;
|
||||
uint32_t labelBreak;
|
||||
uint32_t iteratorPtr;
|
||||
|
||||
uint32_t strideVar;
|
||||
uint32_t countBackup;
|
||||
};
|
||||
|
||||
enum class DxsoCfgBlockType : uint32_t {
|
||||
If, Loop
|
||||
};
|
||||
|
||||
struct DxsoCfgBlock {
|
||||
DxsoCfgBlockType type;
|
||||
|
||||
union {
|
||||
DxsoCfgBlockIf b_if;
|
||||
DxsoCfgBlockLoop b_loop;
|
||||
};
|
||||
};
|
||||
|
||||
using DxsoSrcArray = std::array<DxsoRegisterValue, DxsoMaxOperandCount>;
|
||||
|
||||
class DxsoCompiler {
|
||||
|
||||
public:
|
||||
|
||||
DxsoCompiler(
|
||||
const std::string& fileName,
|
||||
const DxsoModuleInfo& moduleInfo,
|
||||
const DxsoProgramInfo& programInfo,
|
||||
const DxsoAnalysisInfo& analysis,
|
||||
const D3D9ConstantLayout& layout);
|
||||
|
||||
/**
|
||||
* \brief Processes a single instruction
|
||||
* \param [in] ins The instruction
|
||||
*/
|
||||
void processInstruction(
|
||||
const DxsoInstructionContext& ctx);
|
||||
|
||||
/**
|
||||
* \brief Finalizes the shader
|
||||
*/
|
||||
void finalize();
|
||||
|
||||
/**
|
||||
* \brief Compiles the shader
|
||||
* \returns The final shader objects
|
||||
*/
|
||||
DxsoPermutations compile();
|
||||
|
||||
const DxsoIsgn& isgn() { return m_isgn; }
|
||||
const DxsoIsgn& osgn() { return m_osgn; }
|
||||
|
||||
const DxsoShaderMetaInfo& meta() { return m_meta; }
|
||||
const DxsoDefinedConstants& constants() { return m_constants; }
|
||||
uint32_t usedSamplers() const { return m_usedSamplers; }
|
||||
uint32_t usedRTs() const { return m_usedRTs; }
|
||||
|
||||
private:
|
||||
|
||||
DxsoModuleInfo m_moduleInfo;
|
||||
DxsoProgramInfo m_programInfo;
|
||||
const DxsoAnalysisInfo* m_analysis;
|
||||
const D3D9ConstantLayout* m_layout;
|
||||
|
||||
DxsoShaderMetaInfo m_meta;
|
||||
DxsoDefinedConstants m_constants;
|
||||
|
||||
SpirvModule m_module;
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// Resource slot description for the shader. This will
|
||||
// be used to map D3D9 bindings to DXVK bindings.
|
||||
std::vector<DxvkResourceSlot> m_resourceSlots;
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Temporary r# vector registers with immediate
|
||||
// indexing, and x# vector array registers.
|
||||
std::array<
|
||||
DxsoRegisterPointer,
|
||||
DxsoMaxTempRegs> m_rRegs;
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Predicate registers
|
||||
std::array<
|
||||
DxsoRegisterPointer,
|
||||
1> m_pRegs;
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Array of input values. Since v# and o# registers are indexable
|
||||
// in DXSO, we need to copy them into an array first.
|
||||
uint32_t m_vArray = 0;
|
||||
uint32_t m_oArray = 0;
|
||||
|
||||
////////////////////////////////
|
||||
// Input and output signatures
|
||||
DxsoIsgn m_isgn;
|
||||
DxsoIsgn m_osgn;
|
||||
|
||||
////////////////////////////////////
|
||||
// Ptr to the constant buffer array
|
||||
uint32_t m_cBuffer;
|
||||
|
||||
////////////////////////////////////////
|
||||
// Constant buffer deffed mappings
|
||||
std::array<uint32_t, caps::MaxFloatConstantsSoftware> m_cFloat;
|
||||
std::array<uint32_t, caps::MaxOtherConstantsSoftware> m_cInt;
|
||||
std::array<uint32_t, caps::MaxOtherConstantsSoftware> m_cBool;
|
||||
|
||||
//////////////////////
|
||||
// Loop counter
|
||||
DxsoRegisterPointer m_loopCounter;
|
||||
|
||||
///////////////////////////////////
|
||||
// Working tex/coord registers (PS)
|
||||
std::array<
|
||||
DxsoRegisterPointer,
|
||||
DxsoMaxTextureRegs> m_tRegs;
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Control flow information. Stores labels for
|
||||
// currently active if-else blocks and loops.
|
||||
std::vector<DxsoCfgBlock> m_controlFlowBlocks;
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Function state tracking. Required in order
|
||||
// to properly end functions in some cases.
|
||||
bool m_insideFunction = false;
|
||||
|
||||
////////////
|
||||
// Samplers
|
||||
std::array<DxsoSampler, 17> m_samplers;
|
||||
|
||||
////////////////////////////////////////////
|
||||
// What io regswe need to
|
||||
// NOT generate semantics for
|
||||
uint16_t m_explicitInputs = 0;
|
||||
uint16_t m_explicitOutputs = 0;
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// Entry point description - we'll need to declare
|
||||
// the function ID and all input/output variables.
|
||||
std::vector<uint32_t> m_entryPointInterfaces;
|
||||
uint32_t m_entryPointId = 0;
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Inter-stage shader interface slots. Also
|
||||
// covers vertex input and fragment output.
|
||||
DxvkInterfaceSlots m_interfaceSlots;
|
||||
|
||||
///////////////////////////////////
|
||||
// Shader-specific data structures
|
||||
DxsoCompilerVsPart m_vs;
|
||||
DxsoCompilerPsPart m_ps;
|
||||
|
||||
DxsoRegisterPointer m_fog;
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Bit masks containing used samplers
|
||||
// and render targets for hazard tracking
|
||||
uint32_t m_usedSamplers;
|
||||
uint32_t m_usedRTs;
|
||||
|
||||
uint32_t m_rsBlock = 0;
|
||||
uint32_t m_mainFuncLabel = 0;
|
||||
|
||||
//////////////////////////////////////
|
||||
// Common function definition methods
|
||||
void emitInit();
|
||||
|
||||
//////////////////////
|
||||
// Common shader dcls
|
||||
void emitDclConstantBuffer();
|
||||
|
||||
void emitDclInputArray();
|
||||
void emitDclOutputArray();
|
||||
|
||||
/////////////////////////////////
|
||||
// Shader initialization methods
|
||||
void emitVsInit();
|
||||
|
||||
void emitPsSharedConstants();
|
||||
void emitPsInit();
|
||||
|
||||
void emitFunctionBegin(
|
||||
uint32_t entryPoint,
|
||||
uint32_t returnType,
|
||||
uint32_t funcType);
|
||||
|
||||
void emitFunctionEnd();
|
||||
|
||||
uint32_t emitFunctionLabel();
|
||||
|
||||
void emitMainFunctionBegin();
|
||||
|
||||
///////////////////////////////
|
||||
// Variable definition methods
|
||||
uint32_t emitNewVariable(
|
||||
const DxsoRegisterInfo& info);
|
||||
|
||||
uint32_t emitNewVariableDefault(
|
||||
const DxsoRegisterInfo& info,
|
||||
uint32_t value);
|
||||
|
||||
uint32_t emitNewBuiltinVariable(
|
||||
const DxsoRegisterInfo& info,
|
||||
spv::BuiltIn builtIn,
|
||||
const char* name,
|
||||
uint32_t value);
|
||||
|
||||
DxsoCfgBlock* cfgFindBlock(
|
||||
const std::initializer_list<DxsoCfgBlockType>& types);
|
||||
|
||||
void emitDclInterface(
|
||||
bool input,
|
||||
uint32_t regNumber,
|
||||
DxsoSemantic semantic,
|
||||
DxsoRegMask mask,
|
||||
bool centroid);
|
||||
|
||||
void emitDclSampler(
|
||||
uint32_t idx,
|
||||
DxsoTextureType type);
|
||||
|
||||
bool defineInput(uint32_t idx) {
|
||||
bool alreadyDefined = m_interfaceSlots.inputSlots & 1u << idx;
|
||||
m_interfaceSlots.inputSlots |= 1u << idx;
|
||||
return alreadyDefined;
|
||||
}
|
||||
|
||||
bool defineOutput(uint32_t idx) {
|
||||
bool alreadyDefined = m_interfaceSlots.outputSlots & 1u << idx;
|
||||
m_interfaceSlots.outputSlots |= 1u << idx;
|
||||
return alreadyDefined;
|
||||
}
|
||||
|
||||
uint32_t emitArrayIndex(
|
||||
uint32_t idx,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterPointer emitInputPtr(
|
||||
bool texture,
|
||||
const DxsoBaseRegister& reg,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterPointer emitRegisterPtr(
|
||||
const char* name,
|
||||
DxsoScalarType ctype,
|
||||
uint32_t ccount,
|
||||
uint32_t defaultVal,
|
||||
spv::StorageClass storageClass = spv::StorageClassPrivate,
|
||||
spv::BuiltIn builtIn = spv::BuiltInMax);
|
||||
|
||||
DxsoRegisterValue emitLoadConstant(
|
||||
const DxsoBaseRegister& reg,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterPointer emitOutputPtr(
|
||||
bool texcrdOut,
|
||||
const DxsoBaseRegister& reg,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterPointer emitGetOperandPtr(
|
||||
const DxsoBaseRegister& reg,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterPointer emitGetOperandPtr(
|
||||
const DxsoRegister& reg) {
|
||||
return this->emitGetOperandPtr(
|
||||
reg,
|
||||
reg.hasRelative ? ®.relative : nullptr);
|
||||
}
|
||||
|
||||
uint32_t emitBoolComparison(DxsoVectorType type, DxsoComparison cmp, uint32_t a, uint32_t b);
|
||||
|
||||
DxsoRegisterValue emitValueLoad(
|
||||
DxsoRegisterPointer ptr);
|
||||
|
||||
void emitDstStore(
|
||||
DxsoRegisterPointer ptr,
|
||||
DxsoRegisterValue value,
|
||||
DxsoRegMask writeMask,
|
||||
bool saturate,
|
||||
DxsoRegisterValue predicate,
|
||||
int8_t shift,
|
||||
DxsoRegisterId regId) {
|
||||
if (regId.type == DxsoRegisterType::RasterizerOut && regId.num == RasterOutFog)
|
||||
saturate = true;
|
||||
|
||||
if (value.type.ctype == DxsoScalarType::Float32) {
|
||||
const uint32_t typeId = getVectorTypeId(value.type);
|
||||
|
||||
// Saturating only makes sense on floats
|
||||
if (saturate) {
|
||||
value.id = m_module.opNClamp(
|
||||
typeId, value.id,
|
||||
m_module.constfReplicant(0.0f, value.type.ccount),
|
||||
m_module.constfReplicant(1.0f, value.type.ccount));
|
||||
}
|
||||
|
||||
// There doesn't seem to be a nice float bitshift method for float vectors
|
||||
// in Spirv that I can see... Resorting to multiplication.
|
||||
if (shift != 0) {
|
||||
float shiftAmount = shift < 0
|
||||
? 1.0f / (1 << -shift)
|
||||
: float(1 << shift);
|
||||
|
||||
uint32_t shiftConst = m_module.constf32(shiftAmount);
|
||||
|
||||
if (value.type.ccount == 1)
|
||||
value.id = m_module.opFMul(typeId, value.id, shiftConst);
|
||||
else
|
||||
value.id = m_module.opVectorTimesScalar(typeId, value.id, shiftConst);
|
||||
}
|
||||
}
|
||||
|
||||
this->emitValueStore(ptr, value, writeMask, predicate);
|
||||
}
|
||||
|
||||
DxsoRegisterValue applyPredicate(DxsoRegisterValue pred, DxsoRegisterValue dst, DxsoRegisterValue src);
|
||||
|
||||
void emitValueStore(
|
||||
DxsoRegisterPointer ptr,
|
||||
DxsoRegisterValue value,
|
||||
DxsoRegMask writeMask,
|
||||
DxsoRegisterValue predicate);
|
||||
|
||||
DxsoRegisterValue emitClampBoundReplicant(
|
||||
DxsoRegisterValue srcValue,
|
||||
float lb,
|
||||
float ub);
|
||||
|
||||
DxsoRegisterValue emitSaturate(
|
||||
DxsoRegisterValue srcValue);
|
||||
|
||||
DxsoRegisterValue emitDot(
|
||||
DxsoRegisterValue a,
|
||||
DxsoRegisterValue b);
|
||||
|
||||
DxsoRegisterValue emitRegisterInsert(
|
||||
DxsoRegisterValue dstValue,
|
||||
DxsoRegisterValue srcValue,
|
||||
DxsoRegMask srcMask);
|
||||
|
||||
DxsoRegisterValue emitRegisterLoadRaw(
|
||||
const DxsoBaseRegister& reg,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterValue emitRegisterExtend(
|
||||
DxsoRegisterValue value,
|
||||
uint32_t size);
|
||||
|
||||
DxsoRegisterValue emitSrcOperandPreSwizzleModifiers(
|
||||
DxsoRegisterValue value,
|
||||
DxsoRegModifier modifier);
|
||||
|
||||
DxsoRegisterValue emitSrcOperandPostSwizzleModifiers(
|
||||
DxsoRegisterValue value,
|
||||
DxsoRegModifier modifier);
|
||||
|
||||
DxsoRegisterValue emitRegisterSwizzle(
|
||||
DxsoRegisterValue value,
|
||||
DxsoRegSwizzle swizzle,
|
||||
DxsoRegMask writeMask);
|
||||
|
||||
DxsoRegisterValue emitRegisterLoad(
|
||||
const DxsoBaseRegister& reg,
|
||||
DxsoRegMask writeMask,
|
||||
const DxsoBaseRegister* relative);
|
||||
|
||||
DxsoRegisterValue emitRegisterLoad(
|
||||
const DxsoRegister& reg,
|
||||
DxsoRegMask writeMask) {
|
||||
return this->emitRegisterLoad(
|
||||
reg, writeMask,
|
||||
reg.hasRelative ? ®.relative : nullptr);
|
||||
}
|
||||
|
||||
DxsoRegisterValue emitPredicateLoad(const DxsoInstructionContext& ctx) {
|
||||
if (!ctx.instruction.predicated)
|
||||
return DxsoRegisterValue();
|
||||
|
||||
return emitRegisterLoad(ctx.pred, IdentityWriteMask);
|
||||
}
|
||||
|
||||
DxsoRegisterValue emitRegisterLoadTexcoord(
|
||||
const DxsoRegister& reg,
|
||||
DxsoRegMask writeMask) {
|
||||
DxsoRegister lookup = reg;
|
||||
if (reg.id.type == DxsoRegisterType::Texture)
|
||||
lookup.id.type = DxsoRegisterType::PixelTexcoord;
|
||||
|
||||
return this->emitRegisterLoad(lookup, writeMask);
|
||||
}
|
||||
|
||||
Rc<DxvkShader> compileShader();
|
||||
|
||||
///////////////////////////////
|
||||
// Handle shader ops
|
||||
void emitDcl(const DxsoInstructionContext& ctx);
|
||||
|
||||
void emitDef(const DxsoInstructionContext& ctx);
|
||||
void emitDefF(const DxsoInstructionContext& ctx);
|
||||
void emitDefI(const DxsoInstructionContext& ctx);
|
||||
void emitDefB(const DxsoInstructionContext& ctx);
|
||||
|
||||
bool isScalarRegister(DxsoRegisterId id);
|
||||
|
||||
void emitMov(const DxsoInstructionContext& ctx);
|
||||
void emitPredicateOp(const DxsoInstructionContext& ctx);
|
||||
void emitVectorAlu(const DxsoInstructionContext& ctx);
|
||||
void emitMatrixAlu(const DxsoInstructionContext& ctx);
|
||||
|
||||
void emitControlFlowGenericLoop(
|
||||
bool count,
|
||||
uint32_t initialVar,
|
||||
uint32_t strideVar,
|
||||
uint32_t iterationCountVar);
|
||||
|
||||
void emitControlFlowGenericLoopEnd();
|
||||
|
||||
void emitControlFlowRep(const DxsoInstructionContext& ctx);
|
||||
void emitControlFlowEndRep(const DxsoInstructionContext& ctx);
|
||||
|
||||
void emitControlFlowLoop(const DxsoInstructionContext& ctx);
|
||||
void emitControlFlowEndLoop(const DxsoInstructionContext& ctx);
|
||||
|
||||
void emitControlFlowBreak(const DxsoInstructionContext& ctx);
|
||||
void emitControlFlowBreakC(const DxsoInstructionContext& ctx);
|
||||
|
||||
void emitControlFlowIf(const DxsoInstructionContext& ctx);
|
||||
void emitControlFlowElse(const DxsoInstructionContext& ctx);
|
||||
void emitControlFlowEndIf(const DxsoInstructionContext& ctx);
|
||||
|
||||
void emitTexCoord(const DxsoInstructionContext& ctx);
|
||||
void emitTextureSample(const DxsoInstructionContext& ctx);
|
||||
void emitTextureKill(const DxsoInstructionContext& ctx);
|
||||
|
||||
uint32_t emitSample(
|
||||
bool projected,
|
||||
uint32_t resultType,
|
||||
uint32_t sampledImage,
|
||||
uint32_t coordinates,
|
||||
uint32_t reference,
|
||||
const SpirvImageOperands& operands);
|
||||
|
||||
///////////////////////////////
|
||||
// Shader finalization methods
|
||||
void emitInputSetup();
|
||||
|
||||
void emitVsClipping();
|
||||
void setupRenderStateInfo();
|
||||
void emitFog();
|
||||
void emitPsProcessing();
|
||||
void emitOutputDepthClamp();
|
||||
|
||||
void emitLinkerOutputSetup();
|
||||
|
||||
void emitVsFinalize();
|
||||
void emitPsFinalize();
|
||||
|
||||
///////////////////////////
|
||||
// Type definition methods
|
||||
uint32_t getScalarTypeId(
|
||||
DxsoScalarType type);
|
||||
|
||||
uint32_t getVectorTypeId(
|
||||
const DxsoVectorType& type);
|
||||
|
||||
uint32_t getArrayTypeId(
|
||||
const DxsoArrayType& type);
|
||||
|
||||
uint32_t getPointerTypeId(
|
||||
const DxsoRegisterInfo& type);
|
||||
|
||||
};
|
||||
|
||||
}
|
19
src/dxso/dxso_ctab.cpp
Normal file
19
src/dxso/dxso_ctab.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "dxso_ctab.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxsoCtab::DxsoCtab(DxsoReader& reader, uint32_t commentTokenCount) {
|
||||
m_size = reader.readu32();
|
||||
|
||||
if (m_size != sizeof(DxsoCtab))
|
||||
throw DxvkError("DxsoCtab: ctab size invalid");
|
||||
|
||||
m_creator = reader.readu32();
|
||||
m_version = reader.readu32();
|
||||
m_constants = reader.readu32();
|
||||
m_constantInfo = reader.readu32();
|
||||
m_flags = reader.readu32();
|
||||
m_target = reader.readu32();
|
||||
}
|
||||
|
||||
}
|
32
src/dxso/dxso_ctab.h
Normal file
32
src/dxso/dxso_ctab.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_common.h"
|
||||
|
||||
#include "dxso_reader.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXSO CTAB
|
||||
*
|
||||
* Stores meta information about the shader
|
||||
*/
|
||||
class DxsoCtab : public RcObject {
|
||||
|
||||
public:
|
||||
|
||||
DxsoCtab(DxsoReader& reader, uint32_t commentTokenCount);
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_size;
|
||||
uint32_t m_creator;
|
||||
uint32_t m_version;
|
||||
uint32_t m_constants;
|
||||
uint32_t m_constantInfo;
|
||||
uint32_t m_flags;
|
||||
uint32_t m_target;
|
||||
|
||||
};
|
||||
|
||||
}
|
276
src/dxso/dxso_decoder.cpp
Normal file
276
src/dxso/dxso_decoder.cpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
#include "dxso_decoder.h"
|
||||
|
||||
#include "dxso_tables.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
bool DxsoSemantic::operator== (const DxsoSemantic& b) const {
|
||||
return usage == b.usage && usageIndex == b.usageIndex;
|
||||
}
|
||||
|
||||
bool DxsoSemantic::operator!= (const DxsoSemantic& b) const {
|
||||
return usage != b.usage || usageIndex != b.usageIndex;
|
||||
}
|
||||
|
||||
uint32_t DxsoDecodeContext::decodeInstructionLength(uint32_t token) {
|
||||
auto opcode = m_ctx.instruction.opcode;
|
||||
|
||||
uint32_t length = 0;
|
||||
const auto& info = this->getProgramInfo();
|
||||
|
||||
// Comment ops have their own system for getting length.
|
||||
if (opcode == DxsoOpcode::Comment)
|
||||
return (token & 0x7fff0000) >> 16;
|
||||
|
||||
if (opcode == DxsoOpcode::End)
|
||||
return 0;
|
||||
|
||||
// SM2.0 and above has the length of the op in instruction count baked into it.
|
||||
// SM1.4 and below have fixed lengths and run off expectation.
|
||||
// Phase does not respect the following rules. :shrug:
|
||||
if (opcode != DxsoOpcode::Phase) {
|
||||
if (info.majorVersion() >= 2)
|
||||
length = (token & 0x0f000000) >> 24;
|
||||
else
|
||||
length = DxsoGetDefaultOpcodeLength(opcode);
|
||||
}
|
||||
|
||||
// We've already logged this...
|
||||
if (length == InvalidOpcodeLength)
|
||||
return 0;
|
||||
|
||||
// SM 1.4 has an extra param on Tex and TexCoord
|
||||
// As stated before, it also doesn't have the length of the op baked into the opcode
|
||||
if (info.majorVersion() == 1
|
||||
&& info.minorVersion() == 4) {
|
||||
switch (opcode) {
|
||||
case DxsoOpcode::TexCoord:
|
||||
case DxsoOpcode::Tex: length += 1;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
bool DxsoDecodeContext::relativeAddressingUsesToken(
|
||||
DxsoInstructionArgumentType type) {
|
||||
auto& info = this->getProgramInfo();
|
||||
|
||||
return (info.majorVersion() >= 2 && type == DxsoInstructionArgumentType::Source)
|
||||
|| (info.majorVersion() >= 3 && type == DxsoInstructionArgumentType::Destination);
|
||||
}
|
||||
|
||||
void DxsoDecodeContext::decodeDeclaration(DxsoCodeIter& iter) {
|
||||
uint32_t dclToken = iter.read();
|
||||
|
||||
m_ctx.dcl.textureType = static_cast<DxsoTextureType>((dclToken & 0x78000000) >> 27);
|
||||
m_ctx.dcl.semantic.usage = static_cast<DxsoUsage>(dclToken & 0x0000000f);
|
||||
m_ctx.dcl.semantic.usageIndex = (dclToken & 0x000f0000) >> 16;
|
||||
}
|
||||
|
||||
void DxsoDecodeContext::decodeDefinition(DxsoOpcode opcode, DxsoCodeIter& iter) {
|
||||
const uint32_t instructionLength = std::min(m_ctx.instruction.tokenLength - 1, 4u);
|
||||
|
||||
for (uint32_t i = 0; i < instructionLength; i++)
|
||||
m_ctx.def.uint32[i] = iter.read();
|
||||
}
|
||||
|
||||
void DxsoDecodeContext::decodeBaseRegister(
|
||||
DxsoBaseRegister& reg,
|
||||
uint32_t token) {
|
||||
reg.id.type = static_cast<DxsoRegisterType>(
|
||||
((token & 0x00001800) >> 8)
|
||||
| ((token & 0x70000000) >> 28));
|
||||
|
||||
reg.id.num = token & 0x000007ff;
|
||||
}
|
||||
|
||||
void DxsoDecodeContext::decodeGenericRegister(
|
||||
DxsoRegister& reg,
|
||||
uint32_t token) {
|
||||
this->decodeBaseRegister(reg, token);
|
||||
|
||||
reg.hasRelative = (token & (1 << 13)) == 8192;
|
||||
reg.relative.id = DxsoRegisterId {
|
||||
DxsoRegisterType::Addr, 0 };
|
||||
reg.relative.swizzle = IdentitySwizzle;
|
||||
|
||||
reg.centroid = token & (4 << 20);
|
||||
reg.partialPrecision = token & (2 << 20);
|
||||
}
|
||||
|
||||
void DxsoDecodeContext::decodeRelativeRegister(
|
||||
DxsoBaseRegister& reg,
|
||||
uint32_t token) {
|
||||
this->decodeBaseRegister(reg, token);
|
||||
|
||||
reg.swizzle = DxsoRegSwizzle(
|
||||
uint8_t((token & 0x00ff0000) >> 16));
|
||||
}
|
||||
|
||||
bool DxsoDecodeContext::decodeDestinationRegister(DxsoCodeIter& iter) {
|
||||
uint32_t token = iter.read();
|
||||
|
||||
this->decodeGenericRegister(m_ctx.dst, token);
|
||||
|
||||
m_ctx.dst.mask = DxsoRegMask(
|
||||
uint8_t((token & 0x000f0000) >> 16));
|
||||
|
||||
m_ctx.dst.saturate = (token & (1 << 20)) != 0;
|
||||
|
||||
m_ctx.dst.shift = (token & 0x0f000000) >> 24;
|
||||
m_ctx.dst.shift = (m_ctx.dst.shift & 0x7) - (m_ctx.dst.shift & 0x8);
|
||||
|
||||
const bool extraToken =
|
||||
relativeAddressingUsesToken(DxsoInstructionArgumentType::Destination);
|
||||
|
||||
if (m_ctx.dst.hasRelative && extraToken) {
|
||||
this->decodeRelativeRegister(m_ctx.dst.relative, iter.read());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DxsoDecodeContext::decodeSourceRegister(uint32_t i, DxsoCodeIter& iter) {
|
||||
if (i >= m_ctx.src.size())
|
||||
throw DxvkError("DxsoDecodeContext::decodeSourceRegister: source register out of range.");
|
||||
|
||||
uint32_t token = iter.read();
|
||||
|
||||
this->decodeGenericRegister(m_ctx.src[i], token);
|
||||
|
||||
m_ctx.src[i].swizzle = DxsoRegSwizzle(
|
||||
uint8_t((token & 0x00ff0000) >> 16));
|
||||
|
||||
m_ctx.src[i].modifier = static_cast<DxsoRegModifier>(
|
||||
(token & 0x0f000000) >> 24);
|
||||
|
||||
const bool extraToken =
|
||||
relativeAddressingUsesToken(DxsoInstructionArgumentType::Source);
|
||||
|
||||
if (m_ctx.src[i].hasRelative && extraToken) {
|
||||
this->decodeRelativeRegister(m_ctx.src[i].relative, iter.read());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void DxsoDecodeContext::decodePredicateRegister(DxsoCodeIter& iter) {
|
||||
uint32_t token = iter.read();
|
||||
|
||||
this->decodeGenericRegister(m_ctx.pred, token);
|
||||
|
||||
m_ctx.pred.swizzle = DxsoRegSwizzle(
|
||||
uint8_t((token & 0x00ff0000) >> 16));
|
||||
|
||||
m_ctx.pred.modifier = static_cast<DxsoRegModifier>(
|
||||
(token & 0x0f000000) >> 24);
|
||||
}
|
||||
|
||||
|
||||
bool DxsoDecodeContext::decodeInstruction(DxsoCodeIter& iter) {
|
||||
uint32_t token = iter.read();
|
||||
|
||||
m_ctx.instruction.opcode = static_cast<DxsoOpcode>(
|
||||
token & 0x0000ffff);
|
||||
|
||||
m_ctx.instruction.predicated = token & (1 << 28);
|
||||
|
||||
m_ctx.instruction.specificData.uint32 =
|
||||
(token & 0x00ff0000) >> 16;
|
||||
|
||||
m_ctx.instruction.tokenLength =
|
||||
this->decodeInstructionLength(token);
|
||||
|
||||
uint32_t tokenLength =
|
||||
m_ctx.instruction.tokenLength;
|
||||
|
||||
switch (m_ctx.instruction.opcode) {
|
||||
case DxsoOpcode::If:
|
||||
case DxsoOpcode::Ifc:
|
||||
case DxsoOpcode::Rep:
|
||||
case DxsoOpcode::Loop:
|
||||
case DxsoOpcode::BreakC:
|
||||
case DxsoOpcode::BreakP: {
|
||||
uint32_t sourceIdx = 0;
|
||||
for (uint32_t i = 0; i < tokenLength; i++) {
|
||||
if (this->decodeSourceRegister(sourceIdx, iter))
|
||||
i++;
|
||||
|
||||
sourceIdx++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case DxsoOpcode::Dcl:
|
||||
this->decodeDeclaration(iter);
|
||||
this->decodeDestinationRegister(iter);
|
||||
return true;
|
||||
|
||||
case DxsoOpcode::Def:
|
||||
case DxsoOpcode::DefI:
|
||||
case DxsoOpcode::DefB:
|
||||
this->decodeDestinationRegister(iter);
|
||||
this->decodeDefinition(
|
||||
m_ctx.instruction.opcode, iter);
|
||||
return true;
|
||||
|
||||
case DxsoOpcode::Comment:
|
||||
iter = iter.skip(tokenLength);
|
||||
return true;
|
||||
|
||||
default: {
|
||||
uint32_t sourceIdx = 0;
|
||||
for (uint32_t i = 0; i < tokenLength; i++) {
|
||||
if (i == 0) {
|
||||
if (this->decodeDestinationRegister(iter))
|
||||
i++;
|
||||
}
|
||||
else if (i == 1 && m_ctx.instruction.predicated) {
|
||||
// Relative addressing makes no sense
|
||||
// for predicate registers.
|
||||
this->decodePredicateRegister(iter);
|
||||
}
|
||||
else {
|
||||
if (this->decodeSourceRegister(sourceIdx, iter))
|
||||
i++;
|
||||
|
||||
sourceIdx++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case DxsoOpcode::End:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator << (std::ostream& os, DxsoUsage usage) {
|
||||
switch (usage) {
|
||||
case DxsoUsage::Position: os << "Position"; break;
|
||||
case DxsoUsage::BlendWeight: os << "BlendWeight"; break;
|
||||
case DxsoUsage::BlendIndices: os << "BlendIndices"; break;
|
||||
case DxsoUsage::Normal: os << "Normal"; break;
|
||||
case DxsoUsage::PointSize: os << "PointSize"; break;
|
||||
case DxsoUsage::Texcoord: os << "Texcoord"; break;
|
||||
case DxsoUsage::Tangent: os << "Tangent"; break;
|
||||
case DxsoUsage::Binormal: os << "Binormal"; break;
|
||||
case DxsoUsage::TessFactor: os << "TessFactor"; break;
|
||||
case DxsoUsage::PositionT: os << "PositionT"; break;
|
||||
case DxsoUsage::Color: os << "Color"; break;
|
||||
case DxsoUsage::Fog: os << "Fog"; break;
|
||||
case DxsoUsage::Depth: os << "Depth"; break;
|
||||
case DxsoUsage::Sample: os << "Sample"; break;
|
||||
default:
|
||||
os << "Invalid Format (" << static_cast<uint32_t>(usage) << ")"; break;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
271
src/dxso/dxso_decoder.h
Normal file
271
src/dxso/dxso_decoder.h
Normal file
|
@ -0,0 +1,271 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_common.h"
|
||||
#include "dxso_enums.h"
|
||||
#include "dxso_code.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
constexpr size_t DxsoMaxTempRegs = 32;
|
||||
constexpr size_t DxsoMaxTextureRegs = 10;
|
||||
constexpr size_t DxsoMaxInterfaceRegs = 16;
|
||||
constexpr size_t DxsoMaxOperandCount = 8;
|
||||
|
||||
constexpr uint32_t DxsoRegModifierShift = 24;
|
||||
|
||||
class DxsoDecodeContext;
|
||||
|
||||
/**
|
||||
* \brief Source operand modifiers
|
||||
*
|
||||
* These are applied after loading
|
||||
* an operand register.
|
||||
*/
|
||||
enum class DxsoRegModifier : uint32_t {
|
||||
None = 0, // r
|
||||
Neg = 1, // -r
|
||||
Bias = 2, // r - 0.5
|
||||
BiasNeg = 3, // -(r - 0.5)
|
||||
Sign = 4, // fma(r, 2.0f, -1.0f)
|
||||
SignNeg = 5, // -fma(r, 2.0f, -1.0f)
|
||||
Comp = 6, // 1 - r
|
||||
X2 = 7, // r * 2
|
||||
X2Neg = 8, // -r * 2
|
||||
Dz = 9, // r / r.z
|
||||
Dw = 10, // r / r.w
|
||||
Abs = 11, // abs(r)
|
||||
AbsNeg = 12, // -abs(r)
|
||||
Not = 13, // !r
|
||||
};
|
||||
|
||||
enum class DxsoInstructionArgumentType : uint16_t {
|
||||
Source,
|
||||
Destination
|
||||
};
|
||||
|
||||
enum class DxsoComparison : uint32_t {
|
||||
// < = >
|
||||
Never = 0, // 0 0 0
|
||||
GreaterThan = 1, // 0 0 1
|
||||
Equal = 2, // 0 1 0
|
||||
GreaterEqual = 3, // 0 1 1
|
||||
LessThan = 4, // 1 0 0
|
||||
NotEqual = 5, // 1 0 1
|
||||
LessEqual = 6, // 1 1 0
|
||||
Always = 7 // 1 1 1
|
||||
};
|
||||
|
||||
enum class DxsoTexLdMode : uint32_t {
|
||||
Regular = 0,
|
||||
Project = 1,
|
||||
Bias = 2
|
||||
};
|
||||
|
||||
union DxsoOpcodeSpecificData {
|
||||
DxsoComparison comparison;
|
||||
DxsoTexLdMode texld;
|
||||
|
||||
uint32_t uint32;
|
||||
};
|
||||
|
||||
struct DxsoShaderInstruction {
|
||||
DxsoOpcode opcode;
|
||||
bool predicated;
|
||||
DxsoOpcodeSpecificData specificData;
|
||||
|
||||
uint32_t tokenLength;
|
||||
};
|
||||
|
||||
struct DxsoRegisterId {
|
||||
DxsoRegisterType type;
|
||||
uint32_t num;
|
||||
|
||||
bool operator == (const DxsoRegisterId& other) const { return type == other.type && num == other.num; }
|
||||
bool operator != (const DxsoRegisterId& other) const { return type != other.type || num != other.num; }
|
||||
};
|
||||
|
||||
class DxsoRegMask {
|
||||
|
||||
public:
|
||||
|
||||
DxsoRegMask(uint8_t mask)
|
||||
: m_mask(mask) { }
|
||||
|
||||
DxsoRegMask(bool x, bool y, bool z, bool w)
|
||||
: m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
|
||||
| (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
|
||||
|
||||
bool operator [] (uint32_t id) const {
|
||||
return ((m_mask & (1u << id)) != 0);
|
||||
}
|
||||
|
||||
uint32_t popCount() const {
|
||||
const uint8_t n[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
|
||||
1, 2, 2, 3, 2, 3, 3, 4 };
|
||||
return n[m_mask & 0xF];
|
||||
}
|
||||
|
||||
uint32_t firstSet() const {
|
||||
const uint8_t n[16] = { 4, 0, 1, 0, 2, 0, 1, 0,
|
||||
3, 0, 1, 0, 2, 0, 1, 0 };
|
||||
return n[m_mask & 0xF];
|
||||
}
|
||||
|
||||
uint32_t minComponents() const {
|
||||
const uint8_t n[16] = { 0, 1, 2, 2, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 4, 4 };
|
||||
return n[m_mask & 0xF];
|
||||
}
|
||||
|
||||
bool operator == (const DxsoRegMask& other) const { return m_mask == other.m_mask; }
|
||||
bool operator != (const DxsoRegMask& other) const { return m_mask != other.m_mask; }
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_mask;
|
||||
|
||||
};
|
||||
|
||||
const DxsoRegMask IdentityWriteMask = DxsoRegMask(true, true, true, true);
|
||||
|
||||
class DxsoRegSwizzle {
|
||||
|
||||
public:
|
||||
|
||||
DxsoRegSwizzle(uint8_t mask)
|
||||
: m_mask(mask) { }
|
||||
|
||||
DxsoRegSwizzle(uint32_t x, uint32_t y, uint32_t z, uint32_t w)
|
||||
: m_mask((x << 0) | (y << 2) | (z << 4) | (w << 6)) {}
|
||||
|
||||
uint32_t operator [] (uint32_t id) const {
|
||||
return (m_mask >> (id + id)) & 0x3;
|
||||
}
|
||||
|
||||
bool operator == (const DxsoRegSwizzle& other) const { return m_mask == other.m_mask; }
|
||||
bool operator != (const DxsoRegSwizzle& other) const { return m_mask != other.m_mask; }
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_mask;
|
||||
|
||||
};
|
||||
|
||||
const DxsoRegSwizzle IdentitySwizzle{ 0, 1, 2, 3 };
|
||||
|
||||
struct DxsoBaseRegister {
|
||||
DxsoRegisterId id = { DxsoRegisterType::Temp, 0 };
|
||||
bool centroid = false;
|
||||
bool partialPrecision = false;
|
||||
bool saturate = false;
|
||||
DxsoRegModifier modifier = DxsoRegModifier::None;
|
||||
DxsoRegMask mask = IdentityWriteMask;
|
||||
DxsoRegSwizzle swizzle = IdentitySwizzle;
|
||||
int8_t shift = 0;
|
||||
};
|
||||
|
||||
struct DxsoRegister : public DxsoBaseRegister {
|
||||
bool hasRelative = false;
|
||||
DxsoBaseRegister relative;
|
||||
};
|
||||
|
||||
struct DxsoSemantic {
|
||||
DxsoUsage usage;
|
||||
uint32_t usageIndex;
|
||||
|
||||
bool operator== (const DxsoSemantic& b) const;
|
||||
bool operator!= (const DxsoSemantic& b) const;
|
||||
};
|
||||
|
||||
struct DxsoDeclaration {
|
||||
DxsoSemantic semantic;
|
||||
|
||||
DxsoTextureType textureType;
|
||||
};
|
||||
|
||||
union DxsoDefinition {
|
||||
float float32[4];
|
||||
int32_t int32[4];
|
||||
|
||||
// Not a type we actually use in compiler, but used for decoding.
|
||||
uint32_t uint32[4];
|
||||
};
|
||||
|
||||
struct DxsoInstructionContext {
|
||||
DxsoShaderInstruction instruction;
|
||||
|
||||
DxsoRegister pred;
|
||||
|
||||
DxsoRegister dst;
|
||||
std::array<
|
||||
DxsoRegister,
|
||||
DxsoMaxOperandCount> src;
|
||||
|
||||
DxsoDefinition def;
|
||||
|
||||
DxsoDeclaration dcl;
|
||||
};
|
||||
|
||||
class DxsoDecodeContext {
|
||||
|
||||
public:
|
||||
|
||||
DxsoDecodeContext(const DxsoProgramInfo& programInfo)
|
||||
: m_programInfo( programInfo ) { }
|
||||
|
||||
/**
|
||||
* \brief Retrieves current instruction context
|
||||
*
|
||||
* This is only valid after a call to \ref decode.
|
||||
* \returns Reference to last decoded instruction & its context
|
||||
*/
|
||||
const DxsoInstructionContext& getInstructionContext() const {
|
||||
return m_ctx;
|
||||
}
|
||||
|
||||
const DxsoProgramInfo& getProgramInfo() const {
|
||||
return m_programInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Decodes an instruction
|
||||
*
|
||||
* This also advances the given code slice by the
|
||||
* number of dwords consumed by the instruction.
|
||||
* \param [in] code Code slice
|
||||
*/
|
||||
bool decodeInstruction(DxsoCodeIter& iter);
|
||||
|
||||
private:
|
||||
|
||||
uint32_t decodeInstructionLength(uint32_t token);
|
||||
|
||||
void decodeBaseRegister(
|
||||
DxsoBaseRegister& reg,
|
||||
uint32_t token);
|
||||
void decodeGenericRegister(
|
||||
DxsoRegister& reg,
|
||||
uint32_t token);
|
||||
void decodeRelativeRegister(
|
||||
DxsoBaseRegister& reg,
|
||||
uint32_t token);
|
||||
|
||||
// Returns whether an extra token was read.
|
||||
bool decodeDestinationRegister(DxsoCodeIter& iter);
|
||||
bool decodeSourceRegister(uint32_t i, DxsoCodeIter& iter);
|
||||
void decodePredicateRegister(DxsoCodeIter& iter);
|
||||
|
||||
void decodeDeclaration(DxsoCodeIter& iter);
|
||||
void decodeDefinition(DxsoOpcode opcode, DxsoCodeIter& iter);
|
||||
|
||||
bool relativeAddressingUsesToken(DxsoInstructionArgumentType type);
|
||||
|
||||
const DxsoProgramInfo& m_programInfo;
|
||||
|
||||
DxsoInstructionContext m_ctx;
|
||||
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, DxsoUsage usage);
|
||||
|
||||
}
|
101
src/dxso/dxso_enums.cpp
Normal file
101
src/dxso/dxso_enums.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
#include "dxso_enums.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
std::ostream& operator << (std::ostream& os, DxsoOpcode opcode) {
|
||||
switch (opcode) {
|
||||
case DxsoOpcode::Nop: os << "Nop"; break;
|
||||
case DxsoOpcode::Mov: os << "Mov"; break;
|
||||
case DxsoOpcode::Add: os << "Add"; break;
|
||||
case DxsoOpcode::Sub: os << "Sub"; break;
|
||||
case DxsoOpcode::Mad: os << "Mad"; break;
|
||||
case DxsoOpcode::Mul: os << "Mul"; break;
|
||||
case DxsoOpcode::Rcp: os << "Rcp"; break;
|
||||
case DxsoOpcode::Rsq: os << "Rsq"; break;
|
||||
case DxsoOpcode::Dp3: os << "Dp3"; break;
|
||||
case DxsoOpcode::Dp4: os << "Dp4"; break;
|
||||
case DxsoOpcode::Min: os << "Min"; break;
|
||||
case DxsoOpcode::Max: os << "Max"; break;
|
||||
case DxsoOpcode::Slt: os << "Slt"; break;
|
||||
case DxsoOpcode::Sge: os << "Sge"; break;
|
||||
case DxsoOpcode::Exp: os << "Exp"; break;
|
||||
case DxsoOpcode::Log: os << "Log"; break;
|
||||
case DxsoOpcode::Lit: os << "Lit"; break;
|
||||
case DxsoOpcode::Dst: os << "Dst"; break;
|
||||
case DxsoOpcode::Lrp: os << "Lrp"; break;
|
||||
case DxsoOpcode::Frc: os << "Frc"; break;
|
||||
case DxsoOpcode::M4x4: os << "M4x4"; break;
|
||||
case DxsoOpcode::M4x3: os << "M4x3"; break;
|
||||
case DxsoOpcode::M3x4: os << "M3x4"; break;
|
||||
case DxsoOpcode::M3x3: os << "M3x3"; break;
|
||||
case DxsoOpcode::M3x2: os << "M3x2"; break;
|
||||
case DxsoOpcode::Call: os << "Call"; break;
|
||||
case DxsoOpcode::CallNz: os << "CallNz"; break;
|
||||
case DxsoOpcode::Loop: os << "Loop"; break;
|
||||
case DxsoOpcode::Ret: os << "Ret"; break;
|
||||
case DxsoOpcode::EndLoop: os << "EndLoop"; break;
|
||||
case DxsoOpcode::Label: os << "Label"; break;
|
||||
case DxsoOpcode::Dcl: os << "Dcl"; break;
|
||||
case DxsoOpcode::Pow: os << "Pow"; break;
|
||||
case DxsoOpcode::Crs: os << "Crs"; break;
|
||||
case DxsoOpcode::Sgn: os << "Sgn"; break;
|
||||
case DxsoOpcode::Abs: os << "Abs"; break;
|
||||
case DxsoOpcode::Nrm: os << "Nrm"; break;
|
||||
case DxsoOpcode::SinCos: os << "SinCos"; break;
|
||||
case DxsoOpcode::Rep: os << "Rep"; break;
|
||||
case DxsoOpcode::EndRep: os << "EndRep"; break;
|
||||
case DxsoOpcode::If: os << "If"; break;
|
||||
case DxsoOpcode::Ifc: os << "Ifc"; break;
|
||||
case DxsoOpcode::Else: os << "Else"; break;
|
||||
case DxsoOpcode::EndIf: os << "EndIf"; break;
|
||||
case DxsoOpcode::Break: os << "Break"; break;
|
||||
case DxsoOpcode::BreakC: os << "BreakC"; break;
|
||||
case DxsoOpcode::Mova: os << "Mova"; break;
|
||||
case DxsoOpcode::DefB: os << "DefB"; break;
|
||||
case DxsoOpcode::DefI: os << "DefI"; break;
|
||||
|
||||
case DxsoOpcode::TexCoord: os << "TexCoord"; break;
|
||||
case DxsoOpcode::TexKill: os << "TexKill"; break;
|
||||
case DxsoOpcode::Tex: os << "Tex"; break;
|
||||
case DxsoOpcode::TexBem: os << "TexBem"; break;
|
||||
case DxsoOpcode::TexBemL: os << "TexBemL"; break;
|
||||
case DxsoOpcode::TexReg2Ar: os << "TexReg2Ar"; break;
|
||||
case DxsoOpcode::TexReg2Gb: os << "TexReg2Gb"; break;
|
||||
case DxsoOpcode::TexM3x2Pad: os << "TexM3x2Pad"; break;
|
||||
case DxsoOpcode::TexM3x2Tex: os << "TexM3x2Tex"; break;
|
||||
case DxsoOpcode::TexM3x3Pad: os << "TexM3x3Pad"; break;
|
||||
case DxsoOpcode::TexM3x3Tex: os << "TexM3x3Tex"; break;
|
||||
case DxsoOpcode::Reserved0: os << "Reserved0"; break;
|
||||
case DxsoOpcode::TexM3x3Spec: os << "TexM3x3Spec"; break;
|
||||
case DxsoOpcode::TexM3x3VSpec: os << "TexM3x3VSpec"; break;
|
||||
case DxsoOpcode::ExpP: os << "ExpP"; break;
|
||||
case DxsoOpcode::LogP: os << "LogP"; break;
|
||||
case DxsoOpcode::Cnd: os << "Cnd"; break;
|
||||
case DxsoOpcode::Def: os << "Def"; break;
|
||||
case DxsoOpcode::TexReg2Rgb: os << "TexReg2Rgb"; break;
|
||||
case DxsoOpcode::TexDp3Tex: os << "TexDp3Tex"; break;
|
||||
case DxsoOpcode::TexM3x2Depth: os << "TexM3x2Depth"; break;
|
||||
case DxsoOpcode::TexDp3: os << "TexDp3"; break;
|
||||
case DxsoOpcode::TexM3x3: os << "TexM3x3"; break;
|
||||
case DxsoOpcode::TexDepth: os << "TexDepth"; break;
|
||||
case DxsoOpcode::Cmp: os << "Cmp"; break;
|
||||
case DxsoOpcode::Bem: os << "Bem"; break;
|
||||
case DxsoOpcode::Dp2Add: os << "Dp2Add"; break;
|
||||
case DxsoOpcode::DsX: os << "DsX"; break;
|
||||
case DxsoOpcode::DsY: os << "DsY"; break;
|
||||
case DxsoOpcode::TexLdd: os << "TexLdd"; break;
|
||||
case DxsoOpcode::SetP: os << "SetP"; break;
|
||||
case DxsoOpcode::TexLdl: os << "TexLdl"; break;
|
||||
case DxsoOpcode::BreakP: os << "BreakP"; break;
|
||||
|
||||
case DxsoOpcode::Phase: os << "Phase"; break;
|
||||
case DxsoOpcode::Comment: os << "Comment"; break;
|
||||
case DxsoOpcode::End: os << "End"; break;
|
||||
default:
|
||||
os << "Invalid Opcode (" << static_cast<uint32_t>(opcode) << ")"; break;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
164
src/dxso/dxso_enums.h
Normal file
164
src/dxso/dxso_enums.h
Normal file
|
@ -0,0 +1,164 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_include.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Instruction code listing
|
||||
*/
|
||||
enum class DxsoOpcode : uint32_t {
|
||||
Nop = 0,
|
||||
Mov ,
|
||||
Add ,
|
||||
Sub ,
|
||||
Mad ,
|
||||
Mul ,
|
||||
Rcp ,
|
||||
Rsq ,
|
||||
Dp3 ,
|
||||
Dp4 ,
|
||||
Min ,
|
||||
Max ,
|
||||
Slt ,
|
||||
Sge ,
|
||||
Exp ,
|
||||
Log ,
|
||||
Lit ,
|
||||
Dst ,
|
||||
Lrp ,
|
||||
Frc ,
|
||||
M4x4 ,
|
||||
M4x3 ,
|
||||
M3x4 ,
|
||||
M3x3 ,
|
||||
M3x2 ,
|
||||
Call ,
|
||||
CallNz ,
|
||||
Loop ,
|
||||
Ret ,
|
||||
EndLoop ,
|
||||
Label ,
|
||||
Dcl ,
|
||||
Pow ,
|
||||
Crs ,
|
||||
Sgn ,
|
||||
Abs ,
|
||||
Nrm ,
|
||||
SinCos ,
|
||||
Rep ,
|
||||
EndRep ,
|
||||
If ,
|
||||
Ifc ,
|
||||
Else ,
|
||||
EndIf ,
|
||||
Break ,
|
||||
BreakC ,
|
||||
Mova ,
|
||||
DefB ,
|
||||
DefI ,
|
||||
|
||||
TexCoord = 64,
|
||||
TexKill ,
|
||||
Tex ,
|
||||
TexBem ,
|
||||
TexBemL ,
|
||||
TexReg2Ar ,
|
||||
TexReg2Gb ,
|
||||
TexM3x2Pad ,
|
||||
TexM3x2Tex ,
|
||||
TexM3x3Pad ,
|
||||
TexM3x3Tex ,
|
||||
Reserved0 ,
|
||||
TexM3x3Spec ,
|
||||
TexM3x3VSpec ,
|
||||
ExpP ,
|
||||
LogP ,
|
||||
Cnd ,
|
||||
Def ,
|
||||
TexReg2Rgb ,
|
||||
TexDp3Tex ,
|
||||
TexM3x2Depth ,
|
||||
TexDp3 ,
|
||||
TexM3x3 ,
|
||||
TexDepth ,
|
||||
Cmp ,
|
||||
Bem ,
|
||||
Dp2Add ,
|
||||
DsX ,
|
||||
DsY ,
|
||||
TexLdd ,
|
||||
SetP ,
|
||||
TexLdl ,
|
||||
BreakP ,
|
||||
|
||||
Phase = 0xfffd,
|
||||
Comment = 0xfffe,
|
||||
End = 0xffff
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& os, DxsoOpcode opcode);
|
||||
|
||||
enum class DxsoRegisterType : uint32_t {
|
||||
Temp = 0, // Temporary Register File
|
||||
Input = 1, // Input Register File
|
||||
Const = 2, // Constant Register File
|
||||
Addr = 3, // Address Register (VS)
|
||||
Texture = 3, // Texture Register File (PS)
|
||||
RasterizerOut = 4, // Rasterizer Register File
|
||||
AttributeOut = 5, // Attribute Output Register File
|
||||
TexcoordOut = 6, // Texture Coordinate Output Register File
|
||||
Output = 6, // Output register file for VS3.0+
|
||||
ConstInt = 7, // Constant Integer Vector Register File
|
||||
ColorOut = 8, // Color Output Register File
|
||||
DepthOut = 9, // Depth Output Register File
|
||||
Sampler = 10, // Sampler State Register File
|
||||
Const2 = 11, // Constant Register File 2048 - 4095
|
||||
Const3 = 12, // Constant Register File 4096 - 6143
|
||||
Const4 = 13, // Constant Register File 6144 - 8191
|
||||
ConstBool = 14, // Constant Boolean register file
|
||||
Loop = 15, // Loop counter register file
|
||||
TempFloat16 = 16, // 16-bit float temp register file
|
||||
MiscType = 17, // Miscellaneous (single) registers.
|
||||
Label = 18, // Label
|
||||
Predicate = 19, // Predicate register
|
||||
PixelTexcoord = 20
|
||||
};
|
||||
|
||||
enum class DxsoUsage : uint32_t {
|
||||
Position = 0,
|
||||
BlendWeight, // 1
|
||||
BlendIndices, // 2
|
||||
Normal, // 3
|
||||
PointSize, // 4
|
||||
Texcoord, // 5
|
||||
Tangent, // 6
|
||||
Binormal, // 7
|
||||
TessFactor, // 8
|
||||
PositionT, // 9
|
||||
Color, // 10
|
||||
Fog, // 11
|
||||
Depth, // 12
|
||||
Sample, // 13
|
||||
};
|
||||
|
||||
enum class DxsoTextureType : uint32_t {
|
||||
Texture2D = 2,
|
||||
TextureCube = 3,
|
||||
Texture3D = 4
|
||||
};
|
||||
|
||||
enum DxsoReasterizerOutIndices : uint32_t {
|
||||
RasterOutPosition = 0,
|
||||
RasterOutFog = 1,
|
||||
RasterOutPointSize = 2
|
||||
};
|
||||
|
||||
enum DxsoMiscTypeIndices : uint32_t {
|
||||
MiscTypePosition,
|
||||
MiscTypeFace,
|
||||
};
|
||||
|
||||
}
|
24
src/dxso/dxso_header.cpp
Normal file
24
src/dxso/dxso_header.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "dxso_header.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
DxsoHeader::DxsoHeader(DxsoReader& reader) {
|
||||
uint32_t headerToken = reader.readu32();
|
||||
|
||||
uint32_t headerTypeMask = headerToken & 0xffff0000;
|
||||
|
||||
DxsoProgramType programType;
|
||||
if (headerTypeMask == 0xffff0000)
|
||||
programType = DxsoProgramTypes::PixelShader;
|
||||
else if (headerTypeMask == 0xfffe0000)
|
||||
programType = DxsoProgramTypes::VertexShader;
|
||||
else
|
||||
throw DxvkError("DxsoHeader: invalid header - invalid version");
|
||||
|
||||
const uint32_t majorVersion = (headerToken >> 8) & 0xff;
|
||||
const uint32_t minorVersion = headerToken & 0xff;
|
||||
|
||||
m_info = DxsoProgramInfo{ programType, minorVersion, majorVersion };
|
||||
}
|
||||
|
||||
}
|
31
src/dxso/dxso_header.h
Normal file
31
src/dxso/dxso_header.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_common.h"
|
||||
|
||||
#include "dxso_reader.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief DXSO header
|
||||
*
|
||||
* Stores meta information about the shader such
|
||||
* as the version and the type.
|
||||
*/
|
||||
class DxsoHeader {
|
||||
|
||||
public:
|
||||
|
||||
DxsoHeader(DxsoReader& reader);
|
||||
|
||||
const DxsoProgramInfo& info() const {
|
||||
return m_info;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DxsoProgramInfo m_info;
|
||||
|
||||
};
|
||||
|
||||
}
|
0
src/dxso/dxso_helpers.h
Normal file
0
src/dxso/dxso_helpers.h
Normal file
18
src/dxso/dxso_include.h
Normal file
18
src/dxso/dxso_include.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "../dxvk/dxvk_shader.h"
|
||||
|
||||
#include "../util/com/com_guid.h"
|
||||
#include "../util/com/com_object.h"
|
||||
#include "../util/com/com_pointer.h"
|
||||
|
||||
#include "../util/log/log.h"
|
||||
#include "../util/log/log_debug.h"
|
||||
|
||||
#include "../util/rc/util_rc.h"
|
||||
#include "../util/rc/util_rc_ptr.h"
|
||||
|
||||
#include "../util/util_bit.h"
|
||||
#include "../util/util_enum.h"
|
||||
#include "../util/util_error.h"
|
||||
#include "../util/util_string.h"
|
39
src/dxso/dxso_isgn.h
Normal file
39
src/dxso/dxso_isgn.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_decoder.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
struct DxsoIsgnEntry {
|
||||
uint32_t regNumber = 0;
|
||||
uint32_t slot = 0;
|
||||
DxsoSemantic semantic = DxsoSemantic{ DxsoUsage::Position, 0 };
|
||||
DxsoRegMask mask = IdentityWriteMask;
|
||||
bool centroid = false;
|
||||
};
|
||||
|
||||
struct DxsoIsgn {
|
||||
std::array<
|
||||
DxsoIsgnEntry,
|
||||
2 * DxsoMaxInterfaceRegs> elems;
|
||||
uint32_t elemCount = 0;
|
||||
};
|
||||
|
||||
struct DxsoDefinedConstant {
|
||||
uint32_t uboIdx;
|
||||
|
||||
// Only float constants may be indexed.
|
||||
// So that's the only ones we care about putting in the UBO.
|
||||
float float32[4];
|
||||
};
|
||||
|
||||
using DxsoDefinedConstants = std::vector<DxsoDefinedConstant>;
|
||||
|
||||
struct DxsoShaderMetaInfo {
|
||||
bool needsConstantCopies = false;
|
||||
uint32_t maxConstIndexF = 0;
|
||||
uint32_t maxConstIndexI = 0;
|
||||
uint32_t maxConstIndexB = 0;
|
||||
};
|
||||
|
||||
}
|
17
src/dxso/dxso_modinfo.h
Normal file
17
src/dxso/dxso_modinfo.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "dxso_options.h"
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Shader module info
|
||||
*
|
||||
* Stores information which may affect shader compilation.
|
||||
* This data can be supplied by the client API implementation.
|
||||
*/
|
||||
struct DxsoModuleInfo {
|
||||
DxsoOptions options;
|
||||
};
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue