Skip to content

Commit

Permalink
GPUDevice: Add API version field
Browse files Browse the repository at this point in the history
Also tie shader caches to API version and device LUID. That way we don't
have tons of cache files, and they're regenerated if the GPU/driver
changes.
  • Loading branch information
stenzek committed Sep 8, 2024
1 parent c42fb7c commit 4c31218
Show file tree
Hide file tree
Showing 23 changed files with 222 additions and 195 deletions.
12 changes: 12 additions & 0 deletions src/common/small_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ void SmallStringBase::shrink_to_fit()
m_buffer_size = buffer_size;
}

void SmallStringBase::convert_to_lower_case()
{
for (u32 i = 0; i < m_length; i++)
m_buffer[i] = static_cast<char>(std::tolower(m_buffer[i]));
}

void SmallStringBase::convert_to_upper_case()
{
for (u32 i = 0; i < m_length; i++)
m_buffer[i] = static_cast<char>(std::toupper(m_buffer[i]));
}

std::string_view SmallStringBase::view() const
{
return (m_length == 0) ? std::string_view() : std::string_view(m_buffer, m_length);
Expand Down
4 changes: 4 additions & 0 deletions src/common/small_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@ class SmallStringBase
ALWAYS_INLINE void push_back(value_type val) { append(val); }
ALWAYS_INLINE void pop_back() { erase(-1); }

// case conversion
void convert_to_lower_case();
void convert_to_upper_case();

// returns a string view for this string
std::string_view view() const;

Expand Down
2 changes: 1 addition & 1 deletion src/core/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SettingsInterface;
struct WindowInfo;
enum class AudioBackend : u8;
enum class AudioStretchMode : u8;
enum class RenderAPI : u32;
enum class RenderAPI : u8;
class AudioStream;
class CDImage;

Expand Down
2 changes: 1 addition & 1 deletion src/core/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#include <string_view>
#include <vector>

enum class RenderAPI : u32;
enum class RenderAPI : u8;
enum class MediaCaptureBackend : u8;

struct SettingInfo
Expand Down
17 changes: 7 additions & 10 deletions src/util/d3d11_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,6 @@ D3D11Device::~D3D11Device()
Assert(!m_device);
}

RenderAPI D3D11Device::GetRenderAPI() const
{
return RenderAPI::D3D11;
}

bool D3D11Device::HasSurface() const
{
return static_cast<bool>(m_swap_chain);
Expand Down Expand Up @@ -127,7 +122,8 @@ bool D3D11Device::CreateDevice(std::string_view adapter, std::optional<bool> exc
INFO_LOG("D3D Adapter: {}", D3DCommon::GetAdapterName(dxgi_adapter.Get()));
else
ERROR_LOG("Failed to obtain D3D adapter name.");
INFO_LOG("Max device feature level: {}", D3DCommon::GetFeatureLevelString(m_max_feature_level));
INFO_LOG("Max device feature level: {}",
D3DCommon::GetFeatureLevelString(D3DCommon::GetRenderAPIVersionForFeatureLevel(m_max_feature_level)));

BOOL allow_tearing_supported = false;
hr = m_dxgi_factory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing_supported,
Expand Down Expand Up @@ -164,6 +160,8 @@ void D3D11Device::SetFeatures(FeatureMask disabled_features)
{
const D3D_FEATURE_LEVEL feature_level = m_device->GetFeatureLevel();

m_render_api = RenderAPI::D3D11;
m_render_api_version = D3DCommon::GetRenderAPIVersionForFeatureLevel(feature_level);
m_max_texture_size = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
m_max_multisamples = 1;
for (u32 multisamples = 2; multisamples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; multisamples++)
Expand Down Expand Up @@ -443,12 +441,11 @@ bool D3D11Device::SupportsExclusiveFullscreen() const

std::string D3D11Device::GetDriverInfo() const
{
const D3D_FEATURE_LEVEL fl = m_device->GetFeatureLevel();
std::string ret =
fmt::format("{} ({})\n", D3DCommon::GetFeatureLevelString(fl), D3DCommon::GetFeatureLevelShaderModelString(fl));
std::string ret = fmt::format("{} (Shader Model {})\n", D3DCommon::GetFeatureLevelString(m_render_api_version),
D3DCommon::GetShaderModelForFeatureLevelNumber(m_render_api_version));

ComPtr<IDXGIDevice> dxgi_dev;
if (m_device.As(&dxgi_dev))
if (SUCCEEDED(m_device.As(&dxgi_dev)))
{
ComPtr<IDXGIAdapter> dxgi_adapter;
if (SUCCEEDED(dxgi_dev->GetAdapter(dxgi_adapter.GetAddressOf())))
Expand Down
2 changes: 0 additions & 2 deletions src/util/d3d11_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ class D3D11Device final : public GPUDevice
ALWAYS_INLINE static ID3D11DeviceContext1* GetD3DContext() { return GetInstance().m_context.Get(); }
ALWAYS_INLINE static D3D_FEATURE_LEVEL GetMaxFeatureLevel() { return GetInstance().m_max_feature_level; }

RenderAPI GetRenderAPI() const override;

bool HasSurface() const override;

bool UpdateWindow() override;
Expand Down
2 changes: 1 addition & 1 deletion src/util/d3d11_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ std::unique_ptr<GPUShader> D3D11Device::CreateShaderFromSource(GPUShaderStage st
std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error)
{
const u32 shader_model = D3DCommon::GetShaderModelForFeatureLevel(m_device->GetFeatureLevel());
const u32 shader_model = D3DCommon::GetShaderModelForFeatureLevelNumber(m_render_api_version);
if (language != GPUShaderLanguage::HLSL)
{
return TranspileAndCreateShaderFromSource(stage, language, source, entry_point, GPUShaderLanguage::HLSL,
Expand Down
47 changes: 34 additions & 13 deletions src/util/d3d12_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,13 @@ bool D3D12Device::CreateDevice(std::string_view adapter, std::optional<bool> exc
}

// Create the actual device.
D3D_FEATURE_LEVEL feature_level = D3D_FEATURE_LEVEL_1_0_CORE;
for (D3D_FEATURE_LEVEL try_feature_level : {D3D_FEATURE_LEVEL_11_0})
{
hr = D3D12CreateDevice(m_adapter.Get(), try_feature_level, IID_PPV_ARGS(&m_device));
if (SUCCEEDED(hr))
{
m_feature_level = try_feature_level;
feature_level = try_feature_level;
break;
}
}
Expand Down Expand Up @@ -232,7 +233,7 @@ bool D3D12Device::CreateDevice(std::string_view adapter, std::optional<bool> exc
return false;
}

SetFeatures(disabled_features);
SetFeatures(feature_level, disabled_features);

if (!CreateCommandLists(error) || !CreateDescriptorHeaps(error))
return false;
Expand Down Expand Up @@ -282,10 +283,28 @@ void D3D12Device::DestroyDevice()
m_dxgi_factory.Reset();
}

void D3D12Device::GetPipelineCacheHeader(PIPELINE_CACHE_HEADER* hdr)
{
const LUID adapter_luid = m_device->GetAdapterLuid();
std::memcpy(&hdr->adapter_luid, &adapter_luid, sizeof(hdr->adapter_luid));
hdr->render_api_version = m_render_api_version;
hdr->unused = 0;
}

bool D3D12Device::ReadPipelineCache(std::optional<DynamicHeapArray<u8>> data)
{
PIPELINE_CACHE_HEADER expected_header;
GetPipelineCacheHeader(&expected_header);
if (data.has_value() && (data->size() < sizeof(PIPELINE_CACHE_HEADER) ||
std::memcmp(data->data(), &expected_header, sizeof(PIPELINE_CACHE_HEADER)) != 0))
{
WARNING_LOG("Pipeline cache header does not match current device, ignoring.");
data.reset();
}

HRESULT hr =
m_device->CreatePipelineLibrary(data.has_value() ? data->data() : nullptr, data.has_value() ? data->size() : 0,
m_device->CreatePipelineLibrary(data.has_value() ? (data->data() + sizeof(PIPELINE_CACHE_HEADER)) : nullptr,
data.has_value() ? (data->size() - sizeof(PIPELINE_CACHE_HEADER)) : 0,
IID_PPV_ARGS(m_pipeline_library.ReleaseAndGetAddressOf()));
if (SUCCEEDED(hr))
{
Expand Down Expand Up @@ -328,8 +347,13 @@ bool D3D12Device::GetPipelineCacheData(DynamicHeapArray<u8>* data)
return true;
}

data->resize(size);
const HRESULT hr = m_pipeline_library->Serialize(data->data(), data->size());
PIPELINE_CACHE_HEADER header;
GetPipelineCacheHeader(&header);

data->resize(sizeof(PIPELINE_CACHE_HEADER) + size);
std::memcpy(data->data(), &header, sizeof(PIPELINE_CACHE_HEADER));

const HRESULT hr = m_pipeline_library->Serialize(data->data() + sizeof(PIPELINE_CACHE_HEADER), size);
if (FAILED(hr))
{
ERROR_LOG("Serialize() failed with HRESULT {:08X}", static_cast<unsigned>(hr));
Expand Down Expand Up @@ -771,11 +795,6 @@ void D3D12Device::DestroyDeferredObjects(u64 fence_value)
}
}

RenderAPI D3D12Device::GetRenderAPI() const
{
return RenderAPI::D3D12;
}

bool D3D12Device::HasSurface() const
{
return static_cast<bool>(m_swap_chain);
Expand Down Expand Up @@ -1070,8 +1089,8 @@ bool D3D12Device::SupportsTextureFormat(GPUTexture::Format format) const

std::string D3D12Device::GetDriverInfo() const
{
std::string ret = fmt::format("{} ({})\n", D3DCommon::GetFeatureLevelString(m_feature_level),
D3DCommon::GetFeatureLevelShaderModelString(m_feature_level));
std::string ret = fmt::format("{} (Shader Model {})\n", D3DCommon::GetFeatureLevelString(m_render_api_version),
D3DCommon::GetShaderModelForFeatureLevelNumber(m_render_api_version));

DXGI_ADAPTER_DESC desc;
if (m_adapter && SUCCEEDED(m_adapter->GetDesc(&desc)))
Expand Down Expand Up @@ -1234,8 +1253,10 @@ void D3D12Device::InsertDebugMessage(const char* msg)
#endif
}

void D3D12Device::SetFeatures(FeatureMask disabled_features)
void D3D12Device::SetFeatures(D3D_FEATURE_LEVEL feature_level, FeatureMask disabled_features)
{
m_render_api = RenderAPI::D3D12;
m_render_api_version = D3DCommon::GetRenderAPIVersionForFeatureLevel(feature_level);
m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
m_max_multisamples = 1;
for (u32 multisamples = 2; multisamples < D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT; multisamples++)
Expand Down
14 changes: 10 additions & 4 deletions src/util/d3d12_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ class D3D12Device final : public GPUDevice
D3D12Device();
~D3D12Device() override;

RenderAPI GetRenderAPI() const override;

bool HasSurface() const override;

bool UpdateWindow() override;
Expand Down Expand Up @@ -220,9 +218,18 @@ class D3D12Device final : public GPUDevice
bool has_timestamp_query = false;
};

struct PIPELINE_CACHE_HEADER
{
u64 adapter_luid;
u32 render_api_version;
u32 unused;
};
static_assert(sizeof(PIPELINE_CACHE_HEADER) == 16);

using SamplerMap = std::unordered_map<u64, D3D12DescriptorHandle>;

void SetFeatures(FeatureMask disabled_features);
void GetPipelineCacheHeader(PIPELINE_CACHE_HEADER* hdr);
void SetFeatures(D3D_FEATURE_LEVEL feature_level, FeatureMask disabled_features);

u32 GetSwapChainBufferCount() const;
bool CreateSwapChain(Error* error);
Expand Down Expand Up @@ -291,7 +298,6 @@ class D3D12Device final : public GPUDevice

std::array<CommandList, NUM_COMMAND_LISTS> m_command_lists;
u32 m_current_command_list = NUM_COMMAND_LISTS - 1;
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;

ComPtr<IDXGIFactory5> m_dxgi_factory;
ComPtr<IDXGISwapChain1> m_swap_chain;
Expand Down
2 changes: 1 addition & 1 deletion src/util/d3d12_pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ std::unique_ptr<GPUShader> D3D12Device::CreateShaderFromSource(GPUShaderStage st
std::string_view source, const char* entry_point,
DynamicHeapArray<u8>* out_binary, Error* error)
{
const u32 shader_model = D3DCommon::GetShaderModelForFeatureLevel(m_feature_level);
const u32 shader_model = D3DCommon::GetShaderModelForFeatureLevelNumber(m_render_api_version);
if (language != GPUShaderLanguage::HLSL)
{
return TranspileAndCreateShaderFromSource(stage, language, source, entry_point, GPUShaderLanguage::HLSL,
Expand Down
101 changes: 51 additions & 50 deletions src/util/d3d_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,47 +19,65 @@

Log_SetChannel(D3DCommon);

const char* D3DCommon::GetFeatureLevelString(D3D_FEATURE_LEVEL feature_level)
namespace D3DCommon {
namespace {
struct FeatureLevelTableEntry
{
static constexpr std::array<std::tuple<D3D_FEATURE_LEVEL, const char*>, 11> feature_level_names = {{
{D3D_FEATURE_LEVEL_1_0_CORE, "D3D_FEATURE_LEVEL_1_0_CORE"},
{D3D_FEATURE_LEVEL_9_1, "D3D_FEATURE_LEVEL_9_1"},
{D3D_FEATURE_LEVEL_9_2, "D3D_FEATURE_LEVEL_9_2"},
{D3D_FEATURE_LEVEL_9_3, "D3D_FEATURE_LEVEL_9_3"},
{D3D_FEATURE_LEVEL_10_0, "D3D_FEATURE_LEVEL_10_0"},
{D3D_FEATURE_LEVEL_10_1, "D3D_FEATURE_LEVEL_10_1"},
{D3D_FEATURE_LEVEL_11_0, "D3D_FEATURE_LEVEL_11_0"},
{D3D_FEATURE_LEVEL_11_1, "D3D_FEATURE_LEVEL_11_1"},
{D3D_FEATURE_LEVEL_12_0, "D3D_FEATURE_LEVEL_12_0"},
{D3D_FEATURE_LEVEL_12_1, "D3D_FEATURE_LEVEL_12_1"},
{D3D_FEATURE_LEVEL_12_2, "D3D_FEATURE_LEVEL_12_2"},
}};
D3D_FEATURE_LEVEL d3d_feature_level;
u16 render_api_version;
u16 shader_model_number;
const char* feature_level_str;
};
} // namespace

static constexpr std::array<FeatureLevelTableEntry, 11> s_feature_levels = {{
{D3D_FEATURE_LEVEL_1_0_CORE, 100, 40, "D3D_FEATURE_LEVEL_1_0_CORE"},
{D3D_FEATURE_LEVEL_9_1, 910, 40, "D3D_FEATURE_LEVEL_9_1"},
{D3D_FEATURE_LEVEL_9_2, 920, 40, "D3D_FEATURE_LEVEL_9_2"},
{D3D_FEATURE_LEVEL_9_3, 930, 40, "D3D_FEATURE_LEVEL_9_3"},
{D3D_FEATURE_LEVEL_10_0, 1000, 40, "D3D_FEATURE_LEVEL_10_0"},
{D3D_FEATURE_LEVEL_10_1, 1010, 41, "D3D_FEATURE_LEVEL_10_1"},
{D3D_FEATURE_LEVEL_11_0, 1100, 50, "D3D_FEATURE_LEVEL_11_0"},
{D3D_FEATURE_LEVEL_11_1, 1110, 50, "D3D_FEATURE_LEVEL_11_1"},
{D3D_FEATURE_LEVEL_12_0, 1200, 50, "D3D_FEATURE_LEVEL_12_0"},
{D3D_FEATURE_LEVEL_12_1, 1210, 50, "D3D_FEATURE_LEVEL_12_1"},
{D3D_FEATURE_LEVEL_12_2, 1220, 50, "D3D_FEATURE_LEVEL_12_2"},
}};
} // namespace D3DCommon

const char* D3DCommon::GetFeatureLevelString(u32 render_api_version)
{
const auto iter =
std::find_if(s_feature_levels.begin(), s_feature_levels.end(),
[&render_api_version](const auto& it) { return it.render_api_version == render_api_version; });
return (iter != s_feature_levels.end()) ? iter->feature_level_str : "D3D_FEATURE_LEVEL_UNKNOWN";
}

for (const auto& [fl, name] : feature_level_names)
u32 D3DCommon::GetRenderAPIVersionForFeatureLevel(D3D_FEATURE_LEVEL feature_level)
{
const FeatureLevelTableEntry* highest_entry = nullptr;
for (const FeatureLevelTableEntry& entry : s_feature_levels)
{
if (fl == feature_level)
return name;
if (feature_level >= entry.d3d_feature_level)
highest_entry = &entry;
}

return "D3D_FEATURE_LEVEL_UNKNOWN";
return highest_entry ? highest_entry->render_api_version : 0;
}

const char* D3DCommon::GetFeatureLevelShaderModelString(D3D_FEATURE_LEVEL feature_level)
D3D_FEATURE_LEVEL D3DCommon::GetFeatureLevelForNumber(u32 render_api_version)
{
static constexpr std::array<std::tuple<D3D_FEATURE_LEVEL, const char*>, 4> feature_level_names = {{
{D3D_FEATURE_LEVEL_10_0, "sm40"},
{D3D_FEATURE_LEVEL_10_1, "sm41"},
{D3D_FEATURE_LEVEL_11_0, "sm50"},
{D3D_FEATURE_LEVEL_11_1, "sm50"},
}};

for (const auto& [fl, name] : feature_level_names)
{
if (fl == feature_level)
return name;
}
const auto iter =
std::find_if(s_feature_levels.begin(), s_feature_levels.end(),
[&render_api_version](const auto& it) { return it.render_api_version == render_api_version; });
return (iter != s_feature_levels.end()) ? iter->d3d_feature_level : D3D_FEATURE_LEVEL_1_0_CORE;
}

return "unk";
u32 D3DCommon::GetShaderModelForFeatureLevelNumber(u32 render_api_version)
{
const auto iter =
std::find_if(s_feature_levels.begin(), s_feature_levels.end(),
[&render_api_version](const auto& it) { return it.render_api_version == render_api_version; });
return (iter != s_feature_levels.end()) ? iter->shader_model_number : 40;
}

D3D_FEATURE_LEVEL D3DCommon::GetDeviceMaxFeatureLevel(IDXGIAdapter1* adapter)
Expand Down Expand Up @@ -379,23 +397,6 @@ std::string D3DCommon::GetDriverVersionFromLUID(const LUID& luid)
return ret;
}

u32 D3DCommon::GetShaderModelForFeatureLevel(D3D_FEATURE_LEVEL feature_level)
{
switch (feature_level)
{
case D3D_FEATURE_LEVEL_10_0:
return 40;

case D3D_FEATURE_LEVEL_10_1:
return 41;

case D3D_FEATURE_LEVEL_11_0:
case D3D_FEATURE_LEVEL_11_1:
default:
return 50;
}
}

std::optional<DynamicHeapArray<u8>> D3DCommon::CompileShader(u32 shader_model, bool debug_device, GPUShaderStage stage,
std::string_view source, const char* entry_point,
Error* error)
Expand Down
Loading

0 comments on commit 4c31218

Please sign in to comment.